зеркало из https://github.com/github/ruby.git
Add Thread.ignore_deadlock accessor
Setting this to true disables the deadlock detector. It should only be used in cases where the deadlock could be broken via some external means, such as via a signal. Now that $SAFE is no longer used, replace the safe_level_ VM flag with ignore_deadlock for storing the setting. Fixes [Bug #13768]
This commit is contained in:
Родитель
a99f52d511
Коммит
dfb3605bbe
3
NEWS.md
3
NEWS.md
|
@ -178,6 +178,9 @@ Outstanding ones only.
|
||||||
blocking. [[Feature #16786]]
|
blocking. [[Feature #16786]]
|
||||||
* `Thread#join` invokes the scheduler hooks `block`/`unblock` in a
|
* `Thread#join` invokes the scheduler hooks `block`/`unblock` in a
|
||||||
non-blocking execution context. [[Feature #16786]]
|
non-blocking execution context. [[Feature #16786]]
|
||||||
|
* `Thread.ignore_deadlock` accessor for disabling the default deadlock
|
||||||
|
detection, allowing the use of signal handlers to break deadlock.
|
||||||
|
[[Bug #13768]]
|
||||||
|
|
||||||
* Mutex
|
* Mutex
|
||||||
|
|
||||||
|
|
|
@ -490,6 +490,19 @@ class TestThread < Test::Unit::TestCase
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_ignore_deadlock
|
||||||
|
if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
|
skip "can't trap a signal from another process on Windows"
|
||||||
|
end
|
||||||
|
assert_in_out_err([], <<-INPUT, %w(false :sig), [], :signal=>:INT, timeout: 1, timeout_error: nil)
|
||||||
|
p Thread.ignore_deadlock
|
||||||
|
q = Queue.new
|
||||||
|
trap(:INT){q.push :sig}
|
||||||
|
Thread.ignore_deadlock = true
|
||||||
|
p q.pop
|
||||||
|
INPUT
|
||||||
|
end
|
||||||
|
|
||||||
def test_status_and_stop_p
|
def test_status_and_stop_p
|
||||||
a = ::Thread.new {
|
a = ::Thread.new {
|
||||||
Thread.current.report_on_exception = false
|
Thread.current.report_on_exception = false
|
||||||
|
|
52
thread.c
52
thread.c
|
@ -3065,7 +3065,7 @@ rb_thread_abort_exc_set(VALUE thread, VALUE val)
|
||||||
*
|
*
|
||||||
* There is also an instance level method to set this for a specific thread,
|
* There is also an instance level method to set this for a specific thread,
|
||||||
* see #report_on_exception=.
|
* see #report_on_exception=.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -3113,6 +3113,52 @@ rb_thread_s_report_exc_set(VALUE self, VALUE val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.ignore_deadlock -> true or false
|
||||||
|
*
|
||||||
|
* Returns the status of the global ``ignore deadlock'' condition.
|
||||||
|
* The default is +false+, so that deadlock conditions are not ignored.
|
||||||
|
*
|
||||||
|
* See also ::ignore_deadlock=.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_thread_s_ignore_deadlock(VALUE _)
|
||||||
|
{
|
||||||
|
return GET_THREAD()->vm->thread_ignore_deadlock ? Qtrue : Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.ignore_deadlock = boolean -> true or false
|
||||||
|
*
|
||||||
|
* Returns the new state.
|
||||||
|
* When set to +true+, the VM will not check for deadlock conditions.
|
||||||
|
* It is only useful to set this if your application can break a
|
||||||
|
* deadlock condition via some other means, such as a signal.
|
||||||
|
*
|
||||||
|
* Thread.ignore_deadlock = true
|
||||||
|
* queue = Queue.new
|
||||||
|
*
|
||||||
|
* trap(:SIGUSR1){queue.push "Received signal"}
|
||||||
|
*
|
||||||
|
* # raises fatal error unless ignoring deadlock
|
||||||
|
* puts queue.pop
|
||||||
|
*
|
||||||
|
* See also ::ignore_deadlock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_thread_s_ignore_deadlock_set(VALUE self, VALUE val)
|
||||||
|
{
|
||||||
|
GET_THREAD()->vm->thread_ignore_deadlock = RTEST(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* thr.report_on_exception -> true or false
|
* thr.report_on_exception -> true or false
|
||||||
|
@ -5480,6 +5526,8 @@ Init_Thread(void)
|
||||||
rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
|
rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
|
||||||
rb_define_singleton_method(rb_cThread, "report_on_exception", rb_thread_s_report_exc, 0);
|
rb_define_singleton_method(rb_cThread, "report_on_exception", rb_thread_s_report_exc, 0);
|
||||||
rb_define_singleton_method(rb_cThread, "report_on_exception=", rb_thread_s_report_exc_set, 1);
|
rb_define_singleton_method(rb_cThread, "report_on_exception=", rb_thread_s_report_exc_set, 1);
|
||||||
|
rb_define_singleton_method(rb_cThread, "ignore_deadlock", rb_thread_s_ignore_deadlock, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "ignore_deadlock=", rb_thread_s_ignore_deadlock_set, 1);
|
||||||
#if THREAD_DEBUG < 0
|
#if THREAD_DEBUG < 0
|
||||||
rb_define_singleton_method(rb_cThread, "DEBUG", rb_thread_s_debug, 0);
|
rb_define_singleton_method(rb_cThread, "DEBUG", rb_thread_s_debug, 0);
|
||||||
rb_define_singleton_method(rb_cThread, "DEBUG=", rb_thread_s_debug_set, 1);
|
rb_define_singleton_method(rb_cThread, "DEBUG=", rb_thread_s_debug_set, 1);
|
||||||
|
@ -5611,6 +5659,8 @@ debug_deadlock_check(rb_ractor_t *r, VALUE msg)
|
||||||
static void
|
static void
|
||||||
rb_check_deadlock(rb_ractor_t *r)
|
rb_check_deadlock(rb_ractor_t *r)
|
||||||
{
|
{
|
||||||
|
if (GET_THREAD()->vm->thread_ignore_deadlock) return;
|
||||||
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
rb_thread_t *th = NULL;
|
rb_thread_t *th = NULL;
|
||||||
int sleeper_num = rb_ractor_sleeper_thread_num(r);
|
int sleeper_num = rb_ractor_sleeper_thread_num(r);
|
||||||
|
|
|
@ -595,7 +595,7 @@ typedef struct rb_vm_struct {
|
||||||
unsigned int running: 1;
|
unsigned int running: 1;
|
||||||
unsigned int thread_abort_on_exception: 1;
|
unsigned int thread_abort_on_exception: 1;
|
||||||
unsigned int thread_report_on_exception: 1;
|
unsigned int thread_report_on_exception: 1;
|
||||||
unsigned int safe_level_: 1;
|
unsigned int thread_ignore_deadlock: 1;
|
||||||
|
|
||||||
/* object management */
|
/* object management */
|
||||||
VALUE mark_object_ary;
|
VALUE mark_object_ary;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче