Skip to content
Browse files

Implement rb_thread_create

This uses a macro so we can setup the original filename and function
name properly. This makes sure they end up in backtraces.

Fixes #2000
  • Loading branch information...
1 parent efe1662 commit c7c130de544efffaa694d5132d1875e43f189d95 @dbussink dbussink committed Nov 27, 2012
Showing with 113 additions and 0 deletions.
  1. +14 −0 vm/builtin/thread.cpp
  2. +8 −0 vm/builtin/thread.hpp
  3. +2 −0 vm/capi/18/include/ruby.h
  4. +2 −0 vm/capi/19/include/ruby/ruby.h
  5. +87 −0 vm/capi/thread.cpp
View
14 vm/builtin/thread.cpp
@@ -143,6 +143,20 @@ namespace rubinius {
return fib->locals()->store(state, key, value);
}
+ Object* Thread::locals_remove(STATE, Symbol* key) {
+ if(state->vm() != vm()) {
+ return locals()->remove(state, key);
+ }
+ Fiber* fib = state->vm()->current_fiber.get();
+ if(fib->nil_p() || fib->root_p()) {
+ return locals()->remove(state, key);
+ }
+ if(fib->locals()->nil_p()) {
+ return cNil;
+ }
+ return fib->locals()->remove(state, key);
+ }
+
Array* Thread::locals_keys(STATE) {
/*
* If we're not trying to set values on the current thread,
View
8 vm/builtin/thread.hpp
@@ -235,6 +235,14 @@ namespace rubinius {
Object* locals_store(STATE, Symbol* key, Object* value);
/**
+ * Remove a value from the thread locals.
+ * This is done in a primitive because it also has
+ * to consider any running fibers.
+ */
+ // Rubinius.primitive :thread_locals_remove
+ Object* locals_remove(STATE, Symbol* key);
+
+ /**
* Retrieve the keys for all thread locals.
* This is done in a primitive because it also has
* to consider any running fibers.
View
2 vm/capi/18/include/ruby.h
@@ -1194,6 +1194,8 @@ VALUE rb_uint2big(unsigned long number);
void rb_thread_wait_fd(int fd);
void rb_thread_fd_writable(int fd);
void rb_thread_wait_for(struct timeval time);
+#define rb_thread_create(func, arg) capi_thread_create(func, arg, #func, __FILE__)
+ VALUE capi_thread_create(VALUE (*)(ANYARGS), void*, const char* name, const char* file);
/* This is a HACK. */
#define rb_io_taint_check(io) rb_check_frozen(io)
View
2 vm/capi/19/include/ruby/ruby.h
@@ -1320,6 +1320,8 @@ VALUE rb_uint2big(unsigned long number);
void rb_thread_wait_fd(int fd);
void rb_thread_fd_writable(int fd);
void rb_thread_wait_for(struct timeval time);
+#define rb_thread_create(func, arg) capi_thread_create(func, arg, #func, __FILE__)
+ VALUE capi_thread_create(VALUE (*)(ANYARGS), void*, const char* name, const char* file);
/** Mark ruby object ptr. */
void rb_gc_mark(VALUE ptr);
View
87 vm/capi/thread.cpp
@@ -6,7 +6,13 @@
#include "capi/capi.hpp"
#include "capi/18/include/ruby.h"
+
+#include "on_stack.hpp"
+#include "call_frame.hpp"
+#include "exception_point.hpp"
#include "builtin/thread.hpp"
+#include "builtin/nativemethod.hpp"
+#include "builtin/ffi_pointer.hpp"
#include "windows_compat.h"
@@ -157,4 +163,85 @@ extern "C" {
return ret;
}
+
+ Object* run_function(STATE) {
+
+ NativeMethodEnvironment* env = NativeMethodEnvironment::get();
+
+ NativeMethodFrame nmf(0);
+ CallFrame cf;
+ cf.previous = 0;
+ cf.constant_scope_ = 0;
+ cf.dispatch_data = (void*)&nmf;
+ cf.compiled_code = 0;
+ cf.flags = CallFrame::cNativeMethod;
+ cf.optional_jit_data = 0;
+ cf.top_scope_ = 0;
+ cf.scope = 0;
+ cf.arguments = 0;
+
+ CallFrame* saved_frame = env->current_call_frame();
+ env->set_current_call_frame(&cf);
+ env->set_current_native_frame(&nmf);
+
+ Thread* self = state->vm()->thread.get();
+ NativeMethod* nm = as<NativeMethod>(self->locals_aref(state, state->symbol("function")));
+ Pointer* ptr = as<Pointer>(self->locals_aref(state, state->symbol("argument")));
+
+ self->locals_remove(state, state->symbol("function"));
+ self->locals_remove(state, state->symbol("argument"));
+
+ nmf.setup(
+ env->get_handle(self),
+ env->get_handle(cNil),
+ env->get_handle(nm),
+ env->get_handle(nm->module()));
+
+ ENTER_CAPI(state);
+
+ Object* ret = NULL;
+
+ ExceptionPoint ep(env);
+
+ PLACE_EXCEPTION_POINT(ep);
+
+ if(unlikely(ep.jumped_to())) {
+ // Setup exception in thread so it's raised when joining
+ self->set_ivar(state, state->symbol("@exception"), self->current_exception(state));
+ return NULL;
+ } else {
+ ret = env->get_object(nm->func()(ptr->pointer));
+ }
+
+ env->set_current_call_frame(saved_frame);
+ env->set_current_native_frame(nmf.previous());
+ ep.pop(env);
+
+ LEAVE_CAPI(state);
+
+ return ret;
+ }
+
+ VALUE capi_thread_create(VALUE (*func)(ANYARGS), void* arg, const char* name, const char* file) {
+ NativeMethodEnvironment* env = NativeMethodEnvironment::get();
+ State* state = env->state();
+
+ NativeMethod* nm = NativeMethod::create(state,
+ String::create(state, file), G(thread),
+ state->symbol(name), (void*)func,
+ Fixnum::from(1));
+
+ Pointer* ptr = Pointer::create(state, arg);
+
+ VM* vm = state->shared().new_vm();
+ Thread* thr = Thread::create(env->state(), vm, G(thread), run_function);
+ vm->thread.set(thr);
+
+ thr->locals_store(state, state->symbol("function"), nm);
+ thr->locals_store(state, state->symbol("argument"), ptr);
+
+ thr->fork(state);
+ return env->get_handle(thr);
+ }
+
}

0 comments on commit c7c130d

Please sign in to comment.
Something went wrong with that request. Please try again.