/*
Copyright (C) 2001-2007, The Perl Foundation.
$Id: /mirror/trunk/src/pmc/parrotthread.pmc 28287 2008-06-12T19:34:51.229254Z Whiteknight  $

=head1 NAME

src/pmc/parrotthread.pmc - Threaded Interpreter

=head1 DESCRIPTION

ParrotThread extends ParrotInterpreter to provide a threaded interpreter
which supports:

    new P2, "ParrotThread"        # create new threaded interp
    find_method P0, P2, "thread3" # thread-run function
    find_global P5, "_th1"        # locate thread function
    invoke                        # run thread

    set I0, P2                    # get thread id

and these methods:

    thread1
    thread2
    thread3                   # start thread of type 1..3
    join
    detach
    yield
    kill

=head2 Methods

=over 4

=cut

*/

#include "parrot/parrot.h"
#include "parrot/embed.h"

/*
 * can't do multi-threaded DOD/GC yet
 * XXX a quick hack to pass the few tests
 */
static void
stop_GC(Interp *parent, Interp *thread)
{
#if 0
    Parrot_block_GC_mark(parent);
    Parrot_block_GC_mark(thread);
    Parrot_block_GC_sweep(parent);
    Parrot_block_GC_sweep(thread);
#endif
}

/* XXX FIXME probably not the best interface [see also list post of
   coke's]
 */

static INTVAL do_thread_run(PARROT_INTERP, PMC *thread,
                            INTVAL clone_flags, PMC *sub, PMC *args) {
    INTVAL tid = VTABLE_get_integer(interp, thread);

    clone_interpreter(PMC_data_typed(thread, Parrot_Interp),
                      interp, clone_flags);

    interp->flags &= ~PARROT_THR_COPY_INTERP; /* XXX */
    pt_thread_run(interp, thread, sub, args);

    pmc_reuse(interp, thread, enum_class_ParrotRunningThread, 0);

    PObj_active_destroy_CLEAR(thread);
    PObj_custom_mark_CLEAR(thread);
    PMC_int_val(thread) = tid;

    return tid;
}

static INTVAL do_thread_run_clone_default(PARROT_INTERP,
                                          PMC *thread, PMC *sub, PMC *args) {
    return do_thread_run(interp, thread, PARROT_CLONE_DEFAULT, sub, args);
}


pmclass ParrotThread extends ParrotInterpreter need_ext no_ro {

/*

=item C<thread_id = thread.'run'(CLONE_FLAGS, sub, args...)>

Run the thread. This object is morphed into an appropriate
ParrotRunningThread PMC.  The CLONE_FLAGS are or'd together values
taken from C<cloneflags.pasm>.

=item C<thread_id = thread.'run_clone'(sub, args...)>

Equivalent to calling run with PARROT_CLONE_DEFAULT.

=cut

*/

    void class_init() {
        const int typ = enum_class_ParrotThread;

        if (pass) {
            register_nci_method(INTERP, typ,
                    F2DPTR(do_thread_run), "run", "IJOIP@");

            /* XXX appropriate name given that this won't clone globals? */
            register_nci_method(INTERP, typ,
                    F2DPTR(do_thread_run_clone_default), "run_clone", "IJOP@");
        }
    }

/*

=item C<void init()>

Initializes the thread.

=cut

*/

    VTABLE void init() {
        /* protect interpreter creation and list handling */
        LOCK(interpreter_array_mutex);

        SUPER();
        pt_add_to_interpreters(INTERP, PMC_data_typed(SELF, Parrot_Interp));

        UNLOCK(interpreter_array_mutex);

        /* can't allow DOD runs for now */
        stop_GC(INTERP, PMC_data_typed(SELF, Parrot_Interp));
    }

/*

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

Create a new thread by cloning the passed interpreter.

=cut

*/

    VTABLE void init_pmc(PMC *parent) {
        LOCK(interpreter_array_mutex);
        SUPER(parent);

        pt_add_to_interpreters(PMC_data_typed(parent, Parrot_Interp),
                               PMC_data_typed(SELF,   Parrot_Interp));

        UNLOCK(interpreter_array_mutex);

        /* can't allow DOD runs for now */
        stop_GC(INTERP, PMC_data_typed(SELF, Parrot_Interp));
    }
}

/*

=back

=head1 HISTORY

2003.12.18 leo initial review.

=cut

*/

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