[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