/*
Copyright (C) 2001-2008, Parrot Foundation.
$Id: task.pmc 46300 2010-05-05 03:58:50Z jimmy $

=head1 NAME

src/pmc/task.pmc - A concurrent task

=head1 DESCRIPTION

Implements the basic task behavior for the concurrency scheduler.

=head2 Functions

=over 4

=cut

*/

#include "parrot/scheduler_private.h"

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */

pmclass Task auto_attrs {
    ATTR INTVAL        id;        /* The task ID. */
    ATTR INTVAL        priority;  /* The priority of the task. */
    ATTR FLOATVAL      birthtime; /* The creation time stamp of the task. */
    ATTR STRING       *type;      /* The type of the task. */
    ATTR STRING       *subtype;   /* The subtype of the task. */
    ATTR STRING       *status;    /* The status of the task. */
    ATTR Parrot_Interp interp;    /* The interpreter that created the task. */
    ATTR PMC          *codeblock; /* An (optional) codeblock for the task. */
    ATTR PMC          *data;      /* Additional data for the task. */
    ATTR char         *cb_data;   /* Additional data for a callback event. */

/*

=item C<void init()>

Initialize a concurrency task object.

=cut

*/

    VTABLE void init() {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);

        /* Set flags for custom GC mark. */
        PObj_custom_mark_SET(SELF);

        /* Set up the core struct. */
        core_struct->id          = 0;
        core_struct->type        = CONST_STRING(INTERP, "");
        core_struct->subtype     = CONST_STRING(INTERP, "");
        core_struct->priority    = 0;
        core_struct->status      = CONST_STRING(INTERP, "created");
        core_struct->birthtime   = 0.0;
        core_struct->codeblock   = PMCNULL;
        core_struct->data        = PMCNULL;
        core_struct->interp      = INTERP;

        /* Make sure the flag is cleared by default */
        TASK_terminate_runloop_CLEAR(SELF);

    }

/*

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

Initializes a new Task with a C<Hash> PMC with any or all of the keys:

=over 4

=item C<id>

An C<Integer> representing the task's unique identifier.

=item C<type>

A C<String> representing the type of the task.

=item C<subtype>

A C<String> representing the subtype of the task. (Used mostly by events and
exceptions to identify appropriate handlers.)

=item C<priority>

An C<Integer> representing the task's priority, from 0 to 100.

=item C<status>

A C<String> representing the task's status, one of C<created>, C<invoked>,
C<inprocess>, or C<completed>.

=item C<birthtime>

The time at which this Task was inserted into the task list.

=item C<code>

A C<Sub> or descendant PMC related to this task.

=item C<interp>

An interpreter in which to execute this task.

=back

=cut

*/

    VTABLE void init_pmc(PMC *data) {
        PMC         *elem;
        Parrot_Task_attributes *core_struct;

        if (! VTABLE_isa(INTERP, data, CONST_STRING(INTERP, "Hash")))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "Task initializer must be a Hash");

        core_struct = (Parrot_Task_attributes *) PMC_data(SELF);

        /* Set flags for custom GC mark. */
        PObj_custom_mark_SET(SELF);

        /* Set up the core struct. */

        elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "id"));
        if (! PMC_IS_NULL(elem))
            core_struct->id = VTABLE_get_integer(INTERP, elem);
        else
            core_struct->id = 0;

        elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "type"));
        if (! PMC_IS_NULL(elem))
            core_struct->type = VTABLE_get_string(INTERP, elem);
        else
            core_struct->type = CONST_STRING(INTERP, "");

        elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "subtype"));
        if (! PMC_IS_NULL(elem))
            core_struct->subtype = VTABLE_get_string(INTERP, elem);
        else
            core_struct->subtype = CONST_STRING(INTERP, "");

        elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "priority"));
        if (! PMC_IS_NULL(elem))
            core_struct->priority = VTABLE_get_integer(INTERP, elem);
        else
            core_struct->priority = 0;

        elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "status"));
        if (! PMC_IS_NULL(elem))
            core_struct->status = VTABLE_get_string(INTERP, elem);
        else
            core_struct->status = CONST_STRING(INTERP, "created");

        elem = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "birthtime"));
        if (! PMC_IS_NULL(elem))
            core_struct->birthtime = VTABLE_get_number(INTERP, elem);
        else
            core_struct->birthtime = 0.0;

        core_struct->codeblock = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "code"));
        core_struct->interp = (Parrot_Interp)VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "data"));
    }

