* thread.c: fix comment (terminology: Global VM Lock).

* thread.c (blocking_region_begin, blocking_region_end):
  save and clear th->blocking_region_buffer.
* thread.c (rb_thread_call_with_gvl): check if it has GVL.
* thread.c (ruby_thread_has_gvl_p): added.
* vm_core.h: add decls.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21438 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2009-01-12 01:43:23 +00:00
parent af12cefe06
commit 6f09fc2efd
3 changed files with 56 additions and 6 deletions

View File

@ -1,3 +1,16 @@
Mon Jan 12 10:39:19 2009 Koichi Sasada <ko1@atdot.net>
* thread.c: fix comment (terminology: Global VM Lock).
* thread.c (blocking_region_begin, blocking_region_end):
save and clear th->blocking_region_buffer.
* thread.c (rb_thread_call_with_gvl): check if it has GVL.
* thread.c (ruby_thread_has_gvl_p): added.
* vm_core.h: add decls.
Mon Jan 12 10:21:11 2009 Koichi Sasada <ko1@atdot.net> Mon Jan 12 10:21:11 2009 Koichi Sasada <ko1@atdot.net>
* eval.c: remove unused decl. * eval.c: remove unused decl.

View File

@ -14,7 +14,7 @@
model 1: Userlevel Thread model 1: Userlevel Thread
Same as traditional ruby thread. Same as traditional ruby thread.
model 2: Native Thread with Giant VM lock model 2: Native Thread with Global VM lock
Using pthread (or Windows thread) and Ruby threads run concurrent. Using pthread (or Windows thread) and Ruby threads run concurrent.
model 3: Native Thread with fine grain lock model 3: Native Thread with fine grain lock
@ -23,8 +23,8 @@
------------------------------------------------------------------------ ------------------------------------------------------------------------
model 2: model 2:
A thread has mutex (GVL: Global VM Lock) can run. When thread A thread has mutex (GVL: Global VM Lock or Giant VM Lock) can run.
scheduling, running thread release GVL. If running thread When thread scheduling, running thread release GVL. If running thread
try blocking operation, this thread must release GVL and another try blocking operation, this thread must release GVL and another
thread can continue this flow. After blocking operation, thread thread can continue this flow. After blocking operation, thread
must check interrupt (RUBY_VM_CHECK_INTS). must check interrupt (RUBY_VM_CHECK_INTS).
@ -953,6 +953,7 @@ blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region,
rb_unblock_function_t *func, void *arg) rb_unblock_function_t *func, void *arg)
{ {
region->prev_status = th->status; region->prev_status = th->status;
th->blocking_region_buffer = region;
set_unblock_function(th, func, arg, &region->oldubf); set_unblock_function(th, func, arg, &region->oldubf);
th->status = THREAD_STOPPED; th->status = THREAD_STOPPED;
thread_debug("enter blocking region (%p)\n", (void *)th); thread_debug("enter blocking region (%p)\n", (void *)th);
@ -967,6 +968,7 @@ blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
rb_thread_set_current(th); rb_thread_set_current(th);
thread_debug("leave blocking region (%p)\n", (void *)th); thread_debug("leave blocking region (%p)\n", (void *)th);
remove_signal_thread_list(th); remove_signal_thread_list(th);
th->blocking_region_buffer = 0;
reset_unblock_function(th, &region->oldubf); reset_unblock_function(th, &region->oldubf);
if (th->status == THREAD_STOPPED) { if (th->status == THREAD_STOPPED) {
th->status = region->prev_status; th->status = region->prev_status;
@ -1014,8 +1016,7 @@ rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
* *
* NOTE: You can not execute most of Ruby C API and touch Ruby objects * NOTE: You can not execute most of Ruby C API and touch Ruby objects
* in `func()' and `ubf()' because current thread doesn't acquire * in `func()' and `ubf()' because current thread doesn't acquire
* GVL (cause synchronization problem). Especially, ALLOC*() are * GVL (cause synchronization problem). If you need to do it,
* forbidden because they are related to GC. If you need to do it,
* read source code of C APIs and confirm by yourself. * read source code of C APIs and confirm by yourself.
* *
* NOTE: In short, this API is difficult to use safely. I recommend you * NOTE: In short, this API is difficult to use safely. I recommend you
@ -1024,6 +1025,8 @@ rb_thread_blocking_region_end(struct rb_blocking_region_buffer *region)
* *
* Safe C API: * Safe C API:
* * rb_thread_interrupted() - check interrupt flag * * rb_thread_interrupted() - check interrupt flag
* * ruby_xalloc(), ruby_xrealloc(), ruby_xfree() -
* if they called without GVL, acquire GVL automatically.
*/ */
VALUE VALUE
rb_thread_blocking_region( rb_thread_blocking_region(
@ -1058,6 +1061,11 @@ rb_thread_call_without_gvl(
/* /*
* rb_thread_call_with_gvl - re-enter into Ruby world while releasing GVL. * rb_thread_call_with_gvl - re-enter into Ruby world while releasing GVL.
* *
***
*** This API is EXPERIMENTAL!
*** We do not guarantee that this API remains in ruby 1.9.2 or later.
***
*
* While releasing GVL using rb_thread_blocking_region() or * While releasing GVL using rb_thread_blocking_region() or
* rb_thread_call_without_gvl(), you can not access Ruby values or invoke methods. * rb_thread_call_without_gvl(), you can not access Ruby values or invoke methods.
* If you need to access it, you must use this function rb_thread_call_with_gvl(). * If you need to access it, you must use this function rb_thread_call_with_gvl().
@ -1103,6 +1111,10 @@ rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer; brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
prev_unblock = th->unblock; prev_unblock = th->unblock;
if (brb == 0) {
rb_bug("rb_thread_call_with_gvl: called by a thread which has GVL.");
}
blocking_region_end(th, brb); blocking_region_end(th, brb);
/* enter to Ruby world: You can access Ruby values, methods and so on. */ /* enter to Ruby world: You can access Ruby values, methods and so on. */
r = (*func)(data1); r = (*func)(data1);
@ -1111,6 +1123,28 @@ rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
return r; return r;
} }
/*
* ruby_thread_has_gvl_p - check if current native thread has GVL.
*
***
*** This API is EXPERIMENTAL!
*** We do not guarantee that this API remains in ruby 1.9.2 or later.
***
*/
int
ruby_thread_has_gvl_p(void)
{
rb_thread_t *th = ruby_thread_from_native();
if (th && th->blocking_region_buffer == 0) {
return 1;
}
else {
return 0;
}
}
/* /*
* call-seq: * call-seq:
* Thread.pass => nil * Thread.pass => nil
@ -3721,7 +3755,7 @@ Init_Thread(void)
{ {
/* main thread setting */ /* main thread setting */
{ {
/* acquire global interpreter lock */ /* acquire global vm lock */
rb_thread_lock_t *lp = &GET_THREAD()->vm->global_vm_lock; rb_thread_lock_t *lp = &GET_THREAD()->vm->global_vm_lock;
native_mutex_initialize(lp); native_mutex_initialize(lp);
native_mutex_lock(lp); native_mutex_lock(lp);

View File

@ -588,6 +588,9 @@ VALUE vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
VALUE vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass); VALUE vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass);
VALUE vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp); VALUE vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp);
void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
int ruby_thread_has_gvl_p(void);
NOINLINE(void rb_gc_save_machine_context(rb_thread_t *)); NOINLINE(void rb_gc_save_machine_context(rb_thread_t *));
#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack] #define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack]