[svn:parrot] r48331 - in branches/gsoc_threads: config/gen/makefiles include/parrot src src/gc src/interp src/runcore

Chandon at svn.parrot.org Chandon at svn.parrot.org
Thu Aug 5 22:12:06 UTC 2010


Author: Chandon
Date: Thu Aug  5 22:12:05 2010
New Revision: 48331
URL: https://trac.parrot.org/parrot/changeset/48331

Log:
[gsoc_threads] Infrastructure for multiple (IO) threads per interp.

Added:
   branches/gsoc_threads/include/parrot/threads.h
   branches/gsoc_threads/src/threads.c
Modified:
   branches/gsoc_threads/config/gen/makefiles/root.in
   branches/gsoc_threads/include/parrot/alarm.h
   branches/gsoc_threads/include/parrot/extend.h
   branches/gsoc_threads/include/parrot/interpreter.h
   branches/gsoc_threads/include/parrot/scheduler.h
   branches/gsoc_threads/include/parrot/thr_pthread.h
   branches/gsoc_threads/include/parrot/thread.h
   branches/gsoc_threads/src/alarm.c
   branches/gsoc_threads/src/embed.c
   branches/gsoc_threads/src/gc/api.c
   branches/gsoc_threads/src/gc/system.c
   branches/gsoc_threads/src/interp/inter_cb.c
   branches/gsoc_threads/src/interp/inter_create.c
   branches/gsoc_threads/src/packfile.c
   branches/gsoc_threads/src/runcore/cores.c
   branches/gsoc_threads/src/scheduler.c
   branches/gsoc_threads/src/thread.c

Modified: branches/gsoc_threads/config/gen/makefiles/root.in
==============================================================================
--- branches/gsoc_threads/config/gen/makefiles/root.in	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/config/gen/makefiles/root.in	Thu Aug  5 22:12:05 2010	(r48331)
@@ -385,6 +385,7 @@
 	$(INC_DIR)/exit.h \
 	$(INC_DIR)/nci.h \
 	$(INC_DIR)/thread.h \
+	$(INC_DIR)/threads.h \
 	$(INC_DIR)/scheduler.h \
 	$(INC_DIR)/longopt.h \
 	$(INC_DIR)/oo.h \
@@ -490,6 +491,7 @@
     src/string/primitives$(O) \
     src/sub$(O) \
     src/thread$(O) \
+    src/threads$(O) \
     src/runcore/trace$(O) \
     src/utils$(O) \
     src/vtables$(O) \
@@ -1328,6 +1330,8 @@
 	include/pmc/pmc_parrotinterpreter.h \
 	$(INC_DIR)/runcore_api.h
 
+src/threads$(O) : $(PARROT_H_HEADERS) $(INC_DIR)/atomic.h src/threads.c
+
 ## SUFFIX OVERRIDE - dynloaded files need cc_shared
 src/extend$(O) : $(PARROT_H_HEADERS) $(INC_DIR)/extend.h \
     include/pmc/pmc_sub.h $(INC_DIR)/extend_vtable.h src/extend.c

Modified: branches/gsoc_threads/include/parrot/alarm.h
==============================================================================
--- branches/gsoc_threads/include/parrot/alarm.h	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/include/parrot/alarm.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -18,10 +18,14 @@
 void Parrot_alarm_set(FLOATVAL when);
 
 void Parrot_alarm_callback(NULLOK(int sig_number));
+void Parrot_alarm_mask(SHIM_INTERP);
+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_mask __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/extend.h
==============================================================================
--- branches/gsoc_threads/include/parrot/extend.h	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/include/parrot/extend.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -29,18 +29,20 @@
 
 #define Parrot_Language Parrot_Int
 
+#include "parrot/threads.h"
+
 /* Macro to save off the original stack pointer for GC scanning. If
    the stacktop was NULL, then set it to the address of the cached
    pointer, which is on the stack and as good a thing as any to use as
    an anchor */
-#define PARROT_CALLIN_START(x) void *oldtop = (x)->lo_var_ptr; \
-                               if (oldtop) {} else (x)->lo_var_ptr = &oldtop
+#define PARROT_CALLIN_START(x) void *oldtop = (x)->thread_table->threads[0].lo_var_ptr; \
+                               if (oldtop) {} else (x)->thread_table->threads[0].lo_var_ptr = &oldtop
 /* Put the stack top back, if what we cached was NULL. Otherwise we
    leave it alone and assume it's OK */
 #define PARROT_CALLIN_END(x)   do {\
                 if (!oldtop) {\
-                    PARROT_ASSERT((x)->lo_var_ptr == &oldtop);\
-                    (x)->lo_var_ptr = NULL;\
+                    PARROT_ASSERT((x)->thread_table->threads[0].lo_var_ptr == &oldtop);\
+                    (x)->thread_table->threads[0].lo_var_ptr = NULL;\
                 }\
             } while (0)
 

