[macruby-changes] [1930] MacRuby/branches/experimental

source_changes at macosforge.org source_changes at macosforge.org
Thu Jun 25 21:21:04 PDT 2009


Revision: 1930
          http://trac.macosforge.org/projects/ruby/changeset/1930
Author:   lsansonetti at apple.com
Date:     2009-06-25 21:21:03 -0700 (Thu, 25 Jun 2009)
Log Message:
-----------
more work on MacRuby MT

Modified Paths:
--------------
    MacRuby/branches/experimental/include/ruby/intern.h
    MacRuby/branches/experimental/thread.c
    MacRuby/branches/experimental/vm.cpp
    MacRuby/branches/experimental/vm.h

Modified: MacRuby/branches/experimental/include/ruby/intern.h
===================================================================
--- MacRuby/branches/experimental/include/ruby/intern.h	2009-06-25 18:09:46 UTC (rev 1929)
+++ MacRuby/branches/experimental/include/ruby/intern.h	2009-06-26 04:21:03 UTC (rev 1930)
@@ -297,10 +297,6 @@
 void rb_thread_polling(void);
 void rb_thread_sleep(int);
 void rb_thread_sleep_forever(void);
-VALUE rb_thread_stop(void);
-VALUE rb_thread_wakeup(VALUE);
-VALUE rb_thread_run(VALUE);
-VALUE rb_thread_kill(VALUE);
 VALUE rb_thread_create(VALUE (*)(ANYARGS), void*);
 void rb_thread_signal_raise(void *, int);
 void rb_thread_signal_exit(void *);
@@ -608,6 +604,7 @@
 /* time.c */
 VALUE rb_time_new(time_t, long);
 VALUE rb_time_nano_new(time_t, long);
+struct timeval rb_time_interval(VALUE num);
 /* variable.c */
 //VALUE rb_mod_name(VALUE);
 VALUE rb_class_path(VALUE);

Modified: MacRuby/branches/experimental/thread.c
===================================================================
--- MacRuby/branches/experimental/thread.c	2009-06-25 18:09:46 UTC (rev 1929)
+++ MacRuby/branches/experimental/thread.c	2009-06-26 04:21:03 UTC (rev 1930)
@@ -1,3 +1,12 @@
+/* 
+ * MacRuby implementation of Thread.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ * 
+ * Copyright (C) 2009, Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2007 Koichi Sasada
+ */
+
 #include "ruby/ruby.h"
 #include "ruby/node.h"
 #include "vm.h"
@@ -2,7 +11,5 @@
 
-#include <pthread.h>
-
 typedef struct rb_vm_mutex {
     pthread_mutex_t mutex;
-    pthread_t thread;
+    rb_vm_thread_t *thread;
 } rb_vm_mutex_t;
@@ -56,7 +63,7 @@
 }
 
 static VALUE
-thread_initialize(VALUE thread, SEL sel, int argc, VALUE *argv)
+thread_initialize(VALUE thread, SEL sel, int argc, const VALUE *argv)
 {
     if (!rb_block_given_p()) {
 	rb_raise(rb_eThreadError, "must be called with a block");
@@ -65,21 +72,8 @@
     assert(b != NULL);
 
     rb_vm_thread_t *t = GetThreadPtr(thread);
-    assert(t->body == NULL);
-    GC_WB(&t->body, b);
+    rb_vm_thread_pre_init(t, b, argc, argv, rb_vm_create_vm());
 
-    if (argc > 0) {
-	t->argc = argc;
-	GC_WB(&t->argv, xmalloc(sizeof(VALUE) * argc));
-	int i;
-	for (i = 0; i < argc; i++) {
-	    GC_WB(&t->argv[i], argv[i]);
-	}
-    }
-
-    t->vm = rb_vm_create_vm();
-    t->value = Qundef;
-
     // Retain the Thread object to avoid a potential GC, the corresponding
     // release is done in rb_vm_thread_run().
     rb_objc_retain((void *)thread);
@@ -89,6 +83,8 @@
 	rb_sys_fail("pthread_create() failed");
     }
 
+    //assert(pthread_detach(t->thread) == 0);
+
     return thread;
 }
 
@@ -148,7 +144,7 @@
     }
 
     rb_vm_thread_t *t = GetThreadPtr(self);
-    pthread_join(t->thread, NULL);
+    assert(pthread_join(t->thread, NULL) == 0);
 
     return self;
 }
