[svn:parrot] r48374 - in branches/gsoc_threads: include/parrot src src/gc src/interp src/io src/pmc src/runcore t/src
Chandon at svn.parrot.org
Chandon at svn.parrot.org
Tue Aug 10 01:10:49 UTC 2010
Author: Chandon
Date: Tue Aug 10 01:10:47 2010
New Revision: 48374
URL: https://trac.parrot.org/parrot/changeset/48374
Log:
[gsoc_threads] Just need a couple less explosions...
Added:
branches/gsoc_threads/t/src/threads_io.t
Modified:
branches/gsoc_threads/include/parrot/alarm.h
branches/gsoc_threads/include/parrot/atomic.h
branches/gsoc_threads/include/parrot/interpreter.h
branches/gsoc_threads/include/parrot/scheduler.h
branches/gsoc_threads/include/parrot/thread.h
branches/gsoc_threads/include/parrot/threads.h
branches/gsoc_threads/src/alarm.c
branches/gsoc_threads/src/exceptions.c
branches/gsoc_threads/src/gc/gc_ms.c
branches/gsoc_threads/src/gc/system.c
branches/gsoc_threads/src/interp/inter_create.c
branches/gsoc_threads/src/io/unix.c
branches/gsoc_threads/src/main.c
branches/gsoc_threads/src/pmc/pmclist.pmc
branches/gsoc_threads/src/runcore/trace.c
branches/gsoc_threads/src/scheduler.c
branches/gsoc_threads/src/threads.c
Modified: branches/gsoc_threads/include/parrot/alarm.h
==============================================================================
--- branches/gsoc_threads/include/parrot/alarm.h Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/include/parrot/alarm.h Tue Aug 10 01:10:47 2010 (r48374)
@@ -18,13 +18,17 @@
void Parrot_alarm_set(FLOATVAL when);
void Parrot_alarm_callback(NULLOK(int sig_number));
+void Parrot_alarm_init(void);
void Parrot_alarm_mask(SHIM_INTERP);
+void Parrot_alarm_now(void);
void Parrot_alarm_unmask(SHIM_INTERP);
#define ASSERT_ARGS_Parrot_alarm_check __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(last_serial))
#define ASSERT_ARGS_Parrot_alarm_set __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_Parrot_alarm_callback __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_Parrot_alarm_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_Parrot_alarm_mask __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_Parrot_alarm_now __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_Parrot_alarm_unmask __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: src/alarm.c */
Modified: branches/gsoc_threads/include/parrot/atomic.h
==============================================================================
--- branches/gsoc_threads/include/parrot/atomic.h Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/include/parrot/atomic.h Tue Aug 10 01:10:47 2010 (r48374)
@@ -15,7 +15,7 @@
#define PARROT_ATOMIC_H_GUARD
# include "parrot/has_header.h"
-# include "parrot/thread.h"
+//# include "parrot/thread.h"
#ifdef PARROT_HAS_THREADS
# if defined(PARROT_HAS_I386_GCC_CMPXCHG)
Modified: branches/gsoc_threads/include/parrot/interpreter.h
==============================================================================
--- branches/gsoc_threads/include/parrot/interpreter.h Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/include/parrot/interpreter.h Tue Aug 10 01:10:47 2010 (r48374)
@@ -132,6 +132,8 @@
#include "parrot/multidispatch.h"
#include "parrot/call.h"
+#include "parrot/atomic.h"
+
typedef struct warnings_t {
Warnings_classes classes;
} *Warnings;
@@ -272,7 +274,10 @@
Parrot_mutex interp_lock; /* Enforce one running thread per interp */
INTVAL active_thread; /* Index of the active thread in thread_table */
- struct Thread_table *thread_table; /* Array of this interpreter's threads */
+
+ struct Thread_table *thread_table; /* Array of this interpreter's threads */
+ Parrot_atomic_integer thread_signal; /* Flag. Set if threads need rescheduling */
+ Parrot_mutex thread_lock; /* Lock for the thread_table */
struct _Thread_data *thread_data; /* thread specific items */
Modified: branches/gsoc_threads/include/parrot/scheduler.h
==============================================================================
--- branches/gsoc_threads/include/parrot/scheduler.h Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/include/parrot/scheduler.h Tue Aug 10 01:10:47 2010 (r48374)
@@ -49,10 +49,6 @@
__attribute__nonnull__(1);
PARROT_EXPORT
-void Parrot_cx_outer_runloop(PARROT_INTERP, INTVAL tidx)
- __attribute__nonnull__(1);
-
-PARROT_EXPORT
void Parrot_cx_request_suspend_for_gc(PARROT_INTERP)
__attribute__nonnull__(1);
@@ -67,15 +63,6 @@
FUNC_MODIFIES(*scheduler);
PARROT_EXPORT
-void Parrot_cx_runloop_end(PARROT_INTERP)
- __attribute__nonnull__(1);
-
-PARROT_EXPORT
-void Parrot_cx_schedule_alarm(PARROT_INTERP, ARGIN(PMC *alarm))
- __attribute__nonnull__(1)
- __attribute__nonnull__(2);
-
-PARROT_EXPORT
void Parrot_cx_schedule_immediate(PARROT_INTERP, ARGIN(PMC *task_or_sub))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
@@ -100,6 +87,12 @@
__attribute__nonnull__(1)
__attribute__nonnull__(2);
+PARROT_EXPORT
+PARROT_CANNOT_RETURN_NULL
+PMC* Parrot_cx_stop_task(PARROT_INTERP, ARGIN(opcode_t *next))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2);
+
void Parrot_cx_check_quantum(PARROT_INTERP, ARGMOD(PMC *scheduler))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
@@ -127,13 +120,15 @@
__attribute__nonnull__(3)
FUNC_MODIFIES(*scheduler);
+void Parrot_cx_runloop_end(PARROT_INTERP)
+ __attribute__nonnull__(1);
+
void Parrot_cx_runloop_wake(PARROT_INTERP, ARGMOD(PMC *scheduler))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
FUNC_MODIFIES(*scheduler);
-PARROT_CANNOT_RETURN_NULL
-PMC* Parrot_cx_stop_task(PARROT_INTERP, ARGIN(opcode_t *next))
+void Parrot_cx_schedule_alarm(PARROT_INTERP, ARGIN(PMC *alarm))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
@@ -150,8 +145,6 @@
#define ASSERT_ARGS_Parrot_cx_delete_suspend_for_gc \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
-#define ASSERT_ARGS_Parrot_cx_outer_runloop __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_cx_request_suspend_for_gc \
__attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
@@ -159,11 +152,6 @@
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(scheduler) \
, PARROT_ASSERT_ARG(next))
-#define ASSERT_ARGS_Parrot_cx_runloop_end __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp))
-#define ASSERT_ARGS_Parrot_cx_schedule_alarm __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(alarm))
#define ASSERT_ARGS_Parrot_cx_schedule_immediate __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(task_or_sub))
@@ -175,6 +163,9 @@
#define ASSERT_ARGS_Parrot_cx_send_message __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(messagetype))
+#define ASSERT_ARGS_Parrot_cx_stop_task __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(next))
#define ASSERT_ARGS_Parrot_cx_check_quantum __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(scheduler))
@@ -190,12 +181,14 @@
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(scheduler) \
, PARROT_ASSERT_ARG(next))
+#define ASSERT_ARGS_Parrot_cx_runloop_end __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_cx_runloop_wake __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(scheduler))
-#define ASSERT_ARGS_Parrot_cx_stop_task __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_Parrot_cx_schedule_alarm __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(next))
+ , PARROT_ASSERT_ARG(alarm))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: src/scheduler.c */
Modified: branches/gsoc_threads/include/parrot/thread.h
==============================================================================
--- branches/gsoc_threads/include/parrot/thread.h Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/include/parrot/thread.h Tue Aug 10 01:10:47 2010 (r48374)
@@ -56,18 +56,6 @@
#endif /* PARROT_HAS_THREADS */
-#define LOCK_INTERP(interp) \
- LOCK((interp)->interp_lock)
-
-#define UNLOCK_INTERP(interp) \
- UNLOCK((interp)->interp_lock)
-
-#define BLOCK_THREAD(interp) \
- Parrot_cx_block_thread(interp)
-
-#define UNBLOCK_THREAD(interp) \
- Parrot_cx_unblock_thread(interp)
-
#ifndef YIELD
# define YIELD
#endif /* YIELD */
Modified: branches/gsoc_threads/include/parrot/threads.h
==============================================================================
--- branches/gsoc_threads/include/parrot/threads.h Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/include/parrot/threads.h Tue Aug 10 01:10:47 2010 (r48374)
@@ -7,11 +7,26 @@
#include "parrot/thread.h"
+enum Thread_states {
+ THREAD_STATE_INITIALIZED = 0x01, /* Thread has been created */
+ THREAD_STATE_RUNNABLE = 0x02, /* We could signal this thread and it would run */
+ THREAD_STATE_SCAN_STACK = 0x04, /* This thread may have PMCs on its stack */
+ THREAD_STATE_RESTLESS = 0x08, /* This thread wants to run ASAP */
+ THREAD_STATE_DEATH_MARK = 0x10 /* This thread is marked for death */
+};
+
+#define THREAD_STATE_TEST(interp, tidx, flag) \
+ ((interp)->thread_table->threads[(tidx)].state & (THREAD_STATE_ ## flag))
+#define THREAD_STATE_SET(interp, tidx, flag) \
+ ((interp)->thread_table->threads[(tidx)].state |= (THREAD_STATE_ ## flag))
+#define THREAD_STATE_CLEAR(interp, tidx, flag) \
+ ((interp)->thread_table->threads[(tidx)].state &= ~(THREAD_STATE_ ## flag))
+
typedef struct Thread_info {
Parrot_thread id;
- INTVAL blocked;
+ INTVAL state;
Parrot_cond cvar;
- void *lo_var_ptr;
+ void *lo_var_ptr; /* Full range of stack for GC scan */
void *hi_var_ptr;
} Thread_info;
@@ -26,6 +41,26 @@
INTVAL idx;
} Thread_args;
+#define LOCK_INTERP(interp) \
+ LOCK((interp)->interp_lock)
+
+#define UNLOCK_INTERP(interp) \
+ UNLOCK((interp)->interp_lock)
+
+#define BLOCK_THREAD_ON(interp, blocking_call) \
+ do { \
+ INTVAL tid, runloop_id, runloop_level; \
+ PMC *context = Parrot_pmc_new((interp), enum_class_Continuation); \
+ runloop_id = interp->current_runloop_id; \
+ runloop_level = interp->current_runloop_level; \
+ Parrot_threads_block((interp), &tid); \
+ blocking_call; \
+ Parrot_threads_unblock((interp), &tid); \
+ (void) VTABLE_invoke((interp), context, 0); \
+ interp->current_runloop_id = runloop_id; \
+ interp->current_runloop_level = runloop_level; \
+ } while (0)
+
/* HEADERIZER BEGIN: src/threads.c */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
@@ -34,10 +69,13 @@
__attribute__nonnull__(2)
FUNC_MODIFIES(*tidx);
-INTVAL Parrot_threads_count_blocked(PARROT_INTERP)
+INTVAL Parrot_threads_check_and_reset(PARROT_INTERP)
+ __attribute__nonnull__(1);
+
+INTVAL Parrot_threads_count_active(PARROT_INTERP)
__attribute__nonnull__(1);
-INTVAL Parrot_threads_current_idx(PARROT_INTERP)
+INTVAL Parrot_threads_current(PARROT_INTERP)
__attribute__nonnull__(1);
void Parrot_threads_idle(PARROT_INTERP, INTVAL tidx)
@@ -51,22 +89,37 @@
__attribute__nonnull__(1)
FUNC_MODIFIES(*args_ptr);
+INTVAL Parrot_threads_next_to_run(PARROT_INTERP, INTVAL cur_idx)
+ __attribute__nonnull__(1);
+
+void Parrot_threads_outer_runloop(PARROT_INTERP, INTVAL tidx)
+ __attribute__nonnull__(1);
+
+void Parrot_threads_print_table(PARROT_INTERP)
+ __attribute__nonnull__(1);
+
void Parrot_threads_reap(PARROT_INTERP)
__attribute__nonnull__(1);
+void Parrot_threads_set_signal(PARROT_INTERP)
+ __attribute__nonnull__(1);
+
void Parrot_threads_spawn(PARROT_INTERP)
__attribute__nonnull__(1);
-void Parrot_threads_unblock(PARROT_INTERP, ARGIN(INTVAL *tidx))
+void Parrot_threads_unblock(PARROT_INTERP, ARGIN(INTVAL *tidx_ptr))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
#define ASSERT_ARGS_Parrot_threads_block __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(tidx))
-#define ASSERT_ARGS_Parrot_threads_count_blocked __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_Parrot_threads_check_and_reset \
+ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_threads_count_active __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
-#define ASSERT_ARGS_Parrot_threads_current_idx __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_Parrot_threads_current __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_threads_idle __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
@@ -74,13 +127,21 @@
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_threads_main __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(args_ptr))
+#define ASSERT_ARGS_Parrot_threads_next_to_run __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_threads_outer_runloop __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_threads_print_table __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_threads_reap __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_threads_set_signal __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_threads_spawn __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp))
#define ASSERT_ARGS_Parrot_threads_unblock __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(tidx))
+ , PARROT_ASSERT_ARG(tidx_ptr))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: src/threads.c */
Modified: branches/gsoc_threads/src/alarm.c
==============================================================================
--- branches/gsoc_threads/src/alarm.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/alarm.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -15,7 +15,6 @@
/* Some per-process state */
static volatile UINTVAL alarm_serial = 0;
-static volatile UINTVAL alarm_init = 0;
static volatile FLOATVAL alarm_set_to = 0.0;
/* This file relies on POSIX. Probably need two other versions of it:
@@ -30,9 +29,7 @@
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
-static void posix_alarm_init(void);
static void posix_alarm_set(FLOATVAL wait);
-#define ASSERT_ARGS_posix_alarm_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
#define ASSERT_ARGS_posix_alarm_set __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
@@ -42,7 +39,7 @@
=over 4
-=item C<static void posix_alarm_init(void)>
+=item C<void Parrot_alarm_init(void)>
Initialize the alarm queue. This function should only be called from the initial
pthread. Any other pthreads should make sure to mask out SIGALRM.
@@ -53,10 +50,10 @@
void Parrot_alarm_callback(SHIM(int sig_number));
-static void
-posix_alarm_init(void)
+void
+Parrot_alarm_init(void)
{
- ASSERT_ARGS(posix_alarm_init)
+ ASSERT_ARGS(Parrot_alarm_init)
struct sigaction sa;
sa.sa_handler = Parrot_alarm_callback;
@@ -68,8 +65,6 @@
}
Parrot_alarm_unmask(NULL);
-
- alarm_init = 1;
}
/*
@@ -91,9 +86,6 @@
struct itimerval itmr;
int sec, usec;
- if (!alarm_init)
- posix_alarm_init();
-
sec = (int) wait;
usec = (int) ((wait - sec) * MIL);
@@ -221,6 +213,23 @@
}
/*
+
+=item C<void Parrot_alarm_now(void)>
+
+Trigger an alarm wakeup.
+
+=cut
+
+*/
+
+void
+Parrot_alarm_now(void)
+{
+ ASSERT_ARGS(Parrot_alarm_now)
+ kill(getpid(), SIGALRM);
+}
+
+/*
* Local variables:
* c-file-style: "parrot"
* End:
Modified: branches/gsoc_threads/src/exceptions.c
==============================================================================
--- branches/gsoc_threads/src/exceptions.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/exceptions.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -21,6 +21,8 @@
#include "parrot/parrot.h"
#include "exceptions.str"
#include "pmc/pmc_continuation.h"
+#include "parrot/exceptions.h"
+#include "parrot/events.h"
/* HEADERIZER HFILE: include/parrot/exceptions.h */
Modified: branches/gsoc_threads/src/gc/gc_ms.c
==============================================================================
--- branches/gsoc_threads/src/gc/gc_ms.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/gc/gc_ms.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -636,6 +636,7 @@
/* keep the scheduler and its kids alive for Task-like PMCs to destroy
* themselves; run a sweep to collect them */
+
if (interp->scheduler) {
Parrot_gc_mark_PMC_alive(interp, interp->scheduler);
VTABLE_mark(interp, interp->scheduler);
Modified: branches/gsoc_threads/src/gc/system.c
==============================================================================
--- branches/gsoc_threads/src/gc/system.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/gc/system.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -253,11 +253,7 @@
int i, cur_idx;
/* We need to trace the stack in one running thread (this thread) as
- well as the stack in each blocked thread.
-
- If a thread isn't running or in the "blocked" state, then it's waiting
- on something outside of any runloop, so it doesn't have any PMCs on its
- stack.
+ well as the stack in each other active thread.
*/
cur_idx = Parrot_threads_current(interp);
@@ -268,7 +264,7 @@
void *hi = &i;
trace_mem_block(interp, mem_pools, (size_t)lo, (size_t)hi);
}
- else if (tbl->threads[i].blocked) {
+ else if (THREAD_STATE_TEST(interp, i, SCAN_STACK)) {
void *hi = tbl->threads[i].hi_var_ptr;
trace_mem_block(interp, mem_pools, (size_t)lo, (size_t)hi);
}
Modified: branches/gsoc_threads/src/interp/inter_create.c
==============================================================================
--- branches/gsoc_threads/src/interp/inter_create.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/interp/inter_create.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -296,7 +296,6 @@
*/
interp->thread_data = NULL;
- MUTEX_INIT(interp->interp_lock);
Parrot_cx_init_scheduler(interp);
#ifdef ATEXIT_DESTROY
@@ -355,6 +354,10 @@
Parrot_really_destroy(PARROT_INTERP, SHIM(int exit_code), SHIM(void *arg))
{
ASSERT_ARGS(Parrot_really_destroy)
+
+ /* Chandon TODO: Restore this functionality */
+ return;
+
/* wait for threads to complete if needed; terminate the event loop */
if (!interp->parent_interpreter) {
Parrot_cx_runloop_end(interp);
Modified: branches/gsoc_threads/src/io/unix.c
==============================================================================
--- branches/gsoc_threads/src/io/unix.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/io/unix.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -31,6 +31,7 @@
#include "parrot/parrot.h"
#include "io_private.h"
#include "pmc/pmc_filehandle.h"
+#include "parrot/threads.h"
#ifdef PIO_OS_UNIX
@@ -515,7 +516,12 @@
void * const buffer = Buffer_bufstart(s);
for (;;) {
- const int bytes = read(file_descriptor, buffer, len);
+ int bytes;
+ INTVAL tid;
+
+ BLOCK_THREAD_ON(interp,
+ bytes = read(file_descriptor, buffer, len));
+
if (bytes > 0) {
s->bufused = s->strlen = bytes;
return bytes;
Modified: branches/gsoc_threads/src/main.c
==============================================================================
--- branches/gsoc_threads/src/main.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/main.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -25,7 +25,6 @@
#include "parrot/imcc.h"
#include "parrot/longopt.h"
#include "parrot/runcore_api.h"
-#include "parrot/alarm.h"
#include "pmc/pmc_callcontext.h"
/* For gc_sys_type_enum */
Modified: branches/gsoc_threads/src/pmc/pmclist.pmc
==============================================================================
--- branches/gsoc_threads/src/pmc/pmclist.pmc Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/pmc/pmclist.pmc Tue Aug 10 01:10:47 2010 (r48374)
@@ -38,6 +38,9 @@
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
+void Parrot_pmc_list_insert_by_number(PARROT_INTERP, PMC *list, PMC *value);
+
+
/* It's a doubly linked list */
typedef struct PMC_List_Item {
PMC *data;
Modified: branches/gsoc_threads/src/runcore/trace.c
==============================================================================
--- branches/gsoc_threads/src/runcore/trace.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/runcore/trace.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -239,7 +239,7 @@
break;
case KEY_string_FLAG|KEY_register_FLAG:
{
- const INTVAL keynum = VTABLE_get_integer(interp, key);
+ const UINTVAL keynum = VTABLE_get_integer(interp, key);
if (keynum < Parrot_pcc_get_regs_used(interp, CURRENT_CONTEXT(interp), REGNO_STR)) {
const STRING * const s = REG_STR(interp, keynum);
STRING * const escaped = Parrot_str_escape_truncate(interp, s, 20);
Modified: branches/gsoc_threads/src/scheduler.c
==============================================================================
--- branches/gsoc_threads/src/scheduler.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/scheduler.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -85,6 +85,9 @@
scheduler = VTABLE_share_ro(interp, scheduler);
interp->scheduler = scheduler;
+
+ /* Make sure the program can handle alarm signals */
+ Parrot_alarm_init();
}
}
@@ -121,7 +124,7 @@
do {
Parrot_cx_check_alarms(interp, interp->scheduler);
- Parrot_threads_wakeup(interp);
+ (void) Parrot_threads_next_to_run(interp, 0);
UNLOCK_INTERP(interp);
pause();
@@ -129,7 +132,7 @@
task_count = VTABLE_get_integer(interp, sched->task_queue);
alarm_count = VTABLE_get_integer(interp, sched->alarms);
- blocked_count = Parrot_threads_count_blocked(interp);
+ blocked_count = Parrot_threads_count_active(interp);
} while (task_count + alarm_count + blocked_count > 0);
Parrot_threads_reap(interp);
@@ -142,42 +145,6 @@
/*
-=item C<void Parrot_cx_outer_runloop(PARROT_INTERP, INTVAL tidx)>
-
-This is the core loop performed by each active OS thread, looking for Tasks
-to run and running them.
-
-=cut
-
-*/
-
-void
-Parrot_cx_outer_runloop(PARROT_INTERP, INTVAL tidx)
-{
- ASSERT_ARGS(Parrot_cx_outer_runloop)
- PMC* scheduler = interp->scheduler;
- Parrot_Scheduler_attributes *sched = PARROT_SCHEDULER(scheduler);
- INTVAL task_count;
-
- for (;;) {
- LOCK_INTERP(interp);
- interp->active_thread = tidx;
-
- task_count = VTABLE_get_integer(interp, sched->task_queue);
-
- if (task_count > 0) {
- Parrot_cx_next_task(interp, scheduler);
- }
- else {
- Parrot_threads_idle(interp, tidx);
- }
-
- UNLOCK(interp->interp_lock);
- }
-}
-
-/*
-
=item C<void Parrot_cx_next_task(PARROT_INTERP, PMC *scheduler)>
Run the task at the head of the task queue until it ends or is
@@ -210,6 +177,9 @@
Parrot_alarm_set(interp->quantum_done);
Parrot_ext_call(interp, interp->current_task, "->");
+ }
+ else {
+ Parrot_alarm_now();
}
}
@@ -230,8 +200,13 @@
ASSERT_ARGS(Parrot_cx_check_scheduler)
PMC *scheduler = interp->scheduler;
- if (Parrot_alarm_check(&(interp->last_alarm))
- || SCHEDULER_wake_requested_TEST(scheduler)) {
+ if (Parrot_threads_check_and_reset(interp)) {
+ SCHEDULER_wake_requested_SET(scheduler);
+ SCHEDULER_resched_requested_SET(scheduler);
+ }
+
+ if (Parrot_alarm_check(&(interp->last_alarm))
+ || SCHEDULER_wake_requested_TEST(scheduler)) {
SCHEDULER_wake_requested_CLEAR(scheduler);
return Parrot_cx_run_scheduler(interp, scheduler, next);
}
@@ -257,6 +232,7 @@
Parrot_cx_run_scheduler(PARROT_INTERP, ARGMOD(PMC *scheduler), ARGIN(opcode_t *next))
{
ASSERT_ARGS(Parrot_cx_run_scheduler)
+ INTVAL tid = interp->active_thread;
Parrot_cx_check_alarms(interp, scheduler);
Parrot_cx_check_quantum(interp, scheduler);
@@ -264,10 +240,16 @@
if (SCHEDULER_resched_requested_TEST(scheduler)) {
SCHEDULER_resched_requested_CLEAR(scheduler);
- /* Exiting the runloop to swap tasks doesn't play
- nice with nested runloops */
- if (interp->current_runloop_level <= 1)
+ /* A task switch will only work in the outer runloop of a fully
+ booted Parrot. In a Parrot that hasn't called begin_execution,
+ or in a nested runloop, we silently ignore task switches. */
+ if (interp->current_task && interp->current_runloop_level <= 1)
return Parrot_cx_preempt_task(interp, scheduler, next);
+
+#ifdef ARBITRARY_DEBUG_STATEMENT
+ fprintf(stderr, "Should have exited runloop. Didn't (%lx, %ld)\n",
+ interp->current_task, interp->current_runloop_level);
+#endif
}
return next;
Modified: branches/gsoc_threads/src/threads.c
==============================================================================
--- branches/gsoc_threads/src/threads.c Tue Aug 10 00:18:55 2010 (r48373)
+++ branches/gsoc_threads/src/threads.c Tue Aug 10 01:10:47 2010 (r48374)
@@ -20,6 +20,7 @@
#include "parrot/threads.h"
#include "parrot/alarm.h"
+#include "pmc/pmc_scheduler.h"
/* HEADERIZER HFILE: include/parrot/threads.h */
@@ -41,6 +42,12 @@
ASSERT_ARGS(Parrot_threads_init)
Thread_table *tbl;
+ MUTEX_INIT(interp->interp_lock);
+ PARROT_ATOMIC_INT_INIT(interp->thread_signal);
+ PARROT_ATOMIC_INT_SET(interp->thread_signal, 0);
+
+ MUTEX_INIT(interp->thread_lock);
+
interp->thread_table = (Thread_table*) malloc(sizeof(Thread_table));
interp->active_thread = 0;
@@ -50,8 +57,9 @@
tbl->count = 1;
tbl->threads = (Thread_info*) malloc(sizeof(Thread_info) * tbl->size);
- tbl->threads[0].id = THREAD_SELF();
- tbl->threads[0].blocked = 0;
+ tbl->threads[0].id = THREAD_SELF();
+ tbl->threads[0].state = 0;
+ THREAD_STATE_SET(interp, 0, INITIALIZED);
COND_INIT(tbl->threads[0].cvar);
LOCK_INTERP(interp);
@@ -82,23 +90,70 @@
Parrot_alarm_mask(interp);
/* Yay stack scanning */
+ LOCK(interp->thread_lock);
tbl->threads[tidx].lo_var_ptr = &tidx;
+ UNLOCK(interp->thread_lock);
- //fprintf(stderr, "Thread id# %d started.\n", (int) tidx);
+ Parrot_threads_outer_runloop(interp, tidx);
+ return 0;
+}
- Parrot_cx_outer_runloop(interp, tidx);
+/*
- //fprintf(stderr, "Thread id# %d ending.\n", (int) tidx);
- return 0;
+=item C<void Parrot_threads_outer_runloop(PARROT_INTERP, INTVAL tidx)>
+
+This is the core loop performed by each active OS thread. If it's the
+thread that needs to be running, it invokes the Scheduler to pick a
+task.
+
+=cut
+
+*/
+
+void
+Parrot_threads_outer_runloop(PARROT_INTERP, INTVAL tidx)
+{
+ ASSERT_ARGS(Parrot_threads_outer_runloop)
+ PMC* scheduler = interp->scheduler;
+ Parrot_Scheduler_attributes *sched = PARROT_SCHEDULER(scheduler);
+ INTVAL next_thread, task_count;
+
+ for (;;) {
+ LOCK_INTERP(interp);
+ interp->active_thread = tidx;
+ interp->current_runloop_level = 0;
+
+ LOCK(interp->thread_lock);
+ if (THREAD_STATE_TEST(interp, tidx, DEATH_MARK)) {
+ UNLOCK(interp->thread_lock);
+ UNLOCK_INTERP(interp);
+ return;
+ }
+ UNLOCK(interp->thread_lock);
+
+ /* Are we the best thread to be running right now? */
+ next_thread = Parrot_threads_next_to_run(interp, tidx);
+ task_count = VTABLE_get_integer(interp, sched->task_queue);
+
+ if (next_thread == tidx && task_count > 0) {
+ Parrot_cx_next_task(interp, scheduler);
+ } else {
+ /* Wake up the main thread to check if we're done before
+ going idle. */
+ Parrot_alarm_now();
+ Parrot_threads_idle(interp, tidx);
+ }
+
+ UNLOCK(interp->interp_lock);
+ }
}
/*
=item C<void Parrot_threads_block(PARROT_INTERP, INTVAL *tidx)>
-The current thread is about to block. Make sure there's
-another thread ready to do work once we release the
-interpreter lock.
+The current thread is about to block. Make sure there's another thread ready
+to do work once we release the interpreter lock.
Use macros BLOCK_THREAD and UNBLOCK_THREAD rather than
calling this directly.
@@ -112,34 +167,41 @@
{
ASSERT_ARGS(Parrot_threads_block)
Thread_table *tbl = interp->thread_table;
- int next;
+ int next, i, have_runnable;
- /* scan to find who's next */
- for (next = 1; next < tbl->count; ++next) {
- if(tbl->threads[next].blocked == 0)
- break;
- }
+ *tidx = interp->active_thread;
- /* Maybe spawn more threads */
- if (next > tbl->count) {
- Parrot_threads_spawn(interp);
- }
+ next = Parrot_threads_next_to_run(interp, *tidx);
- *tidx = interp->active_thread;
+ LOCK(interp->thread_lock);
/* While we're blocked, we might have PMCs on stack */
tbl->threads[*tidx].hi_var_ptr = &next;
+ THREAD_STATE_CLEAR(interp, *tidx, RUNNABLE);
+ THREAD_STATE_SET(interp, *tidx, SCAN_STACK);
+
+ /* Maybe spawn more threads */
+ have_runnable = 0;
+ for (i = 1; i < tbl->count; ++i) {
+ if (THREAD_STATE_TEST(interp, i, RUNNABLE)) {
+ have_runnable = 1;
+ break;
+ }
+ }
- tbl->threads[*tidx].blocked = 1;
+ if (!have_runnable) {
+ Parrot_threads_spawn(interp);
+ }
COND_SIGNAL(tbl->threads[*tidx].cvar);
+ UNLOCK(interp->thread_lock);
UNLOCK_INTERP(interp);
}
/*
-=item C<void Parrot_threads_unblock(PARROT_INTERP, INTVAL *tidx)>
+=item C<void Parrot_threads_unblock(PARROT_INTERP, INTVAL *tidx_ptr)>
The current thread has completed a blocking operation.
It's going to have to wait for someone else to finish.
@@ -152,41 +214,58 @@
*/
void
-Parrot_threads_unblock(PARROT_INTERP, ARGIN(INTVAL *tidx))
+Parrot_threads_unblock(PARROT_INTERP, ARGIN(INTVAL *tidx_ptr))
{
ASSERT_ARGS(Parrot_threads_unblock)
Thread_table *tbl;
+ const INTVAL tidx = *tidx_ptr;
- LOCK_INTERP(interp);
+ /* We need to signal that we want the interpreter back. */
+ Parrot_alarm_now();
+
+ LOCK(interp->thread_lock);
tbl = interp->thread_table;
- interp->active_thread = *tidx;
- tbl->threads[*tidx].blocked = 0;
+ interp->active_thread = tidx;
+ THREAD_STATE_SET(interp, tidx, RESTLESS);
+
+ UNLOCK(interp->thread_lock);
+
+ Parrot_threads_set_signal(interp);
+
+ LOCK_INTERP(interp);
+ THREAD_STATE_CLEAR(interp, tidx, SCAN_STACK);
+ THREAD_STATE_CLEAR(interp, tidx, RESTLESS);
}
/*
-=item C<INTVAL Parrot_threads_count_blocked(PARROT_INTERP)>
+=item C<INTVAL Parrot_threads_count_active(PARROT_INTERP)>
-Scan the interpreter's thread table to find how many are blocked.
+Scan the interpreter's thread table to find how many threads currently
+have an active task.
=cut
*/
INTVAL
-Parrot_threads_count_blocked(PARROT_INTERP)
+Parrot_threads_count_active(PARROT_INTERP)
{
- ASSERT_ARGS(Parrot_threads_count_blocked)
+ ASSERT_ARGS(Parrot_threads_count_active)
Thread_table *tbl = interp->thread_table;
int i;
INTVAL count = 0;
+ /* An active thread will have its SCAN_STACK flag set */
+
+ LOCK(interp->thread_lock);
for (i = 1; i < tbl->count; ++i) {
- if(tbl->threads[i].blocked)
+ if (THREAD_STATE_TEST(interp, i, SCAN_STACK))
++count;
}
+ UNLOCK(interp->thread_lock);
return count;
}
@@ -197,6 +276,9 @@
Someone needs another thread. Add one at the end of table.
+Important: You must have interp->thread_lock before calling
+ this function.
+
=cut
*/
@@ -209,18 +291,21 @@
INTVAL new_idx = tbl->count;
Thread_args *args = (Thread_args*) malloc(sizeof(Thread_args));
+
tbl->count += 1;
/* Maybe grow table */
if (tbl->count > tbl->size) {
tbl->size *= 2;
- tbl = (Thread_table*) realloc(tbl, sizeof(Thread_info) * tbl->size);
+ tbl->threads = (Thread_info*) realloc(tbl, sizeof(Thread_info) * tbl->size);
}
args->interp = interp;
args->idx = new_idx;
- tbl->threads[new_idx].blocked = 0;
+ tbl->threads[new_idx].state = 0;
+ THREAD_STATE_SET(interp, new_idx, INITIALIZED);
+ THREAD_STATE_SET(interp, new_idx, RUNNABLE);
COND_INIT(tbl->threads[new_idx].cvar);
THREAD_CREATE_JOINABLE(tbl->threads[new_idx].id, Parrot_threads_main, args);
@@ -232,6 +317,8 @@
Clean up any excess threads at the end of table.
+Important: You must have the interpreter lock to call this function.
+
=cut
*/
@@ -240,7 +327,45 @@
Parrot_threads_reap(PARROT_INTERP)
{
ASSERT_ARGS(Parrot_threads_reap)
- /* fprintf(stderr, "Parrot_reap_threads not implemented.\n"); */
+ Thread_table *tbl = interp->thread_table;
+ int i;
+
+ LOCK(interp->thread_lock);
+ for (i = tbl->count - 1; i > interp->active_thread; --i) {
+ void *rv;
+
+ if (THREAD_STATE_TEST(interp, i, SCAN_STACK))
+ break;
+
+ if (THREAD_STATE_TEST(interp, i, RUNNABLE)) {
+ THREAD_STATE_SET(interp, i, DEATH_MARK);
+ THREAD_STATE_SET(interp, i, RESTLESS);
+
+ COND_SIGNAL(tbl->threads[i].cvar);
+
+ UNLOCK_INTERP(interp);
+ UNLOCK(interp->thread_lock);
+
+ JOIN(tbl->threads[i].id, rv);
+
+ LOCK_INTERP(interp);
+ LOCK(interp->thread_lock);
+
+ tbl->threads[i].state = 0;
+ COND_DESTROY(tbl->threads[i].cvar);
+
+ tbl->count -= 1;
+ }
+
+ }
+
+ if (i < (long)tbl->size / 3) {
+ /* Shrink that table */
+ tbl->size /= 2;
+ tbl->threads = (Thread_info*) realloc(tbl, sizeof(Thread_info) * tbl->size);
+ }
+
+ UNLOCK(interp->thread_lock);
}
/*
@@ -258,35 +383,56 @@
{
ASSERT_ARGS(Parrot_threads_idle)
Thread_table *tbl = interp->thread_table;
+ THREAD_STATE_SET(interp, tidx, RUNNABLE);
COND_WAIT(tbl->threads[tidx].cvar, interp->interp_lock);
interp->active_thread = tidx;
}
/*
-=item C<void Parrot_threads_wakeup(PARROT_INTERP)>
+=item C<INTVAL Parrot_threads_check_and_reset(PARROT_INTERP)>
-There might be work to do, wake up a thread.
+Sees if a thread signal has occured and, if so, resets the
+signal flag.
=cut
*/
-void
-Parrot_threads_wakeup(PARROT_INTERP)
+INTVAL
+Parrot_threads_check_and_reset(PARROT_INTERP)
{
- ASSERT_ARGS(Parrot_threads_idle)
- Thread_table *tbl = interp->thread_table;
- int i;
+ ASSERT_ARGS(Parrot_threads_check_and_reset)
- for(i = 1; i < tbl->count; ++i) {
- if (tbl->threads[i].blocked == 0) {
- COND_SIGNAL(tbl->threads[i].cvar);
- return;
- }
+ INTVAL flag;
+ PARROT_ATOMIC_INT_GET(flag, interp->thread_signal);
+
+ /* If we reset thread_signal unconditionally here
+ then there would be a race and we could miss
+ the flag being set. */
+ if (flag) {
+ PARROT_ATOMIC_INT_SET(interp->thread_signal, 0);
}
- Parrot_threads_spawn(interp);
+ return flag;
+}
+
+/*
+
+=item C<void Parrot_threads_set_signal(PARROT_INTERP)>
+
+Set the thread signal, indicating that a thread reschedule
+wants to occur.
+
+=cut
+
+*/
+
+void
+Parrot_threads_set_signal(PARROT_INTERP)
+{
+ ASSERT_ARGS(Parrot_threads_set_signal)
+ PARROT_ATOMIC_INT_SET(interp->thread_signal, 1);
}
/*
@@ -302,19 +448,107 @@
INTVAL
Parrot_threads_current(PARROT_INTERP)
{
+ ASSERT_ARGS(Parrot_threads_current)
+
INTVAL idx;
Thread_table *tbl = interp->thread_table;
Parrot_thread tid = THREAD_SELF();
-
+ LOCK(interp->thread_lock);
for(idx = 0; idx < tbl->count; ++idx) {
- if (THREAD_EQUAL(tbl->threads[idx].id, tid))
+ if (THREAD_EQUAL(tbl->threads[idx].id, tid)) {
+ UNLOCK(interp->thread_lock);
return idx;
+ }
}
+ UNLOCK(interp->thread_lock);
exit_fatal(1, "threads.c: Current thread is not in the threads table.");
}
+/*
+
+=item C<INTVAL Parrot_threads_next_to_run(PARROT_INTERP, INTVAL cur_idx)>
+
+Scan the thread table for the best thread to run now.
+
+=cut
+
+*/
+
+INTVAL
+Parrot_threads_next_to_run(PARROT_INTERP, INTVAL cur_idx)
+{
+ ASSERT_ARGS(Parrot_threads_next_to_run)
+
+ Thread_table *tbl = interp->thread_table;
+ int i;
+
+ LOCK(interp->thread_lock);
+
+ /* Pick threads to run to try to fill the thread table
+ at the beginning, so we can shrink it at the end. */
+
+
+ /* If there's a restless thread, run the last one. */
+ for (i = tbl->count - 1; i > 0; --i) {
+ if (THREAD_STATE_TEST(interp, i, RESTLESS)) {
+ COND_SIGNAL(tbl->threads[i].cvar);
+ UNLOCK(interp->thread_lock);
+ return i;
+ }
+ }
+
+ /* Otherwise there's a runnable thread, run the first one. */
+ for (i = 1; i < tbl->count; ++i) {
+ if (THREAD_STATE_TEST(interp, i, RUNNABLE)) {
+ COND_SIGNAL(tbl->threads[i].cvar);
+ UNLOCK(interp->thread_lock);
+ return i;
+ }
+ }
+
+ UNLOCK(interp->thread_lock);
+
+ /* Otherwise, the current thread is fine. */
+ return cur_idx;
+}
+
+/*
+
+=item C<void Parrot_threads_print_table(PARROT_INTERP)>
+
+Print the current thread table, which hopefully shows what's horribly
+broken this time.
+
+=cut
+
+*/
+
+void
+Parrot_threads_print_table(PARROT_INTERP)
+{
+ ASSERT_ARGS(Parrot_threads_print_table)
+ Thread_table *tbl = interp->thread_table;
+ INTVAL i;
+
+ fprintf(stderr, " === Thread Info ===\n");
+ fprintf(stderr, "Table count/size: %ld / %ld.\n", tbl->count, tbl->size);
+ fprintf(stderr, "Current thread: %ld\n", Parrot_threads_current(interp));
+
+ for (i = 0; i < tbl->count; ++i) {
+ fprintf(stderr, " %ld\t", i);
+ if (THREAD_STATE_TEST(interp, i, INITIALIZED))
+ fprintf(stderr, "init ");
+ if (THREAD_STATE_TEST(interp, i, RUNNABLE))
+ fprintf(stderr, "runnable ");
+ if (THREAD_STATE_TEST(interp, i, SCAN_STACK))
+ fprintf(stderr, "scan_stack ");
+ if (THREAD_STATE_TEST(interp, i, RESTLESS))
+ fprintf(stderr, "restless ");
+ fprintf(stderr, "\n");
+ }
+}
/*
Added: branches/gsoc_threads/t/src/threads_io.t
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/gsoc_threads/t/src/threads_io.t Tue Aug 10 01:10:47 2010 (r48374)
@@ -0,0 +1,73 @@
+#! perl
+# Copyright (C) 2010, Parrot Foundation.
+# $Id$
+
+use strict;
+use warnings;
+use File::Temp;
+use Time::HiRes qw(sleep);
+
+# TAP Plan
+print "1..4\n";
+
+my $pir = File::Temp->new(TEMPLATE => 'thread_io_XXXX', SUFFIX => '.pir');
+my $tmp = File::Temp->new(TEMPLATE => 'thread_io_XXXX', SUFFIX => '.tmp');
+
+$pir->print(<<'EOF');
+#! ./parrot
+
+.sub main :main
+ .local pmc insub, spinsub, spintask
+
+ insub = get_global 'insub'
+ $P0 = new 'Task', insub
+ schedule $P0
+
+ spinsub = get_global 'spin'
+ spintask = new 'Task', spinsub
+ schedule spintask
+
+ pass
+
+ say "ok 2 - main task sleeping"
+ sleep 0.2
+ say "ok 4 - main task back"
+
+ spintask.'kill'()
+.end
+
+.sub insub
+ .local pmc stdin
+ stdin = getstdin
+
+ $P0 = stdin.'readline'()
+
+ $S0 = $P0
+ if $S0 == "grumblecake\n" goto good
+ say "not ok 3"
+ .return()
+
+good:
+ say "ok 3 - got input"
+ .return()
+.end
+
+.sub spin
+ say "ok 1 - spinning"
+ $I0 = 0
+spin_more:
+ $I0 = $I0 + 1
+ goto spin_more
+.end
+
+EOF
+
+my $pir_file = $pir->filename;
+
+open my $run, "|perl ${\$pir->filename} ${\$tmp->filename}";
+
+sleep(0.1);
+$run->print("grumblecake\n");
+sleep(0.3);
+
+close($run);
More information about the parrot-commits
mailing list