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

=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"
#include <assert.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_DOD(parent);
    Parrot_block_DOD(thread);
    Parrot_block_GC(parent);
    Parrot_block_GC(thread);
#endif
}

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

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

    tid = VTABLE_get_integer(interp, thread);
    clone_interpreter(PMC_data(thread), 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(Interp *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() {
        int typ = enum_class_ParrotThread;

        if (pass) {
            enter_nci_method(INTERP, typ,
                    F2DPTR(do_thread_run), "run", "IJOIP@");
            /* XXX appropriate name given that this won't clone globals? */
            enter_nci_method(INTERP, typ,
                    F2DPTR(do_thread_run_clone_default), "run_clone", "IJOP@");
        }
    }

/*

=item C<void init()>

Initializes the thread.

=cut

*/

    void init() {
        /*
         * protect interpreter creation and list handling
         */
        LOCK(interpreter_array_mutex);
        SUPER();
        pt_add_to_interpreters(INTERP, PMC_data(SELF));
        UNLOCK(interpreter_array_mutex);
        /*
         * can't allow DOD runs for now
         */
        stop_GC(INTERP, PMC_data(SELF));
    }

/*

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

Create a new thread by cloning the passed interpreter.

=cut

*/

    void init_pmc(PMC *parent) {
        LOCK(interpreter_array_mutex);
        SUPER(parent);
        pt_add_to_interpreters(PMC_data(parent), PMC_data(SELF));
        UNLOCK(interpreter_array_mutex);
        /*
         * can't allow DOD runs for now
         */
        stop_GC(INTERP, PMC_data(SELF));
    }
}

/*

=back

=head1 HISTORY

2003.12.18 leo initial review.

=cut

*/

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