@@ -172,30 +168,12 @@
 }
 
 void
-rb_thread_sleep_forever()
-{
-    // TODO
-}
-
-void
-rb_thread_wait_for(struct timeval time)
-{
-    // TODO
-}
-
-void
 rb_thread_polling(void)
 {
     // TODO
 }
 
 void
-rb_thread_sleep(int sec)
-{
-    // TODO
-}
-
-void
 rb_thread_schedule(void)
 {
     // TODO
@@ -224,9 +202,9 @@
  */
 
 static VALUE
-thread_s_pass(VALUE klass)
+thread_s_pass(VALUE klass, SEL sel)
 {
-    // TODO
+    pthread_yield_np();
     return Qnil;
 }
 
@@ -258,9 +236,9 @@
 
 /*
  *  call-seq:
- *     thr.exit        => thr or nil
- *     thr.kill        => thr or nil
- *     thr.terminate   => thr or nil
+ *     thr.exit        => thr
+ *     thr.kill        => thr
+ *     thr.terminate   => thr
  *
  *  Terminates <i>thr</i> and schedules another thread to be run. If this thread
  *  is already marked to be killed, <code>exit</code> returns the
@@ -268,11 +246,16 @@
  *  the process.
  */
 
-VALUE
-rb_thread_kill(VALUE thread)
+static VALUE
+rb_thread_kill(VALUE thread, SEL sel)
 {
-    // TODO
-    return Qnil;
+    rb_vm_thread_t *t = GetThreadPtr(thread);
+    if (t->status == THREAD_KILLED) {
+	// Already being killed!
+	return thread;
+    }
+    rb_vm_thread_cancel(t);
+    return thread;
 }
 
 /*
@@ -328,10 +311,10 @@
  *     hey!
  */
 
-VALUE
-rb_thread_wakeup(VALUE thread)
+static VALUE
+rb_thread_wakeup(VALUE thread, SEL sel)
 {
-    // TODO
+    rb_vm_thread_wakeup(GetThreadPtr(thread));
     return Qnil;
 }
 
@@ -354,11 +337,11 @@
  *     c
  */
 
-VALUE
-rb_thread_run(VALUE thread)
+static VALUE
+rb_thread_run(VALUE thread, SEL sel)
 {
-    // TODO
-    return Qnil;
+    // On MacRuby, #wakeup and #run are the same.
+    return rb_thread_wakeup(thread, 0);
 }
 
 /*
@@ -379,10 +362,10 @@
  *     abc
  */
 
-VALUE
-rb_thread_stop(void)
+static VALUE
+rb_thread_stop(VALUE rcv, SEL sel)
 {
-    // TODO
+    rb_thread_sleep_forever();
     return Qnil;
 }
 
@@ -446,10 +429,9 @@
  */
 
 static VALUE
-rb_thread_s_abort_exc(void)
+rb_thread_s_abort_exc(VALUE rcv, SEL sel)
 {
-    // TODO
-    return Qnil;
+    return rb_vm_abort_on_exception() ? Qtrue : Qfalse;
 }
 
 /*
@@ -477,10 +459,10 @@
  */
 
 static VALUE
-rb_thread_s_abort_exc_set(VALUE self, VALUE val)
+rb_thread_s_abort_exc_set(VALUE self, SEL sel, VALUE val)
 {
-    // TODO
-    return Qnil;
+    rb_vm_set_abort_on_exception(RTEST(val));
+    return val;
 }
 
 /*
@@ -554,11 +536,30 @@
  *     Thread.current.status   #=> "run"
  */
 
+static const char *
+rb_thread_status_cstr(VALUE thread)
+{
+    rb_vm_thread_t *t = GetThreadPtr(thread);
+    switch (t->status) {
+	case THREAD_ALIVE:
+	    return "run";
+
+	case THREAD_SLEEP:
+	    return "sleep";
+
+	case THREAD_KILLED:
+	    return "abort";
+
+	case THREAD_DEAD:
+	    return "dead";
+    }
+    return "unknown";
+}
+
 static VALUE
-rb_thread_status(VALUE thread)
+rb_thread_status(VALUE thread, SEL sel)
 {
-    // TODO
-    return Qnil;
+    return rb_str_new2(rb_thread_status_cstr(thread));
 }
 
 /*
@@ -574,10 +575,10 @@
  */
 
 static VALUE
-rb_thread_alive_p(VALUE thread)
+rb_thread_alive_p(VALUE thread, SEL sel)
 {
-    // TODO
-    return Qnil;
+    rb_vm_thread_status_t s = GetThreadPtr(thread)->status;
+    return s == THREAD_ALIVE || s == THREAD_SLEEP ? Qtrue : Qfalse;
 }
 
 /*
@@ -595,7 +596,8 @@
 static VALUE
 rb_thread_stop_p(VALUE thread)
 {
-    return Qnil;
+    rb_vm_thread_status_t s = GetThreadPtr(thread)->status;
+    return s == THREAD_DEAD || s == THREAD_SLEEP ? Qtrue : Qfalse;
 }
 
 /*
@@ -627,7 +629,7 @@
 static VALUE
 rb_thread_inspect(VALUE thread, SEL sel)
 {
-    const char *status = "unknown"; // TODO
+    const char *status = rb_thread_status_cstr(thread);
 
     char buf[100];
     snprintf(buf, sizeof buf, "#<%s:%p %s>", rb_obj_classname(thread),
@@ -1182,7 +1184,7 @@
 rb_mutex_trylock(VALUE self, SEL sel)
 {
     if (pthread_mutex_trylock(&GetMutexPtr(self)->mutex) == 0) {
-	GetMutexPtr(self)->thread = pthread_self();
+	GetMutexPtr(self)->thread = GetThreadPtr(rb_vm_current_thread());
 	return Qtrue;
     }
     return Qfalse;
@@ -1199,13 +1201,15 @@
 static VALUE
 rb_mutex_lock(VALUE self, SEL sel)
 {
-    pthread_t current = pthread_self();
+    rb_vm_thread_t *current = GetThreadPtr(rb_vm_current_thread());
     rb_vm_mutex_t *m = GetMutexPtr(self);
     if (m->thread == current) {
 	rb_raise(rb_eThreadError, "deadlock; recursive locking");
     }
 
+    current->status = THREAD_SLEEP;
     assert_ok(pthread_mutex_lock(&m->mutex));
+    current->status = THREAD_ALIVE;
     m->thread = current;
 
     return self;
@@ -1244,10 +1248,26 @@
  */
 
 static VALUE
-mutex_sleep(int argc, VALUE *argv, VALUE self)
+mutex_sleep(VALUE self, SEL sel, int argc, VALUE *argv)
 {
-    // TODO
-    return Qnil;
+    VALUE timeout;
+    rb_scan_args(argc, argv, "01", &timeout);
+
+    rb_mutex_unlock(self, 0);
+    
+    time_t beg, end;
+    beg = time(0);
+
+    if (timeout == Qnil) {
+	rb_thread_sleep_forever();	
+    }
+    else {
+	struct timeval t = rb_time_interval(timeout);
+	rb_thread_wait_for(t);
+    }
+
+    end = time(0) - beg;
+    return INT2FIX(end);        
 }
 
 /*
@@ -1262,9 +1282,16 @@
 mutex_synchronize(VALUE self, SEL sel)
 {
     rb_mutex_lock(self, 0);
+    
     // TODO catch exception
     VALUE ret = rb_yield(Qundef);
-    rb_mutex_unlock(self, 0);
+
+    if (rb_mutex_locked_p(self, 0) == Qtrue) {
+	// We only unlock the mutex if it's still locked, since it could have
+	// been unlocked in the block!
+	rb_mutex_unlock(self, 0);
+    }
+
     return ret;
 }
 
@@ -1297,32 +1324,32 @@
     rb_define_singleton_method(rb_cThread, "fork", thread_start, -2);
     rb_objc_define_method(*(VALUE *)rb_cThread, "main", rb_thread_s_main, 0);
     rb_objc_define_method(*(VALUE *)rb_cThread, "current", thread_s_current, 0);
-    rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
+    rb_objc_define_method(*(VALUE *)rb_cThread, "stop", rb_thread_stop, 0);
     rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
     rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
-    rb_define_singleton_method(rb_cThread, "pass", thread_s_pass, 0);
+    rb_objc_define_method(*(VALUE *)rb_cThread, "pass", thread_s_pass, 0);
     rb_objc_define_method(*(VALUE *)rb_cThread, "list", rb_thread_list, 0);
-    rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
-    rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
+    rb_objc_define_method(*(VALUE *)rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
+    rb_objc_define_method(*(VALUE *)rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
 
     rb_objc_define_method(rb_cThread, "initialize", thread_initialize, -1);
     rb_define_method(rb_cThread, "raise", thread_raise_m, -1);
     rb_objc_define_method(rb_cThread, "join", thread_join_m, -1);
     rb_objc_define_method(rb_cThread, "value", thread_value, 0);
-    rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
-    rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
-    rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
-    rb_define_method(rb_cThread, "run", rb_thread_run, 0);
-    rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
+    rb_objc_define_method(rb_cThread, "kill", rb_thread_kill, 0);
+    rb_objc_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
+    rb_objc_define_method(rb_cThread, "exit", rb_thread_kill, 0);
+    rb_objc_define_method(rb_cThread, "run", rb_thread_run, 0);
+    rb_objc_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
     rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
     rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
     rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
     rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
     rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
     rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
-    rb_define_method(rb_cThread, "status", rb_thread_status, 0);
-    rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
-    rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
+    rb_objc_define_method(rb_cThread, "status", rb_thread_status, 0);
+    rb_objc_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
+    rb_objc_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
     rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
     rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
     rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
@@ -1343,7 +1370,7 @@
     rb_objc_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
     rb_objc_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
     rb_objc_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
-    rb_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
+    rb_objc_define_method(rb_cMutex, "sleep", mutex_sleep, -1);
     rb_objc_define_method(rb_cMutex, "synchronize", mutex_synchronize, 0);
 
     rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);

Modified: MacRuby/branches/experimental/vm.cpp
===================================================================
--- MacRuby/branches/experimental/vm.cpp	2009-06-25 18:09:46 UTC (rev 1929)
+++ MacRuby/branches/experimental/vm.cpp	2009-06-26 04:21:03 UTC (rev 1930)
@@ -186,6 +186,7 @@
 {
     running = false;
     multithreaded = false;
+    abort_on_exception = false;
 
     assert(pthread_mutex_init(&gl, 0) == 0);
 
@@ -697,6 +698,20 @@
 }
 
 extern "C"
+bool
+rb_vm_abort_on_exception(void)
+{
+    return GET_CORE()->get_abort_on_exception();
+}
+
+extern "C"
+void
+rb_vm_set_abort_on_exception(bool flag)
+{
+    GET_CORE()->set_abort_on_exception(flag);
+}
+
+extern "C"
 void 
 rb_vm_set_const(VALUE outer, ID id, VALUE obj)
 {
@@ -3695,7 +3710,10 @@
     assert(argc > 0);
 
     VALUE current_exception = GET_VM()->current_exception();
-    assert(current_exception != Qnil);
+    if (current_exception == Qnil) {
+	// Not a Ruby exception...
+	return 0;
+    }
 
     va_list ar;
     unsigned char active = 0;
@@ -4241,13 +4259,41 @@
     unlock();
 
     rb_vm_thread_t *t = GetThreadPtr(thread);
+
+    const int code = pthread_mutex_destroy(&t->sleep_mutex);
+    if (code == EBUSY) {
+	// The mutex is already locked, which means we are being called from
+	// a cancellation point inside the wait logic. Let's unlock the mutex
+	// and try again.
+	assert(pthread_mutex_unlock(&t->sleep_mutex) == 0);
+	assert(pthread_mutex_destroy(&t->sleep_mutex) == 0);
+    }
+    else if (code != 0) {
+	abort();
+    }
+    assert(pthread_cond_destroy(&t->sleep_cond) == 0);
+
     RoxorVM *vm = (RoxorVM *)t->vm;
     delete vm;
     t->vm = NULL;
 
     assert(pthread_setspecific(RoxorVM::vm_thread_key, NULL) == 0);
+
+    t->status = THREAD_DEAD;
 }
 
+static inline void
+rb_vm_thread_throw_kill(void)
+{
+    rb_vm_rethrow();
+}
+
+static void
+rb_vm_thread_destructor(void *userdata)
+{
+    rb_vm_thread_throw_kill();
+}
+
 extern "C"
 void *
 rb_vm_thread_run(VALUE thread)
@@ -4255,24 +4301,30 @@
     rb_objc_gc_register_thread();
     GET_CORE()->register_thread(thread);
 
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+
     // Release the thread now.
     rb_objc_release((void *)thread);
 
+    pthread_cleanup_push(rb_vm_thread_destructor, (void *)thread);
+
+    rb_vm_thread_t *t = GetThreadPtr(thread);
     try {
-	rb_vm_thread_t *t = GetThreadPtr(thread);
 	VALUE val = rb_vm_block_eval(t->body, t->argc, t->argv);
 	GC_WB(&t->value, val);
     }
     catch (...) {
 	// TODO handle thread-level exceptions.
-	printf("exception raised inside thread %p\n", pthread_self());
+	//printf("exception raised inside thread %p\n", pthread_self());
     }
 
+    pthread_cleanup_pop(0);
+
     GET_CORE()->unregister_thread(thread);
     rb_objc_gc_unregister_thread();
 
     return NULL;
-
 }
 
 extern "C"
@@ -4296,6 +4348,118 @@
     return RoxorVM::main->get_thread();
 }
 
+extern "C"
+void
+rb_vm_thread_pre_init(rb_vm_thread_t *t, rb_vm_block_t *body, int argc,
+	const VALUE *argv, void *vm)
+{
+    t->thread = 0; // this will be set later
+
+    if (body != NULL) {
+	GC_WB(&t->body, body);
+    }
+    else {
+	t->body = NULL;
+    }
+   
+    if (argc > 0) {
+	t->argc = argc;
+	GC_WB(&t->argv, xmalloc(sizeof(VALUE) * argc));
+	int i;
+	for (i = 0; i < argc; i++) {
+	    GC_WB(&t->argv[i], argv[i]);
+	}
+    }
+    else {
+	t->argc = 0;
+	t->argv = NULL;
+    }
+
+    t->vm  = vm;
+    t->value = Qundef;
+    t->status = THREAD_ALIVE;
+
+    assert(pthread_mutex_init(&t->sleep_mutex, NULL) == 0);
+    assert(pthread_cond_init(&t->sleep_cond, NULL) == 0); 
+}
+
+extern "C"
+void
+rb_thread_sleep_forever()
+{
+    rb_vm_thread_t *t = GET_THREAD();
+    t->status = THREAD_SLEEP;
+
+    assert(pthread_mutex_lock(&t->sleep_mutex) == 0);
+    const int code = pthread_cond_wait(&t->sleep_cond, &t->sleep_mutex);
+    assert(code == 0 || code == ETIMEDOUT);
+    assert(pthread_mutex_unlock(&t->sleep_mutex) == 0);
+
+    t->status = THREAD_ALIVE;
+}
+
+extern "C"
+void
+rb_thread_wait_for(struct timeval time)
+{
+    struct timeval tvn;
+    gettimeofday(&tvn, NULL);
+
+    struct timespec ts;
+    ts.tv_sec = tvn.tv_sec + time.tv_sec;
+    ts.tv_nsec = (tvn.tv_usec + time.tv_usec) * 1000;
+    while (ts.tv_nsec >= 1000000000) {
+	ts.tv_sec += 1;
+	ts.tv_nsec -= 1000000000;
+    }
+
+    rb_vm_thread_t *t = GET_THREAD();
+    t->status = THREAD_SLEEP;
+
+    assert(pthread_mutex_lock(&t->sleep_mutex) == 0);
+    const int code = pthread_cond_timedwait(&t->sleep_cond, &t->sleep_mutex,
+	    &ts);
+    assert(code == 0 || code == ETIMEDOUT);
+    assert(pthread_mutex_unlock(&t->sleep_mutex) == 0);
+
+    t->status = THREAD_ALIVE;
+}
+
+extern "C"
+void
+rb_vm_thread_wakeup(rb_vm_thread_t *t)
+{
+    if (t->status == THREAD_DEAD) {
+	rb_raise(rb_eThreadError, "can't wake up thread from the dead");
+    }
+    if (t->status == THREAD_SLEEP) {
+	assert(pthread_cond_signal(&t->sleep_cond) == 0);
+    }
+}
+
+extern "C"
+void
+rb_vm_thread_cancel(rb_vm_thread_t *t)
+{
+    t->status = THREAD_KILLED;
+    if (t->thread == pthread_self()) {
+	rb_vm_thread_throw_kill();
+    }
+    else {
+	assert(pthread_cancel(t->thread) == 0);
+    }
+}
+
+extern "C"
+void
+rb_thread_sleep(int sec)
+{
+    struct timeval time;
+    time.tv_sec = sec;
+    time.tv_usec = 0;
+    rb_thread_wait_for(time);
+}
+
 static VALUE
 builtin_ostub1(IMP imp, id self, SEL sel, int argc, VALUE *argv)
 {
@@ -4384,11 +4548,13 @@
 Init_PostVM(void)
 {
     // Create and register the main thread;
+    RoxorVM *main_vm = GET_VM();
     rb_vm_thread_t *t = (rb_vm_thread_t *)xmalloc(sizeof(rb_vm_thread_t));
+    rb_vm_thread_pre_init(t, NULL, 0, NULL, (void *)main_vm);
     t->thread = pthread_self();
-    t->vm = (void *)GET_VM();
     VALUE main = Data_Wrap_Struct(rb_cThread, NULL, NULL, t);
     GET_CORE()->register_thread(main);
+    main_vm->set_thread(main);
 }
 
 extern "C"

Modified: MacRuby/branches/experimental/vm.h
===================================================================
--- MacRuby/branches/experimental/vm.h	2009-06-25 18:09:46 UTC (rev 1929)
+++ MacRuby/branches/experimental/vm.h	2009-06-26 04:21:03 UTC (rev 1930)
@@ -71,6 +71,15 @@
 
 #define GetThreadPtr(obj) ((rb_vm_thread_t *)DATA_PTR(obj))
 
+typedef enum {
+    THREAD_ALIVE,  // this thread was born to be alive
+    THREAD_SLEEP,  // this thread is sleeping
+    THREAD_KILLED, // this thread is being killed!
+    THREAD_DEAD    // this thread is dead, sigh
+} rb_vm_thread_status_t;
+
+#include <pthread.h>
+
 typedef struct rb_vm_thread {
     pthread_t thread;
     rb_vm_block_t *body;
@@ -78,6 +87,9 @@
     const VALUE *argv;
     void *vm;  // an instance of RoxorVM
     VALUE value;
+    pthread_mutex_t sleep_mutex;
+    pthread_cond_t sleep_cond;
+    rb_vm_thread_status_t status;
 } rb_vm_thread_t;
 
 typedef struct rb_vm_outer {
@@ -323,12 +335,19 @@
 void rb_vm_add_binding(rb_vm_binding_t *binding);
 void rb_vm_pop_binding();
 
+void rb_vm_thread_pre_init(rb_vm_thread_t *t, rb_vm_block_t *body, int argc,
+	const VALUE *argv, void *vm);
 void *rb_vm_create_vm(void);
 void *rb_vm_thread_run(VALUE thread);
 VALUE rb_vm_current_thread(void);
 VALUE rb_vm_main_thread(void);
 VALUE rb_vm_threads(void);
+void rb_vm_thread_wakeup(rb_vm_thread_t *t);
+void rb_vm_thread_cancel(rb_vm_thread_t *t);
 
+bool rb_vm_abort_on_exception(void);
+void rb_vm_set_abort_on_exception(bool flag);
+
 static inline VALUE
 rb_robject_allocate_instance(VALUE klass)
 {
@@ -360,6 +379,7 @@
 VALUE rb_vm_pop_broken_value(void);
 #define RETURN_IF_BROKEN() \
     do { \
+	pthread_testcancel(); \
 	VALUE __v = rb_vm_pop_broken_value(); \
 	if (__v != Qundef) { \
 	    return __v; \
@@ -472,6 +492,7 @@
 	// State.
 	bool running;
 	bool multithreaded;
+	bool abort_on_exception;
 	pthread_mutex_t gl;
 	VALUE loaded_features;
 	VALUE load_path;
@@ -525,6 +546,7 @@
 
 	ACCESSOR(running, bool);
 	ACCESSOR(multithreaded, bool);
+	ACCESSOR(abort_on_exception, bool);
 	READER(loaded_features, VALUE);
 	READER(load_path, VALUE);
 	READER(threads, VALUE);
@@ -826,6 +848,7 @@
 };
 
 #define GET_VM() (RoxorVM::current())
+#define GET_THREAD() (GetThreadPtr(GET_VM()->get_thread()))
 
 #endif /* __cplusplus */
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090625/5b1930c6/attachment-0001.html>


More information about the macruby-changes mailing list