Skip to content

Commit

Permalink
Add simplicit rb_thread_blocking_region
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Phoenix committed May 18, 2010
1 parent 823d5a4 commit ff0fb8f
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 0 deletions.
14 changes: 14 additions & 0 deletions spec/capi/ext/thread_spec.c
Expand Up @@ -28,11 +28,25 @@ static VALUE thread_spec_rb_thread_current() {
return rb_thread_current();
}

static VALUE do_unlocked(void* data) {
if(data == (void*)1) return (VALUE)1;
return (VALUE)0;
}

// There is really no way to know we're unlocked. So just make sure the arguments
// go through fine.
static VALUE thread_spec_rb_thread_blocking_region() {
VALUE ret = rb_thread_blocking_region(do_unlocked, (void*)1, 0, 0);
if(ret == (VALUE)1) return Qtrue;
return Qfalse;
}

void Init_thread_spec() {
VALUE cls;
cls = rb_define_class("CApiThreadSpecs", rb_cObject);
rb_define_method(cls, "rb_thread_select_fd", thread_spec_rb_thread_select_fd, 2);
rb_define_method(cls, "rb_thread_select", thread_spec_rb_thread_select, 1);
rb_define_method(cls, "rb_thread_alone", thread_spec_rb_thread_alone, 0);
rb_define_method(cls, "rb_thread_current", thread_spec_rb_thread_current, 0);
rb_define_method(cls, "rb_thread_blocking_region", thread_spec_rb_thread_blocking_region, 0);
}
6 changes: 6 additions & 0 deletions spec/capi/thread_spec.rb
Expand Up @@ -44,4 +44,10 @@
@t.rb_thread_current.should == Thread.current
end
end

describe "rb_thread_blocking_region" do
it "runs a C function with the global lock unlocked" do
@t.rb_thread_blocking_region.should be_true
end
end
end
16 changes: 16 additions & 0 deletions vm/capi/ruby.h
Expand Up @@ -1459,6 +1459,22 @@ double rb_num2dbl(VALUE);
/** Get current thread */
VALUE rb_thread_current(void);

/** Release the GIL and let func run in a parallel.
*
* Seriously, crazy restriction here. While the return value is the
* value returned by func, it MUST not be a VALUE for a reference
* object, since that means that reference objects were mutated
* in an unmanaged way.
*
* The ubf function is not supported at all, so it can be anything.
*/
typedef VALUE rb_blocking_function_t(void *);
typedef void rb_unblock_function_t(void *);
VALUE rb_thread_blocking_region(rb_blocking_function_t* func, void* data,
rb_unblock_function_t* ubf, void* ubf_data);

#define HAVE_RB_THREAD_BLOCKING_REGION 1

/** Return a new time object based on the given offset from the epoch */
VALUE rb_time_new(time_t sec, time_t usec);

Expand Down
21 changes: 21 additions & 0 deletions vm/capi/thread.cpp
Expand Up @@ -29,4 +29,25 @@ extern "C" {
int rb_thread_alone() {
return 0;
}

// THAR BE DRAGONS.
//
// When venturing through the valleys of the unmanaged, our hero must
// remain vigilant and disiplined! If she should ever find a VALUE for
// a reference in her travels: Look away! For these VALUEs are pure
// death! Our hero must steel herself and continue on her quest, returning
// as soon as possible to the castle of the managed.
VALUE rb_thread_blocking_region(rb_blocking_function_t func, void* data,
rb_unblock_function_t ubf, void* ubf_data) {
VALUE ret = Qnil;

// ubf is ignored entirely.
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
{
GlobalLock::UnlockGuard guard(env->state()->global_lock());
ret = (*func)(data);
}

return ret;
}
}

0 comments on commit ff0fb8f

Please sign in to comment.