[svn:parrot] r48156 - in branches/gsoc_threads: include/parrot include/parrot/oplib src src/ops src/pmc t/pmc

Chandon at svn.parrot.org Chandon at svn.parrot.org
Wed Jul 21 04:28:22 UTC 2010


Author: Chandon
Date: Wed Jul 21 04:28:22 2010
New Revision: 48156
URL: https://trac.parrot.org/parrot/changeset/48156

Log:
[gsoc_threads] More green threads API.

Modified:
   branches/gsoc_threads/include/parrot/oplib/core_ops.h
   branches/gsoc_threads/include/parrot/oplib/ops.h
   branches/gsoc_threads/include/parrot/opsenum.h
   branches/gsoc_threads/include/parrot/scheduler_private.h
   branches/gsoc_threads/src/ops/core_ops.c
   branches/gsoc_threads/src/ops/experimental.ops
   branches/gsoc_threads/src/pmc/scheduler.pmc
   branches/gsoc_threads/src/pmc/task.pmc
   branches/gsoc_threads/src/scheduler.c
   branches/gsoc_threads/t/pmc/task.t

Modified: branches/gsoc_threads/include/parrot/oplib/core_ops.h
==============================================================================
--- branches/gsoc_threads/include/parrot/oplib/core_ops.h	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/include/parrot/oplib/core_ops.h	Wed Jul 21 04:28:22 2010	(r48156)
@@ -1108,6 +1108,7 @@
  opcode_t * Parrot_recv_p(opcode_t *, PARROT_INTERP);
  opcode_t * Parrot_wait_p(opcode_t *, PARROT_INTERP);
  opcode_t * Parrot_wait_pc(opcode_t *, PARROT_INTERP);
+ opcode_t * Parrot_pass(opcode_t *, PARROT_INTERP);
 
 
 #endif /* PARROT_OPLIB_CORE_OPS_H_GUARD */

Modified: branches/gsoc_threads/include/parrot/oplib/ops.h
==============================================================================
--- branches/gsoc_threads/include/parrot/oplib/ops.h	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/include/parrot/oplib/ops.h	Wed Jul 21 04:28:22 2010	(r48156)
@@ -1102,7 +1102,8 @@
     PARROT_OP_finalize_pc,                     /* 1082 */
     PARROT_OP_recv_p,                          /* 1083 */
     PARROT_OP_wait_p,                          /* 1084 */
-    PARROT_OP_wait_pc                          /* 1085 */
+    PARROT_OP_wait_pc,                         /* 1085 */
+    PARROT_OP_pass                             /* 1086 */
 
 } parrot_opcode_enums;
 

Modified: branches/gsoc_threads/include/parrot/opsenum.h
==============================================================================
--- branches/gsoc_threads/include/parrot/opsenum.h	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/include/parrot/opsenum.h	Wed Jul 21 04:28:22 2010	(r48156)
@@ -1102,6 +1102,7 @@
     enum_ops_recv_p                        = 1083,
     enum_ops_wait_p                        = 1084,
     enum_ops_wait_pc                       = 1085,
+    enum_ops_pass                          = 1086,
 };
 
 

Modified: branches/gsoc_threads/include/parrot/scheduler_private.h
==============================================================================
--- branches/gsoc_threads/include/parrot/scheduler_private.h	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/include/parrot/scheduler_private.h	Wed Jul 21 04:28:22 2010	(r48156)
@@ -47,12 +47,11 @@
 /*
  * Task private flags
  *
- * in_preempt - This flag is set if the runloop is ending because the current
- *              task has been pre-empted. When the runloop ends because a task
- *              is done, this flag is not set.
  */
 typedef enum {
-    TASK_in_preempt_FLAG = PObj_private0_FLAG
+    TASK_active_FLAG     = PObj_private0_FLAG,
+    TASK_in_preempt_FLAG = PObj_private1_FLAG,
+    TASK_recv_block_FLAG = PObj_private2_FLAG
 } task_flags_enum;
 
 #define TASK_get_FLAGS(o) (PObj_get_FLAGS(o))
@@ -60,11 +59,23 @@
 #define TASK_flag_SET(flag, o) (TASK_get_FLAGS(o) |= TASK_ ## flag ## _FLAG)
 #define TASK_flag_CLEAR(flag, o) (TASK_get_FLAGS(o) &= ~(UINTVAL)(TASK_ ## flag ## _FLAG))
 
-/* Mark a task to terminate the scheduler runloop */
+/* Flag is set if the task has been started and has not finished */
+#define TASK_active_TEST(o)  TASK_flag_TEST(active, o)
+#define TASK_active_SET(o)   TASK_flag_SET(active, o)
+#define TASK_active_CLEAR(o) TASK_flag_CLEAR(active, o)
+
+/* Flag is set iff the runloop is ending because the current task has
+ * been pre-empted but is not yet done running */
 #define TASK_in_preempt_TEST(o)  TASK_flag_TEST(in_preempt, o)
 #define TASK_in_preempt_SET(o)   TASK_flag_SET(in_preempt, o)
 #define TASK_in_preempt_CLEAR(o) TASK_flag_CLEAR(in_preempt, o)
 
+/* Flag is set if the task is blocked in a recv call. */
+#define TASK_recv_block_TEST(o)  TASK_flag_TEST(recv_block, o)
+#define TASK_recv_block_SET(o)   TASK_flag_SET(recv_block, o)
+#define TASK_recv_block_CLEAR(o) TASK_flag_CLEAR(recv_block, o)
+
+
 #endif /* PARROT_SCHEDULER_PRIVATE_H_GUARD */
 
 /*

Modified: branches/gsoc_threads/src/ops/core_ops.c
==============================================================================
--- branches/gsoc_threads/src/ops/core_ops.c	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/src/ops/core_ops.c	Wed Jul 21 04:28:22 2010	(r48156)
@@ -62,17 +62,18 @@
 #  include <unicode/uchar.h>
 #endif
 
+#include "parrot/scheduler_private.h"
 #include "pmc/pmc_task.h"
 
 
 
-INTVAL core_numops = 1087;
+INTVAL core_numops = 1088;
 
 /*
 ** Op Function Table:
 */
 
