summaryrefslogtreecommitdiff
path: root/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'thread.c')
-rw-r--r--thread.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/thread.c b/thread.c
index f425df19a81..f27c4d6a652 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);