=== ruby.h ================================================================== --- ruby.h (/trunk) (revision 16) +++ ruby.h (/branches/thread-hooks) (revision 16) @@ -749,6 +749,19 @@ void ruby_native_thread_kill _((int)); #endif + +typedef unsigned int rb_threadswitch_event_t; + +#define RUBY_THREADSWITCH_INIT 0x01 +#define RUBY_THREADSWITCH_FREE 0x02 +#define RUBY_THREADSWITCH_SAVE 0x04 +#define RUBY_THREADSWITCH_RESTORE 0x08 + +typedef void (*rb_threadswitch_hook_func_t) _((rb_threadswitch_event_t,VALUE)); + +void *rb_add_threadswitch_hook _((rb_threadswitch_hook_func_t func)); +void rb_remove_threadswitch_hook _((void *handle)); + #if defined(__cplusplus) #if 0 { /* satisfy cc-mode */ === eval.c ================================================================== --- eval.c (/trunk) (revision 16) +++ eval.c (/branches/thread-hooks) (revision 16) @@ -218,6 +218,25 @@ #include + +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; + +#define EXEC_THREADSWITCH_HOOK(event, thread) \ + do { \ + rb_threadswitch_hook_t *hook = threadswitch_hooks; \ + \ + while (hook) { \ + (*hook->func)(event, thread); \ + hook = hook->next; \ + } \ + } while (0) + + VALUE rb_cProc; VALUE rb_cBinding; static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE)); @@ -10167,6 +10186,8 @@ thread_free(th) rb_thread_t th; { + EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_FREE,th->thread); + if (th->stk_ptr) free(th->stk_ptr); th->stk_ptr = 0; #ifdef __ia64__ @@ -10219,6 +10240,8 @@ VALUE *pos; int len; static VALUE tval; + + EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_SAVE,th->thread); len = ruby_stack_length(&pos); th->stk_len = 0; @@ -10418,6 +10441,8 @@ if (!th->stk_ptr) rb_bug("unsaved context"); + EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_RESTORE,th->thread); + #if STACK_GROW_DIRECTION < 0 if (&v > th->stk_pos) stack_extend(th, exit); #elif STACK_GROW_DIRECTION > 0 @@ -10534,6 +10559,41 @@ rb_thread_main_jump(e, RESTORE_RAISE); } +void * +rb_add_threadswitch_hook(func) + rb_threadswitch_hook_func_t func; +{ + rb_threadswitch_hook_t *hook; + rb_thread_t th; + + hook = ALLOC(rb_threadswitch_hook_t); + hook->func = func; + hook->next = threadswitch_hooks; + threadswitch_hooks = hook; + + FOREACH_THREAD(th) { + (*func)(RUBY_THREADSWITCH_INIT, th->thread); + } END_FOREACH(th); + + 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); + return; + } + } +} + static void copy_fds(dst, src, max) fd_set *dst, *src; @@ -11770,6 +11830,8 @@ THREAD_ALLOC(th); th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th); + EXEC_THREADSWITCH_HOOK(RUBY_THREADSWITCH_INIT,th->thread); + for (vars = th->dyna_vars; vars; vars = vars->next) { if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; FL_SET(vars, DVAR_DONT_RECYCLE);