Index: vm_core.h =================================================================== --- vm_core.h (revision 37482) +++ vm_core.h (working copy) @@ -584,6 +584,7 @@ void *altstack; #endif unsigned long running_time_us; + int trap_enabled; } rb_thread_t; /* iseq.c */ @@ -857,7 +858,7 @@ #define RUBY_VM_SET_TIMER_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x01) #define RUBY_VM_SET_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x02) #define RUBY_VM_SET_FINALIZER_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x04) -#define RUBY_VM_INTERRUPTED(th) ((th)->interrupt_flag & 0x02) +#define RUBY_VM_INTERRUPTED(th) ((th)->trap_enabled && ((th)->interrupt_flag & 0x02)) int rb_signal_buff_size(void); void rb_signal_exec(rb_thread_t *th, int sig); @@ -874,14 +875,16 @@ void rb_thread_lock_unlock(rb_thread_lock_t *); void rb_thread_lock_destroy(rb_thread_lock_t *); +#define THREAD_INTERRUPTED(th) ((th)->trap_enabled && (th)->interrupt_flag) + #define RUBY_VM_CHECK_INTS_BLOCKING(th) do { \ - if (UNLIKELY((th)->interrupt_flag)) { \ + if (UNLIKELY(THREAD_INTERRUPTED(th))) { \ rb_threadptr_execute_interrupts(th, 1); \ } \ } while (0) #define RUBY_VM_CHECK_INTS(th) do { \ - if (UNLIKELY((th)->interrupt_flag)) { \ + if (UNLIKELY(THREAD_INTERRUPTED(th))) { \ rb_threadptr_execute_interrupts(th, 0); \ } \ } while (0) Index: io.c =================================================================== --- io.c (revision 37482) +++ io.c (working copy) @@ -1160,7 +1160,7 @@ arg.ptr = ptr + offset; arg.length = n; if (fptr->write_lock) { - r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg); + r = rb_mutex_synchronize_notrap(fptr->write_lock, io_binwrite_string, (VALUE)&arg); } else { long l = io_writable_length(fptr, n); Index: thread.c =================================================================== --- thread.c (revision 37482) +++ thread.c (working copy) @@ -267,7 +267,7 @@ check_ints: RUBY_VM_CHECK_INTS(th); /* check signal or so */ native_mutex_lock(&th->interrupt_lock); - if (th->interrupt_flag) { + if (THREAD_INTERRUPTED(th)) { native_mutex_unlock(&th->interrupt_lock); goto check_ints; } @@ -569,6 +569,8 @@ native_mutex_initialize(&th->interrupt_lock); + th->trap_enabled = 1; + /* kick thread */ st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id); err = native_thread_create(th); @@ -1038,7 +1040,7 @@ { rb_thread_schedule_limits(0); - if (UNLIKELY(GET_THREAD()->interrupt_flag)) { + if (UNLIKELY(THREAD_INTERRUPTED(GET_THREAD()))) { rb_threadptr_execute_interrupts_common(GET_THREAD(), 0); } } @@ -4285,7 +4287,47 @@ return rb_ensure(func, arg, rb_mutex_unlock, mutex); } +typedef struct { + VALUE mutex; + int old_trap_enabled; +} sync_notrap_t; + + +/* :nodoc: */ +VALUE +rb_mutex_unlock_notrap(VALUE value) +{ + sync_notrap_t *arg = (sync_notrap_t*)value; + VALUE ret; + rb_thread_t *th = GET_THREAD(); + + ret = rb_mutex_unlock(arg->mutex); + th->trap_enabled = arg->old_trap_enabled; + + return ret; +} + /* + * :nodoc: + * similar rb_mutex_synchronize(), but also prevent trap + */ +VALUE +rb_mutex_synchronize_notrap(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg) +{ + rb_thread_t *th = GET_THREAD(); + sync_notrap_t ensure_arg; + + ensure_arg.mutex = mutex; + ensure_arg.old_trap_enabled = th->trap_enabled; + + /* mask trap handler for prevent recursive mutex lock */ + th->trap_enabled = 0; + + rb_mutex_lock(mutex); + return rb_ensure(func, arg, rb_mutex_unlock_notrap, (VALUE)&ensure_arg); +} + +/* * Document-class: ThreadShield */ static void @@ -4749,6 +4791,8 @@ th->async_errinfo_queue = rb_ary_tmp_new(0); th->async_errinfo_queue_checked = 0; th->async_errinfo_mask_stack = rb_ary_tmp_new(0); + + th->trap_enabled = 1; } } Index: internal.h =================================================================== --- internal.h (revision 37482) +++ internal.h (working copy) @@ -271,6 +271,7 @@ VALUE rb_thread_shield_wait(VALUE self); VALUE rb_thread_shield_release(VALUE self); VALUE rb_thread_shield_destroy(VALUE self); +VALUE rb_mutex_synchronize_notrap(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg); /* thread_pthread.c, thread_win32.c */ void Init_native_thread(void);