summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--thread.c46
-rw-r--r--vm_core.h3
3 files changed, 56 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 461c04731a..b69568df5d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
* eval.c: remove unused decl.
diff --git a/thread.c b/thread.c
index f425df19a8..f27c4d6a65 100644
--- a/thread.c
+++ b/thread.c
@@ -14,7 +14,7 @@
model 1: Userlevel 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.
model 3: Native Thread with fine grain lock
@@ -23,8 +23,8 @@
------------------------------------------------------------------------
model 2:
- A thread has mutex (GVL: Global VM Lock) can run. When thread
- scheduling, running thread release GVL. If running thread
+ A thread has mutex (GVL: Global VM Lock or Giant VM Lock) can run.
+ When thread scheduling, running thread release GVL. If running thread
try blocking operation, this thread must release GVL and another
thread can continue this flow. After blocking operation, thread
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)
{
region->prev_status = th->status;
+ th->blocking_region_buffer = region;
set_unblock_function(th, func, arg, &region->oldubf);
th->status = THREAD_STOPPED;
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);
thread_debug("leave blocking region (%p)\n", (void *)th);
remove_signal_thread_list(th);
+ th->blocking_region_buffer = 0;
reset_unblock_function(th, &region->oldubf);
if (th->status == THREAD_STOPPED) {
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
* in `func()' and `ubf()' because current thread doesn't acquire
- * GVL (cause synchronization problem). Especially, ALLOC*() are
- * forbidden because they are related to GC. If you need to do it,
+ * GVL (cause synchronization problem). If you need to do it,
* read source code of C APIs and confirm by yourself.
*
* 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:
* * rb_thread_interrupted() - check interrupt flag
+ * * ruby_xalloc(), ruby_xrealloc(), ruby_xfree() -
+ * if they called without GVL, acquire GVL automatically.
*/
VALUE
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.
*
+ ***
+ *** 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
* 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().
@@ -1103,6 +1111,10 @@ rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
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);
/* enter to Ruby world: You can access Ruby values, methods and so on. */
r = (*func)(data1);
@@ -1112,6 +1124,28 @@ rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
}
/*
+ * 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:
* Thread.pass => nil
*
@@ -3721,7 +3755,7 @@ Init_Thread(void)
{
/* main thread setting */
{
- /* acquire global interpreter lock */
+ /* acquire global vm lock */
rb_thread_lock_t *lp = &GET_THREAD()->vm->global_vm_lock;
native_mutex_initialize(lp);
native_mutex_lock(lp);
diff --git a/vm_core.h b/vm_core.h
index fea803986f..7ccd0de16d 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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_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 *));
#define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack]