summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--thread.c73
-rw-r--r--vm_core.h1
3 files changed, 85 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 6b299bd0e0..c265a5f824 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Tue Dec 30 16:56:09 2008 Koichi Sasada <ko1@atdot.net>
+
+ * thread.c (rb_thread_blocking_region): add a comment.
+
+ * thread.c (rb_thread_call_without_gvl): added as a alias of
+ rb_thread_blocking_region().
+
+ * thread.c (rb_thread_call_with_gvl): added.
+
+ * vm_core.h (rb_thread_t#blocking_region_buffer): added for
+ rb_thread_call_with_gvl().
+
Mon Dec 29 22:37:17 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
* process.c (rb_waitpid): retries waitpid when EINTR.
diff --git a/thread.c b/thread.c
index 081c3cd507..f4a8ba2714 100644
--- a/thread.c
+++ b/thread.c
@@ -1014,9 +1014,14 @@ 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). If you need to do it,
+ * GVL (cause synchronization problem). Especially, ALLOC*() are
+ * forbidden because they are related to GC. 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
+ * use other ways if you have. We lack experiences to use this API.
+ * Please report your problem related on it.
+ *
* Safe C API:
* * rb_thread_interrupted() - check interrupt flag
*/
@@ -1040,6 +1045,72 @@ rb_thread_blocking_region(
return val;
}
+/* alias of rb_thread_blocking_region() */
+
+VALUE
+rb_thread_call_without_gvl(
+ rb_blocking_function_t *func, void *data1,
+ rb_unblock_function_t *ubf, void *data2)
+{
+ return rb_thread_blocking_region(func, data1, ubf, data2);
+}
+
+/*
+ * rb_thread_call_with_gvl - re-enter into Ruby world while releasing GVL.
+ *
+ * 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().
+ *
+ * This function rb_thread_call_with_gvl() does:
+ * (1) acquire GVL.
+ * (2) call passed function `func'.
+ * (3) release GVL.
+ * (4) return a value which is returned at (2).
+ *
+ * NOTE: You should not return Ruby object at (2) because such Object
+ * will not marked.
+ *
+ * NOTE: If an exception is raised in `func', this function "DOES NOT"
+ * protect (catch) the exception. If you have any resources
+ * which should free before throwing exception, you need use
+ * rb_protect() in `func' and return a value which represents
+ * exception is raised.
+ *
+ * NOTE: This functions should not be called by a thread which
+ * is not created as Ruby thread (created by Thread.new or so).
+ * In other words, this function *DOES NOT* associate
+ * NON-Ruby thread to Ruby thread.
+ */
+void *
+rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
+{
+ rb_thread_t *th = ruby_thread_from_native();
+ struct rb_blocking_region_buffer *brb;
+ struct rb_unblock_callback prev_unblock;
+ void *r;
+
+ if (th == 0) {
+ /* Error is occurred, but we can't use rb_bug()
+ * because this thread is not Ruby's thread.
+ * What should we do?
+ */
+
+ fprintf(stderr, "[BUG] rb_thread_call_with_gvl() is called by non-ruby thread\n");
+ exit(1);
+ }
+
+ brb = (struct rb_blocking_region_buffer *)th->blocking_region_buffer;
+ prev_unblock = th->unblock;
+
+ blocking_region_end(th, brb);
+ /* enter to Ruby world: You can access Ruby values, methods and so on. */
+ r = (*func)(data1);
+ /* levae from Ruby world: You can not access Ruby values, etc. */
+ blocking_region_begin(th, brb, prev_unblock.func, prev_unblock.arg);
+ return r;
+}
+
/*
* call-seq:
* Thread.pass => nil
diff --git a/vm_core.h b/vm_core.h
index c3f5c013f9..b2ebbc8155 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -363,6 +363,7 @@ typedef struct rb_thread_struct
int slice;
native_thread_data_t native_thread_data;
+ void *blocking_region_buffer;
VALUE thgroup;
VALUE value;