Modified: branches/gsoc_threads/include/parrot/interpreter.h
==============================================================================
--- branches/gsoc_threads/include/parrot/interpreter.h	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/include/parrot/interpreter.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -141,6 +141,7 @@
 struct _imc_info_t;
 
 
+struct Thread_table;    /* in threads.h */
 struct _Thread_data;    /* in thread.h */
 struct _Caches;         /* caches .h */
 
@@ -223,9 +224,6 @@
 
     PMC * dynamic_env;                        /* Dynamic environment stack */
 
-    void *lo_var_ptr;                         /* Pointer to memory on runops
-                                               * system stack */
-
     Interp *parent_interpreter;
 
     /* per interpreter global vars */
@@ -272,9 +270,9 @@
     FLOATVAL         quantum_done;            /* expiration of current quantum */
     PMC             *current_task;            /* there's always one running task */
 
-    INTVAL           blocked_count;           /* Number of threads currently blocked */
-    INTVAL           thread_count;            /* Number of threads assigned to this interp */
     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_data *thread_data;         /* thread specific items */
 

Modified: branches/gsoc_threads/include/parrot/scheduler.h
==============================================================================
--- branches/gsoc_threads/include/parrot/scheduler.h	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/include/parrot/scheduler.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -49,7 +49,7 @@
         __attribute__nonnull__(1);
 
 PARROT_EXPORT
-void Parrot_cx_outer_runloop(PARROT_INTERP)
+void Parrot_cx_outer_runloop(PARROT_INTERP, INTVAL tidx)
         __attribute__nonnull__(1);
 
 PARROT_EXPORT
@@ -137,11 +137,6 @@
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
-PARROT_CAN_RETURN_NULL
-void* Parrot_cx_thread_main(ARGMOD(void *interp_ptr))
-        __attribute__nonnull__(1)
-        FUNC_MODIFIES(*interp_ptr);
-
 #define ASSERT_ARGS_Parrot_cx_begin_execution __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(main) \
@@ -201,8 +196,6 @@
 #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_thread_main __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp_ptr))
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/scheduler.c */
 

Modified: branches/gsoc_threads/include/parrot/thr_pthread.h
==============================================================================
--- branches/gsoc_threads/include/parrot/thr_pthread.h	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/include/parrot/thr_pthread.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -50,6 +50,7 @@
         pthread_create(&(t), NULL, (func), (arg))
 
 #  define THREAD_SELF() pthread_self()
+#  define THREAD_EQUAL(t1, t2) pthread_equal((t1), (t2))
 
 #  define JOIN(t, ret) pthread_join((t), &(ret))
 #  define DETACH(t)    pthread_detach(t)

Modified: branches/gsoc_threads/include/parrot/thread.h
==============================================================================
--- branches/gsoc_threads/include/parrot/thread.h	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/include/parrot/thread.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -56,14 +56,17 @@
 
 #endif /* PARROT_HAS_THREADS */
 
+#define LOCK_INTERP(interp) \
+    LOCK((interp)->interp_lock)
 
-#define THREAD_BLOCK(interp) \
-    do { (interp)->blocked_count += 1; \
-        UNLOCK((interp)->interp_lock); } while (0)
-
-#define THREAD_UNBLOCK(interp) \
-    do { LOCK((interp)->interp_lock); \
-        (interp)->blocked_count -= 1; } while (0)
+#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

