mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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:
parent
a99f52d511
commit
dfb3605bbe
Notes:
git
2020-10-29 07:27:27 +09:00
Merged: https://github.com/ruby/ruby/pull/3710 Merged-By: jeremyevans <code@jeremyevans.net>
4 changed files with 68 additions and 2 deletions
3
NEWS.md
3
NEWS.md
|
@ -178,6 +178,9 @@ Outstanding ones only.
|
|||
blocking. [[Feature #16786]]
|
||||
* `Thread#join` invokes the scheduler hooks `block`/`unblock` in a
|
||||
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
|
||||
|
||||
|
|
|
@ -490,6 +490,19 @@ class TestThread < Test::Unit::TestCase
|
|||
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
|
||||
a = ::Thread.new {
|
||||
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,
|
||||
* see #report_on_exception=.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
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:
|
||||
* 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, "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, "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
|
||||
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);
|
||||
|
@ -5611,6 +5659,8 @@ debug_deadlock_check(rb_ractor_t *r, VALUE msg)
|
|||
static void
|
||||
rb_check_deadlock(rb_ractor_t *r)
|
||||
{
|
||||
if (GET_THREAD()->vm->thread_ignore_deadlock) return;
|
||||
|
||||
int found = 0;
|
||||
rb_thread_t *th = NULL;
|
||||
int sleeper_num = rb_ractor_sleeper_thread_num(r);
|
||||
|
|
|
@ -595,7 +595,7 @@ typedef struct rb_vm_struct {
|
|||
unsigned int running: 1;
|
||||
unsigned int thread_abort_on_exception: 1;
|
||||
unsigned int thread_report_on_exception: 1;
|
||||
unsigned int safe_level_: 1;
|
||||
unsigned int thread_ignore_deadlock: 1;
|
||||
|
||||
/* object management */
|
||||
VALUE mark_object_ary;
|
||||
|
|
Loading…
Add table
Reference in a new issue