[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