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

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 24 21:04:56 PDT 2009


Revision: 1925
          http://trac.macosforge.org/projects/ruby/changeset/1925
Author:   lsansonetti at apple.com
Date:     2009-06-24 21:04:55 -0700 (Wed, 24 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-24 19:13:48 UTC (rev 1924)
+++ MacRuby/branches/experimental/thread.c	2009-06-25 04:04:55 UTC (rev 1925)
@@ -6,8 +6,19 @@
 
 typedef struct rb_vm_mutex {
     pthread_mutex_t mutex;
+    pthread_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;
 
@@ -67,6 +78,7 @@
     }
 
     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().
@@ -136,11 +148,8 @@
     }
 
     rb_vm_thread_t *t = GetThreadPtr(self);
+    pthread_join(t->thread, NULL);
 
-    if (pthread_join(t->thread, NULL) != 0) {
-	rb_sys_fail("pthread_join() failed");
-    }
-
     return self;
 }
 
@@ -156,10 +165,10 @@
  */
 
 static VALUE
-thread_value(VALUE self)
+thread_value(VALUE self, SEL sel)
 {
-    // TODO
-    return Qnil;
+    thread_join_m(self, 0, 0, NULL);
+    return GetThreadPtr(self)->value;
 }
 
 void
@@ -616,10 +625,15 @@
  */
 
 static VALUE
-rb_thread_inspect(VALUE thread)
+rb_thread_inspect(VALUE thread, SEL sel)
 {
-    // TODO
-    return Qnil;
+    const char *status = "unknown"; // TODO
+
+    char buf[100];
+    snprintf(buf, sizeof buf, "#<%s:%p %s>", rb_obj_classname(thread),
+	    (void *)thread, status);
+
+    return rb_str_new2(buf);
 }
 
 /*
@@ -1134,22 +1148,12 @@
     return Data_Wrap_Struct(rb_cMutex, NULL, NULL, t);
 }
 
-#define GetMutex(obj) (((rb_vm_mutex_t *)DATA_PTR(obj))->mutex)
+#define GetMutexPtr(obj) ((rb_vm_mutex_t *)DATA_PTR(obj))
 
-#define assert_ok(call) \
-    do { \
-	const int __r = call; \
-	if (__r != 0) { \
-	    rb_raise(rb_eRuntimeError, "mutex operation failed: error %d", \
-		    __r); \
-	} \
-    } \
-    while (0)
-
 static VALUE
 mutex_initialize(VALUE self, SEL sel)
 {
-    assert_ok(pthread_mutex_init(&GetMutex(self), NULL));
+    assert_ok(pthread_mutex_init(&GetMutexPtr(self)->mutex, NULL));
     return self;
 }
 
@@ -1160,11 +1164,10 @@
  * Returns +true+ if this lock is currently held by some thread.
  */
 
-VALUE
-rb_mutex_locked_p(VALUE self)
+static VALUE
+rb_mutex_locked_p(VALUE self, SEL sel)
 {
-    // TODO
-    return Qnil;
+    return GetMutexPtr(self)->thread == 0 ? Qfalse : Qtrue;
 }
 
 /*
@@ -1178,23 +1181,34 @@
 static VALUE
 rb_mutex_trylock(VALUE self, SEL sel)
 {
-    // TODO
-    return Qnil;
+    if (pthread_mutex_trylock(&GetMutexPtr(self)->mutex) == 0) {
+	GetMutexPtr(self)->thread = pthread_self();
+	return Qtrue;
+    }
+    return Qfalse;
 }
 
 /*
  * call-seq:
- *    mutex.lock  => true or false
+ *    mutex.lock  => self
  *
  * Attempts to grab the lock and waits if it isn't available.
  * Raises +ThreadError+ if +mutex+ was locked by the current thread.
  */
 
-VALUE
-rb_mutex_lock(VALUE self)
+static VALUE
+rb_mutex_lock(VALUE self, SEL sel)
 {
-    // TODO
-    return Qnil;
+    pthread_t current = pthread_self();
+    rb_vm_mutex_t *m = GetMutexPtr(self);
+    if (m->thread == current) {
+	rb_raise(rb_eThreadError, "deadlock; recursive locking");
+    }
+
+    assert_ok(pthread_mutex_lock(&m->mutex));
+    m->thread = current;
+
+    return self;
 }
 
 /*
@@ -1205,11 +1219,19 @@
  * Raises +ThreadError+ if +mutex+ wasn't locked by the current thread.
  */
 