-static op_func_t core_op_func_table[1087] = {
+static op_func_t core_op_func_table[1088] = {
   Parrot_end,                                        /*      0 */
   Parrot_noop,                                       /*      1 */
   Parrot_check_events,                               /*      2 */
@@ -1159,6 +1160,7 @@
   Parrot_recv_p,                                     /*   1083 */
   Parrot_wait_p,                                     /*   1084 */
   Parrot_wait_pc,                                    /*   1085 */
+  Parrot_pass,                                       /*   1086 */
 
   NULL /* NULL function pointer */
 };
@@ -1169,7 +1171,7 @@
 ** Op Info Table:
 */
 
-static op_info_t core_op_info_table[1087] = {
+static op_info_t core_op_info_table[1088] = {
   { /* 0 */
     /* type PARROT_INLINE_OP, */
     "end",
@@ -14202,6 +14204,18 @@
     { PARROT_ARGDIR_IN },
     { 0 }
   },
+  { /* 1086 */
+    /* type PARROT_FUNCTION_OP, */
+    "pass",
+    "pass",
+    "Parrot_pass",
+    /* "",  body */
+    0,
+    1,
+    { (arg_type_t) 0 },
+    { (arg_dir_t) 0 },
+    { 0 }
+  },
 
 };
 
@@ -25056,7 +25070,17 @@
 Parrot_recv_p(opcode_t *cur_opcode, PARROT_INTERP)  {
     const Parrot_Context * const CUR_CTX = Parrot_pcc_get_context_struct(interp, interp->ctx);
     opcode_t *const dest = cur_opcode + 2;
-    PREG(1) = PMCNULL;
+    PMC *cur_task = interp->current_task;
+    Parrot_Task_attributes *tdata = PARROT_TASK(cur_task);
+    int msg_count = VTABLE_get_integer(interp, tdata->mailbox);
+
+    if (msg_count > 0) {
+        PREG(1) = VTABLE_shift_pmc(interp, tdata->mailbox);return (opcode_t *)dest;
+    }
+    else {
+        TASK_recv_block_SET(interp->current_task);
+        (void) Parrot_cx_stop_task(interp, cur_opcode);return (opcode_t *)0;
+    }
 
 return (opcode_t *)cur_opcode + 2;}
 
@@ -25096,6 +25120,14 @@
 
 return (opcode_t *)cur_opcode + 2;}
 
+opcode_t *
+Parrot_pass(opcode_t *cur_opcode, PARROT_INTERP)  {
+    const Parrot_Context * const CUR_CTX = Parrot_pcc_get_context_struct(interp, interp->ctx);
+    opcode_t *const next = cur_opcode + 1;
+    opcode_t *const addr = Parrot_cx_preempt_task(interp, interp->scheduler, next);return (opcode_t *)addr;
+
+return (opcode_t *)cur_opcode + 1;}
+
 
 /*
 ** op lib descriptor:
@@ -25109,7 +25141,7 @@
   2,    /* major_version */
   5,    /* minor_version */
   0,    /* patch_version */
-  1086,             /* op_count */
+  1087,             /* op_count */
   core_op_info_table,       /* op_info_table */
   core_op_func_table,       /* op_func_table */
   get_op          /* op_code() */ 

Modified: branches/gsoc_threads/src/ops/experimental.ops
==============================================================================
--- branches/gsoc_threads/src/ops/experimental.ops	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/src/ops/experimental.ops	Wed Jul 21 04:28:22 2010	(r48156)
@@ -9,6 +9,7 @@
 #  include <unicode/uchar.h>
 #endif
 
+#include "parrot/scheduler_private.h"
 #include "pmc/pmc_task.h"
 
 END_OPS_PREAMBLE
@@ -420,11 +421,25 @@
 
 Recieve a message sent to the current task.
 
+If there is no waiting message, block and wait.
+
 =cut
 
 op recv(out PMC) {
     opcode_t *const dest = expr NEXT();
-    $1 = PMCNULL;
+    PMC *cur_task = interp->current_task;
+    Parrot_Task_attributes *tdata = PARROT_TASK(cur_task);
+    int msg_count = VTABLE_get_integer(interp, tdata->mailbox);
+
+    if (msg_count > 0) {
+        $1 = VTABLE_shift_pmc(interp, tdata->mailbox);
+        goto ADDRESS(dest);
+    }
+    else {
+        TASK_recv_block_SET(interp->current_task);
+        (void) Parrot_cx_stop_task(interp, cur_opcode);
+        goto ADDRESS(0);
+    }
 }
 
 =item B<wait>(in PMC)
@@ -450,6 +465,20 @@
     goto ADDRESS(0);
 }
 
+=item B<pass>()
+
+Pass the rest of the current quantum and schedule the next
+task in the task queue.
+
+=cut
+
+op pass() {
+    opcode_t *const next = expr NEXT();
+    opcode_t *const addr = Parrot_cx_preempt_task(interp, interp->scheduler, next);
+    goto ADDRESS(addr);
+}
+
+
 =back
 
 =head1 COPYRIGHT

Modified: branches/gsoc_threads/src/pmc/scheduler.pmc
==============================================================================
--- branches/gsoc_threads/src/pmc/scheduler.pmc	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/src/pmc/scheduler.pmc	Wed Jul 21 04:28:22 2010	(r48156)
@@ -25,7 +25,6 @@
 /* HEADERIZER END: static */
 
 pmclass Scheduler auto_attrs {
-
     ATTR INTVAL        id;           /* The scheduler's ID. */
     ATTR PMC          *handlers;     /* The list of currently active handlers. */
     ATTR PMC          *messages;     /* A message queue used for communication
@@ -34,6 +33,9 @@
     ATTR PMC          *task_queue;   /* List of tasks/green threads waiting to run */
     ATTR PMC          *alarms;       /* List of future alarms ordered by time */
 
+    ATTR PMC          *all_tasks;    /* Hash of all active tasks by ID */
+    ATTR UINTVAL       next_task_id; /* ID to assign to the next created task */
+
     ATTR Parrot_mutex  msg_lock;     /* Lock to synchronize the message queue. */
     ATTR Parrot_Interp interp;       /* A link to the scheduler's interpreter. */
 
@@ -56,13 +58,19 @@
         PObj_custom_destroy_SET(SELF);
 
         /* Set up the core struct. */
-        core_struct->id          = 0;
-        core_struct->handlers    = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
-        core_struct->messages    = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
-        core_struct->task_queue  = Parrot_pmc_new(INTERP, enum_class_PMCList);
-        core_struct->alarms      = Parrot_pmc_new(INTERP, enum_class_PMCList);
-        core_struct->interp      = INTERP;
+        core_struct->id           = 0;
+        core_struct->handlers     = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
+        core_struct->messages     = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
+        core_struct->task_queue   = Parrot_pmc_new(INTERP, enum_class_PMCList);
+        core_struct->alarms       = Parrot_pmc_new(INTERP, enum_class_PMCList);
+        core_struct->all_tasks    = Parrot_pmc_new(INTERP, enum_class_Hash);
+        core_struct->next_task_id = 0;
+        core_struct->interp       = INTERP;
         MUTEX_INIT(core_struct->msg_lock);
+
+        /* Chandon TODO: Delete from int-keyed hash doesn't like me. */
+        /* VTABLE_set_integer_native(interp, core_struct->all_tasks, Hash_key_type_int); */
+
     }
 
 
