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

source_changes at macosforge.org source_changes at macosforge.org
Fri Jun 26 22:57:25 PDT 2009


Revision: 1944
          http://trac.macosforge.org/projects/ruby/changeset/1944
Author:   lsansonetti at apple.com
Date:     2009-06-26 22:57:24 -0700 (Fri, 26 Jun 2009)
Log Message:
-----------
more MT work

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

Modified: MacRuby/branches/experimental/thread.c
===================================================================
--- MacRuby/branches/experimental/thread.c	2009-06-27 02:04:20 UTC (rev 1943)
+++ MacRuby/branches/experimental/thread.c	2009-06-27 05:57:24 UTC (rev 1944)
@@ -16,16 +16,6 @@
     rb_vm_thread_t *thread;
 } rb_vm_mutex_t;
 
-#define assert_ok(call) \
-    do { \
-	const int __r = call; \
-	if (__r != 0) { \
-	    rb_raise(rb_eRuntimeError, "pthread operation failed: error %d", \
-		    __r); \
-	} \
-    } \
-    while (0)
-
 VALUE rb_cThread;
 VALUE rb_cMutex;
 
@@ -136,16 +126,36 @@
 static VALUE
 thread_join_m(VALUE self, SEL sel, int argc, VALUE *argv)
 {
-    if (argc != 0) {
-	rb_raise(rb_eArgError,
-		"calling #join with an argument is not implemented yet");
-    }
+    VALUE timeout;
 
+    rb_scan_args(argc, argv, "01", &timeout);
+
     rb_vm_thread_t *t = GetThreadPtr(self);
-    if (t->status != THREAD_DEAD) {
-	assert(pthread_join(t->thread, NULL) == 0);
+    if (t->status == THREAD_DEAD) {
+	return self;
     }
 
+    if (timeout == Qnil) {
+	// No timeout given: block until the thread finishes.
+	pthread_assert(pthread_join(t->thread, NULL));
+    }
+    else {
+	// Timeout given: sleep then check if the thread is dead.
+	// TODO do multiple sleeps instead of only one.
+	struct timeval tv = rb_time_interval(timeout);
+	struct timespec ts;
+	ts.tv_sec = tv.tv_sec;
+	ts.tv_nsec = tv.tv_usec * 1000;
+	while (ts.tv_nsec >= 1000000000) {
+	    ts.tv_sec += 1;
+	    ts.tv_nsec -= 1000000000;
+	}
+	nanosleep(&ts, NULL);
+	if (t->status != THREAD_DEAD) {
+	    return Qnil;
+	}
+    }
+
     return self;
 }
 
@@ -558,6 +568,11 @@
 static VALUE
 rb_thread_status(VALUE thread, SEL sel)
 {
+    rb_vm_thread_t *t = GetThreadPtr(thread);
+    if (t->status == THREAD_DEAD) {
+	// TODO should return Qnil in case the thread got an exception.
+	return Qfalse;
+    }
     return rb_str_new2(rb_thread_status_cstr(thread));
 }
 
@@ -1162,7 +1177,7 @@
 static VALUE
 mutex_initialize(VALUE self, SEL sel)
 {
-    assert_ok(pthread_mutex_init(&GetMutexPtr(self)->mutex, NULL));
+    pthread_assert(pthread_mutex_init(&GetMutexPtr(self)->mutex, NULL));
     return self;
 }
 
@@ -1215,7 +1230,7 @@
     }
 
     current->status = THREAD_SLEEP;
-    assert_ok(pthread_mutex_lock(&m->mutex));
+    pthread_assert(pthread_mutex_lock(&m->mutex));
     current->status = THREAD_ALIVE;
     m->thread = current;
 
@@ -1239,7 +1254,7 @@
 		"Attempt to unlock a mutex which is not locked");
     }
 
-    assert_ok(pthread_mutex_unlock(&m->mutex));
+    pthread_assert(pthread_mutex_unlock(&m->mutex));
     m->thread = 0;
 
     return self;

Modified: MacRuby/branches/experimental/vm.cpp
===================================================================
--- MacRuby/branches/experimental/vm.cpp	2009-06-27 02:04:20 UTC (rev 1943)
+++ MacRuby/branches/experimental/vm.cpp	2009-06-27 05:57:24 UTC (rev 1944)
@@ -188,7 +188,7 @@
     multithreaded = false;
     abort_on_exception = false;
 
-    assert(pthread_mutex_init(&gl, 0) == 0);
+    pthread_assert(pthread_mutex_init(&gl, 0));
 
     load_path = rb_ary_new();
     rb_objc_retain((void *)load_path);
@@ -4340,7 +4340,7 @@
     unlock();
 
     rb_vm_thread_t *t = GetThreadPtr(thread);
-    assert(pthread_setspecific(RoxorVM::vm_thread_key, t->vm) == 0);
+    pthread_assert(pthread_setspecific(RoxorVM::vm_thread_key, t->vm));
 
     RoxorVM *vm = (RoxorVM *)t->vm;
     vm->set_thread(thread);
@@ -4364,19 +4364,19 @@
 	// 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);
+	pthread_assert(pthread_mutex_unlock(&t->sleep_mutex));
+	pthread_assert(pthread_mutex_destroy(&t->sleep_mutex));
     }
     else if (code != 0) {
 	abort();
     }
-    assert(pthread_cond_destroy(&t->sleep_cond) == 0);
+    pthread_assert(pthread_cond_destroy(&t->sleep_cond));
 
     RoxorVM *vm = (RoxorVM *)t->vm;
     delete vm;
     t->vm = NULL;
 
