1=== ruby.h 2================================================================== 3--- ruby.h (/trunk) (revision 16) 4+++ ruby.h (/branches/thread-hooks) (revision 16) 5@@ -724,6 +724,19 @@ 6 void ruby_native_thread_kill _((int)); 7 #endif 8 9+ 10+typedef unsigned int rb_threadswitch_event_t; 11+ 12+#define RUBY_THREADSWITCH_INIT 0x01 13+#define RUBY_THREADSWITCH_FREE 0x02 14+#define RUBY_THREADSWITCH_SAVE 0x04 15+#define RUBY_THREADSWITCH_RESTORE 0x08 16+ 17+typedef void (*rb_threadswitch_hook_func_t) _((rb_threadswitch_event_t,VALUE)); 18+ 19+void *rb_add_threadswitch_hook _((rb_threadswitch_hook_func_t func)); 20+void rb_remove_threadswitch_hook _((void *handle)); 21+ 22 #if defined(__cplusplus) 23 #if 0 24 { /* satisfy cc-mode */ 25=== eval.c 26================================================================== 27--- eval.c (/trunk) (revision 16) 28+++ eval.c (/branches/thread-hooks) (revision 16) 29@@ -227,6 +227,25 @@ 30 31 #include <sys/stat.h> 32 33+ 34+typedef struct threadswitch_hook { 35+ rb_threadswitch_hook_func_t func; 36+ struct threadswitch_hook *next; 37+} rb_threadswitch_hook_t; 38+ 39+static rb_threadswitch_hook_t *threadswitch_hooks; 40+ 41+#define EXEC_THREADSWITCH_HOOK(event, thread) \ 42+ do { \ 43+ rb_threadswitch_hook_t *hook = threadswitch_hooks; \ 44+ \ 45+ while (hook) { \ 46+ (*hook->func)(event, thread); \ 47+ hook = hook->next; \ 48+ } \ 49+ } while (0) 50+ 51+ 52 VALUE rb_cProc; 53 VALUE rb_cBinding; 54 static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE)); 55@@ -10131,6 +10150,8 @@ 56 thread_free(th) 57 rb_thread_t th; 58 { 59+ EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_FREE,th->thread); 60+ 61 if (th->stk_ptr) free(th->stk_ptr); 62 th->stk_ptr = 0; 63 #ifdef __ia64__ 64@@ -10181,6 +10202,8 @@ 65 VALUE *pos; 66 int len; 67 static VALUE tval; 68+ 69+ EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_SAVE,th->thread); 70 71 len = ruby_stack_length(&pos); 72 th->stk_len = 0; 73@@ -10313,6 +10336,8 @@ 74 75 if (!th->stk_ptr) rb_bug("unsaved context"); 76 77+ EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_RESTORE,th->thread); 78+ 79 #if STACK_GROW_DIRECTION < 0 80 if (&v > th->stk_pos) stack_extend(th, exit); 81 #elif STACK_GROW_DIRECTION > 0 82@@ -10452,6 +10477,41 @@ 83 rb_thread_main_jump(e, RESTORE_RAISE); 84 } 85 86+void * 87+rb_add_threadswitch_hook(func) 88+ rb_threadswitch_hook_func_t func; 89+{ 90+ rb_threadswitch_hook_t *hook; 91+ rb_thread_t th; 92+ 93+ hook = ALLOC(rb_threadswitch_hook_t); 94+ hook->func = func; 95+ hook->next = threadswitch_hooks; 96+ threadswitch_hooks = hook; 97+ 98+ FOREACH_THREAD(th) { 99+ (*func)(RUBY_THREADSWITCH_INIT, th->thread); 100+ } END_FOREACH(th); 101+ 102+ return hook; 103+} 104+ 105+void 106+rb_remove_threadswitch_hook(handle) 107+ void *handle; 108+{ 109+ rb_threadswitch_hook_t **hook_p, *hook; 110+ 111+ for (hook_p = &threadswitch_hooks; *hook_p; hook_p = &hook->next) { 112+ hook = *hook_p; 113+ if (hook == (rb_threadswitch_hook_t*)handle) { 114+ *hook_p = hook->next; 115+ xfree(hook); 116+ return; 117+ } 118+ } 119+} 120+ 121 static void 122 copy_fds(dst, src, max) 123 fd_set *dst, *src; 124@@ -11631,6 +11691,8 @@ 125 THREAD_ALLOC(th); 126 th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th); 127 128+ EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_INIT,th->thread); 129+ 130 for (vars = th->dyna_vars; vars; vars = vars->next) { 131 if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; 132 FL_SET(vars, DVAR_DONT_RECYCLE); 133