@@ -101,7 +109,6 @@
             core_struct->id = VTABLE_get_integer(INTERP, elem);
     }
 
-
 /*
 
 =item C<void push_pmc(PMC *value)>
@@ -246,6 +253,7 @@
             Parrot_gc_mark_PMC_alive(INTERP, core_struct->messages);
             Parrot_gc_mark_PMC_alive(INTERP, core_struct->task_queue);
             Parrot_gc_mark_PMC_alive(INTERP, core_struct->alarms);
+            Parrot_gc_mark_PMC_alive(INTERP, core_struct->all_tasks);
        }
     }
 
@@ -271,6 +279,9 @@
 
         /* 3) visit the alarms */
         VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, alarms);
+
+        /* 3) visit all tasks */
+        VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, all_tasks);
     }
 
 
@@ -342,6 +353,33 @@
 
 /*
 
+=item C<METHOD active_tasks()>
+
+Returns a ResizablePMCArray containing pointers to all active tasks.
+
+=cut
+
+*/
+
+    METHOD active_tasks() {
+        Parrot_Scheduler_attributes *sdata = PARROT_SCHEDULER(SELF);
+        PMC *tasks = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
+        PMC *iter  = Parrot_pmc_new_init(interp, enum_class_HashIterator, sdata->all_tasks);
+
+        while (!VTABLE_get_bool(interp, iter)) {
+            PMC *pair = VTABLE_shift_pmc(interp, iter);
+            PMC *task;
+            STRING *value = CONST_STRING(interp, "value");
+            Parrot_pcc_invoke_method_from_c_args(interp, pair,
+                value, "->P", task);
+            VTABLE_push_pmc(interp, tasks, task);
+        }
+
+        RETURN(PMC* tasks);
+    }
+
+/*
+
 =item C<METHOD add_handler(PMC *handler)>
 
 Adds a handler to the scheduler.

Modified: branches/gsoc_threads/src/pmc/task.pmc
==============================================================================
--- branches/gsoc_threads/src/pmc/task.pmc	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/src/pmc/task.pmc	Wed Jul 21 04:28:22 2010	(r48156)
@@ -19,19 +19,21 @@
 */
 
 #include "parrot/scheduler_private.h"
