/*
Copyright (C) 2001-2006, The Perl Foundation.
$Id: sharedref.pmc 16275 2006-12-28 01:20:44Z particle $

=head1 NAME

src/pmc/sharedref.pmc - Shared PMC Reference

=head1 DESCRIPTION

The vtable functions for the SharedRef base class.

This class wraps locking around PMC access.

All methods not present below get a default body autogenerated inside
C<Parrot::Pmc2c>.

Currently all access is locked. When we have a non-copying GC allocator
we can relax that a bit.

=head2 Methods

=over 4

=cut

*/

#include "parrot/parrot.h"

/*
 * TODO we should catch exceptions around these locks
 *      if the vtable meth throws the lock is never unlocked
 */
#define LOCK_PMC(interp, pmc) LOCK(PMC_sync(pmc)->pmc_lock);
#define UNLOCK_PMC(interp, pmc) UNLOCK(PMC_sync(pmc)->pmc_lock);

pmclass SharedRef does ref need_ext is_shared extends Ref {


    void init() {
        SUPER();
    }

/*

=item C<void init_pmc(PMC *init)>

Initialize the shared reference.

TODO - If the PMC we refer to is an aggregate (or has properties) then:

=over 4

=item *

call C<share()> on the aggregate, which calls C<share()> on its contents
- so getting aggregate members only yields shared PMCs

=item *

and unshare the aggregate itself, because we lock on behalf of the
referee

=back

A direct dereference of the C<SharedRef> is currently not enabled so we
shouldn't leak unshared PMCs into different threads.

=cut

*/

    void init_pmc(PMC* initializer) {
        SUPER(initializer);
        PObj_active_destroy_SET(SELF);
    }

/*

=item C<void share()>

We do already sharing - so just ignore.

=cut

*/

    void share() {
    }

/*

=item C<void mark()>

Marks the reference as live.

=cut

*/

    void mark() {
        SUPER();
    }

/*

=item C<void set_pmc(PMC *other)>

Sets the referenced PMC to C<*other>.

=item C<PMC* get_pmc()>

Catch dereferencing. This would unshare the referred PMC.

=cut

*/

    void set_pmc(PMC* other) {
        SUPER(other);
        PObj_active_destroy_SET(SELF);
    }

    PMC* get_pmc() {
        real_exception(INTERP, NULL, E_ReferenceError,
                "deref not allowed");
        return NULL;
    }

/*

=item C<void destroy()>

Destroys the referred object and itself. This probably needs destroy ordering
or at least a detection if the referred PMC is already destroyed.

=cut

*/

    void destroy() {
        PMC * const ref = PMC_pmc_val(SELF);
        if (PObj_active_destroy_TEST(ref))
            VTABLE_destroy(INTERP, ref);
        if (PMC_sync(SELF)->owner != INTERP)
            PANIC("SharedRef destroyed by wrong interpreter");
    }
}

/*

=back

=head1 HISTORY

Initial revision by leo 2004.01.14.

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
