9 #include "jdb_module.h"
10 #include "jdb_screen.h"
11 #include "jdb_thread.h"
12 #include "jdb_kobject_names.h"
13 #include "kernel_console.h"
19 #include "thread_state.h"
20 #include "static_init.h"
22 class Jdb_thread_list : public Jdb_module
25 Jdb_thread_list() FIASCO_INIT;
28 static char long_output;
35 static Thread *_t_head, *_t_start;
39 enum { LIST_UNSORTED, LIST_SORT_PRIO, LIST_SORT_TID, LIST_SORT_SPACE,
44 char Jdb_thread_list::subcmd;
45 char Jdb_thread_list::long_output;
46 unsigned Jdb_thread_list::cpu;
49 // available from the jdb_tcb module
50 extern int jdb_show_tcb(Thread* thread, int level)
51 __attribute__((weak));
53 char Jdb_thread_list::_pr;
54 int Jdb_thread_list::_mode = LIST_SORT_TID;
55 int Jdb_thread_list::_count;
57 Thread *Jdb_thread_list::_t_head;
58 Thread *Jdb_thread_list::_t_start;
62 Jdb_thread_list::init(char pr, Thread *t_head)
68 // return string describing current sorting mode of list
69 PUBLIC static inline NOEXPORT
71 Jdb_thread_list::get_mode_str(void)
73 static const char * const mode_str[] =
74 { "(unsorted)", "(prio-sorted)", "(tid-sorted)", "(space-sorted)" };
76 return mode_str[_mode];
79 // switch to next sorting mode
82 Jdb_thread_list::switch_mode(void)
84 if (++_mode >= LIST_SORT_END)
85 _mode = LIST_UNSORTED;
88 // set _t_start element of list
91 Jdb_thread_list::set_start(Thread *t_start)
94 iter(+Jdb_screen::height()-3, &_t_start);
95 iter(-Jdb_screen::height()+3, &_t_start);
98 // _t_start-- if possible
101 Jdb_thread_list::line_back(void)
103 return iter(-1, &_t_start);
106 // _t_start++ if possible
109 Jdb_thread_list::line_forw(void)
111 Thread *t = _t_start;
112 iter(+Jdb_screen::height()-2, &_t_start);
113 iter(-Jdb_screen::height()+3, &_t_start);
114 return t != _t_start;
117 // _t_start -= 24 if possible
120 Jdb_thread_list::page_back(void)
122 return iter(-Jdb_screen::height()+2, &_t_start);
125 // _t_start += 24 if possible
128 Jdb_thread_list::page_forw(void)
130 Thread *t = _t_start;
131 iter(+Jdb_screen::height()*2-5, &_t_start);
132 iter(-Jdb_screen::height() +3, &_t_start);
133 return t != _t_start;
136 // _t_start = first element of list
139 Jdb_thread_list::goto_home(void)
141 return iter(-9999, &_t_start);
144 // _t_start = last element of list
147 Jdb_thread_list::goto_end(void)
149 Thread *t = _t_start;
150 iter(+9999, &_t_start);
151 iter(-Jdb_screen::height()+2, &_t_start);
152 return t != _t_start;
155 // search index of t_search starting from _t_start
158 Jdb_thread_list::lookup(Thread *t_search)
163 for (i=0, t=_t_start; i<Jdb_screen::height()-3; i++)
173 // get y'th element of thread list starting from _t_start
176 Jdb_thread_list::index(int y)
178 Thread *t = _t_start;
184 // helper function for iter() -- use priority as sorting key
187 Jdb_thread_list::get_prio(Thread *t)
189 return t->sched()->prio();
192 // helper function for iter() -- use thread id as sorting key
195 Jdb_thread_list::get_tid(Thread *t)
197 return t->dbg_info()->dbg_id();
200 // helper function for iter() -- use space as sorting key
203 Jdb_thread_list::get_space_dbgid(Thread *t)
205 return Kobject_dbg::pointer_to_id(t->space());
209 // --------------------------------------------------------------------------
210 IMPLEMENTATION [sched_wfq]:
212 static inline NOEXPORT
214 Jdb_thread_list::sc_iter_prev(Sched_context *t)
216 Sched_context::Ready_queue &rq = Sched_context::rq(cpu);
217 Sched_context **rl = t->_ready_link;
218 if (!rl || rl == &rq.idle)
219 return rq._cnt ? rq._heap[rq._cnt - 1] : rq.idle;
227 static inline NOEXPORT
229 Jdb_thread_list::sc_iter_next(Sched_context *t)
231 Sched_context::Ready_queue &rq = Sched_context::rq(cpu);
232 Sched_context **rl = t->_ready_link;
233 if (!rl || rl == &rq.idle)
234 return rq._cnt ? rq._heap[0] : rq.idle;
236 if ((unsigned)(rl - rq._heap) >= rq._cnt)
243 // --------------------------------------------------------------------------
244 IMPLEMENTATION [sched_fixed_prio]:
247 static inline NOEXPORT
249 Jdb_thread_list::sc_iter_prev(Sched_context *t)
251 unsigned prio = t->prio();
252 Sched_context::Ready_queue &rq = Sched_context::_ready_q.cpu(cpu);
254 if (t != rq.prio_next[prio])
255 return t->_ready_prev;
259 if (++prio > rq.prio_highest)
261 if (rq.prio_next[prio])
262 return rq.prio_next[prio]->_ready_prev;
266 static inline NOEXPORT
268 Jdb_thread_list::sc_iter_next(Sched_context *t)
270 unsigned prio = t->prio();
271 Sched_context::Ready_queue &rq = Sched_context::_ready_q.cpu(cpu);
273 if (t->_ready_next != rq.prio_next[prio])
274 return t->_ready_next;
278 if (--prio > rq.prio_highest) // prio is unsigned
279 prio = rq.prio_highest;
280 if (rq.prio_next[prio])
281 return rq.prio_next[prio];
287 // --------------------------------------------------------------------------
288 IMPLEMENTATION [sched_fp_wfq]:
290 static inline NOEXPORT
292 Jdb_thread_list::sc_iter_prev(Sched_context *)
297 static inline NOEXPORT
299 Jdb_thread_list::sc_iter_next(Sched_context *)
305 // --------------------------------------------------------------------------
309 static inline NOEXPORT
311 Jdb_thread_list::iter_prev(Thread *t)
318 o = Kobject::from_dbg(o->dbg_info()->_pref);
320 o = Kobject::from_dbg(Kobject_dbg::_jdb_tail);
322 while (!Kobject::dcast<Thread*>(o));
323 return Kobject::dcast<Thread*>(o);
326 return static_cast<Thread*>(sc_iter_prev(t->sched())->context());
330 static inline NOEXPORT
332 Jdb_thread_list::iter_next(Thread *t)
339 o = Kobject::from_dbg(o->dbg_info()->_next);
341 o = Kobject::from_dbg(Kobject_dbg::_jdb_head.get_unused());
343 while (!Kobject::dcast<Thread*>(o));
344 return Kobject::dcast<Thread*>(o);
347 return static_cast<Thread*>(sc_iter_next(t->sched())->context());
350 // walk though list <count> times
351 // abort walking if no more elements
352 // do iter if iter != 0
355 Jdb_thread_list::iter(int count, Thread **t_start,
356 void (*iter)(Thread *t)=0)
359 int forw = (count >= 0);
360 Thread *t, *t_new = *t_start, *t_head = _t_head;
361 long (*get_key)(Thread *t) = 0;
364 return false; // nothing changed
369 // if we are stepping backwards, begin at end-of-list
371 t_head = iter_prev(t_head);
376 // list threads in order of list
383 t = forw ? iter_next(t) : iter_prev(t);
398 // list threads sorted by priority
399 case LIST_SORT_SPACE:
400 // list threads sorted by space
402 get_key = (_mode == LIST_SORT_SPACE) ? get_space_dbgid : get_prio;
407 // list threads sorted by thread id
410 int start_skipped = 0;
415 long key_current = get_key(*t_start);
416 long key_next = (forw) ? LONG_MIN : LONG_MAX;
428 // while walking through the current list, look for next key
429 if ( ( forw && (key > key_next) && (key < key_current))
430 || (!forw && (key < key_next) && (key > key_current)))
433 if (t_head == (t = (forw) ? iter_next(t) : iter_prev(t)))
435 if ( ( forw && (key_next == LONG_MIN))
436 || (!forw && (key_next == LONG_MAX)))
438 key_current = key_next;
439 key_next = forw ? LONG_MIN : LONG_MAX;
442 if (start_skipped && (get_key(t) == key_current))
457 bool changed = (*t_start != t_new);
463 // show complete page using show callback function
466 Jdb_thread_list::page_show(void (*show)(Thread *t))
468 Thread *t = _t_start;
470 iter(Jdb_screen::height()-3, &t, show);
474 // show complete list using show callback function
477 Jdb_thread_list::complete_show(void (*show)(Thread *t))
479 Thread *t = _t_start;
481 iter(9999, &t, show);
486 Jdb_thread_list::Jdb_thread_list()
491 Jdb_module::Action_code
492 Jdb_thread_list::action(int cmd, void *&argbuf, char const *&fmt, int &)
494 static char const *const cpu_fmt = " cpu=%i\n";
495 static char const *const nfmt = "";
498 if (fmt != cpu_fmt && fmt != nfmt)
510 Thread *t = Jdb::get_current_active();
513 case 'r': cpu = 0; list_threads(t, 'r'); break;
514 case 'p': list_threads(t, 'p'); break;
516 if (Cpu::online(cpu))
517 list_threads(Jdb::get_thread(cpu), 'r');
519 printf("\nCPU %u is not online!\n", cpu);
522 case 't': Jdb::execute_command("lt"); break; // other module
523 case 's': Jdb::execute_command("ls"); break; // other module
528 Console *gzip = Kconsole::console()->find_console(Console::GZIP);
531 Thread *t = Jdb::get_current_active();
532 gzip->state(gzip->state() | Console::OUTENABLED);
534 Jdb_thread_list::init('p', t);
535 Jdb_thread_list::set_start(t);
536 Jdb_thread_list::goto_home();
537 Jdb_thread_list::complete_show(list_threads_show_thread);
539 gzip->state(gzip->state() & ~Console::OUTENABLED);
542 puts(" gzip module not available");
548 PRIVATE static inline
550 Jdb_thread_list::print_thread_name(Kobject_common const * o)
552 Jdb_kobject_name *nx = Jdb_kobject_extension::find_extension<Jdb_kobject_name>(o);
557 len = min(nx->max_len(), len);
558 printf("%-*.*s", len, len, nx->name());
561 printf("%-*.*s", len, len, "-----");
565 Jdb_thread_list::list_threads_show_thread(Thread *t)
572 Kconsole::console()->getchar_chance();
574 Jdb_kobject::print_uid(t, 5);
576 printf(" %-3u ", t->cpu());
578 print_thread_name(t);
580 printf(" %2lx ", get_prio(t));
582 if (get_space_dbgid(t) == ~0L)
585 printf(" %5lx ", get_space_dbgid(t));
588 if ((t->state(false) & Thread_ipc_mask) == Thread_receive_wait)
590 Jdb_thread::print_partner(t, 5);
598 if (t->_timeout && t->_timeout->is_set())
600 Signed64 diff = (t->_timeout->get_timeout(Kip::k()->clock));
603 else if (diff >= 100000000LL)
611 snprintf(to, sizeof(to), " %3us", us / 1000000);
613 snprintf(to, sizeof(to), " %3um", us / 1000);
615 snprintf(to, sizeof(to), " %3u%c", us, Config::char_micro);
624 Jdb_thread::print_state_long(t, 47);
629 if (Config::stack_depth)
631 Mword i, stack_depth;
632 char *c = (char*)t + sizeof (Thread);
633 for (i = sizeof (Thread), stack_depth = Config::thread_block_size;
634 i < Config::thread_block_size;
635 i++, stack_depth--, c++)
639 printf("(%4ld) ", stack_depth - sizeof (Thread));
640 Jdb_thread::print_state_long(t, 23);
643 Jdb_thread::print_state_long(t, 30);
649 Jdb_thread_list::show_header()
652 printf("%s id cpu name pr sp wait to%s state\033[m\033[K",
653 Jdb::esc_emph, Config::stack_depth ? " stack" : "");
657 Jdb_thread_list::list_threads(Thread *t_start, char pr)
660 Thread *t, *t_current = t_start;
663 // Hm, we are in JDB, however we have to make the assertion in
664 // ready_enqueue happy.
665 Lock_guard<Cpu_lock> g(&cpu_lock);
666 // enqueue current, which may not be in the ready list due to lazy queueing
667 if (!t_current->in_ready_list())
668 t_current->ready_enqueue(false);
673 Jdb_thread_list::init(pr, t_current);
677 Jdb_thread_list::set_start(t_current);
679 // set y to position of t_current in current displayed list
680 y = Jdb_thread_list::lookup(t_current);
682 for (bool resync=false; !resync;)
685 y_max = Jdb_thread_list::page_show(list_threads_show_thread);
687 // clear rest of screen (if where less than 24 lines)
688 for (unsigned i=y_max; i < Jdb_screen::height()-3; i++)
691 Jdb::printf_statline(pr=='r' ? "ready list" : "present list",
692 "<Space>=mode " /*"<Tab>=partner "*/ "<CR>=select",
693 "%-15s", Jdb_thread_list::get_mode_str());
696 for (bool redraw=false; !redraw; )
699 switch (int c=Jdb_core::getchar())
706 redraw = Jdb_thread_list::line_back();
708 case KEY_CURSOR_DOWN:
713 redraw = Jdb_thread_list::line_forw();
717 if (!(redraw = Jdb_thread_list::page_back()))
722 if (!(redraw = Jdb_thread_list::page_forw()))
725 case KEY_CURSOR_HOME:
727 redraw = Jdb_thread_list::goto_home();
732 redraw = Jdb_thread_list::goto_end();
735 case ' ': // switch mode
736 t_current = Jdb_thread_list::index(y);
737 Jdb_thread_list::switch_mode();
742 case KEY_TAB: // goto thread we are waiting for
743 t = Jdb_thread_list::index(y);
745 && (t->state(false) & (Thread_receiving |
747 Thread_rcvlong_in_progress))
748 && (!t->partner()->id().is_irq() ||
749 t->partner()->id().irq() > Config::Max_num_dirqs))
751 t_current = static_cast<Thread*>(t->partner());
757 case KEY_RETURN: // show current tcb
758 if (jdb_show_tcb != 0)
760 t = Jdb_thread_list::index(y);
761 if (!jdb_show_tcb(t, 1))
768 Jdb::abort_command();
771 if (Jdb::is_toplevel_cmd(c))
781 Jdb_module::Cmd const *
782 Jdb_thread_list::cmds() const
786 { 0, "l", "list", "%C", "l{r|p}\tshow ready/present list", &subcmd },
787 { 1, "lgzip", "", "", 0 /* invisible */, 0 },
795 Jdb_thread_list::num_cmds() const
800 static Jdb_thread_list jdb_list_threads INIT_PRIORITY(JDB_MODULE_INIT_PRIO);