summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--configure.in14
-rw-r--r--eval.c64
-rw-r--r--ext/-test-/threadswitch/extconf.rb2
-rw-r--r--ext/-test-/threadswitch/threadswitch_hook.c148
-rw-r--r--node.h15
-rw-r--r--test/-ext-/test_threadswitch_hook.rb16
-rw-r--r--test/ruby/envutil.rb12
-rw-r--r--version.h6
9 files changed, 281 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index f90f84f1c3..2c8007a9f1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Fri Sep 24 03:00:26 2010 Nobuyoshi Nakada <[email protected]>
+
+ * eval.c (rb_add_threadswitch_hook): wrapper for unofficial APIs
+ in Mac OS X port. the use of them is strongly discouraged.
+
+ * eval.c (rb_remove_threadswitch_hook): ditto.
+
Fri Sep 3 16:42:59 2010 Akinori MUSHA <[email protected]>
* parse.y (method_call): Add support for Ruby 1.9 style method
diff --git a/configure.in b/configure.in
index a564a6b116..56807251d9 100644
--- a/configure.in
+++ b/configure.in
@@ -145,6 +145,20 @@ if test $frame_address = yes; then
AC_DEFINE(USE_BUILTIN_FRAME_ADDRESS)
fi
+threadswitch_hook=no
+AC_ARG_ENABLE(macosx-unofficial-threadswitch-hook,
+ AS_HELP_STRING([--enable-macosx-unofficial-threadswitch-hook],
+ [enable Mac OS X unofficial thread switch hook, the use of this option is discouraged.]),
+ [threadswitch_hook=$enableval])
+AS_CASE($threadswitch_hook:$target_os,
+[yes:darwin*], [
+ AC_MSG_WARN([enabled Mac OS X unofficial thread switch hook])
+ AC_DEFINE(RUBY_ENABLE_MACOSX_UNOFFICIAL_THREADSWITCH)
+],
+[yes:*], [
+ AC_MSG_ERROR([--enable-macosx-unofficial-threadswitch-hook is valid only for Mac OS X.])
+])
+
AC_ARG_PROGRAM
dnl Checks for programs.
diff --git a/eval.c b/eval.c
index 50c7e13fbc..a54fdce6b9 100644
--- a/eval.c
+++ b/eval.c
@@ -2663,6 +2663,70 @@ rb_remove_event_hook(func)
return -1;
}
+#if defined __APPLE__ && defined __MACH__ && defined RUBY_ENABLE_MACOSX_UNOFFICIAL_THREADSWITCH
+typedef struct threadswitch_hook {
+ rb_threadswitch_hook_func_t func;
+ struct threadswitch_hook *next;
+} rb_threadswitch_hook_t;
+
+static rb_threadswitch_hook_t *threadswitch_hooks;
+
+static void
+call_threadswitch_hook(event, node, thread, mid, klass)
+ rb_event_t event;
+ NODE *node;
+ VALUE thread;
+ ID mid;
+ VALUE klass;
+{
+ rb_threadswitch_hook_t *hook = threadswitch_hooks;
+ rb_threadswitch_event_t thevent = event >> RUBY_THREADSWITCH_SHIFT;
+
+ for (; hook; hook = hook->next) {
+ (*hook->func)(thevent, thread);
+ }
+}
+
+void *
+rb_add_threadswitch_hook(func)
+ rb_threadswitch_hook_func_t func;
+{
+ rb_threadswitch_hook_t *hook;
+ int new_hook = !threadswitch_hooks;
+
+ rb_warn("rb_add_threadswitch_hook is not an official API; use rb_add_event_hook");
+
+ hook = ALLOC(rb_threadswitch_hook_t);
+ hook->func = func;
+ hook->next = threadswitch_hooks;
+ threadswitch_hooks = hook;
+ if (new_hook) {
+ rb_add_event_hook(call_threadswitch_hook, RUBY_EVENT_THREAD_ALL);
+ }
+
+ return hook;
+}
+
+void
+rb_remove_threadswitch_hook(handle)
+ void *handle;
+{
+ rb_threadswitch_hook_t **hook_p, *hook;
+
+ for (hook_p = &threadswitch_hooks; *hook_p; hook_p = &hook->next) {
+ hook = *hook_p;
+ if (hook == (rb_threadswitch_hook_t*)handle) {
+ *hook_p = hook->next;
+ xfree(hook);
+ if (!threadswitch_hooks) {
+ rb_remove_event_hook(call_threadswitch_hook);
+ }
+ break;
+ }
+ }
+}
+#endif
+
/*
* call-seq:
* set_trace_func(proc) => proc
diff --git a/ext/-test-/threadswitch/extconf.rb b/ext/-test-/threadswitch/extconf.rb
new file mode 100644
index 0000000000..4cd833b614
--- /dev/null
+++ b/ext/-test-/threadswitch/extconf.rb
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile("-test-/threadswitch/event_hook")
diff --git a/ext/-test-/threadswitch/threadswitch_hook.c b/ext/-test-/threadswitch/threadswitch_hook.c
new file mode 100644
index 0000000000..18d80bdde4
--- /dev/null
+++ b/ext/-test-/threadswitch/threadswitch_hook.c
@@ -0,0 +1,148 @@
+#include <ruby.h>
+#include <node.h>
+
+/* copied from eval.c */
+static const char *
+get_event_name(rb_event_t event)
+{
+ switch (event) {
+ case RUBY_EVENT_LINE:
+ return "line";
+ case RUBY_EVENT_CLASS:
+ return "class";
+ case RUBY_EVENT_END:
+ return "end";
+ case RUBY_EVENT_CALL:
+ return "call";
+ case RUBY_EVENT_RETURN:
+ return "return";
+ case RUBY_EVENT_C_CALL:
+ return "c-call";
+ case RUBY_EVENT_C_RETURN:
+ return "c-return";
+ case RUBY_EVENT_RAISE:
+ return "raise";
+ case RUBY_EVENT_THREAD_INIT:
+ return "thread-init";
+ case RUBY_EVENT_THREAD_FREE:
+ return "thread-free";
+ case RUBY_EVENT_THREAD_SAVE:
+ return "thread-save";
+ case RUBY_EVENT_THREAD_RESTORE:
+ return "thread-restore";
+ default:
+ return "unknown";
+ }
+}
+
+static VALUE event_callback;
+
+static void
+event_hook(event, node, obj, mid, klass)
+ rb_event_t event;
+ NODE *node;
+ VALUE obj;
+ ID mid;
+ VALUE klass;
+{
+ VALUE block = rb_thread_local_aref(rb_curr_thread->thread, event_callback);
+ if (!NIL_P(block)) {
+ VALUE args = rb_ary_new();
+ rb_ary_push(args, rb_str_new2(get_event_name(event)));
+ rb_ary_push(args, obj);
+ rb_ary_push(args, ID2SYM(mid));
+ rb_ary_push(args, klass);
+ rb_proc_call(block, args);
+ }
+}
+
+static VALUE
+add_event_hook(obj)
+ VALUE obj;
+{
+ rb_add_event_hook(event_hook, RUBY_EVENT_ALL);
+ return obj;
+}
+
+#ifdef RUBY_ENABLE_MACOSX_UNOFFICIAL_THREADSWITCH
+#define get_threadswitch_event_name(thevent) get_event_name((thevent) << RUBY_THREADSWITCH_SHIFT)
+
+static void
+threadswitch_event_hook(event, thread)
+ rb_threadswitch_event_t event;
+ VALUE thread;
+{
+ VALUE block = rb_thread_local_aref(rb_curr_thread->thread, event_callback);
+ if (!NIL_P(block)) {
+ VALUE args = rb_ary_new();
+ rb_ary_push(args, rb_str_new2(get_threadswitch_event_name(event)));
+ rb_ary_push(args, thread);
+ rb_proc_call(block, args);
+ }
+}
+
+static VALUE rb_cThreadSwitchHook;
+
+static VALUE
+threadswitch_add_event_hook(klass)
+ VALUE klass;
+{
+ void *handle = rb_add_threadswitch_hook(threadswitch_event_hook);
+ return Data_Wrap_Struct(klass, 0, rb_remove_threadswitch_hook, handle);
+}
+
+static VALUE
+threadswitch_remove_event_hook(obj)
+ VALUE obj;
+{
+ void *handle = DATA_PTR(obj);
+ DATA_PTR(obj) = 0;
+ if (handle) {
+ rb_remove_threadswitch_hook(handle);
+ }
+ return obj;
+}
+
+static VALUE
+restore_hook(arg)
+ VALUE arg;
+{
+ VALUE *save = (VALUE *)arg;
+ threadswitch_remove_event_hook(save[0]);
+ rb_thread_local_aset(rb_curr_thread->thread, event_callback, save[1]);
+ return Qnil;
+}
+
+static VALUE
+threadswitch_hook(klass)
+ VALUE klass;
+{
+ VALUE save[2];
+ save[1] = rb_thread_local_aref(rb_curr_thread->thread, event_callback);
+ rb_thread_local_aset(rb_curr_thread->thread, event_callback, rb_block_proc());
+ save[0] = threadswitch_add_event_hook(klass);
+ return rb_ensure(rb_yield, save[0], restore_hook, (VALUE)save);
+}
+
+static void
+Init_threadswitch_hook(mEventHook)
+ VALUE mEventHook;
+{
+ rb_cThreadSwitchHook = rb_define_class_under(mEventHook, "ThreadSwitch", rb_cObject);
+ rb_define_singleton_method(rb_cThreadSwitchHook, "add", threadswitch_add_event_hook, 0);
+ rb_define_singleton_method(rb_cThreadSwitchHook, "hook", threadswitch_hook, 0);
+ rb_define_method(rb_cThreadSwitchHook, "remove", threadswitch_remove_event_hook, 0);
+}
+#else
+#define Init_threadswitch_hook(mEventHook) (void)(mEventHook)
+#endif
+
+void
+Init_event_hook()
+{
+ VALUE mEventHook = rb_define_module("EventHook");
+
+ event_callback = rb_intern("rb_event_callback");
+ rb_define_module_function(mEventHook, "hook", add_event_hook, 0);
+ Init_threadswitch_hook(mEventHook);
+}
diff --git a/node.h b/node.h
index 3dd8e75d22..c664c28fcd 100644
--- a/node.h
+++ b/node.h
@@ -384,6 +384,21 @@ void rb_add_event_hook _((rb_event_hook_func_t,rb_event_t));
int rb_remove_event_hook _((rb_event_hook_func_t));
extern const rb_event_t rb_event_all;
+#if defined RUBY_ENABLE_MACOSX_UNOFFICIAL_THREADSWITCH
+typedef rb_event_t rb_threadswitch_event_t;
+
+#define RUBY_THREADSWITCH_SHIFT 8
+#define RUBY_THREADSWITCH_INIT (RUBY_EVENT_THREAD_INIT>>RUBY_THREADSWITCH_SHIFT)
+#define RUBY_THREADSWITCH_FREE (RUBY_EVENT_THREAD_FREE>>RUBY_THREADSWITCH_SHIFT)
+#define RUBY_THREADSWITCH_SAVE (RUBY_EVENT_THREAD_SAVE>>RUBY_THREADSWITCH_SHIFT)
+#define RUBY_THREADSWITCH_RESTORE (RUBY_EVENT_THREAD_RESTORE>>RUBY_THREADSWITCH_SHIFT)
+
+typedef void (*rb_threadswitch_hook_func_t) _((rb_threadswitch_event_t,VALUE));
+
+DEPRECATED(void *rb_add_threadswitch_hook _((rb_threadswitch_hook_func_t func)));
+DEPRECATED(void rb_remove_threadswitch_hook _((void *handle)));
+#endif
+
#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
#include <ucontext.h>
#define USE_CONTEXT
diff --git a/test/-ext-/test_threadswitch_hook.rb b/test/-ext-/test_threadswitch_hook.rb
new file mode 100644
index 0000000000..8374ca4487
--- /dev/null
+++ b/test/-ext-/test_threadswitch_hook.rb
@@ -0,0 +1,16 @@
+require 'test/unit'
+require '-test-/threadswitch/event_hook'
+require 'ruby/envutil'
+
+class Test_ThreadSwitch < Test::Unit::TestCase
+ def test_threadswitch_init
+ threads = []
+ warning = EnvUtil.verbose_warning {
+ EventHook::ThreadSwitch.hook {|name, thread|
+ threads << thread if name == "thread-init"
+ }
+ }
+ assert_match(/not an official API/, warning)
+ assert_operator(threads, :include?, Thread.current)
+ end
+end
diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb
index 639aee00ca..01b1afe8af 100644
--- a/test/ruby/envutil.rb
+++ b/test/ruby/envutil.rb
@@ -25,6 +25,18 @@ module EnvUtil
end
end
module_function :rubybin
+
+ def verbose_warning
+ class << (stderr = "")
+ alias write <<
+ end
+ stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
+ yield stderr
+ ensure
+ stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
+ return stderr
+ end
+ module_function :verbose_warning
end
begin
diff --git a/version.h b/version.h
index 6f84962921..772bc063b0 100644
--- a/version.h
+++ b/version.h
@@ -1,7 +1,7 @@
#define RUBY_VERSION "1.8.8"
-#define RUBY_RELEASE_DATE "2010-09-03"
+#define RUBY_RELEASE_DATE "2010-09-24"
#define RUBY_VERSION_CODE 188
-#define RUBY_RELEASE_CODE 20100903
+#define RUBY_RELEASE_CODE 20100924
#define RUBY_PATCHLEVEL -1
#define RUBY_VERSION_MAJOR 1
@@ -9,7 +9,7 @@
#define RUBY_VERSION_TEENY 8
#define RUBY_RELEASE_YEAR 2010
#define RUBY_RELEASE_MONTH 9
-#define RUBY_RELEASE_DAY 3
+#define RUBY_RELEASE_DAY 24
#define NO_STRING_LITERAL_CONCATENATION 1
#ifdef RUBY_EXTERN