-VALUE
-rb_mutex_unlock(VALUE self)
+static VALUE
+rb_mutex_unlock(VALUE self, SEL sel)
 {
-    // TODO
-    return Qnil;
+    rb_vm_mutex_t *m = GetMutexPtr(self);
+    if (m->thread == 0) {
+	rb_raise(rb_eThreadError,
+		"Attempt to unlock a mutex which is not locked");
+    }
+
+    assert_ok(pthread_mutex_unlock(&m->mutex));
+    m->thread = 0;
+
+    return self;
 }
 
 /*
@@ -1239,10 +1261,10 @@
 static VALUE
 mutex_synchronize(VALUE self, SEL sel)
 {
-    assert_ok(pthread_mutex_lock(&GetMutex(self)));
+    rb_mutex_lock(self, 0);
     // TODO catch exception
     VALUE ret = rb_yield(Qundef);
-    assert_ok(pthread_mutex_unlock(&GetMutex(self)));
+    rb_mutex_unlock(self, 0);
     return ret;
 }
 
@@ -1286,7 +1308,7 @@
     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_define_method(rb_cThread, "value", thread_value, 0);
+    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);
@@ -1306,7 +1328,7 @@
     rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
     rb_define_method(rb_cThread, "group", rb_thread_group, 0);
 
-    rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
+    rb_objc_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
 
     cThGroup = rb_define_class("ThreadGroup", rb_cObject);
     rb_define_method(cThGroup, "list", thgroup_list, 0);
@@ -1317,10 +1339,10 @@
     rb_cMutex = rb_define_class("Mutex", rb_cObject);
     rb_objc_define_method(*(VALUE *)rb_cMutex, "alloc", mutex_s_alloc, 0);
     rb_objc_define_method(rb_cMutex, "initialize", mutex_initialize, 0);
-    rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
-    rb_define_method(rb_cMutex, "try_lock", rb_mutex_trylock, 0);
-    rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
-    rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
+    rb_objc_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
+    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, "synchronize", mutex_synchronize, 0);
 

Modified: MacRuby/branches/experimental/vm.cpp
===================================================================
--- MacRuby/branches/experimental/vm.cpp	2009-06-24 19:13:48 UTC (rev 1924)
+++ MacRuby/branches/experimental/vm.cpp	2009-06-25 04:04:55 UTC (rev 1925)
@@ -443,10 +443,8 @@
 RoxorCore::method_node_get(IMP imp)
 {
     std::map<IMP, rb_vm_method_node_t *>::iterator iter = ruby_imps.find(imp);
-    if (iter == ruby_imps.end()) {
-	return NULL;
-    }
-    return iter->second;
+    rb_vm_method_node_t *m = iter == ruby_imps.end() ? NULL : iter->second;
+    return m;
 }
 
 extern "C"
@@ -1834,7 +1832,8 @@
 }
 
 static force_inline void
-__rb_vm_fix_args(const VALUE *argv, VALUE *new_argv, const rb_vm_arity_t &arity, int argc)
+__rb_vm_fix_args(const VALUE *argv, VALUE *new_argv,
+	const rb_vm_arity_t &arity, int argc)
 {
     assert(argc >= arity.min);
     assert((arity.max == -1) || (argc <= arity.max));
@@ -2121,16 +2120,22 @@
 inline void *
 RoxorCore::gen_stub(std::string types, int argc, bool is_objc)
 {
+    lock();
+
     std::map<std::string, void *> &stubs = is_objc ? objc_stubs : c_stubs;
     std::map<std::string, void *>::iterator iter = stubs.find(types);
-    if (iter != stubs.end()) {
-	return iter->second;
+    void *stub;
+    if (iter == stubs.end()) {
+	Function *f = RoxorCompiler::shared->compile_stub(types.c_str(), argc,
+		is_objc);
+	stub = (void *)compile(f);
+	stubs.insert(std::make_pair(types, stub));
     }
+    else {
+	stub = iter->second;
+    }
 
-    Function *f = RoxorCompiler::shared->compile_stub(types.c_str(), argc,
-	    is_objc);
-    void *stub = (void *)compile(f);
-    stubs.insert(std::make_pair(types, stub));
+    unlock();
 
     return stub;
 }
@@ -2295,10 +2300,8 @@
 	    argc = real_argc;
 	}
     }
-    GET_CORE()->lock();
     ocache.stub = (rb_vm_objc_stub_t *)GET_CORE()->gen_stub(types, 
 	    argc, true);
-    GET_CORE()->unlock();
 }
 
 static force_inline VALUE
@@ -2833,7 +2836,7 @@
 }
 
 rb_vm_block_t *
-RoxorCore::uncache_or_create_block(NODE *key, bool *cached, int dvars_size)
+RoxorVM::uncache_or_create_block(NODE *key, bool *cached, int dvars_size)
 {
     std::map<NODE *, rb_vm_block_t *>::iterator iter = blocks.find(key);
 
@@ -2845,12 +2848,10 @@
 	if (iter != blocks.end()) {
 	    rb_objc_release(iter->second);
 	}
-
 	b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t)
 		+ (sizeof(VALUE *) * dvars_size));
 	rb_objc_retain(b);
 	blocks[key] = b;
-
 	*cached = false;
     }
     else {
@@ -2878,10 +2879,8 @@
 	cache_key = node;
     }
 
-    GET_CORE()->lock();
-
     bool cached = false;
-    rb_vm_block_t *b = GET_CORE()->uncache_or_create_block(cache_key, &cached,
+    rb_vm_block_t *b = GET_VM()->uncache_or_create_block(cache_key, &cached,
 	dvars_size);
 
     if (!cached) {
@@ -2892,7 +2891,9 @@
 	}
 	else {
 	    assert(llvm_function != NULL);
+	    GET_CORE()->lock();
 	    b->imp = GET_CORE()->compile((Function *)llvm_function);
+	    GET_CORE()->unlock();
 	    b->arity = rb_vm_node_arity(node);
 	}
 	b->flags = 0;
@@ -2904,8 +2905,6 @@
 	assert(b->dvars_size == dvars_size);
     }
 
-    GET_CORE()->unlock();
-
     b->self = self;
     b->node = node;
     b->parent_var_uses = parent_var_uses;
@@ -4219,7 +4218,9 @@
 void
 RoxorCore::register_thread(VALUE thread)
 {
+    lock();
     rb_ary_push(threads, thread);
+    unlock();
 
     rb_vm_thread_t *t = GetThreadPtr(thread);
     assert(pthread_setspecific(RoxorVM::vm_thread_key, t->vm) == 0);
@@ -4231,11 +4232,13 @@
 void
 RoxorCore::unregister_thread(VALUE thread)
 {
+    lock();
     if (rb_ary_delete(threads, thread) != thread) {
 	printf("trying to unregister a thread (%p) that was never registered!",
 		(void *)thread);
 	abort();
     }
+    unlock();
 
     rb_vm_thread_t *t = GetThreadPtr(thread);
     RoxorVM *vm = (RoxorVM *)t->vm;
@@ -4257,10 +4260,12 @@
 
     try {
 	rb_vm_thread_t *t = GetThreadPtr(thread);
-	rb_vm_block_eval(t->body, t->argc, t->argv);
+	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());
     }
 
     GET_CORE()->unregister_thread(thread);

Modified: MacRuby/branches/experimental/vm.h
===================================================================
--- MacRuby/branches/experimental/vm.h	2009-06-24 19:13:48 UTC (rev 1924)
+++ MacRuby/branches/experimental/vm.h	2009-06-25 04:04:55 UTC (rev 1925)
@@ -77,6 +77,7 @@
     int argc;
     const VALUE *argv;
     void *vm;  // an instance of RoxorVM
+    VALUE value;
 } rb_vm_thread_t;
 
 typedef struct rb_vm_outer {
@@ -478,9 +479,6 @@
 	// Cache to avoid compiling the same Function twice.
 	std::map<Function *, IMP> JITcache;
 
-	// Cache to avoid compiling the same block twice.
-	std::map<NODE *, rb_vm_block_t *> blocks;
-
 	// Cache to identify pure Ruby methods.
 	std::map<IMP, rb_vm_method_node_t *> ruby_imps;
 
@@ -652,9 +650,6 @@
 	    }
 	}
 
-	rb_vm_block_t *uncache_or_create_block(NODE *key, bool *cached,
-		int dvars_size);
-
 	size_t get_sizeof(const Type *type);
 	size_t get_sizeof(const char *type);
 	bool is_large_struct_type(const Type *type);
@@ -696,6 +691,10 @@
 	}
 
     private:
+	// Cache to avoid allocating the same block twice.
+	std::map<NODE *, rb_vm_block_t *> blocks;
+
+	// Keeps track of the current VM state (blocks, exceptions, bindings).
 	std::vector<rb_vm_block_t *> current_blocks;
 	std::vector<VALUE> current_exceptions;
 	std::vector<rb_vm_binding_t *> bindings;
@@ -765,6 +764,9 @@
 	    return b;
 	}
 
+	rb_vm_block_t *uncache_or_create_block(NODE *key, bool *cached,
+		int dvars_size);
+
 	rb_vm_binding_t *current_binding(void) {
 	    return bindings.empty()
 		? NULL : bindings.back();
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090624/bef76492/attachment-0001.html>


More information about the macruby-changes mailing list