diff --git a/misc/tsan_suppressions.txt b/misc/tsan_suppressions.txt index c788e927dd..7d6c11987c 100644 --- a/misc/tsan_suppressions.txt +++ b/misc/tsan_suppressions.txt @@ -25,11 +25,6 @@ race:objspace_malloc_increase_body race_top:rb_signal_buff_size race:unregister_ubf_list -# interrupt flag is set atomically, but read non-atomically -race_top:RUBY_VM_INTERRUPTED_ANY -race_top:unblock_function_set -race_top:threadptr_get_interrupts - # It's already crashing. We're doing our best signal:rb_vm_bugreport race:check_reserved_signal_ diff --git a/ruby_atomic.h b/ruby_atomic.h index 57d341082d..085c307ac6 100644 --- a/ruby_atomic.h +++ b/ruby_atomic.h @@ -1,3 +1,6 @@ +#ifndef INTERNAL_ATOMIC_H +#define INTERNAL_ATOMIC_H + #include "ruby/atomic.h" /* shim macros only */ @@ -21,3 +24,16 @@ #define ATOMIC_SUB(var, val) RUBY_ATOMIC_SUB(var, val) #define ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_VALUE_CAS(var, oldval, val) #define ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_VALUE_EXCHANGE(var, val) + +static inline rb_atomic_t +rbimpl_atomic_load_relaxed(rb_atomic_t *ptr) +{ +#if defined(HAVE_GCC_ATOMIC_BUILTINS) + return __atomic_load_n(ptr, __ATOMIC_RELAXED); +#else + return *ptr; +#endif +} +#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load_relaxed(&(var)) + +#endif diff --git a/thread.c b/thread.c index 0494524510..dcd5a64f6b 100644 --- a/thread.c +++ b/thread.c @@ -2465,8 +2465,9 @@ threadptr_get_interrupts(rb_thread_t *th) rb_atomic_t interrupt; rb_atomic_t old; + old = ATOMIC_LOAD_RELAXED(ec->interrupt_flag); do { - interrupt = ec->interrupt_flag; + interrupt = old; old = ATOMIC_CAS(ec->interrupt_flag, interrupt, interrupt & ec->interrupt_mask); } while (old != interrupt); return interrupt & (rb_atomic_t)~ec->interrupt_mask; diff --git a/vm_core.h b/vm_core.h index ed6d3fb401..d6afd585d2 100644 --- a/vm_core.h +++ b/vm_core.h @@ -2102,8 +2102,12 @@ enum { #define RUBY_VM_SET_TRAP_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TRAP_INTERRUPT_MASK) #define RUBY_VM_SET_TERMINATE_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, TERMINATE_INTERRUPT_MASK) #define RUBY_VM_SET_VM_BARRIER_INTERRUPT(ec) ATOMIC_OR((ec)->interrupt_flag, VM_BARRIER_INTERRUPT_MASK) -#define RUBY_VM_INTERRUPTED(ec) ((ec)->interrupt_flag & ~(ec)->interrupt_mask & \ - (PENDING_INTERRUPT_MASK|TRAP_INTERRUPT_MASK)) + +static inline bool +RUBY_VM_INTERRUPTED(rb_execution_context_t *ec) +{ + return (ATOMIC_LOAD_RELAXED(ec->interrupt_flag) & ~(ec->interrupt_mask) & (PENDING_INTERRUPT_MASK|TRAP_INTERRUPT_MASK)); +} static inline bool RUBY_VM_INTERRUPTED_ANY(rb_execution_context_t *ec) @@ -2116,7 +2120,7 @@ RUBY_VM_INTERRUPTED_ANY(rb_execution_context_t *ec) RUBY_VM_SET_TIMER_INTERRUPT(ec); } #endif - return ec->interrupt_flag & ~(ec)->interrupt_mask; + return ATOMIC_LOAD_RELAXED(ec->interrupt_flag) & ~(ec)->interrupt_mask; } VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt);