Add a monitor debug function for rendez waiters When debugging, it's helpful to be able to tell what is waiting on a particular rendez. "db rv 0xWAITER" will do the trick. Like many monitor commands, this is dangerous. Not only will it cast whatever you pass it to an alarm_waiter, but even if you don't mess up, there's no telling that the alarm isn't currently firing and unwinding the stack. That being said, it's been useful for me. Usage: (akaros) / $ m alarm pcpu PCPU Chains: It is now [ 189.392342216] Chain 0xffffffffcc683c48: earliest: [ 189.399452912] latest: [ 482.049028825] Waiter 0xffffffffcc683ac0, time [ 189.399452912] (0x0000008cc62c95fa), func 0xffffffffc205a740 (__ksched_tick) Waiter 0xfffffff000097dd8, time [ 189.416393761] (0x0000008cc965c92b), func 0xffffffffc20586e0 (rendez_alarm_handler) Waiter 0xfffffff0000a9c98, time [ 482.049028825] (0x000001664a5eef19), func 0xffffffffc20586e0 (rendez_alarm_handler) Chain 0xffffffffcc683f08: earliest: [ 189.477399144] latest: [ 189.477399144] Waiter 0xfffffff0000a6cb8, time [ 189.477399144] (0x0000008cd50165fa), func 0xffffffffc20586e0 (rendez_alarm_handler) (akaros) / $ m db rv 0xfffffff0000a6cb8 -------- kth #I0tcpack ---------- Backtrace of kernel context on Core 0: #01 [<0xffffffffc20145ab>] in cv_wait_and_unlock #02 [<0xffffffffc2014651>] in cv_wait #03 [<0xffffffffc20585cd>] in rendez_sleep_timeout #04 [<0xffffffffc2013d72>] in kthread_usleep #05 [<0xffffffffc20327a4>] in tcpackproc #06 [<0xffffffffc2013274>] in __ktask_wrapper #07 [<0xffffffffc2063bad>] in process_routine_kmsg #08 [<0xffffffffc205d59e>] in __smp_idle ----------------- Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/include/rendez.h b/kern/include/rendez.h index f607105..06f257a 100644 --- a/kern/include/rendez.h +++ b/kern/include/rendez.h
@@ -39,6 +39,7 @@ #include <ros/common.h> #include <kthread.h> +#include <alarm.h> struct rendez { struct cond_var cv; @@ -51,3 +52,4 @@ void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg, uint64_t usec); bool rendez_wakeup(struct rendez *rv); +void rendez_debug_waiter(struct alarm_waiter *awaiter);
diff --git a/kern/src/monitor.c b/kern/src/monitor.c index 3f26125..8c137fd 100644 --- a/kern/src/monitor.c +++ b/kern/src/monitor.c
@@ -1007,6 +1007,7 @@ printk("Usage: db OPTION\n"); printk("\tblk [PID]: print all blocked kthreads\n"); printk("\taddr PID 0xADDR: for PID lookup ADDR's file/vmr info\n"); + printk("\trv WAITER: backtrace rendez alarm waiter\n"); return 1; } if (!strcmp(argv[1], "blk") || !strcmp(argv[1], "sem")) { @@ -1019,6 +1020,12 @@ return 1; } debug_addr_pid(strtol(argv[2], 0, 10), strtol(argv[3], 0, 16)); + } else if (!strcmp(argv[1], "rv")) { + if (argc < 3) { + printk("Usage: db rv 0xWAITER\n"); + return 1; + } + rendez_debug_waiter((struct alarm_waiter*)strtoul(argv[2], 0, 16)); } else { printk("Bad option\n"); return 1;
diff --git a/kern/src/rendez.c b/kern/src/rendez.c index 215e85f..6d5de7c 100644 --- a/kern/src/rendez.c +++ b/kern/src/rendez.c
@@ -61,6 +61,24 @@ rendez_wakeup(rv); } +void rendez_debug_waiter(struct alarm_waiter *awaiter) +{ + struct rendez *rv = (struct rendez*)awaiter->data; + struct cond_var *cv = &rv->cv; + struct kthread *kth; + int8_t irq_state = 0; + + cv_lock_irqsave(cv, &irq_state); + TAILQ_FOREACH(kth, &cv->waiters, link) { + print_lock(); + printk("-------- kth %s ----------\n", kth->name); + backtrace_kthread(kth); + printk("-----------------\n"); + print_unlock(); + } + cv_unlock_irqsave(cv, &irq_state); +} + /* Like sleep, but it will timeout in 'usec' microseconds. */ void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg, uint64_t usec)