Added: branches/gsoc_threads/include/parrot/threads.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ branches/gsoc_threads/include/parrot/threads.h	Thu Aug  5 22:12:05 2010	(r48331)
@@ -0,0 +1,94 @@
+/* threads.h
+ *  Copyright (C) 2010, Parrot Foundation.
+ */
+
+#ifndef PARROT_THREADS_H_GUARD
+#define PARROT_THREADS_H_GUARD
+
+#include "parrot/thread.h"
+
+typedef struct Thread_info {
+    Parrot_thread id;
+    INTVAL        blocked;
+    Parrot_cond   cvar;
+    void         *lo_var_ptr;
+    void         *hi_var_ptr;
+} Thread_info;
+
+typedef struct Thread_table {
+    Thread_info *threads;
+    INTVAL       size;
+    INTVAL       count;
+} Thread_table;
+
+typedef struct Thread_args {
+    Interp* interp;
+    INTVAL  idx;
+} Thread_args;
+
+/* HEADERIZER BEGIN: src/threads.c */
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+
+void Parrot_threads_block(PARROT_INTERP, ARGOUT(INTVAL *tidx))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*tidx);
+
+INTVAL Parrot_threads_count_blocked(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+INTVAL Parrot_threads_current_idx(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+void Parrot_threads_idle(PARROT_INTERP, INTVAL tidx)
+        __attribute__nonnull__(1);
+
+void Parrot_threads_init(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+PARROT_CAN_RETURN_NULL
+void* Parrot_threads_main(ARGMOD(void *args_ptr))
+        __attribute__nonnull__(1)
+        FUNC_MODIFIES(*args_ptr);
+
+void Parrot_threads_reap(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+void Parrot_threads_spawn(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
+void Parrot_threads_unblock(PARROT_INTERP, ARGIN(INTVAL *tidx))
+        __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 = (\
+       PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_threads_current_idx __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))
+#define ASSERT_ARGS_Parrot_threads_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       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_reap __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))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
+/* HEADERIZER END: src/threads.c */
+
+#endif /* PARROT_THREADS_H_GUARD */
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Modified: branches/gsoc_threads/src/alarm.c
==============================================================================
--- branches/gsoc_threads/src/alarm.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/alarm.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -58,6 +58,8 @@
 {
     ASSERT_ARGS(posix_alarm_init)
 
+    sigset_t mask;
+
     struct sigaction sa;
     sa.sa_handler = Parrot_alarm_callback;
     sa.sa_flags   = SA_RESTART;
@@ -67,6 +69,8 @@
         exit(EXIT_FAILURE);
     }
 
+    Parrot_alarm_unmask(NULL);
+
     alarm_init = 1;
 }
 
@@ -111,6 +115,37 @@
     }
 }
 
+/*
+
+=item C<void Parrot_alarm_mask(PARROT_INTERP)>
+
+=item C<void Parrot_alarm_unmask(PARROT_INTERP)>
+
+These block or unblock the signal for alarms. Any thread with signals
+unblocked should avoid waiting on a lock or condition variable.
+
+=cut
+
+*/
+
+
+void
+Parrot_alarm_mask(SHIM_INTERP)
+{
+    ASSERT_ARGS(Parrot_alarm_mask)
+    sigset_t mask;
+    sigaddset(&mask, SIGALRM);
+    pthread_sigmask(SIG_BLOCK, &mask, 0);
+}
+
+void
+Parrot_alarm_unmask(SHIM_INTERP)
+{
+    ASSERT_ARGS(Parrot_alarm_unmask)
+    sigset_t mask;
+    sigaddset(&mask, SIGALRM);
+    pthread_sigmask(SIG_UNBLOCK, &mask, 0);
+}
 
 /*
 

Modified: branches/gsoc_threads/src/embed.c
==============================================================================
--- branches/gsoc_threads/src/embed.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/embed.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -25,6 +25,7 @@
 #include "pmc/pmc_sub.h"
 #include "pmc/pmc_callcontext.h"
 #include "parrot/runcore_api.h"
+#include "parrot/threads.h"
 
 #include "../compilers/imcc/imc.h"
 
@@ -114,7 +115,7 @@
 Parrot_init_stacktop(PARROT_INTERP, ARGIN(void *stack_top))
 {
     ASSERT_ARGS(Parrot_init_stacktop)
-    interp->lo_var_ptr = stack_top;
+    interp->thread_table->threads[0].lo_var_ptr = stack_top;
     init_world_once(interp);
 }
 
@@ -841,7 +842,13 @@
     interp               = pdb->debugee;
     interp->pdb          = pdb;
     */
-    debugger->lo_var_ptr = interp->lo_var_ptr;
+
+    /* Chandon FIXME: What's this? How should it work? */
+    /* debugger->lo_var_ptr = interp->lo_var_ptr; */
+
+    fprintf(stderr, "Debugger is broken.\n");
+    exit(1);
+
 
     PDB_disassemble(interp, NULL);
 

Modified: branches/gsoc_threads/src/gc/api.c
==============================================================================
--- branches/gsoc_threads/src/gc/api.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/gc/api.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -92,6 +92,7 @@
 #define GC_C_SOURCE
 #include "parrot/parrot.h"
 #include "parrot/gc_api.h"
+#include "parrot/threads.h"
 #include "gc_private.h"
 
 /* HEADERIZER HFILE: include/parrot/gc_api.h */
@@ -229,7 +230,7 @@
 {
     ASSERT_ARGS(Parrot_gc_initialize)
 
-    interp->lo_var_ptr                    = stacktop;
+    interp->thread_table->threads[0].lo_var_ptr = stacktop;
 
     /*Call appropriate initialization function for GC subsystem*/
     switch (interp->gc_sys->sys_type) {

Modified: branches/gsoc_threads/src/gc/system.c
==============================================================================
--- branches/gsoc_threads/src/gc/system.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/gc/system.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -27,6 +27,7 @@
 */
 
 #include "parrot/parrot.h"
+#include "parrot/threads.h"
 #include "gc_private.h"
 
 /* HEADERIZER HFILE: src/gc/gc_private.h */
@@ -248,11 +249,26 @@
        "top" of the stack. A value stored in interp->lo_var_ptr represents
        the "bottom" of the stack. We must trace the entire area between the
        top and bottom. */
-    const size_t lo_var_ptr = (size_t)interp->lo_var_ptr;
-    PARROT_ASSERT(lo_var_ptr);
+    const Thread_table *tbl = interp->thread_table;
+    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. */
+    cur_idx = Parrot_threads_current(interp);
+
+    for (i = 0; i < tbl->count; ++i) {
+        void *lo  = tbl->threads[i].lo_var_ptr;
+
+        if (i == cur_idx) {
+            void *hi = &i;
+            trace_mem_block(interp, mem_pools, (size_t)lo, (size_t)hi);
+        }
+        else if (tbl->threads[i].blocked) {
+            void *hi = tbl->threads[i].hi_var_ptr;
+            trace_mem_block(interp, mem_pools, (size_t)lo, (size_t)hi);
+        }
+    }
 
-    trace_mem_block(interp, mem_pools, (size_t)lo_var_ptr,
-            (size_t)&lo_var_ptr);
 }
 
 /*

Modified: branches/gsoc_threads/src/interp/inter_cb.c
==============================================================================
--- branches/gsoc_threads/src/interp/inter_cb.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/interp/inter_cb.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -267,8 +267,8 @@
          */
         PMC *callback = Parrot_pmc_new(interp, enum_class_Callback);
         Parrot_Callback_attributes *cb_data = PARROT_CALLBACK(callback);
-        cb_data->user_data     = user_data;
-        cb_data->external_data = external_data;
+        cb_data->user_data     = (PMC*) user_data;
+        cb_data->external_data = (PMC*) external_data;
 
         Parrot_cx_schedule_immediate(interp, callback);
     }

Modified: branches/gsoc_threads/src/interp/inter_create.c
==============================================================================
--- branches/gsoc_threads/src/interp/inter_create.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/interp/inter_create.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -26,6 +26,7 @@
 #include "pmc/pmc_callcontext.h"
 #include "../gc/gc_private.h"
 #include "inter_create.str"
+#include "parrot/threads.h"
 
 /* HEADERIZER HFILE: include/parrot/interpreter.h */
 
@@ -123,8 +124,6 @@
     /* Get an empty interpreter from system memory */
     interp = mem_internal_allocate_zeroed_typed(Interp);
 
-    interp->lo_var_ptr = NULL;
-
     /* the last interpreter (w/o) parent has to cleanup globals
      * so remember parent if any */
     if (parent)
@@ -189,6 +188,9 @@
 {
     ASSERT_ARGS(initialize_interpreter)
 
+    /* Need threads table to init gc */
+    Parrot_threads_init(interp);
+
     /* Set up the memory allocation system */
     Parrot_gc_initialize(interp, stacktop);
     Parrot_block_GC_mark(interp);
@@ -294,11 +296,8 @@
      */
     interp->thread_data = NULL;
 
-    Parrot_cx_init_scheduler(interp);
-    interp->blocked_count = 0;
-    interp->thread_count  = 1;
     MUTEX_INIT(interp->interp_lock);
-    LOCK(interp->interp_lock);
+    Parrot_cx_init_scheduler(interp);
 
 #ifdef ATEXIT_DESTROY
     /*

Modified: branches/gsoc_threads/src/packfile.c
==============================================================================
--- branches/gsoc_threads/src/packfile.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/packfile.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -731,7 +731,8 @@
       case PBC_IMMEDIATE:
         /* run IMMEDIATE sub */
         if (PObj_get_FLAGS(sub_pmc) & SUB_FLAG_PF_IMMEDIATE) {
-            void *lo_var_ptr = interp->lo_var_ptr;
+            /* Chandon TODO: Remove irrelevent lo_var_ptr comments */
+            void *lo_var_ptr = interp->thread_table->threads[0].lo_var_ptr;
             PMC  *result;
 
             PObj_get_FLAGS(sub_pmc) &= ~SUB_FLAG_PF_IMMEDIATE;
@@ -740,7 +741,9 @@
             /* reset initial flag so MAIN detection works
              * and reset lo_var_ptr to prev */
             interp->resume_flag = RESUME_INITIAL;
-            interp->lo_var_ptr  = lo_var_ptr;
+
+            interp->thread_table->threads[0].lo_var_ptr = lo_var_ptr;
+
             return result;
         }
         break;

Modified: branches/gsoc_threads/src/runcore/cores.c
==============================================================================
--- branches/gsoc_threads/src/runcore/cores.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/runcore/cores.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -571,7 +571,8 @@
 
         /* set the top of the stack so GC can trace it for GC-able pointers
          * see trace_system_areas() in src/gc/system.c */
-        debugger->lo_var_ptr = interp->lo_var_ptr;
+        /* Chandon FIXME: debugger */
+        /* debugger->lo_var_ptr = interp->lo_var_ptr; */
 
         pio = Parrot_io_STDERR(debugger);
 

Modified: branches/gsoc_threads/src/scheduler.c
==============================================================================
--- branches/gsoc_threads/src/scheduler.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/scheduler.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -22,6 +22,7 @@
 #include "parrot/runcore_api.h"
 #include "parrot/alarm.h"
 #include "parrot/scheduler.h"
+#include "parrot/threads.h"
 
 #include "pmc/pmc_scheduler.h"
 #include "pmc/pmc_task.h"
@@ -105,6 +106,7 @@
     ASSERT_ARGS(Parrot_cx_begin_execution)
     PMC *scheduler = interp->scheduler;
     Parrot_Scheduler_attributes *sched = PARROT_SCHEDULER(scheduler);
+    INTVAL alarm_count, blocked_count;
     INTVAL task_count  = 1;
 
     PMC* main_task = Parrot_pmc_new(interp, enum_class_Task);
@@ -115,9 +117,22 @@
 
     Parrot_cx_schedule_task(interp, main_task);
 
-    UNLOCK(interp->interp_lock);
+    Parrot_threads_spawn(interp);
 
-    Parrot_cx_outer_runloop(interp);
+    do {
+        Parrot_cx_check_alarms(interp, interp->scheduler);
+        Parrot_threads_wakeup(interp);
+
+        UNLOCK_INTERP(interp);
+        pause();
+        LOCK_INTERP(interp);
+
+        task_count    = VTABLE_get_integer(interp, sched->task_queue);
+        alarm_count   = VTABLE_get_integer(interp, sched->alarms);
+        blocked_count = Parrot_threads_count_blocked(interp);
+    } while (task_count + alarm_count + blocked_count > 0);
+
+    Parrot_threads_reap(interp);
 
     task_count = VTABLE_get_integer(interp, sched->all_tasks);
     if (task_count > 0)
@@ -127,7 +142,7 @@
 
 /*
 
-=item C<void Parrot_cx_outer_runloop(PARROT_INTERP)>
+=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.
@@ -138,7 +153,7 @@
 
 PARROT_EXPORT
 void
-Parrot_cx_outer_runloop(PARROT_INTERP)
+Parrot_cx_outer_runloop(PARROT_INTERP, INTVAL tidx)
 {
     ASSERT_ARGS(Parrot_cx_outer_runloop)
     PMC* scheduler = interp->scheduler;
@@ -146,39 +161,16 @@
     INTVAL task_count;
 
     for (;;) {
-        LOCK(interp->interp_lock);
+        LOCK_INTERP(interp);
+        interp->active_thread = tidx;
 
         task_count = VTABLE_get_integer(interp, sched->task_queue);
 
         if (task_count > 0) {
-            /* Yay! Do some work. */
             Parrot_cx_next_task(interp, scheduler);
         }
         else {
-            INTVAL alarm_count = VTABLE_get_integer(interp, sched->alarms);
-
-            if (alarm_count > 0) {
-                PMC     *alarm      = VTABLE_shift_pmc(interp, sched->alarms);
-                FLOATVAL alarm_time = VTABLE_get_number(interp, alarm);
-                FLOATVAL now_time   = Parrot_floatval_time();
-                FLOATVAL sleep_time = now_time - alarm_time;
-                VTABLE_unshift_pmc(interp, sched->alarms, alarm);
-
-                if (sleep_time > 0.0) {
-                    THREAD_BLOCK(interp);
-                    Parrot_floatval_sleep(sleep_time);
-                    THREAD_UNBLOCK(interp);
-                }
-
-                Parrot_cx_check_alarms(interp, interp->scheduler);
-            }
-            else {
-                /* All done */
-                /* Chandon TODO: Reap dead threads */
-                interp->thread_count -= 1;
-                UNLOCK(interp->interp_lock);
-                return;
-            }
+            Parrot_threads_idle(interp, tidx);
         }
 
         UNLOCK(interp->interp_lock);
@@ -187,28 +179,39 @@
 
 /*
 
-=item C<void* Parrot_cx_thread_main(void *interp_ptr)>
+=item C<void Parrot_cx_next_task(PARROT_INTERP, PMC *scheduler)>
 
-When an interpreter spawns a new worker thread, that thread starts
-here.
+Run the task at the head of the task queue until it ends or is
+pre-empted.
 
 =cut
 
 */
 
-PARROT_CAN_RETURN_NULL
-void*
-Parrot_cx_thread_main(ARGMOD(void *interp_ptr))
+void
+Parrot_cx_next_task(PARROT_INTERP, ARGMOD(PMC *scheduler))
 {
-    ASSERT_ARGS(Parrot_cx_thread_main)
-    Interp* interp = (Interp*) interp_ptr;
+    ASSERT_ARGS(Parrot_cx_next_task)
+    Parrot_Scheduler_attributes *sched = PARROT_SCHEDULER(scheduler);
+    INTVAL task_count;
 
-    LOCK(interp->interp_lock);
-    interp->thread_count += 1;
-    UNLOCK(interp->interp_lock);
+    task_count = VTABLE_get_integer(interp, sched->task_queue);
 
-    Parrot_cx_outer_runloop(interp);
-    return 0;
+    if (task_count > 0) {
+        FLOATVAL  time_now = Parrot_floatval_time();
+        opcode_t *dest;
+
+        interp->current_task = VTABLE_shift_pmc(interp, sched->task_queue);
+
+        if (!VTABLE_isa(interp, interp->current_task, CONST_STRING(interp, "Task")))
+            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
+                "Found a non-Task in the task queue.\n");
+
+        interp->quantum_done = time_now + PARROT_TASK_SWITCH_QUANTUM;
+        Parrot_alarm_set(interp->quantum_done);
+
+        Parrot_ext_call(interp, interp->current_task, "->");
+    }
 }
 
 /*
@@ -293,41 +296,6 @@
 }
 
 /*
-=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
-pre-empted.
-
-=cut
-*/
-
-void
-Parrot_cx_next_task(PARROT_INTERP, ARGMOD(PMC *scheduler))
-{
-    ASSERT_ARGS(Parrot_cx_next_task)
-    Parrot_Scheduler_attributes *sched = PARROT_SCHEDULER(scheduler);
-    INTVAL task_count;
-
-    task_count = VTABLE_get_integer(interp, sched->task_queue);
-
-    if (task_count > 0) {
-        FLOATVAL  time_now = Parrot_floatval_time();
-        opcode_t *dest;
-
-        interp->current_task = VTABLE_shift_pmc(interp, sched->task_queue);
-
-        if (!VTABLE_isa(interp, interp->current_task, CONST_STRING(interp, "Task")))
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
-                "Found a non-Task in the task queue.\n");
-
-        interp->quantum_done = time_now + PARROT_TASK_SWITCH_QUANTUM;
-        Parrot_alarm_set(interp->quantum_done);
-
-        Parrot_ext_call(interp, interp->current_task, "->");
-    }
-}
-
-/*
 =item C<PMC* Parrot_cx_stop_task(PARROT_INTERP, opcode_t *next)>
 
 Stop the current task and pack it up into a PMC what can be used to resume later.
@@ -762,7 +730,7 @@
 
     adata->alarm_time = done_time;
     adata->alarm_task = task;
-    VTABLE_invoke(interp, alarm, 0);
+    (void) VTABLE_invoke(interp, alarm, 0);
 
     return (opcode_t*) 0;
 }

Modified: branches/gsoc_threads/src/thread.c
==============================================================================
--- branches/gsoc_threads/src/thread.c	Thu Aug  5 13:41:24 2010	(r48330)
+++ branches/gsoc_threads/src/thread.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -481,6 +481,8 @@
 thread_func(ARGIN_NULLOK(void *arg))
 {
     ASSERT_ARGS(thread_func)
+
+#ifdef OBSOLETE_THREAD_CODE
     Parrot_runloop   jump_point;
     int              lo_var_ptr;
     UINTVAL          tid;
@@ -547,6 +549,7 @@
     UNLOCK(interpreter_array_mutex);
 
     return ret_val;
+#endif
 }
 
 /*

Added: branches/gsoc_threads/src/threads.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ branches/gsoc_threads/src/threads.c	Thu Aug  5 22:12:05 2010	(r48331)
@@ -0,0 +1,336 @@
+/*
+Copyright (C) 2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/threads.c - Functions supporting hybrid threads.
+
+=head1 DESCRIPTION
+
+These functions transparently manage OS threads in the Parrot interpreter.
+
+=head2 Functions
+
+=over 4
+
+=cut
+
+*/
+
+#include "parrot/threads.h"
+#include "parrot/alarm.h"
+
+/* HEADERIZER HFILE: include/parrot/threads.h */
+
+/*
+
+=item C<void* Parrot_cx_thread_main(void *interp_ptr)>
+
+When an interpreter spawns a new worker thread, that thread starts
+here.
+
+=cut
+
+*/
+
+
+void
+Parrot_threads_init(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_threads_init)
+    Thread_table *tbl;
+
+    interp->thread_table = (Thread_table*) malloc(sizeof(Thread_table));
+    interp->active_thread = 0;
+
+    tbl = interp->thread_table;
+
+    tbl->size    = 8; /* arbitrarily */
+    tbl->count   = 1;
+    tbl->threads = (Thread_info*) malloc(sizeof(Thread_info) * tbl->size);
+
+    tbl->threads[0].id      = THREAD_SELF();
+    tbl->threads[0].blocked = 0;
+    COND_INIT(tbl->threads[0].cvar);
+
+    LOCK_INTERP(interp);
+}
+
+/*
+
+=item C<void* Parrot_threads_main(void *args_ptr)>
+
+When an interpreter spawns a new worker thread, that thread starts
+here.
+
+=cut
+
+*/
+
+PARROT_CAN_RETURN_NULL
+void*
+Parrot_threads_main(ARGMOD(void *args_ptr))
+{
+    ASSERT_ARGS(Parrot_threads_main)
+    Thread_args *args = (Thread_args*) args_ptr;
+    Interp    *interp = args->interp;
+    INTVAL       tidx = args->idx;
+    Thread_table *tbl = interp->thread_table;
+    free(args_ptr);
+
+    Parrot_alarm_mask(interp);
+
+    /* Yay stack scanning */
+    tbl->threads[tidx].lo_var_ptr = &tidx;
+
+    //fprintf(stderr, "Thread id# %d started.\n", (int) tidx);
+
+    Parrot_cx_outer_runloop(interp, tidx);
+
+    //fprintf(stderr, "Thread id# %d ending.\n", (int) tidx);
+    return 0;
+}
+
+/*
+
+=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.
+
+Use macros BLOCK_THREAD and UNBLOCK_THREAD rather than
+calling this directly.
+
+=cut
+
+*/
+
+void
+Parrot_threads_block(PARROT_INTERP, ARGOUT(INTVAL *tidx))
+{
+    ASSERT_ARGS(Parrot_threads_block)
+    Thread_table *tbl = interp->thread_table;
+    int next;
+
+    /* scan to find who's next */
+    for (next = 1; next < tbl->count; ++next) {
+        if(tbl->threads[next].blocked == 0)
+            break;
+    }
+
+    /* Maybe spawn more threads */
+    if (next > tbl->count) {
+        Parrot_threads_spawn(interp);
+    }
+
+    *tidx = interp->active_thread;
+
+    /* While we're blocked, we might have PMCs on stack */
+    tbl->threads[*tidx].hi_var_ptr = &next;
+
+    tbl->threads[*tidx].blocked = 1;
+
+    COND_SIGNAL(tbl->threads[*tidx].cvar);
+
+    UNLOCK_INTERP(interp);
+}
+
+/*
+
+=item C<void Parrot_threads_unblock(PARROT_INTERP, INTVAL *tidx)>
+
+The current thread has completed a blocking operation.
+It's going to have to wait for someone else to finish.
+
+Use macros BLOCK_THREAD and UNBLOCK_THREAD rather than
+calling this directly.
+
+=cut
+
+*/
+
+void
+Parrot_threads_unblock(PARROT_INTERP, ARGIN(INTVAL *tidx))
+{
+    ASSERT_ARGS(Parrot_threads_unblock)
+    Thread_table *tbl;
+
+    LOCK_INTERP(interp);
+
+    tbl = interp->thread_table;
+    interp->active_thread = *tidx;
+    tbl->threads[*tidx].blocked = 0;
+}
+
+/*
+
+=item C<INTVAL Parrot_threads_count_blocked(PARROT_INTERP)>
+
+Scan the interpreter's thread table to find how many are blocked.
+
+=cut
+
+*/
+
+INTVAL
+Parrot_threads_count_blocked(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_threads_count_blocked)
+
+    Thread_table *tbl = interp->thread_table;
+    int i;
+    INTVAL count = 0;
+
+    for (i = 1; i < tbl->count; ++i) {
+        if(tbl->threads[i].blocked)
+            ++count;
+    }
+
+    return count;
+}
+
+/*
+
+=item C<void Parrot_threads_spawn(PARROT_INTERP)>
+
+Someone needs another thread. Add one at the end of table.
+
+=cut
+
+*/
+
+void
+Parrot_threads_spawn(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_threads_spawn)
+    Thread_table *tbl = interp->thread_table;
+    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);
+    }
+
+    args->interp = interp;
+    args->idx    = new_idx;
+
+    tbl->threads[new_idx].blocked = 0;
+    COND_INIT(tbl->threads[new_idx].cvar);
+
+    THREAD_CREATE_JOINABLE(tbl->threads[new_idx].id, Parrot_threads_main, args);
+}
+
+/*
+
+=item C<void Parrot_threads_reap(PARROT_INTERP)>
+
+Clean up any excess threads at the end of table.
+
+=cut
+
+*/
+
+void
+Parrot_threads_reap(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_threads_reap)
+    /* fprintf(stderr, "Parrot_reap_threads not implemented.\n"); */
+}
+
+/*
+
+=item C<void Parrot_threads_idle(PARROT_INTERP, INTVAL tidx)>
+
+Bored thread waits for work to do.
+
+=cut
+
+*/
+
+void
+Parrot_threads_idle(PARROT_INTERP, INTVAL tidx)
+{
+    ASSERT_ARGS(Parrot_threads_idle)
+    Thread_table *tbl = interp->thread_table;
+    COND_WAIT(tbl->threads[tidx].cvar, interp->interp_lock);
+    interp->active_thread = tidx;
+}
+
+/*
+
+=item C<void Parrot_threads_wakeup(PARROT_INTERP)>
+
+There might be work to do, wake up a thread.
+
+=cut
+
+*/
+
+void
+Parrot_threads_wakeup(PARROT_INTERP)
+{
+    ASSERT_ARGS(Parrot_threads_idle)
+    Thread_table *tbl = interp->thread_table;
+    int i;
+
+    for(i = 1; i < tbl->count; ++i) {
+        if (tbl->threads[i].blocked == 0) {
+            COND_SIGNAL(tbl->threads[i].cvar);
+            return;
+        }
+    }
+
+    Parrot_threads_spawn(interp);
+}
+
+/*
+
+=item C<INTVAL Parrot_threads_current(PARROT_INTERP)>
+
+Scan the table for the current thread index.
+
+=cut
+
+*/
+
+INTVAL
+Parrot_threads_current(PARROT_INTERP)
+{
+    INTVAL idx;
+    Thread_table *tbl = interp->thread_table;
+    Parrot_thread tid = THREAD_SELF();
+
+
+    for(idx = 0; idx < tbl->count; ++idx) {
+        if (THREAD_EQUAL(tbl->threads[idx].id, tid))
+            return idx;
+    }
+
+    exit_fatal(1, "threads.c: Current thread is not in the threads table.");
+}
+
+
+/*
+
+=back
+
+=head1 SEE ALSO
+
+L<include/parrot/threads.h>, L<src/scheduler.c>.
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */


More information about the parrot-commits mailing list