summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--ruby_atomic.h3
-rw-r--r--signal.c3
-rw-r--r--thread.c37
-rw-r--r--vm_core.h8
5 files changed, 60 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index f8c7b227e6..bbe77502b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
* iseq.c (make_compile_option_value): add trace_instruction option.
diff --git a/ruby_atomic.h b/ruby_atomic.h
index f4dd5db38a..dd23964f76 100644
--- a/ruby_atomic.h
+++ b/ruby_atomic.h
@@ -13,6 +13,7 @@ typedef unsigned int rb_atomic_t; /* Anything OK */
# define ATOMIC_DEC(var) __sync_fetch_and_sub(&(var), 1)
# 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_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_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))
#endif
# define ATOMIC_EXCHANGE(var, val) InterlockedExchange(&(var), (val))
-
+# define ATOMIC_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval))
# ifdef _M_AMD64
# define ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd64(&(var), (val))
# define ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd64(&(var), -(val))
diff --git a/signal.c b/signal.c
index 713e5cd5b6..4538d901f6 100644
--- a/signal.c
+++ b/signal.c
@@ -625,9 +625,11 @@ signal_exec(VALUE cmd, int safe, int sig)
{
rb_thread_t *cur_th = GET_THREAD();
volatile int old_in_trap = cur_th->in_trap;
+ volatile unsigned long old_interrupt_mask = cur_th->interrupt_mask;
int state;
cur_th->in_trap = 1;
+ cur_th->interrupt_mask |= 0x08;
TH_PUSH_TAG(cur_th);
if ((state = EXEC_TAG()) == 0) {
VALUE signum = INT2NUM(sig);
@@ -635,6 +637,7 @@ signal_exec(VALUE cmd, int safe, int sig)
}
TH_POP_TAG();
cur_th = GET_THREAD();
+ cur_th->interrupt_mask = old_interrupt_mask;
cur_th->in_trap = old_in_trap;
if (state) {
diff --git a/thread.c b/thread.c
index e182552365..c11f57b13b 100644
--- a/thread.c
+++ b/thread.c
@@ -267,7 +267,7 @@ set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
check_ints:
RUBY_VM_CHECK_INTS(th); /* check signal or so */
native_mutex_lock(&th->interrupt_lock);
- if (th->interrupt_flag) {
+ if (RUBY_VM_INTERRUPTED_ANY(th)) {
native_mutex_unlock(&th->interrupt_lock);
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;
th->in_trap = 0;
+ th->interrupt_mask = 0;
native_mutex_initialize(&th->interrupt_lock);
@@ -1054,10 +1055,11 @@ rb_thread_schedule_limits(unsigned long limits_us)
void
rb_thread_schedule(void)
{
+ rb_thread_t *cur_th = GET_THREAD();
rb_thread_schedule_limits(0);
- if (UNLIKELY(GET_THREAD()->interrupt_flag)) {
- rb_threadptr_execute_interrupts(GET_THREAD(), 0);
+ if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(cur_th))) {
+ rb_threadptr_execute_interrupts(cur_th, 0);
}
}
@@ -1725,17 +1727,31 @@ rb_threadptr_to_kill(rb_thread_t *th)
void
rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
{
- rb_atomic_t interrupt;
-
if (th->raised_flag) return;
- while ((interrupt = ATOMIC_EXCHANGE(th->interrupt_flag, 0)) != 0) {
+ while (1) {
enum rb_thread_status status = th->status;
- int timer_interrupt = interrupt & 0x01;
- int async_errinfo_interrupt = interrupt & 0x02;
- int finalizer_interrupt = interrupt & 0x04;
- int trap_interrupt = interrupt & 0x08;
+ rb_atomic_t interrupt;
+ rb_atomic_t old;
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;
@@ -4798,6 +4814,7 @@ Init_Thread(void)
th->async_errinfo_mask_stack = rb_ary_tmp_new(0);
th->in_trap = 0;
+ th->interrupt_mask = 0;
}
}
diff --git a/vm_core.h b/vm_core.h
index b785f95ad9..f6a7a69955 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -521,6 +521,7 @@ typedef struct rb_thread_struct {
VALUE async_errinfo_mask_stack;
rb_atomic_t interrupt_flag;
+ unsigned long interrupt_mask;
rb_thread_lock_t interrupt_lock;
struct rb_unblock_callback unblock;
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_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_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);
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 *);
#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); \
} \
} while (0)
#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); \
} \
} while (0)