/*

=item C<PMC *clone()>

Create a copy of the task, resetting status, ID, and birthtime.

=cut

*/

    VTABLE PMC *clone() {
        /* Create the new task PMC, of the same type of this one (we may
         * have been subclassed). */
        PMC * const copy  = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
        Parrot_Task_attributes * const new_struct = PARROT_TASK(copy);
        Parrot_Task_attributes * const old_struct = PARROT_TASK(SELF);

        new_struct->codeblock = VTABLE_clone(INTERP, old_struct->codeblock);
        new_struct->data      = old_struct->data;
        new_struct->type      = old_struct->type;
        new_struct->subtype   = old_struct->subtype;
        new_struct->priority  = old_struct->priority;

        return copy;
    }
/*

=item C<PMC *get_attr_str(STRING *name)>

Gets the value of an attribute for this task.

=cut

*/
    VTABLE PMC *get_attr_str(STRING *name) {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
        PMC *value;

        if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "id"))) {
            value = Parrot_pmc_new_init_int(INTERP, enum_class_Integer,
                    core_struct->id);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "type"))) {
            value = Parrot_pmc_new(INTERP, enum_class_String);
            VTABLE_set_string_native(INTERP, value, core_struct->type);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "subtype"))) {
            value = Parrot_pmc_new(INTERP, enum_class_String);
            VTABLE_set_string_native(INTERP, value, core_struct->subtype);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "priority"))) {
            value = Parrot_pmc_new_init_int(INTERP, enum_class_Integer,
                    core_struct->priority);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "status"))) {
            value = Parrot_pmc_new(INTERP, enum_class_String);
            VTABLE_set_string_native(INTERP, value, core_struct->status);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "birthtime"))) {
            value = Parrot_pmc_new(INTERP, enum_class_Float);
            VTABLE_set_number_native(INTERP, value, core_struct->birthtime);
        }
        else {
            value = PMCNULL;
        }

        return value;
    }

/*

=item C<void set_attr_str(STRING *name, PMC *value)>

Sets the value of an attribute for this task.

=cut

*/
    VTABLE void set_attr_str(STRING *name, PMC *value) {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);

        if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "id"))) {
            core_struct->id = VTABLE_get_integer(INTERP, value);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "type"))) {
            core_struct->type = VTABLE_get_string(INTERP, value);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "subtype"))) {
            core_struct->subtype = VTABLE_get_string(INTERP, value);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "priority"))) {
            core_struct->priority = VTABLE_get_integer(INTERP, value);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "status"))) {
            core_struct->status = VTABLE_get_string(INTERP, value);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "birthtime"))) {
            core_struct->birthtime = VTABLE_get_number(INTERP, value);
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "code"))) {
            core_struct->codeblock = value;
        }
        else if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "data"))) {
            core_struct->data = value;
        }
    }

/*

=item C<INTVAL get_integer()>

Retrieves the task ID for this task.

=cut

*/
    VTABLE INTVAL get_integer() {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
        return core_struct->id;
    }

/*

=item C<void set_integer_native(INTVAL value)>

Sets the task ID of the task.

=cut

*/

    VTABLE void set_integer_native(INTVAL value) {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
        core_struct->id = value;
    }

/*

=item C<void set_number_native(FLOATVAL value)>

Sets the birthtime of the task.

=cut

*/

    VTABLE void set_number_native(FLOATVAL value) {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
        core_struct->birthtime = value;
    }

/*

=item C<void set_string_native(STRING *value)>

Sets the type of the task.

=cut

*/

    VTABLE void set_string_native(STRING *value) {
        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
        core_struct->type = value;
    }

