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)
314 return static_cast<Thread*>(t->Present_list_item::prev());
316 return static_cast<Thread*>(sc_iter_prev(t->sched())->context());
320 static inline NOEXPORT
322 Jdb_thread_list::iter_next(Thread *t)
325 return static_cast<Thread*>(t->Present_list_item::next());
327 return static_cast<Thread*>(sc_iter_next(t->sched())->context());
330 // walk though list <count> times
331 // abort walking if no more elements
332 // do iter if iter != 0
335 Jdb_thread_list::iter(int count, Thread **t_start,
336 void (*iter)(Thread *t)=0)
339 int forw = (count >= 0);
340 Thread *t, *t_new = *t_start, *t_head = _t_head;
341 long (*get_key)(Thread *t) = 0;
344 return false; // nothing changed
349 // if we are stepping backwards, begin at end-of-list
351 t_head = iter_prev(t_head);
356 // list threads in order of list
363 t = forw ? iter_next(t) : iter_prev(t);
378 // list threads sorted by priority
379 case LIST_SORT_SPACE:
380 // list threads sorted by space
382 get_key = (_mode == LIST_SORT_SPACE) ? get_space_dbgid : get_prio;
387 // list threads sorted by thread id
390 int start_skipped = 0;
395 long key_current = get_key(*t_start);
396 long key_next = (forw) ? LONG_MIN : LONG_MAX;
408 // while walking through the current list, look for next key
409 if ( ( forw && (key > key_next) && (key < key_current))
410 || (!forw && (key < key_next) && (key > key_current)))
413 if (t_head == (t = (forw) ? iter_next(t) : iter_prev(t)))
415 if ( ( forw && (key_next == LONG_MIN))
416 || (!forw && (key_next == LONG_MAX)))
418 key_current = key_next;
419 key_next = forw ? LONG_MIN : LONG_MAX;
422 if (start_skipped && (get_key(t) == key_current))
437 bool changed = (*t_start != t_new);
443 // show complete page using show callback function
446 Jdb_thread_list::page_show(void (*show)(Thread *t))
448 Thread *t = _t_start;
450 iter(Jdb_screen::height()-3, &t, show);
454 // show complete list using show callback function
457 Jdb_thread_list::complete_show(void (*show)(Thread *t))
459 Thread *t = _t_start;
461 iter(9999, &t, show);
466 Jdb_thread_list::Jdb_thread_list()
471 Jdb_module::Action_code
472 Jdb_thread_list::action(int cmd, void *&argbuf, char const *&fmt, int &)
474 static char const *const cpu_fmt = " cpu=%i\n";
475 static char const *const nfmt = "";
478 if (fmt != cpu_fmt && fmt != nfmt)
490 Thread *t = Jdb::get_current_active();
493 case 'r': cpu = 0; list_threads(t, 'r'); break;
494 case 'p': list_threads(t, 'p'); break;
496 if (Cpu::online(cpu))
497 list_threads(Jdb::get_thread(cpu), 'r');
499 printf("\nCPU %u is not online!\n", cpu);
502 case 't': Jdb::execute_command("lt"); break; // other module
507 Console *gzip = Kconsole::console()->find_console(Console::GZIP);
510 Thread *t = Jdb::get_current_active();
511 gzip->state(gzip->state() | Console::OUTENABLED);
513 Jdb_thread_list::init('p', t);
514 Jdb_thread_list::set_start(t);
515 Jdb_thread_list::goto_home();
516 Jdb_thread_list::complete_show(list_threads_show_thread);
518 gzip->state(gzip->state() & ~Console::OUTENABLED);
521 puts(" gzip module not available");
527 PRIVATE static inline
529 Jdb_thread_list::print_thread_name(Kobject const * o)
531 Jdb_kobject_name *nx = Jdb_kobject_extension::find_extension<Jdb_kobject_name>(o);
536 len = min(nx->max_len(), len);
537 printf("%-*.*s", len, len, nx->name());
540 printf("%-*.*s", len, len, "-----");
544 Jdb_thread_list::list_threads_show_thread(Thread *t)
548 bool is_privileged = t->has_privileged_iopl();
552 Kconsole::console()->getchar_chance();
554 if (is_privileged && !long_output)
555 printf("%s", Jdb::esc_emph);
556 Jdb_kobject::print_uid(t->kobject(), 5);
557 if ((is_privileged) && !long_output)
560 printf(" %-3u ", t->cpu());
562 print_thread_name(t->kobject());
564 printf(" %2lx ", get_prio(t));
566 if (get_space_dbgid(t) == ~0L)
569 printf(" %5lx ", get_space_dbgid(t));
572 if (t->state() & Thread_receiving)
574 Jdb_thread::print_partner(t, 5);
582 if (t->_timeout && t->_timeout->is_set())
584 Signed64 diff = (t->_timeout->get_timeout(Kip::k()->clock));
587 else if (diff >= 100000000LL)
595 snprintf(to, sizeof(to), " %3us", us / 1000000);
597 snprintf(to, sizeof(to), " %3um", us / 1000);
599 snprintf(to, sizeof(to), " %3u%c", us, Config::char_micro);
608 t->print_state_long(47);
613 if (Config::stack_depth)
615 Mword i, stack_depth;
616 char *c = (char*)t + sizeof(Thread);
617 for (i=sizeof(Thread), stack_depth=Config::thread_block_size;
618 i<Config::thread_block_size;
619 i++, stack_depth--, c++)
623 printf("(%4ld) ", stack_depth-sizeof(Thread));
624 t->print_state_long(23);
627 t->print_state_long(30);
633 Jdb_thread_list::show_header()
636 printf("%s id cpu name pr sp wait to%s state\033[m\033[K",
637 Jdb::esc_emph, Config::stack_depth ? " stack" : "");
641 Jdb_thread_list::list_threads(Thread *t_start, char pr)
644 Thread *t, *t_current = t_start;
647 // Hm, we are in JDB, however we have to make the assertion in
648 // ready_enqueue happy.
649 Lock_guard<Cpu_lock> g(&cpu_lock);
650 // enqueue current, which may not be in the ready list due to lazy queueing
651 if (!t_current->in_ready_list())
652 t_current->ready_enqueue();
657 Jdb_thread_list::init(pr, t_current);
661 Jdb_thread_list::set_start(t_current);
663 // set y to position of t_current in current displayed list
664 y = Jdb_thread_list::lookup(t_current);
666 for (bool resync=false; !resync;)
669 y_max = Jdb_thread_list::page_show(list_threads_show_thread);
671 // clear rest of screen (if where less than 24 lines)
672 for (unsigned i=y_max; i < Jdb_screen::height()-3; i++)
675 Jdb::printf_statline(pr=='r' ? "ready list" : "present list",
676 "<Space>=mode " /*"<Tab>=partner "*/ "<CR>=select",
677 "%-15s", Jdb_thread_list::get_mode_str());
680 for (bool redraw=false; !redraw; )
683 switch (int c=Jdb_core::getchar())
690 redraw = Jdb_thread_list::line_back();
692 case KEY_CURSOR_DOWN:
697 redraw = Jdb_thread_list::line_forw();
701 if (!(redraw = Jdb_thread_list::page_back()))
706 if (!(redraw = Jdb_thread_list::page_forw()))
709 case KEY_CURSOR_HOME:
711 redraw = Jdb_thread_list::goto_home();
716 redraw = Jdb_thread_list::goto_end();
719 case ' ': // switch mode
720 t_current = Jdb_thread_list::index(y);
721 Jdb_thread_list::switch_mode();
726 case KEY_TAB: // goto thread we are waiting for
727 t = Jdb_thread_list::index(y);
729 && (t->state() & (Thread_receiving |
731 Thread_rcvlong_in_progress))
732 && (!t->partner()->id().is_irq() ||
733 t->partner()->id().irq() > Config::Max_num_irqs))
735 t_current = static_cast<Thread*>(t->partner());
741 case KEY_RETURN: // show current tcb
742 if (jdb_show_tcb != 0)
744 t = Jdb_thread_list::index(y);
745 if (!jdb_show_tcb(t, 1))
752 Jdb::abort_command();
755 if (Jdb::is_toplevel_cmd(c))
765 Jdb_module::Cmd const *
766 Jdb_thread_list::cmds() const
770 { 0, "l", "list", "%C", "l{r|p}\tshow ready/present list", &subcmd },
771 { 1, "lgzip", "", "", 0 /* invisible */, 0 },
779 Jdb_thread_list::num_cmds() const
784 static Jdb_thread_list jdb_list_threads INIT_PRIORITY(JDB_MODULE_INIT_PRIO);