summaryrefslogtreecommitdiff
path: root/thread.c
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-06-13 12:34:06 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-06-13 12:34:06 +0000
commita475df2f25acd975c711ed538148b5da02181809 (patch)
tree80b8ad4275610daa455614a0b57d0d264693d12c /thread.c
parent75a68057c712897bce6d787114ffa72504556756 (diff)
* 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
Diffstat (limited to 'thread.c')
-rw-r--r--thread.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/thread.c b/thread.c
index 7a157639ac..bc573e596d 100644
--- a/thread.c
+++ b/thread.c
@@ -2737,7 +2737,7 @@ rb_thread_group(VALUE thread)
}
static const char *
-thread_status_name(rb_thread_t *th)
+thread_status_name(rb_thread_t *th, int detail)
{
switch (th->status) {
case THREAD_RUNNABLE:
@@ -2745,8 +2745,9 @@ thread_status_name(rb_thread_t *th)
return "aborting";
else
return "run";
- case THREAD_STOPPED:
case THREAD_STOPPED_FOREVER:
+ if (detail) return "sleep_forever";
+ case THREAD_STOPPED:
return "sleep";
case THREAD_KILLED:
return "dead";
@@ -2806,7 +2807,7 @@ rb_thread_status(VALUE thread)
}
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;
GetThreadPtr(thread, th);
- status = thread_status_name(th);
+ status = thread_status_name(th, TRUE);
str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread);
if (!NIL_P(th->name)) {
rb_str_catf(str, "@%"PRIsVALUE, th->name);
@@ -4850,27 +4851,46 @@ ruby_native_thread_p(void)
return th != 0;
}
+VALUE rb_vm_backtrace_str_ary(rb_thread_t *th, long lev, long n);
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;
+ 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) {
- printf("th:%p %d %d", th, th->status, th->interrupt_flag);
if (th->locking_mutex) {
rb_mutex_t *mutex;
+ struct rb_thread_struct volatile *mth;
+ int waiting;
GetMutexPtr(th->locking_mutex, mutex);
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);
+ 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
- puts("");
+ else {
+ 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
@@ -4905,7 +4925,7 @@ rb_check_deadlock(rb_vm_t *vm)
VALUE argv[2];
argv[0] = rb_eFatal;
argv[1] = rb_str_new2("No live threads left. Deadlock?");
- debug_deadlock_check(vm);
+ debug_deadlock_check(vm, argv[1]);
vm->sleeper--;
rb_threadptr_raise(vm->main_thread, 2, argv);
}