]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/jdb_timeout.cpp
update
[l4.git] / kernel / fiasco / src / jdb / jdb_timeout.cpp
1 IMPLEMENTATION:
2
3 #include <cstdio>
4 #include <cstring>
5
6 #include "config.h"
7 #include "globals.h"
8 #include "ipc_timeout.h"
9 #include "jdb.h"
10 #include "jdb_kobject.h"
11 #include "jdb_kobject_names.h"
12 #include "jdb_module.h"
13 #include "jdb_screen.h"
14 #include "kernel_console.h"
15 #include "keycodes.h"
16 #include "kmem.h"
17 #include "simpleio.h"
18 #include "static_init.h"
19 #include "timeout.h"
20 #include "timeslice_timeout.h"
21 #include "thread.h"
22
23 class Jdb_list_timeouts : public Jdb_module
24 {
25 public:
26   Jdb_list_timeouts() FIASCO_INIT;
27 private:
28   enum
29     {
30       Timeout_ipc               = 1,
31       Timeout_deadline          = 2,
32       Timeout_timeslice         = 3,
33       Timeout_root              = 4,
34     };
35 };
36
37 class Jdb_timeout_list
38 {
39 private:
40   static int    _count;
41   static Timeout *_t_start;
42 };
43
44
45 // available from the jdb_tcb module
46 extern int jdb_show_tcb(Thread *thread, int level) __attribute__((weak));
47
48 int      Jdb_timeout_list::_count;
49 Timeout *Jdb_timeout_list::_t_start;
50
51 PUBLIC static
52 void
53 Jdb_timeout_list::init(Timeout *t_head)
54 {
55   _t_start = t_head;
56 }
57
58 static
59 bool
60 Jdb_timeout_list::iter(int count, Timeout **t_start,
61                        void (*iter)(Timeout *t) = 0)
62 {
63   int i = 0;
64   int forw = count >= 0;
65   Timeout *t_new = *t_start;
66
67   if (count == 0)
68     return false;
69
70   if (count < 0)
71     count = -count;
72
73   if (iter)
74     iter(t_new);
75
76   for (; count; count--)
77     {
78       if (forw)
79         {
80           if (t_new->_next == Timeout_q::timeout_queue.cpu(0).first())
81             break;
82           t_new = t_new->_next;
83         }
84       else
85         {
86           if (t_new->_prev == Timeout_q::timeout_queue.cpu(0).first())
87             break;
88           t_new = t_new->_prev;
89         }
90
91       if (iter)
92         iter(t_new);
93
94       i++;
95     };
96
97   _count = i;
98   bool changed = *t_start != t_new;
99   *t_start = t_new;
100
101   return changed;
102 }
103
104 // _t_start-- if possible
105 PUBLIC static
106 int
107 Jdb_timeout_list::line_back(void)
108 {
109   return _t_start ? iter(-1, &_t_start) : 0;
110 }
111
112 // _t_start++ if possible
113 PUBLIC static
114 int
115 Jdb_timeout_list::line_forw(void)
116 {
117   Timeout *t = _t_start;
118   if (t)
119     {
120       iter(+Jdb_screen::height()-2, &_t_start);
121       iter(-Jdb_screen::height()+3, &_t_start);
122     }
123   return t != _t_start;
124 }
125
126 // _t_start -= 24 if possible
127 PUBLIC static
128 int
129 Jdb_timeout_list::page_back(void)
130 {
131   return _t_start ? iter(-Jdb_screen::height()+2, &_t_start) : 0;
132 }
133
134 // _t_start += 24 if possible
135 PUBLIC static
136 int
137 Jdb_timeout_list::page_forw(void)
138 {
139   Timeout *t = _t_start;
140   if (t)
141     {
142       iter(+Jdb_screen::height()*2-5, &_t_start);
143       iter(-Jdb_screen::height()+3,   &_t_start);
144     }
145   return t != _t_start;
146 }
147
148 // _t_start = first element of list
149 PUBLIC static
150 int
151 Jdb_timeout_list::goto_home(void)
152 {
153   return _t_start ? iter(-9999, &_t_start) : 0;
154 }
155
156 // _t_start = last element of list
157 PUBLIC static
158 int
159 Jdb_timeout_list::goto_end(void)
160 {
161   Timeout *t = _t_start;
162   if (t)
163     {
164       iter(+9999, &_t_start);
165       iter(-Jdb_screen::height()+2, &_t_start);
166     }
167   return t != _t_start;
168 }
169
170 PUBLIC static
171 int
172 Jdb_timeout_list::lookup(Timeout *t_search)
173 {
174   unsigned i;
175   Timeout *t;
176
177   for (i=0, t=_t_start; i<Jdb_screen::height()-3; i++)
178     {
179       if (t == t_search)
180         break;
181       iter(+1, &t);
182     }
183
184   return i;
185 }
186
187 PUBLIC static
188 Timeout*
189 Jdb_timeout_list::index(int y)
190 {
191   Timeout *t = _t_start;
192
193   if (!t)
194     return 0;
195
196   iter(y, &t);
197   return t;
198 }
199
200 PUBLIC static
201 int
202 Jdb_timeout_list::page_show(void (*show)(Timeout *t))
203 {
204   Timeout *t = _t_start;
205
206   iter(Jdb_screen::height()-3, &t, show);
207   return _count;
208 }
209
210 // use implicit knowledge to determine the type of a timeout because we
211 // cannot use dynamic_cast (we compile with -fno-rtti)
212 static
213 int
214 Jdb_list_timeouts::get_type(Timeout *t)
215 {
216   Address addr = (Address)t;
217
218   if (t == timeslice_timeout.cpu(0))
219     // there is only one global timeslice timeout
220     return Timeout_timeslice;
221
222   if (Timeout_q::timeout_queue.cpu(0).is_root_node(addr))
223     return Timeout_root;
224
225   if ((addr % Config::thread_block_size) >= sizeof(Thread))
226     // IPC timeouts are located at the kernel stack
227     return Timeout_ipc;
228
229   // unknown
230   return 0;
231 }
232
233 static
234 Thread*
235 Jdb_list_timeouts::get_owner(Timeout *t)
236 {
237   switch (get_type(t))
238     {
239       case Timeout_ipc:
240         return Thread::lookup(context_of (t));
241       case Timeout_deadline:
242         return Thread::lookup(context_of (t));
243       case Timeout_timeslice:
244         return kernel_thread;
245         // XXX: current_sched does not work from the debugger
246         if (Context::current_sched())
247           return Thread::lookup(Context::current_sched()->context());
248       default:
249         return 0;
250     }
251 }
252
253 static
254 void
255 Jdb_list_timeouts::show_header()
256 {
257   Jdb::cursor();
258   printf("%s  type           timeout    owner       name\033[m\033[K\n",
259          Jdb::esc_emph);
260 }
261
262 static
263 void
264 Jdb_list_timeouts::list_timeouts_show_timeout(Timeout *t)
265 {
266   char const *type;
267   char ownerstr[32] = "";
268   Thread *owner;
269   Signed64 timeout = t->get_timeout(Kip::k()->clock);
270
271   Kconsole::console()->getchar_chance();
272
273   switch (get_type(t))
274     {
275     case Timeout_ipc:
276       type  = "ipc";
277       owner = get_owner(t);
278       snprintf (ownerstr, sizeof(ownerstr), "  %p", owner);
279       break;
280     case Timeout_deadline:
281       type  = "deadline";
282       owner = get_owner(t);
283       snprintf (ownerstr, sizeof(ownerstr), "  %p", owner);
284       break;
285     case Timeout_timeslice:
286       type  = "timeslice";
287       owner = get_owner(t);
288       if (owner)
289         snprintf (ownerstr, sizeof(ownerstr), "  %p", owner);
290       else
291        strcpy (ownerstr, "destruct");
292       break;
293     case Timeout_root:
294       type  = "root";
295       owner = 0;
296       strcpy (ownerstr, "kern");
297       break;
298     default:
299       snprintf(ownerstr, sizeof(ownerstr), L4_PTR_FMT, (Address)t);
300       type  = "???";
301       owner = 0;
302       break;
303     }
304
305   printf("  %-10s   ", type);
306   if (timeout < 0)
307     putstr("   over     ");
308   else
309     {
310       char time_str[12];
311       Jdb::write_ll_ns(timeout * 1000, time_str,
312                        11 < sizeof(time_str) - 1 ? 11 : sizeof(time_str) - 1,
313                        false);
314       putstr(time_str);
315     }
316
317   Jdb_kobject_name *nx = 0;
318
319   if (owner)
320     nx = Jdb_kobject_extension::find_extension<Jdb_kobject_name>(owner->kobject());
321
322   printf(" %s  %s\033[K\n", ownerstr, nx ? nx->name() : "");
323 }
324
325 IMPLEMENT
326 Jdb_list_timeouts::Jdb_list_timeouts()
327   : Jdb_module("INFO")
328 {}
329
330 static
331 void
332 Jdb_list_timeouts::list()
333 {
334   unsigned y, y_max;
335   Timeout *t_current = Timeout_q::timeout_queue.cpu(0).first();
336
337   Jdb::clear_screen();
338   show_header();
339   Jdb_timeout_list::init(t_current);
340
341   for (;;)
342     {
343       y = Jdb_timeout_list::lookup(t_current);
344
345       for (bool resync=false; !resync; )
346         {
347           Jdb::cursor(2, 1);
348           y_max = t_current
349                       ? Jdb_timeout_list::page_show(list_timeouts_show_timeout)
350                       : 0;
351
352           for (unsigned i=y_max; i<Jdb_screen::height()-3; i++)
353             putstr("\033[K\n");
354
355           Jdb::printf_statline("timouts", "<CR>=select owner", "_");
356
357           for (bool redraw=false; !redraw; )
358             {
359               Jdb::cursor(y+2, 1);
360               switch (int c=Jdb_core::getchar())
361                 {
362                 case KEY_CURSOR_UP:
363                   if (y > 0)
364                     y--;
365                   else
366                     redraw = Jdb_timeout_list::line_back();
367                   break;
368                 case KEY_CURSOR_DOWN:
369                   if (y < y_max)
370                     y++;
371                   else
372                     redraw = Jdb_timeout_list::line_forw();
373                   break;
374                 case KEY_PAGE_UP:
375                   if (!(redraw = Jdb_timeout_list::page_back()))
376                     y = 0;
377                   break;
378                 case KEY_PAGE_DOWN:
379                   if (!(redraw = Jdb_timeout_list::page_forw()))
380                     y = y_max;
381                   break;
382                 case KEY_CURSOR_HOME:
383                   redraw = Jdb_timeout_list::goto_home();
384                   y = 0;
385                   break;
386                 case KEY_CURSOR_END:
387                   redraw = Jdb_timeout_list::goto_end();
388                   y = y_max;
389                   break;
390                 case KEY_RETURN:
391                   if (jdb_show_tcb != 0)
392                     {
393                       Thread *owner;
394                       Timeout *t = Jdb_timeout_list::index(y);
395                       if (t && (owner = get_owner(t)))
396                         {
397                           if (!jdb_show_tcb(owner, 1))
398                             return;
399                           show_header();
400                           redraw = 1;
401                         }
402                     }
403                   break;
404                 case KEY_ESC:
405                   Jdb::abort_command();
406                   return;
407                 default:
408                   if (Jdb::is_toplevel_cmd(c))
409                     return;
410                 }
411             }
412         }
413     }
414 }
415
416 PUBLIC
417 Jdb_module::Action_code
418 Jdb_list_timeouts::action(int cmd, void *&, char const *&, int &)
419 {
420   if (cmd == 0)
421     list();
422
423   return NOTHING;
424 }
425
426 PUBLIC
427 Jdb_module::Cmd const *
428 Jdb_list_timeouts::cmds() const
429 {
430   static Cmd cs[] =
431     {
432         { 0, "lt", "timeouts", "", "lt\tshow enqueued timeouts", 0 },
433     };
434
435   return cs;
436 }
437
438 PUBLIC
439 int
440 Jdb_list_timeouts::num_cmds() const
441 {
442   return 1;
443 }
444
445 static Jdb_list_timeouts jdb_list_timeouts INIT_PRIORITY(JDB_MODULE_INIT_PRIO);