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 || sched_fp_wfq]:
212 template<typename T> struct Jdb_thread_list_policy;
214 template<typename RQP>
215 static inline NOEXPORT
217 Jdb_thread_list::sc_wfq_iter_prev(Sched_context *t)
219 Sched_context::Ready_queue &rq = Sched_context::rq.cpu(cpu);
220 Sched_context **rl = RQP::link(t);
221 if (!rl || rl == RQP::idle(rq))
222 return RQP::cnt(rq) ? RQP::heap(rq)[RQP::cnt(rq) - 1] : *RQP::idle(rq);
224 if (rl == RQP::heap(rq))
225 return *RQP::idle(rq);
230 template<typename RQP>
231 static inline NOEXPORT
233 Jdb_thread_list::sc_wfq_iter_next(Sched_context *t)
235 Sched_context::Ready_queue &rq = Sched_context::rq.cpu(cpu);
236 Sched_context **rl = RQP::link(t);
237 if (!rl || rl == RQP::idle(rq))
238 return RQP::cnt(rq) ? RQP::heap(rq)[0] : *RQP::idle(rq);
240 if ((unsigned)(rl - RQP::heap(rq)) >= RQP::cnt(rq))
241 return *RQP::idle(rq);
247 // --------------------------------------------------------------------------
248 IMPLEMENTATION [sched_fixed_prio || sched_fp_wfq]:
250 template<typename T> struct Jdb_thread_list_policy;
252 template<typename RQP>
253 static inline NOEXPORT
255 Jdb_thread_list::sc_fp_iter_prev(Sched_context *t)
257 unsigned prio = RQP::prio(t);
258 Sched_context::Ready_queue &rq = Sched_context::rq.cpu(cpu);
260 if (t != RQP::prio_next(rq, prio))
265 if (++prio > RQP::prio_highest(rq))
267 if (RQP::prio_next(rq, prio))
268 return RQP::prev(RQP::prio_next(rq, prio));
272 template<typename RQP>
273 static inline NOEXPORT
275 Jdb_thread_list::sc_fp_iter_next(Sched_context *t)
277 unsigned prio = RQP::prio(t);
278 Sched_context::Ready_queue &rq = Sched_context::rq.cpu(cpu);
280 if (RQP::next(t) != RQP::prio_next(rq, prio))
285 if (--prio > RQP::prio_highest(rq)) // prio is unsigned
286 prio = RQP::prio_highest(rq);
287 if (RQP::prio_next(rq, prio))
288 return RQP::prio_next(rq, prio);
292 // --------------------------------------------------------------------------
293 IMPLEMENTATION [sched_fixed_prio]:
296 struct Jdb_thread_list_policy<Ready_queue_fp<Sched_context> >
298 typedef Ready_queue_fp<Sched_context> Rq;
300 static unsigned prio(Sched_context *t)
301 { return t->prio(); }
303 static Sched_context *prio_next(Sched_context::Ready_queue &rq, unsigned prio)
304 { return rq.prio_next[prio].front(); }
306 static unsigned prio_highest(Sched_context::Ready_queue &rq)
307 { return rq.prio_highest; }
309 static Sched_context *prev(Sched_context *t)
310 { return *--Rq::List::iter(t); }
312 static Sched_context *next(Sched_context *t)
313 { return *++Rq::List::iter(t); }
316 static inline NOEXPORT
318 Jdb_thread_list::sc_iter_prev(Sched_context *t)
319 { return sc_fp_iter_prev<Jdb_thread_list_policy<Ready_queue_fp<Sched_context> > >(t); }
321 static inline NOEXPORT
323 Jdb_thread_list::sc_iter_next(Sched_context *t)
324 { return sc_fp_iter_next<Jdb_thread_list_policy<Ready_queue_fp<Sched_context> > >(t); }
326 // --------------------------------------------------------------------------
327 IMPLEMENTATION [sched_wfq]:
330 struct Jdb_thread_list_policy<Ready_queue_wfq<Sched_context> >
332 static Sched_context **link(Sched_context *t)
333 { return t->_ready_link; }
335 static Sched_context **heap(Sched_context::Ready_queue &rq)
338 static Sched_context **idle(Sched_context::Ready_queue &rq)
341 static unsigned cnt(Sched_context::Ready_queue &rq)
345 static inline NOEXPORT
347 Jdb_thread_list::sc_iter_prev(Sched_context *t)
348 { return sc_wfq_iter_prev<Jdb_thread_list_policy<Ready_queue_wfq<Sched_context> > >(t); }
350 static inline NOEXPORT
352 Jdb_thread_list::sc_iter_next(Sched_context *t)
353 { return sc_wfq_iter_next<Jdb_thread_list_policy<Ready_queue_wfq<Sched_context> > >(t); }
356 // --------------------------------------------------------------------------
357 IMPLEMENTATION [sched_fp_wfq]:
359 static inline NOEXPORT
361 Jdb_thread_list::sc_iter_prev(Sched_context *)
366 static inline NOEXPORT
368 Jdb_thread_list::sc_iter_next(Sched_context *)
374 // --------------------------------------------------------------------------
378 static inline NOEXPORT
380 Jdb_thread_list::iter_prev(Thread *t)
384 Kobject_dbg::Iterator o = Kobject_dbg::Kobject_list::iter(t->dbg_info());
388 if (o == Kobject_dbg::end())
391 while (!Kobject::dcast<Thread*>(Kobject::from_dbg(*o)));
392 return Kobject::dcast<Thread*>(Kobject::from_dbg(*o));
395 return static_cast<Thread*>(sc_iter_prev(t->sched())->context());
399 static inline NOEXPORT
401 Jdb_thread_list::iter_next(Thread *t)
405 Kobject_dbg::Iterator o = Kobject_dbg::Kobject_list::iter(t->dbg_info());
409 if (o == Kobject_dbg::end())
412 while (!Kobject::dcast<Thread*>(Kobject::from_dbg(*o)));
413 return Kobject::dcast<Thread*>(Kobject::from_dbg(*o));
416 return static_cast<Thread*>(sc_iter_next(t->sched())->context());
419 // walk though list <count> times
420 // abort walking if no more elements
421 // do iter if iter != 0
424 Jdb_thread_list::iter(int count, Thread **t_start,
425 void (*iter)(Thread *t)=0)
428 int forw = (count >= 0);
429 Thread *t, *t_new = *t_start, *t_head = _t_head;
430 long (*get_key)(Thread *t) = 0;
433 return false; // nothing changed
438 // if we are stepping backwards, begin at end-of-list
440 t_head = iter_prev(t_head);
445 // list threads in order of list
452 t = forw ? iter_next(t) : iter_prev(t);
467 // list threads sorted by priority
468 case LIST_SORT_SPACE:
469 // list threads sorted by space
471 get_key = (_mode == LIST_SORT_SPACE) ? get_space_dbgid : get_prio;
476 // list threads sorted by thread id
479 int start_skipped = 0;
484 long key_current = get_key(*t_start);
485 long key_next = (forw) ? LONG_MIN : LONG_MAX;
495 // while walking through the current list, look for next key
496 if ( ( forw && (key > key_next) && (key < key_current))
497 || (!forw && (key < key_next) && (key > key_current)))
500 if (t_head == (t = (forw) ? iter_next(t) : iter_prev(t)))
502 if ( ( forw && (key_next == LONG_MIN))
503 || (!forw && (key_next == LONG_MAX)))
505 key_current = key_next;
506 key_next = forw ? LONG_MIN : LONG_MAX;
509 if (start_skipped && (get_key(t) == key_current))
524 bool changed = (*t_start != t_new);
530 // show complete page using show callback function
533 Jdb_thread_list::page_show(void (*show)(Thread *t))
535 Thread *t = _t_start;
537 iter(Jdb_screen::height()-3, &t, show);
541 // show complete list using show callback function
544 Jdb_thread_list::complete_show(void (*show)(Thread *t))
546 Thread *t = _t_start;
548 iter(9999, &t, show);
553 Jdb_thread_list::Jdb_thread_list()
558 Jdb_module::Action_code
559 Jdb_thread_list::action(int cmd, void *&argbuf, char const *&fmt, int &)
561 static char const *const cpu_fmt = " cpu=%i\n";
562 static char const *const nfmt = "";
565 if (fmt != cpu_fmt && fmt != nfmt)
577 Thread *t = Jdb::get_current_active();
580 case 'r': cpu = 0; list_threads(t, 'r'); break;
581 case 'p': list_threads(t, 'p'); break;
583 if (Cpu::online(cpu))
584 list_threads(Jdb::get_thread(cpu), 'r');
586 printf("\nCPU %u is not online!\n", cpu);
589 case 't': Jdb::execute_command("lt"); break; // other module
590 case 's': Jdb::execute_command("ls"); break; // other module
595 Console *gzip = Kconsole::console()->find_console(Console::GZIP);
598 Thread *t = Jdb::get_current_active();
599 gzip->state(gzip->state() | Console::OUTENABLED);
601 Jdb_thread_list::init('p', t);
602 Jdb_thread_list::set_start(t);
603 Jdb_thread_list::goto_home();
604 Jdb_thread_list::complete_show(list_threads_show_thread);
606 gzip->state(gzip->state() & ~Console::OUTENABLED);
609 puts(" gzip module not available");
615 PRIVATE static inline
617 Jdb_thread_list::print_thread_name(Kobject_common const * o)
619 Jdb_kobject_name *nx = Jdb_kobject_extension::find_extension<Jdb_kobject_name>(o);
624 len = min(nx->max_len(), len);
625 printf("%-*.*s", len, len, nx->name());
628 printf("%-*.*s", len, len, "-----");
632 Jdb_thread_list::list_threads_show_thread(Thread *t)
639 Kconsole::console()->getchar_chance();
641 Jdb_kobject::print_uid(t, 5);
643 printf(" %-3u ", t->cpu());
645 print_thread_name(t);
647 printf(" %2lx ", get_prio(t));
649 if (get_space_dbgid(t) == ~0L)
652 printf(" %5lx ", get_space_dbgid(t));
654 if (Jdb_thread::has_partner(t))
656 Jdb_thread::print_partner(t, 5);
659 else if (Jdb_thread::has_snd_partner(t))
661 Jdb_thread::print_snd_partner(t, 5);
670 if (t->_timeout && t->_timeout->is_set())
672 Signed64 diff = (t->_timeout->get_timeout(Kip::k()->clock));
675 else if (diff >= 100000000LL)
683 snprintf(to, sizeof(to), " %3us", us / 1000000);
685 snprintf(to, sizeof(to), " %3um", us / 1000);
687 snprintf(to, sizeof(to), " %3u%c", us, Config::char_micro);
696 Jdb_thread::print_state_long(t, 47);
701 if (Config::Stack_depth)
703 Mword i, stack_depth;
704 char *c = (char*)t + sizeof (Thread);
705 for (i = sizeof (Thread), stack_depth = Context::Size;
707 i++, stack_depth--, c++)
711 printf("(%4ld) ", stack_depth - sizeof (Thread));
712 Jdb_thread::print_state_long(t, 23);
715 Jdb_thread::print_state_long(t, 30);
721 Jdb_thread_list::show_header()
724 printf("%s id cpu name pr sp wait to%s state\033[m\033[K",
725 Jdb::esc_emph, Config::Stack_depth ? " stack" : "");
729 Jdb_thread_list::list_threads(Thread *t_start, char pr)
732 Thread *t, *t_current = t_start;
735 // Hm, we are in JDB, however we have to make the assertion in
736 // ready_enqueue happy.
737 auto g = lock_guard(cpu_lock);
738 // enqueue current, which may not be in the ready list due to lazy queueing
739 if (!t_current->in_ready_list())
740 Sched_context::rq.cpu(t_current->cpu()).ready_enqueue(t_current->sched());
745 Jdb_thread_list::init(pr, t_current);
749 Jdb_thread_list::set_start(t_current);
751 // set y to position of t_current in current displayed list
752 y = Jdb_thread_list::lookup(t_current);
754 for (bool resync=false; !resync;)
757 y_max = Jdb_thread_list::page_show(list_threads_show_thread);
759 // clear rest of screen (if where less than 24 lines)
760 for (unsigned i=y_max; i < Jdb_screen::height()-3; i++)
763 Jdb::printf_statline(pr=='r' ? "ready list" : "present list",
764 "<Space>=mode " /*"<Tab>=partner "*/ "<CR>=select",
765 "%-15s", Jdb_thread_list::get_mode_str());
768 for (bool redraw=false; !redraw; )
771 switch (int c=Jdb_core::getchar())
778 redraw = Jdb_thread_list::line_back();
780 case KEY_CURSOR_DOWN:
785 redraw = Jdb_thread_list::line_forw();
789 if (!(redraw = Jdb_thread_list::page_back()))
794 if (!(redraw = Jdb_thread_list::page_forw()))
797 case KEY_CURSOR_HOME:
799 redraw = Jdb_thread_list::goto_home();
804 redraw = Jdb_thread_list::goto_end();
807 case ' ': // switch mode
808 t_current = Jdb_thread_list::index(y);
809 Jdb_thread_list::switch_mode();
814 case KEY_TAB: // goto thread we are waiting for
815 t = Jdb_thread_list::index(y);
817 && (t->state(false) & (Thread_receiving |
819 Thread_rcvlong_in_progress))
820 && (!t->partner()->id().is_irq() ||
821 t->partner()->id().irq() > Config::Max_num_dirqs))
823 t_current = static_cast<Thread*>(t->partner());
829 case KEY_RETURN: // show current tcb
830 if (jdb_show_tcb != 0)
832 t = Jdb_thread_list::index(y);
833 if (!jdb_show_tcb(t, 1))
840 Jdb::abort_command();
843 if (Jdb::is_toplevel_cmd(c))
853 Jdb_module::Cmd const *
854 Jdb_thread_list::cmds() const
858 { 0, "l", "list", "%C", "l{r|p}\tshow ready/present list", &subcmd },
859 { 1, "lgzip", "", "", 0 /* invisible */, 0 },
867 Jdb_thread_list::num_cmds() const
872 static Jdb_thread_list jdb_list_threads INIT_PRIORITY(JDB_MODULE_INIT_PRIO);