/*

=item C<PMC *share_ro()>

Set this PMC as shared.

=cut

*/

    VTABLE PMC *share_ro() {
        PMC *shared_self;
        Parrot_Task_attributes *shared_struct;

        if (PObj_is_PMC_shared_TEST(SELF))
            return SELF;

        shared_self = pt_shared_fixup(INTERP, SELF);
        shared_struct = PARROT_TASK(shared_self);

        if (!PMC_IS_NULL(shared_struct->codeblock))
            shared_struct->codeblock = pt_shared_fixup(INTERP, shared_struct->codeblock);

        if (!PMC_IS_NULL(shared_struct->data))
            shared_struct->data = pt_shared_fixup(INTERP, shared_struct->data);

        return shared_self;
    }

/*

=item C<void mark()>

Mark any referenced strings and PMCs.

=cut

*/
    VTABLE void mark() {
        if (PARROT_TASK(SELF)) {
            Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);

            Parrot_gc_mark_STRING_alive(INTERP, core_struct->type);
            Parrot_gc_mark_STRING_alive(INTERP, core_struct->subtype);
            Parrot_gc_mark_STRING_alive(INTERP, core_struct->status);
            Parrot_gc_mark_PMC_alive(INTERP, core_struct->codeblock);
            Parrot_gc_mark_PMC_alive(INTERP, core_struct->data);
        }
    }

/*

=item C<void visit(PMC *info)>

This is used by freeze/thaw to visit the contents of the task.

C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).

=cut

*/

    VTABLE void visit(PMC *info) {
        /* 1) visit code block */
        VISIT_PMC_ATTR(INTERP, info, SELF, Task, codeblock);
    }

/*

=item C<void freeze(PMC *info)>

Used to archive the task.

=cut

*/

    VTABLE void freeze(PMC *info) {
        const Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);

        /* 1) freeze task id */
        VTABLE_push_integer(INTERP, info, core_struct->id);

        /* 2) freeze task birthtime */
        VTABLE_push_float(INTERP, info, core_struct->birthtime);

        /* 3) freeze task priority */
        VTABLE_push_integer(INTERP, info, core_struct->priority);

        /* 4) freeze task type */
        VTABLE_push_string(INTERP, info, core_struct->type);

        /* 5) freeze task subtype */
        VTABLE_push_string(INTERP, info, core_struct->subtype);

        /* 6) freeze task status */
        VTABLE_push_string(INTERP, info, core_struct->status);
    }

/*

=item C<void thaw(PMC *info)>

Used to unarchive the task.

=cut

*/

    VTABLE void thaw(PMC *info) {
        /* 1. thaw task id */
        const INTVAL id = VTABLE_shift_integer(INTERP, info);

        /* 2. thaw task birthtime */
        const FLOATVAL birthtime = VTABLE_shift_float(INTERP, info);

        /* 3. thaw task priority */
        const INTVAL priority = VTABLE_shift_integer(INTERP, info);

        /* 4. thaw task type */
        STRING * const type = VTABLE_shift_string(INTERP, info);

        /* 5. thaw task subtype */
        STRING * const subtype = VTABLE_shift_string(INTERP, info);

        /* 6. thaw task status */
        STRING * const status = VTABLE_shift_string(INTERP, info);

        /* Allocate the task's core data struct and set custom flags. */
        SELF.init();

        /* Set the task's id to the frozen id */
        PARROT_TASK(SELF)->id = id;

        /* Set the task's birthtime to the frozen birthtime */
        PARROT_TASK(SELF)->birthtime = birthtime;

        /* Set the task's type to the frozen type */
        PARROT_TASK(SELF)->type = type;

        /* Set the task's subtype to the frozen subtype */
        PARROT_TASK(SELF)->subtype = subtype;

        /* Set the task's priority to the frozen priority */
        PARROT_TASK(SELF)->priority = priority;

        /* Set the task's status to the frozen status */
        PARROT_TASK(SELF)->status = status;

    }

/*

=item C<void thawfinish(PMC *info)>

Called after the task has been thawed.

=cut

*/

    VTABLE void thawfinish(PMC *info) {
        Parrot_Task_attributes * core_struct = PARROT_TASK(SELF);

        UNUSED(core_struct); /* TODO: Rebuild the task index. */
    }

}

/*

=back

=head1 SEE ALSO

F<docs/pdds/pdd15_objects.pod>.

=cut

*/

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