* thread.c (debug_deadlock_check): show thread lock dependency and
backtrace [Feature #8214] [ruby-dev:47217] * thread.c (thread_status_name): show "sleep_forever" instead of "sleep" if called from inspect. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55397 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
75a68057c7
commit
a475df2f25
@ -1,3 +1,11 @@
|
|||||||
|
Mon Jun 13 21:09:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
|
* thread.c (debug_deadlock_check): show thread lock dependency and
|
||||||
|
backtrace [Feature #8214] [ruby-dev:47217]
|
||||||
|
|
||||||
|
* thread.c (thread_status_name): show "sleep_forever" instead of
|
||||||
|
"sleep" if called from inspect.
|
||||||
|
|
||||||
Mon Jun 13 20:50:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Mon Jun 13 20:50:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* parse.y (reg_named_capture_assign_iter): remove named capture
|
* parse.y (reg_named_capture_assign_iter): remove named capture
|
||||||
|
2
NEWS
2
NEWS
@ -167,3 +167,5 @@ with all sufficient information, see the ChangeLog file or Redmine
|
|||||||
be <= 0x100, and Array#max and min must not be redefined. It will work
|
be <= 0x100, and Array#max and min must not be redefined. It will work
|
||||||
in most casual and real-life use case where it is written with intent
|
in most casual and real-life use case where it is written with intent
|
||||||
to `Math.max(x, y)`.
|
to `Math.max(x, y)`.
|
||||||
|
|
||||||
|
* Thread deadlock detection now shows their backtrace and dependency. [Feature #8214]
|
||||||
|
46
thread.c
46
thread.c
@ -2737,7 +2737,7 @@ rb_thread_group(VALUE thread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
thread_status_name(rb_thread_t *th)
|
thread_status_name(rb_thread_t *th, int detail)
|
||||||
{
|
{
|
||||||
switch (th->status) {
|
switch (th->status) {
|
||||||
case THREAD_RUNNABLE:
|
case THREAD_RUNNABLE:
|
||||||
@ -2745,8 +2745,9 @@ thread_status_name(rb_thread_t *th)
|
|||||||
return "aborting";
|
return "aborting";
|
||||||
else
|
else
|
||||||
return "run";
|
return "run";
|
||||||
case THREAD_STOPPED:
|
|
||||||
case THREAD_STOPPED_FOREVER:
|
case THREAD_STOPPED_FOREVER:
|
||||||
|
if (detail) return "sleep_forever";
|
||||||
|
case THREAD_STOPPED:
|
||||||
return "sleep";
|
return "sleep";
|
||||||
case THREAD_KILLED:
|
case THREAD_KILLED:
|
||||||
return "dead";
|
return "dead";
|
||||||
@ -2806,7 +2807,7 @@ rb_thread_status(VALUE thread)
|
|||||||
}
|
}
|
||||||
return Qfalse;
|
return Qfalse;
|
||||||
}
|
}
|
||||||
return rb_str_new2(thread_status_name(th));
|
return rb_str_new2(thread_status_name(th, FALSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2952,7 +2953,7 @@ rb_thread_inspect(VALUE thread)
|
|||||||
VALUE str;
|
VALUE str;
|
||||||
|
|
||||||
GetThreadPtr(thread, th);
|
GetThreadPtr(thread, th);
|
||||||
status = thread_status_name(th);
|
status = thread_status_name(th, TRUE);
|
||||||
str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread);
|
str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread);
|
||||||
if (!NIL_P(th->name)) {
|
if (!NIL_P(th->name)) {
|
||||||
rb_str_catf(str, "@%"PRIsVALUE, th->name);
|
rb_str_catf(str, "@%"PRIsVALUE, th->name);
|
||||||
@ -4850,27 +4851,46 @@ ruby_native_thread_p(void)
|
|||||||
return th != 0;
|
return th != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE rb_vm_backtrace_str_ary(rb_thread_t *th, long lev, long n);
|
||||||
static void
|
static void
|
||||||
debug_deadlock_check(rb_vm_t *vm)
|
debug_deadlock_check(rb_vm_t *vm, VALUE msg)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_DEADLOCK_CHECK
|
|
||||||
rb_thread_t *th = 0;
|
rb_thread_t *th = 0;
|
||||||
|
VALUE sep = rb_str_new_cstr("\n ");
|
||||||
|
|
||||||
printf("%d %d %p %p\n", vm_living_thread_num(vm), vm->sleeper, GET_THREAD(), vm->main_thread);
|
rb_str_catf(msg, "\n%d threads, %d sleeps current:%p main thread:%p\n",
|
||||||
|
vm_living_thread_num(vm), vm->sleeper, GET_THREAD(), vm->main_thread);
|
||||||
list_for_each(&vm->living_threads, th, vmlt_node) {
|
list_for_each(&vm->living_threads, th, vmlt_node) {
|
||||||
printf("th:%p %d %d", th, th->status, th->interrupt_flag);
|
|
||||||
if (th->locking_mutex) {
|
if (th->locking_mutex) {
|
||||||
rb_mutex_t *mutex;
|
rb_mutex_t *mutex;
|
||||||
|
struct rb_thread_struct volatile *mth;
|
||||||
|
int waiting;
|
||||||
GetMutexPtr(th->locking_mutex, mutex);
|
GetMutexPtr(th->locking_mutex, mutex);
|
||||||
|
|
||||||
native_mutex_lock(&mutex->lock);
|
native_mutex_lock(&mutex->lock);
|
||||||
printf(" %p %d\n", mutex->th, mutex->cond_waiting);
|
mth = mutex->th;
|
||||||
|
waiting = mutex->cond_waiting;
|
||||||
native_mutex_unlock(&mutex->lock);
|
native_mutex_unlock(&mutex->lock);
|
||||||
|
rb_str_catf(msg, "* %+"PRIsVALUE"\n rb_thread_t:%p native:%p int:%u mutex:%p cond:%d\n",
|
||||||
|
th->self, th, th->thread_id,
|
||||||
|
th->interrupt_flag, mth, waiting);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
puts("");
|
rb_str_catf(msg, "* %+"PRIsVALUE"\n rb_thread_t:%p native:%p int:%u\n",
|
||||||
|
th->self, th, th->thread_id,
|
||||||
|
th->interrupt_flag);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
rb_thread_list_t *list = th->join_list;
|
||||||
|
while (list) {
|
||||||
|
rb_str_catf(msg, " depended by: tb_thread_id:%p\n", list->th);
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rb_str_catf(msg, " ");
|
||||||
|
rb_str_concat(msg, rb_ary_join(rb_vm_backtrace_str_ary(th, 0, 0), sep));
|
||||||
|
rb_str_catf(msg, "\n");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -4905,7 +4925,7 @@ rb_check_deadlock(rb_vm_t *vm)
|
|||||||
VALUE argv[2];
|
VALUE argv[2];
|
||||||
argv[0] = rb_eFatal;
|
argv[0] = rb_eFatal;
|
||||||
argv[1] = rb_str_new2("No live threads left. Deadlock?");
|
argv[1] = rb_str_new2("No live threads left. Deadlock?");
|
||||||
debug_deadlock_check(vm);
|
debug_deadlock_check(vm, argv[1]);
|
||||||
vm->sleeper--;
|
vm->sleeper--;
|
||||||
rb_threadptr_raise(vm->main_thread, 2, argv);
|
rb_threadptr_raise(vm->main_thread, 2, argv);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user