1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ruby_atomic.h (ATOMIC_CAS): new macro for compare-and-exchange.

* vm_core.h (struct rb_thread_struct): add interrupt_mask member.
* thread.c (thread_create_core, Init_Thread): initialize
  th->thread_mask.

* vm_core.h (RUBY_VM_INTERRUPTED_ANY): new macro for avoiding
  bare th->interrupt_flag.
* vm_core.h (RUBY_VM_INTERRUPTED, RUBY_VM_INTERRUPTED): check
  th->interrupt_mask.
* thread.c (set_unblock_function, rb_thread_schedule): replace
  th->interrupt_flag with RUBY_VM_INTERRUPTED_ANY()

* signal.c (signal_exec): set up thread->interrupt_mask for
  preventing recursive trap handler.
* vm_core.h (RUBY_VM_CHECK_INTS, RUBY_VM_CHECK_INTS_BLOCKING): ditto.

* thread.c (rb_threadptr_execute_interrupts):
  don't process interrupt if it is masked.
  [Bug #6009] [ruby-core:42524]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37861 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
kosaki 2012-11-26 10:57:39 +00:00
parent 8c6ad2b0ae
commit 6190bb4d8a
5 changed files with 60 additions and 14 deletions

View file

@ -1,3 +1,26 @@
Mon Nov 26 19:45:18 2012 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
* ruby_atomic.h (ATOMIC_CAS): new macro for compare-and-exchange.
* vm_core.h (struct rb_thread_struct): add interrupt_mask member.
* thread.c (thread_create_core, Init_Thread): initialize
th->thread_mask.
* vm_core.h (RUBY_VM_INTERRUPTED_ANY): new macro for avoiding
bare th->interrupt_flag.
* vm_core.h (RUBY_VM_INTERRUPTED, RUBY_VM_INTERRUPTED): check
th->interrupt_mask.
* thread.c (set_unblock_function, rb_thread_schedule): replace
th->interrupt_flag with RUBY_VM_INTERRUPTED_ANY()
* signal.c (signal_exec): set up thread->interrupt_mask for
preventing recursive trap handler.
* vm_core.h (RUBY_VM_CHECK_INTS, RUBY_VM_CHECK_INTS_BLOCKING): ditto.
* thread.c (rb_threadptr_execute_interrupts):
don't process interrupt if it is masked.
[Bug #6009] [ruby-core:42524]
Mon Nov 26 19:43:42 2012 Koichi Sasada <ko1@atdot.net> Mon Nov 26 19:43:42 2012 Koichi Sasada <ko1@atdot.net>
* iseq.c (make_compile_option_value): add trace_instruction option. * iseq.c (make_compile_option_value): add trace_instruction option.

View file

@ -13,6 +13,7 @@ typedef unsigned int rb_atomic_t; /* Anything OK */
# define ATOMIC_DEC(var) __sync_fetch_and_sub(&(var), 1) # define ATOMIC_DEC(var) __sync_fetch_and_sub(&(var), 1)
# define ATOMIC_OR(var, val) __sync_or_and_fetch(&(var), (val)) # define ATOMIC_OR(var, val) __sync_or_and_fetch(&(var), (val))
# define ATOMIC_EXCHANGE(var, val) __sync_lock_test_and_set(&(var), (val)) # define ATOMIC_EXCHANGE(var, val) __sync_lock_test_and_set(&(var), (val))
# define ATOMIC_CAS(var, oldval, newval) __sync_val_compare_and_swap(&(var), (oldval), (newval))
# define ATOMIC_SIZE_ADD(var, val) __sync_fetch_and_add(&(var), (val)) # define ATOMIC_SIZE_ADD(var, val) __sync_fetch_and_add(&(var), (val))
# define ATOMIC_SIZE_SUB(var, val) __sync_fetch_and_sub(&(var), (val)) # define ATOMIC_SIZE_SUB(var, val) __sync_fetch_and_sub(&(var), (val))
@ -48,7 +49,7 @@ rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
# define ATOMIC_OR(var, val) _InterlockedOr(&(var), (val)) # define ATOMIC_OR(var, val) _InterlockedOr(&(var), (val))
#endif #endif
# define ATOMIC_EXCHANGE(var, val) InterlockedExchange(&(var), (val)) # define ATOMIC_EXCHANGE(var, val) InterlockedExchange(&(var), (val))
# define ATOMIC_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval))
# ifdef _M_AMD64 # ifdef _M_AMD64
# define ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd64(&(var), (val)) # define ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd64(&(var), (val))
# define ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd64(&(var), -(val)) # define ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd64(&(var), -(val))

View file

@ -625,9 +625,11 @@ signal_exec(VALUE cmd, int safe, int sig)
{ {
rb_thread_t *cur_th = GET_THREAD(); rb_thread_t *cur_th = GET_THREAD();
volatile int old_in_trap = cur_th->in_trap; volatile int old_in_trap = cur_th->in_trap;
volatile unsigned long old_interrupt_mask = cur_th->interrupt_mask;
int state; int state;
cur_th->in_trap = 1; cur_th->in_trap = 1;
cur_th->interrupt_mask |= 0x08;
TH_PUSH_TAG(cur_th); TH_PUSH_TAG(cur_th);
if ((state = EXEC_TAG()) == 0) { if ((state = EXEC_TAG()) == 0) {
VALUE signum = INT2NUM(sig); VALUE signum = INT2NUM(sig);
@ -635,6 +637,7 @@ signal_exec(VALUE cmd, int safe, int sig)
} }
TH_POP_TAG(); TH_POP_TAG();
cur_th = GET_THREAD(); cur_th = GET_THREAD();
cur_th->interrupt_mask = old_interrupt_mask;
cur_th->in_trap = old_in_trap; cur_th->in_trap = old_in_trap;
if (state) { if (state) {

View file

@ -267,7 +267,7 @@ set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
check_ints: check_ints:
RUBY_VM_CHECK_INTS(th); /* check signal or so */ RUBY_VM_CHECK_INTS(th); /* check signal or so */
native_mutex_lock(&th->interrupt_lock); native_mutex_lock(&th->interrupt_lock);
if (th->interrupt_flag) { if (RUBY_VM_INTERRUPTED_ANY(th)) {
native_mutex_unlock(&th->interrupt_lock); native_mutex_unlock(&th->interrupt_lock);
goto check_ints; goto check_ints;
} }
@ -582,6 +582,7 @@ thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(ANYARGS))
RBASIC(th->async_errinfo_mask_stack)->klass = 0; RBASIC(th->async_errinfo_mask_stack)->klass = 0;
th->in_trap = 0; th->in_trap = 0;
th->interrupt_mask = 0;
native_mutex_initialize(&th->interrupt_lock); native_mutex_initialize(&th->interrupt_lock);
@ -1054,10 +1055,11 @@ rb_thread_schedule_limits(unsigned long limits_us)
void void
rb_thread_schedule(void) rb_thread_schedule(void)
{ {
rb_thread_t *cur_th = GET_THREAD();
rb_thread_schedule_limits(0); rb_thread_schedule_limits(0);
if (UNLIKELY(GET_THREAD()->interrupt_flag)) { if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(cur_th))) {
rb_threadptr_execute_interrupts(GET_THREAD(), 0); rb_threadptr_execute_interrupts(cur_th, 0);
} }
} }
@ -1725,17 +1727,31 @@ rb_threadptr_to_kill(rb_thread_t *th)
void void
rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing) rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
{ {
rb_atomic_t interrupt;
if (th->raised_flag) return; if (th->raised_flag) return;
while ((interrupt = ATOMIC_EXCHANGE(th->interrupt_flag, 0)) != 0) { while (1) {
enum rb_thread_status status = th->status; enum rb_thread_status status = th->status;
int timer_interrupt = interrupt & 0x01; rb_atomic_t interrupt;
int async_errinfo_interrupt = interrupt & 0x02; rb_atomic_t old;
int finalizer_interrupt = interrupt & 0x04;
int trap_interrupt = interrupt & 0x08;
int sig; int sig;
int timer_interrupt;
int async_errinfo_interrupt;
int finalizer_interrupt;
int trap_interrupt;
do {
interrupt = th->interrupt_flag;
old = ATOMIC_CAS(th->interrupt_flag, interrupt, interrupt & th->interrupt_mask);
} while (old != interrupt);
interrupt &= ~th->interrupt_mask;
if (!interrupt)
return;
timer_interrupt = interrupt & 0x01;
async_errinfo_interrupt = interrupt & 0x02;
finalizer_interrupt = interrupt & 0x04;
trap_interrupt = interrupt & 0x08;
th->status = THREAD_RUNNABLE; th->status = THREAD_RUNNABLE;
@ -4798,6 +4814,7 @@ Init_Thread(void)
th->async_errinfo_mask_stack = rb_ary_tmp_new(0); th->async_errinfo_mask_stack = rb_ary_tmp_new(0);
th->in_trap = 0; th->in_trap = 0;
th->interrupt_mask = 0;
} }
} }

View file

@ -521,6 +521,7 @@ typedef struct rb_thread_struct {
VALUE async_errinfo_mask_stack; VALUE async_errinfo_mask_stack;
rb_atomic_t interrupt_flag; rb_atomic_t interrupt_flag;
unsigned long interrupt_mask;
rb_thread_lock_t interrupt_lock; rb_thread_lock_t interrupt_lock;
struct rb_unblock_callback unblock; struct rb_unblock_callback unblock;
VALUE locking_mutex; VALUE locking_mutex;
@ -861,7 +862,8 @@ GET_THREAD(void)
#define RUBY_VM_SET_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x02) #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_SET_FINALIZER_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x04)
#define RUBY_VM_SET_TRAP_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x08) #define RUBY_VM_SET_TRAP_INTERRUPT(th) ATOMIC_OR((th)->interrupt_flag, 0x08)
#define RUBY_VM_INTERRUPTED(th) ((th)->interrupt_flag & 0x0A) #define RUBY_VM_INTERRUPTED(th) ((th)->interrupt_flag & 0x0A & ~(th)->interrupt_mask)
#define RUBY_VM_INTERRUPTED_ANY(th) ((th)->interrupt_flag & ~(th)->interrupt_mask)
int rb_signal_buff_size(void); int rb_signal_buff_size(void);
void rb_signal_exec(rb_thread_t *th, int sig); void rb_signal_exec(rb_thread_t *th, int sig);
@ -879,13 +881,13 @@ void rb_thread_lock_unlock(rb_thread_lock_t *);
void rb_thread_lock_destroy(rb_thread_lock_t *); void rb_thread_lock_destroy(rb_thread_lock_t *);
#define RUBY_VM_CHECK_INTS_BLOCKING(th) do { \ #define RUBY_VM_CHECK_INTS_BLOCKING(th) do { \
if (UNLIKELY((th)->interrupt_flag)) { \ if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(th))) { \
rb_threadptr_execute_interrupts(th, 1); \ rb_threadptr_execute_interrupts(th, 1); \
} \ } \
} while (0) } while (0)
#define RUBY_VM_CHECK_INTS(th) do { \ #define RUBY_VM_CHECK_INTS(th) do { \
if (UNLIKELY((th)->interrupt_flag)) { \ if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(th))) { \
rb_threadptr_execute_interrupts(th, 0); \ rb_threadptr_execute_interrupts(th, 0); \
} \ } \
} while (0) } while (0)