-    assert(pthread_setspecific(RoxorVM::vm_thread_key, NULL) == 0);
+    pthread_assert(pthread_setspecific(RoxorVM::vm_thread_key, NULL));
 
     t->status = THREAD_DEAD;
 }
@@ -4410,6 +4410,11 @@
 
     rb_vm_thread_t *t = GetThreadPtr(thread);
 
+    // Normally the pthread ID is set into the VM structure in the other
+    // thread right after pthread_create(), but we might run before the
+    // assignment!
+    t->thread = pthread_self();
+
     try {
 	VALUE val = rb_vm_block_eval(t->body, t->argc, t->argv);
 	GC_WB(&t->value, val);
@@ -4493,15 +4498,15 @@
     t->status = THREAD_ALIVE;
     t->in_cond_wait = false;
 
-    assert(pthread_mutex_init(&t->sleep_mutex, NULL) == 0);
-    assert(pthread_cond_init(&t->sleep_cond, NULL) == 0); 
+    pthread_assert(pthread_mutex_init(&t->sleep_mutex, NULL));
+    pthread_assert(pthread_cond_init(&t->sleep_cond, NULL)); 
 }
 
 static inline void
 pre_wait(rb_vm_thread_t *t)
 {
+    pthread_assert(pthread_mutex_lock(&t->sleep_mutex));
     t->status = THREAD_SLEEP;
-    assert(pthread_mutex_lock(&t->sleep_mutex) == 0);
     t->in_cond_wait = true;
 }
 
@@ -4509,7 +4514,7 @@
 post_wait(rb_vm_thread_t *t)
 {
     t->in_cond_wait = false;
-    assert(pthread_mutex_unlock(&t->sleep_mutex) == 0);
+    pthread_assert(pthread_mutex_unlock(&t->sleep_mutex));
     if (t->status == THREAD_KILLED) {
 	rb_vm_thread_throw_kill();
     }
@@ -4552,14 +4557,6 @@
     post_wait(t);
 }
 
-static inline void
-signal_thread(rb_vm_thread_t *t)
-{
-    assert(pthread_mutex_lock(&t->sleep_mutex) == 0);
-    assert(pthread_cond_signal(&t->sleep_cond) == 0);
-    assert(pthread_mutex_unlock(&t->sleep_mutex) == 0);
-}
-
 extern "C"
 void
 rb_vm_thread_wakeup(rb_vm_thread_t *t)
@@ -4568,7 +4565,9 @@
 	rb_raise(rb_eThreadError, "can't wake up thread from the death");
     }
     if (t->status == THREAD_SLEEP && t->in_cond_wait) {
-	signal_thread(t);
+	pthread_assert(pthread_mutex_lock(&t->sleep_mutex));
+	pthread_assert(pthread_cond_signal(&t->sleep_cond));
+	pthread_assert(pthread_mutex_unlock(&t->sleep_mutex));
     }
 }
 
@@ -4576,22 +4575,26 @@
 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 {
-	if (t->in_cond_wait) {
-	    // We are trying to kill a thread which is currently waiting
-	    // for a condition variable (#sleep). Instead of canceling the
-	    // thread, we are simply signaling the variable, and the thread
-	    // will autodestroy itself, to work around a stack unwinding bug
-	    // in the Mac OS X pthread implementation that messes our C++
-	    // exception handlers.
-	    signal_thread(t);
+    if (t->status != THREAD_KILLED && t->status != THREAD_DEAD) {
+	t->status = THREAD_KILLED;
+	if (t->thread == pthread_self()) {
+	    rb_vm_thread_throw_kill();
 	}
 	else {
-	    assert(pthread_cancel(t->thread) == 0);
+	    pthread_assert(pthread_mutex_lock(&t->sleep_mutex));
+	    if (t->in_cond_wait) {
+		// We are trying to kill a thread which is currently waiting
+		// for a condition variable (#sleep). Instead of canceling the
+		// thread, we are simply signaling the variable, and the thread
+		// will autodestroy itself, to work around a stack unwinding
+		// bug in the Mac OS X pthread implementation that messes our
+		// C++ exception handlers.
+		pthread_assert(pthread_cond_signal(&t->sleep_cond));
+	    }
+	    else {
+		pthread_assert(pthread_cancel(t->thread));
+	    }
+	    pthread_assert(pthread_mutex_unlock(&t->sleep_mutex));
 	}
     }
 }
@@ -4650,7 +4653,7 @@
     RoxorCore::shared = new RoxorCore();
     RoxorVM::main = new RoxorVM();
 
-    assert(pthread_key_create(&RoxorVM::vm_thread_key, NULL) == 0);
+    pthread_assert(pthread_key_create(&RoxorVM::vm_thread_key, NULL));
 
     setup_builtin_stubs();
 

Modified: MacRuby/branches/experimental/vm.h
===================================================================
--- MacRuby/branches/experimental/vm.h	2009-06-27 02:04:20 UTC (rev 1943)
+++ MacRuby/branches/experimental/vm.h	2009-06-27 05:57:24 UTC (rev 1944)
@@ -80,6 +80,17 @@
 
 #include <pthread.h>
 
+#define pthread_assert(cmd) \
+    do { \
+	const int code = cmd; \
+	if (code != 0) { \
+	    printf("pthread command `%s' failed: %s (%d)\n", \
+		#cmd, strerror(code), code); \
+	    abort(); \
+	} \
+    } \
+    while (0)
+
 typedef struct rb_vm_thread {
     pthread_t thread;
     rb_vm_block_t *body;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090626/ebc05e1e/attachment-0001.html>


More information about the macruby-changes mailing list