+#include "pmc/pmc_scheduler.h"
 
 /* HEADERIZER HFILE: none */
 /* HEADERIZER BEGIN: static */
 /* HEADERIZER END: static */
 
 pmclass Task provides invokable auto_attrs {
-    ATTR FLOATVAL      birthtime; /* The creation time stamp of the task. */
-    ATTR Parrot_Interp interp;    /* The interpreter that created the task. */
-    ATTR PMC          *code;      /* An (optional) code for the task. */
-    ATTR PMC          *data;      /* Additional data for the task. */
-    ATTR INTVAL        killed;    /* Dead tasks don't get run. */
-    ATTR PMC          *mailbox;   /* List of incoming messages. */
-    ATTR PMC          *waiters;   /* Tasks waiting on this one. */
+    ATTR UINTVAL       id;        /* Unique identifier for this task */
+    ATTR FLOATVAL      birthtime; /* The creation time stamp of the task */
+    ATTR Parrot_Interp interp;    /* The interpreter that created the task */
+    ATTR PMC          *code;      /* An (optional) code for the task */
+    ATTR PMC          *data;      /* Additional data for the task */
+    ATTR INTVAL        killed;    /* Dead tasks don't get run */
+    ATTR PMC          *mailbox;   /* List of incoming messages */
+    ATTR PMC          *waiters;   /* Tasks waiting on this one */
 
 /*
 
@@ -44,7 +46,8 @@
 */
 
     VTABLE void init() {
-        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
+        Parrot_Task_attributes *const core_struct = PARROT_TASK(SELF);
+        Parrot_Scheduler_attributes  *sched_data  = PARROT_SCHEDULER(interp->scheduler);
 
         /* Set flags for custom GC mark. */
         PObj_custom_mark_SET(SELF);
@@ -58,8 +61,15 @@
         core_struct->mailbox   = Parrot_pmc_new(interp, enum_class_PMCList);
         core_struct->waiters   = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
 
-        /* By default, a task is not being pre-empted */
+        /* Assign a unique ID */
+        /* TODO: Fix collisions. */
+        core_struct->id = sched_data->next_task_id;
+        sched_data->next_task_id += 1;
+
+        /* By default, all flags are clear. */
+        TASK_active_CLEAR(SELF);
         TASK_in_preempt_CLEAR(SELF);
+        TASK_recv_block_CLEAR(SELF);
     }
 
 /*
@@ -130,12 +140,21 @@
 */
 
     VTABLE opcode_t *invoke(void *next) {
-        Parrot_Task_attributes *const task = PARROT_TASK(SELF);
+        Parrot_Task_attributes *const task  = PARROT_TASK(SELF);
+        Parrot_Scheduler_attributes  *sdata = PARROT_SCHEDULER(interp->scheduler);
+        PMC *active_tasks = sdata->all_tasks;
 
         /* If a task is pre-empted, this will be set again. */
         TASK_in_preempt_CLEAR(SELF);
 
         if (!(task->killed || PMC_IS_NULL(task->code))) {
+            /* Add the task to the set of active Tasks */
+            PMC *task_id = Parrot_pmc_new(interp, enum_class_Integer);
+            VTABLE_set_integer_native(interp, task_id, task->id);
+            VTABLE_set_pmc_keyed(interp, active_tasks, task_id, SELF);
+            TASK_active_SET(SELF);
+
+            /* Actually run the task */
             if (PMC_IS_NULL(task->data)) {
                 Parrot_pcc_invoke_sub_from_c_args(interp, task->code, "->");
             }
@@ -145,9 +164,17 @@
         }
 
         if (!TASK_in_preempt_TEST(SELF)) {
-            /* The task is done, schedule any waiters. */
-            int i;
-            int n = VTABLE_get_integer(interp, task->waiters);
+            /* The task is done. */
+            /* Remove it from the set of active Tasks */
+
+            int i, n;
+            PMC *task_id = Parrot_pmc_new(interp, enum_class_Integer);
+            VTABLE_set_integer_native(interp, task_id, task->id);
+            TASK_active_CLEAR(SELF);
+            VTABLE_delete_keyed(interp, active_tasks, task_id);
+
+            /* schedule any waiters. */
+            n = VTABLE_get_integer(interp, task->waiters);
 
             for (i = 0; i < n; ++i) {
                 PMC *wtask = VTABLE_get_pmc_keyed_int(interp, task->waiters, i);
@@ -377,6 +404,11 @@
     METHOD send(PMC *message) {
         Parrot_Task_attributes *tdata = PARROT_TASK(SELF);
         VTABLE_push_pmc(interp, tdata->mailbox, message);
+
+        if (TASK_recv_block_TEST(SELF)) {
+            TASK_recv_block_CLEAR(SELF);
+            Parrot_cx_schedule_task(interp, SELF);
+        }
     }
 
 /*

Modified: branches/gsoc_threads/src/scheduler.c
==============================================================================
--- branches/gsoc_threads/src/scheduler.c	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/src/scheduler.c	Wed Jul 21 04:28:22 2010	(r48156)
@@ -104,7 +104,7 @@
     ASSERT_ARGS(Parrot_cx_begin_execution)
     PMC *scheduler = interp->scheduler;
     Parrot_Scheduler_attributes *sched = PARROT_SCHEDULER(scheduler);
-    INTVAL task_count = 1;
+    INTVAL task_count  = 1;
 
     PMC* main_task = Parrot_pmc_new(interp, enum_class_Task);
     Parrot_Task_attributes *tdata = PARROT_TASK(main_task);
@@ -135,6 +135,11 @@
             }
         }
     } while (task_count > 0);
+
+    task_count = VTABLE_get_integer(interp, sched->all_tasks);
+    if (task_count > 0)
+        Parrot_warn(interp, PARROT_WARNINGS_ALL_FLAG,
+                    "Exiting with %d active tasks.\n", task_count);
 }
 
 

Modified: branches/gsoc_threads/t/pmc/task.t
==============================================================================
--- branches/gsoc_threads/t/pmc/task.t	Wed Jul 21 03:56:41 2010	(r48155)
+++ branches/gsoc_threads/t/pmc/task.t	Wed Jul 21 04:28:22 2010	(r48156)
@@ -5,19 +5,13 @@
 .sub main
     .include 'test_more.pir'
 
-    plan(9)
+    plan(10)
 
     tasks_run_in_order()
     task_send_recv()
     task_kill()
     task_wait()
-
-    $P0 = get_global 'exit0'
-    $P1 = new 'Task', $P0
-    schedule $P1
-
-again:
-    goto again
+    preempt_and_exit()
 .end
 
 .sub tasks_run_in_order
@@ -48,7 +42,7 @@
 
 .sub sub1
     $P0 = get_global 'N'
-    is($P0, 1, "Implicit task ran in order (2)")
+    is($P0, 1, "Implicit task ran in order (1)")
 
     $P0 = 2
     set_global 'N', $P0
@@ -56,26 +50,56 @@
 
 .sub task2
     $P0 = get_global 'N'
-    is($P0, 2, "Task ran in order (3)")
+    is($P0, 2, "Task ran in order (2)")
 
     $P0 = 3
     set_global 'N', $P0
 .end
 
 .sub task_send_recv
-    $P0 = get_global 'recv_msg'
+    $P0 = get_global 'recv_msg1'
+    $P1 = new 'Task', $P0
+    schedule $P1
+    pass
+
+    $P2 = new 'String'
+    $P2 = "Hai 1"
+
+    $P1.'send'($P2)
+
+    wait $P1
+
+    $P0 = get_global 'recv_msg2'
     $P1 = new 'Task', $P0
+
     $P2 = new 'String'
-    $P2 = "Hai"
+    $P2 = "Hai 2"
     $P1.'send'($P2)
+
     schedule $P1
+
+    wait $P1
+.end
+
+.sub recv_msg1
+    $P0 = recv
+    $P1 = new 'String'
+    $P1 = "Hai 1"
+    is($P0, $P1, "Got message after block")
+.end
+
+.sub recv_msg2
+    $P0 = recv
+    $P1 = new 'String'
+    $P1 = "Hai 2"
+    is($P0, $P1, "Got existing message")
 .end
 
 .sub task_kill
     $P0 = get_global 'task_to_kill'
     $P1 = new 'Task', $P0
     schedule $P1
-    sleep 0.001
+    pass
     $P1.'kill'()
     sleep 0.1
     ok(1, "task_to_kill killed")
@@ -87,14 +111,6 @@
     ok(0, "task_to_kill wasn't killed")
 .end
 
-.sub recv_msg
-    $P0 = recv
-    $P1 = new 'String'
-    $P1 = "Hai"
-#is($P0, $P1, "Got message")
-    skip("Chandon TODO: Message Passing")
-.end
-
 .sub task_wait
     $P0 = get_global 'wait_sub1'
     $P1 = new 'Task', $P0
@@ -108,6 +124,15 @@
     ok(1, "in wait_sub1")
 .end
 
+.sub preempt_and_exit
+    $P0 = get_global 'exit0'
+    $P1 = new 'Task', $P0
+    schedule $P1
+
+again:
+    goto again
+.end
+
 .sub exit0
     ok(1, "Pre-empt and exit")
     exit 0


More information about the parrot-commits mailing list