1 // -*- c-basic-offset: 4; related-file-name: "../include/click/routerthread.hh" -*-
2 /*
3 * routerthread.{cc,hh} -- Click threads
4 * Eddie Kohler, Benjie Chen, Petros Zerfos
5 *
6 * Copyright (c) 2000-2001 Massachusetts Institute of Technology
7 * Copyright (c) 2001-2002 International Computer Science Institute
8 * Copyright (c) 2004-2007 Regents of the University of California
9 * Copyright (c) 2008-2010 Meraki, Inc.
10 * Copyright (c) 2000-2016 Eddie Kohler
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, subject to the conditions
15 * listed in the Click LICENSE file. These conditions include: you must
16 * preserve this copyright notice, and you cannot mention the copyright
17 * holders in advertising related to the Software without their permission.
18 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
19 * notice is a summary of the Click LICENSE file; the license in that file is
20 * legally binding.
21 */
22
23 #include <click/config.h>
24 #include <click/glue.hh>
25 #include <click/router.hh>
26 #include <click/routerthread.hh>
27 #include <click/master.hh>
28 #if CLICK_LINUXMODULE
29 # include <click/cxxprotect.h>
30 CLICK_CXX_PROTECT
31 # include <linux/sched.h>
32 CLICK_CXX_UNPROTECT
33 # include <click/cxxunprotect.h>
34 #endif
35 #if CLICK_BSDMODULE
36 # include <click/cxxprotect.h>
37 CLICK_CXX_PROTECT
38 # include <sys/kthread.h>
39 CLICK_CXX_UNPROTECT
40 # include <click/cxxunprotect.h>
41 #elif CLICK_USERLEVEL
42 # include <fcntl.h>
43 #endif
44 CLICK_DECLS
45
46 #define DEBUG_RT_SCHED 0
47
48 #define PROFILE_ELEMENT 20
49
50 #if HAVE_ADAPTIVE_SCHEDULER
51 # define DRIVER_TOTAL_TICKETS 128 /* # tickets shared between clients */
52 # define DRIVER_GLOBAL_STRIDE (Task::STRIDE1 / DRIVER_TOTAL_TICKETS)
53 # define DRIVER_QUANTUM 8 /* microseconds per stride */
54 # define DRIVER_RESTRIDE_INTERVAL 80 /* microseconds between restrides */
55 #endif
56
57 #if CLICK_LINUXMODULE
58 static unsigned long greedy_schedule_jiffies;
59 #endif
60
61 /** @file routerthread.hh
62 * @brief The RouterThread class implementing the Click driver loop.
63 */
64
65 /** @class RouterThread
66 * @brief A set of Tasks scheduled on the same CPU.
67 */
68
RouterThread(Master * master,int id)69 RouterThread::RouterThread(Master *master, int id)
70 : _stop_flag(0), _master(master), _id(id), _driver_entered(false)
71 {
72 _pending_head.x = 0;
73 _pending_tail = &_pending_head;
74
75 #if !HAVE_TASK_HEAP
76 _task_link._prev = _task_link._next = &_task_link;
77 #endif
78 #if CLICK_LINUXMODULE
79 _linux_task = 0;
80 #elif CLICK_USERLEVEL && HAVE_MULTITHREAD
81 _running_processor = click_invalid_processor();
82 #endif
83
84 _task_blocker = 0;
85 _task_blocker_waiting = 0;
86 #if HAVE_ADAPTIVE_SCHEDULER
87 _max_click_share = 80 * Task::MAX_UTILIZATION / 100;
88 _min_click_share = Task::MAX_UTILIZATION / 200;
89 _cur_click_share = 0; // because we aren't yet running
90 #endif
91
92 #if CLICK_NS
93 _tasks_per_iter = 256;
94 #else
95 #ifdef BSD_NETISRSCHED
96 // Must be set low for Luigi's feedback scheduler to work properly
97 _tasks_per_iter = 8;
98 #else
99 _tasks_per_iter = 128;
100 #endif
101 #endif
102
103 _iters_per_os = 2; // userlevel: iterations per select()
104 // kernel: iterations per OS schedule()
105
106 #if CLICK_LINUXMODULE || CLICK_BSDMODULE
107 _greedy = false;
108 #endif
109 #if CLICK_LINUXMODULE
110 greedy_schedule_jiffies = jiffies;
111 #endif
112
113 #if CLICK_NS
114 _ns_scheduled = _ns_last_active = Timestamp(-1, 0);
115 _ns_active_iter = 0;
116 #endif
117
118 #if CLICK_DEBUG_SCHEDULING
119 _thread_state = S_BLOCKED;
120 _driver_epoch = 0;
121 _driver_task_epoch = 0;
122 _task_epoch_first = 0;
123 # if CLICK_DEBUG_SCHEDULING > 1
124 for (int s = 0; s < NSTATES; ++s)
125 _thread_state_count[s] = 0;
126 # endif
127 #endif
128
129 static_assert(THREAD_QUIESCENT == (int) ThreadSched::THREAD_QUIESCENT
130 && THREAD_UNKNOWN == (int) ThreadSched::THREAD_UNKNOWN,
131 "Thread constants screwup.");
132 }
133
~RouterThread()134 RouterThread::~RouterThread()
135 {
136 assert(!active());
137 }
138
139 inline void
driver_lock_tasks()140 RouterThread::driver_lock_tasks()
141 {
142 set_thread_state(S_LOCKTASKS);
143
144 // If other people are waiting for the task lock, give them a chance to
145 // catch it before we claim it.
146 #if CLICK_LINUXMODULE
147 for (int i = 0; _task_blocker_waiting > 0 && i < 10; i++)
148 schedule();
149 #elif HAVE_MULTITHREAD && CLICK_USERLEVEL
150 for (int i = 0; _task_blocker_waiting > 0 && i < 10; i++) {
151 struct timeval waiter = { 0, 1 };
152 select(0, 0, 0, 0, &waiter);
153 }
154 #endif
155
156 while (_task_blocker.compare_swap(0, (uint32_t) -1) != 0) {
157 #if CLICK_LINUXMODULE
158 schedule();
159 #endif
160 }
161 }
162
163 inline void
driver_unlock_tasks()164 RouterThread::driver_unlock_tasks()
165 {
166 uint32_t val = _task_blocker.compare_swap((uint32_t) -1, 0);
167 (void) val;
168 assert(val == (uint32_t) -1);
169 }
170
171 void
scheduled_tasks(Router * router,Vector<Task * > & x)172 RouterThread::scheduled_tasks(Router *router, Vector<Task *> &x)
173 {
174 lock_tasks();
175 for (Task *t = task_begin(); t != task_end(); t = task_next(t))
176 if (t->router() == router)
177 x.push_back(t);
178 unlock_tasks();
179 }
180
181 void
request_stop()182 RouterThread::request_stop()
183 {
184 _stop_flag = 1;
185 if (current_thread_is_running()) {
186 // Set the current thread's tasks to "is_strong_unscheduled 2" so
187 // the driver loop will not run them. (We cannot call
188 // Task::remove_from_scheduled_list(), because run_tasks keeps the
189 // current task in limbo, so it must stay in the scheduled list.)
190 Task::Status want_status;
191 want_status.home_thread_id = thread_id();
192 want_status.is_scheduled = true;
193 want_status.is_strong_unscheduled = false;
194 Task::Status new_status(want_status);
195 new_status.is_strong_unscheduled = 2;
196
197 for (Task *t = task_begin(); t != task_end(); t = task_next(t))
198 atomic_uint32_t::compare_swap(t->_status.status, want_status.status, new_status.status);
199 }
200 }
201
202
203 /******************************/
204 /* Adaptive scheduler */
205 /******************************/
206
207 #if HAVE_ADAPTIVE_SCHEDULER
208
209 void
set_cpu_share(unsigned min_frac,unsigned max_frac)210 RouterThread::set_cpu_share(unsigned min_frac, unsigned max_frac)
211 {
212 if (min_frac == 0)
213 min_frac = 1;
214 if (min_frac > Task::MAX_UTILIZATION - 1)
215 min_frac = Task::MAX_UTILIZATION - 1;
216 if (max_frac > Task::MAX_UTILIZATION - 1)
217 max_frac = Task::MAX_UTILIZATION - 1;
218 if (max_frac < min_frac)
219 max_frac = min_frac;
220 _min_click_share = min_frac;
221 _max_click_share = max_frac;
222 }
223
224 void
client_set_tickets(int client,int new_tickets)225 RouterThread::client_set_tickets(int client, int new_tickets)
226 {
227 Client &c = _clients[client];
228
229 // pin 'tickets' in a reasonable range
230 if (new_tickets < 1)
231 new_tickets = 1;
232 else if (new_tickets > Task::MAX_TICKETS)
233 new_tickets = Task::MAX_TICKETS;
234 unsigned new_stride = Task::STRIDE1 / new_tickets;
235 assert(new_stride < Task::MAX_STRIDE);
236
237 // calculate new pass, based possibly on old pass
238 // start with a full stride on initialization (c.tickets == 0)
239 if (c.tickets == 0)
240 c.pass = _global_pass + new_stride;
241 else {
242 int delta = (c.pass - _global_pass) * new_stride / c.stride;
243 c.pass = _global_pass + delta;
244 }
245
246 c.tickets = new_tickets;
247 c.stride = new_stride;
248 }
249
250 inline void
client_update_pass(int client,const Timestamp & t_before)251 RouterThread::client_update_pass(int client, const Timestamp &t_before)
252 {
253 Client &c = _clients[client];
254 Timestamp t_now = Timestamp::now();
255 Timestamp::value_type elapsed = (t_now - t_before).usecval();
256 if (elapsed > 0)
257 c.pass += (c.stride * elapsed) / DRIVER_QUANTUM;
258 else
259 c.pass += c.stride;
260
261 // check_restride
262 elapsed = (t_now - _adaptive_restride_timestamp).usecval();
263 if (elapsed > DRIVER_RESTRIDE_INTERVAL || elapsed < 0) {
264 // mark new measurement period
265 _adaptive_restride_timestamp = t_now;
266
267 // reset passes every 10 intervals, or when time moves backwards
268 if (++_adaptive_restride_iter == 10 || elapsed < 0) {
269 _global_pass = _clients[C_CLICK].tickets = _clients[C_KERNEL].tickets = 0;
270 _adaptive_restride_iter = 0;
271 } else
272 _global_pass += (DRIVER_GLOBAL_STRIDE * elapsed) / DRIVER_QUANTUM;
273
274 // find out the maximum amount of work any task performed
275 int click_utilization = 0;
276 Task *end = task_end();
277 for (Task *t = task_begin(); t != end; t = task_next(t)) {
278 int u = t->utilization();
279 t->clear_runs();
280 if (u > click_utilization)
281 click_utilization = u;
282 }
283
284 // constrain to bounds
285 if (click_utilization < _min_click_share)
286 click_utilization = _min_click_share;
287 if (click_utilization > _max_click_share)
288 click_utilization = _max_click_share;
289
290 // set tickets
291 int click_tix = (DRIVER_TOTAL_TICKETS * click_utilization) / Task::MAX_UTILIZATION;
292 if (click_tix < 1)
293 click_tix = 1;
294 client_set_tickets(C_CLICK, click_tix);
295 client_set_tickets(C_KERNEL, DRIVER_TOTAL_TICKETS - _clients[C_CLICK].tickets);
296 _cur_click_share = click_utilization;
297 }
298 }
299
300 #endif
301
302 /******************************/
303 /* Debugging */
304 /******************************/
305
306 #if CLICK_DEBUG_SCHEDULING
307 Timestamp
task_epoch_time(uint32_t epoch) const308 RouterThread::task_epoch_time(uint32_t epoch) const
309 {
310 if (epoch >= _task_epoch_first && epoch <= _driver_task_epoch)
311 return _task_epoch_time[epoch - _task_epoch_first];
312 else if (epoch > _driver_task_epoch - TASK_EPOCH_BUFSIZ && epoch <= _task_epoch_first - 1)
313 // "-1" makes this code work even if _task_epoch overflows
314 return _task_epoch_time[epoch - (_task_epoch_first - TASK_EPOCH_BUFSIZ)];
315 else
316 return Timestamp();
317 }
318 #endif
319
320
321 /******************************/
322 /* The driver loop */
323 /******************************/
324
325 #if HAVE_TASK_HEAP
326 #define PASS_GE(a, b) ((int)(a - b) >= 0)
327
328 void
task_reheapify_from(int pos,Task * t)329 RouterThread::task_reheapify_from(int pos, Task* t)
330 {
331 // MUST be called with task lock held
332 task_heap_element *tbegin = _task_heap.begin();
333 task_heap_element *tend = _task_heap.end();
334 int npos;
335
336 while (pos > 0
337 && (npos = (pos-1) >> 1, PASS_GT(tbegin[npos].pass, t->_pass))) {
338 tbegin[pos] = tbegin[npos];
339 tbegin[npos].t->_schedpos = pos;
340 pos = npos;
341 }
342
343 while (1) {
344 Task *smallest = t;
345 task_heap_element *tp = tbegin + 2*pos + 1;
346 if (tp < tend && PASS_GE(smallest->_pass, tp[0].pass))
347 smallest = tp[0].t;
348 if (tp + 1 < tend && PASS_GE(smallest->_pass, tp[1].pass))
349 smallest = tp[1].t, ++tp;
350
351 smallest->_schedpos = pos;
352 tbegin[pos].t = smallest;
353 tbegin[pos].pass = smallest->_pass;
354
355 if (smallest == t)
356 return;
357
358 pos = tp - tbegin;
359 }
360 }
361 #endif
362
363 /* Run at most 'ntasks' tasks. */
364 inline void
run_tasks(int ntasks)365 RouterThread::run_tasks(int ntasks)
366 {
367 set_thread_state(S_RUNTASK);
368 #if CLICK_DEBUG_SCHEDULING
369 _driver_task_epoch++;
370 _task_epoch_time[_driver_task_epoch % TASK_EPOCH_BUFSIZ].assign_now();
371 if ((_driver_task_epoch % TASK_EPOCH_BUFSIZ) == 0)
372 _task_epoch_first = _driver_task_epoch;
373 #endif
374 #if HAVE_ADAPTIVE_SCHEDULER
375 Timestamp t_before = Timestamp::now();
376 #endif
377 #if CLICK_BSDMODULE && !BSD_NETISRSCHED
378 int bsd_spl = splimp();
379 #endif
380
381 // never run more than 32768 tasks
382 if (ntasks > 32768)
383 ntasks = 32768;
384
385 #if HAVE_MULTITHREAD
386 // cycle counter for adaptive scheduling among processors
387 click_cycles_t cycles = 0;
388 #endif
389
390 Task::Status want_status;
391 want_status.home_thread_id = thread_id();
392 want_status.is_scheduled = true;
393 want_status.is_strong_unscheduled = false;
394
395 Task *t;
396 #if HAVE_MULTITHREAD
397 int runs;
398 #endif
399 bool work_done;
400
401 for (; ntasks >= 0; --ntasks) {
402 t = task_begin();
403 if (t == task_end())
404 break;
405 assert(t->_thread == this);
406
407 if (unlikely(t->_status.status != want_status.status)) {
408 if (t->_status.home_thread_id != want_status.home_thread_id
409 || t->_status.is_strong_unscheduled == 2)
410 t->add_pending(0);
411 t->remove_from_scheduled_list();
412 continue;
413 }
414
415 #if HAVE_MULTITHREAD
416 runs = t->cycle_runs();
417 if (runs > PROFILE_ELEMENT)
418 cycles = click_get_cycles();
419 #endif
420
421 t->_status.is_scheduled = false;
422 work_done = t->fire();
423
424 #if HAVE_MULTITHREAD
425 if (runs > PROFILE_ELEMENT) {
426 unsigned delta = click_get_cycles() - cycles;
427 t->update_cycles(delta/32 + (t->cycles()*31)/32);
428 }
429 #endif
430
431 // fix task list
432 if (t->scheduled()) {
433 // adjust position in scheduled list
434 #if HAVE_STRIDE_SCHED
435 t->_pass += t->_stride;
436 #endif
437
438 // If the task didn't do any work, don't run it next. This might
439 // require delaying its pass, or exiting the scheduling loop
440 // entirely.
441 if (!work_done) {
442 #if HAVE_STRIDE_SCHED && HAVE_TASK_HEAP
443 if (_task_heap.size() < 2)
444 break;
445 #else
446 if (t->_next == &_task_link)
447 break;
448 #endif
449 #if HAVE_STRIDE_SCHED
450 # if HAVE_TASK_HEAP
451 unsigned p1 = _task_heap.unchecked_at(1).pass;
452 if (_task_heap.size() > 2 && PASS_GT(p1, _task_heap.unchecked_at(2).pass))
453 p1 = _task_heap.unchecked_at(2).pass;
454 # else
455 unsigned p1 = t->_next->_pass;
456 # endif
457 if (PASS_GT(p1, t->_pass))
458 t->_pass = p1;
459 #endif
460 }
461
462 #if HAVE_STRIDE_SCHED && HAVE_TASK_HEAP
463 task_reheapify_from(0, t);
464 #else
465 # if HAVE_STRIDE_SCHED
466 TaskLink *n = t->_next;
467 while (n != &_task_link && !PASS_GT(n->_pass, t->_pass))
468 n = n->_next;
469 # else
470 TaskLink *n = &_task_link;
471 # endif
472 if (t->_next != n) {
473 t->_next->_prev = t->_prev;
474 t->_prev->_next = t->_next;
475 t->_next = n;
476 t->_prev = n->_prev;
477 n->_prev->_next = t;
478 n->_prev = t;
479 }
480 #endif
481 } else
482 t->remove_from_scheduled_list();
483 }
484
485 #if CLICK_BSDMODULE && !BSD_NETISRSCHED
486 splx(bsd_spl);
487 #endif
488 #if HAVE_ADAPTIVE_SCHEDULER
489 client_update_pass(C_CLICK, t_before);
490 #endif
491 }
492
493 inline void
run_os()494 RouterThread::run_os()
495 {
496 #if CLICK_LINUXMODULE
497 // set state to interruptible early to avoid race conditions
498 set_current_state(TASK_INTERRUPTIBLE);
499 #endif
500 driver_unlock_tasks();
501 #if HAVE_ADAPTIVE_SCHEDULER
502 Timestamp t_before = Timestamp::now();
503 #endif
504
505 #if CLICK_USERLEVEL
506 select_set().run_selects(this);
507 #elif CLICK_MINIOS
508 /*
509 * MiniOS uses a cooperative scheduler. By schedule() we'll give a chance
510 * to the OS threads to run.
511 */
512 schedule();
513 #elif CLICK_LINUXMODULE /* Linux kernel module */
514 if (_greedy) {
515 if (time_after(jiffies, greedy_schedule_jiffies + 5 * CLICK_HZ)) {
516 greedy_schedule_jiffies = jiffies;
517 goto short_pause;
518 }
519 } else if (active()) {
520 short_pause:
521 set_thread_state(S_PAUSED);
522 set_current_state(TASK_RUNNING);
523 schedule();
524 } else if (_id != 0) {
525 block:
526 set_thread_state(S_BLOCKED);
527 schedule();
528 } else if (Timestamp wait = timer_set().timer_expiry_steady_adjusted()) {
529 wait -= Timestamp::now_steady();
530 if (!(wait > Timestamp(0, Timestamp::subsec_per_sec / CLICK_HZ)))
531 goto short_pause;
532 set_thread_state(S_TIMERWAIT);
533 if (wait.sec() >= LONG_MAX / CLICK_HZ - 1)
534 (void) schedule_timeout(LONG_MAX - CLICK_HZ - 1);
535 else
536 (void) schedule_timeout(wait.jiffies() - 1);
537 } else
538 goto block;
539 #elif defined(CLICK_BSDMODULE)
540 if (_greedy)
541 /* do nothing */;
542 else if (active()) { // just schedule others for a moment
543 set_thread_state(S_PAUSED);
544 yield(curthread, NULL);
545 } else {
546 set_thread_state(S_BLOCKED);
547 _sleep_ident = &_sleep_ident; // arbitrary address, != NULL
548 tsleep(&_sleep_ident, PPAUSE, "pause", 1);
549 _sleep_ident = NULL;
550 }
551 #else
552 # error "Compiling for unknown target."
553 #endif
554
555 #if HAVE_ADAPTIVE_SCHEDULER
556 client_update_pass(C_KERNEL, t_before);
557 #endif
558 driver_lock_tasks();
559 }
560
561 void
process_pending()562 RouterThread::process_pending()
563 {
564 // must be called with thread's lock acquired
565
566 // claim the current pending list
567 set_thread_state(RouterThread::S_RUNPENDING);
568 SpinlockIRQ::flags_t flags = _pending_lock.acquire();
569 Task::Pending my_pending = _pending_head;
570 _pending_head.x = 0;
571 _pending_tail = &_pending_head;
572 _pending_lock.release(flags);
573
574 // process the list
575 while (my_pending.x > 1) {
576 Task *t = my_pending.t;
577 my_pending = t->_pending_nextptr;
578 t->process_pending(this);
579 }
580 }
581
582 void
driver()583 RouterThread::driver()
584 {
585 int iter = 0;
586 _driver_entered = true;
587 #if CLICK_LINUXMODULE
588 // this task is running the driver
589 _linux_task = current;
590 #elif CLICK_USERLEVEL
591 select_set().initialize();
592 # if CLICK_USERLEVEL && HAVE_MULTITHREAD
593 _running_processor = click_current_processor();
594 # if HAVE___THREAD_STORAGE_CLASS
595 click_current_thread_id = _id | 0x40000000;
596 # endif
597 # endif
598 #endif
599
600 #if CLICK_NS
601 {
602 Timestamp now = Timestamp::now();
603 if (now >= _ns_scheduled)
604 _ns_scheduled.set_sec(-1);
605 }
606 #endif
607
608 driver_lock_tasks();
609
610 #if HAVE_ADAPTIVE_SCHEDULER
611 client_set_tickets(C_CLICK, DRIVER_TOTAL_TICKETS / 2);
612 client_set_tickets(C_KERNEL, DRIVER_TOTAL_TICKETS / 2);
613 _cur_click_share = Task::MAX_UTILIZATION / 2;
614 _adaptive_restride_timestamp.assign_now();
615 _adaptive_restride_iter = 0;
616 #endif
617
618 while (1) {
619 #if CLICK_DEBUG_SCHEDULING
620 _driver_epoch++;
621 #endif
622
623 #if !BSD_NETISRSCHED
624 // check to see if driver is stopped
625 if (_stop_flag > 0) {
626 driver_unlock_tasks();
627 bool b = _master->check_driver();
628 driver_lock_tasks();
629 if (!b)
630 break;
631 }
632 #endif
633
634 // run occasional tasks: timers, select, etc.
635 iter++;
636
637 // run task requests
638 click_compiler_fence();
639 if (_pending_head.x)
640 process_pending();
641
642 // run tasks
643 do {
644 #if HAVE_ADAPTIVE_SCHEDULER
645 if (PASS_GT(_clients[C_CLICK].pass, _clients[C_KERNEL].pass))
646 break;
647 #endif
648 run_tasks(_tasks_per_iter);
649 } while (0);
650
651 #if CLICK_USERLEVEL
652 // run signals
653 run_signals();
654 #endif
655
656 // run timers
657 do {
658 #if !BSD_NETISRSCHED
659 if (iter % timer_set().timer_stride())
660 break;
661 #elif BSD_NETISRSCHED
662 if (iter % timer_set().timer_stride() && _oticks == ticks)
663 break;
664 _oticks = ticks;
665 #endif
666 timer_set().run_timers(this, _master);
667 } while (0);
668
669 // run operating system
670 do {
671 #if !HAVE_ADAPTIVE_SCHEDULER && !BSD_NETISRSCHED
672 if (iter % _iters_per_os)
673 break;
674 #elif HAVE_ADAPTIVE_SCHEDULER
675 if (!PASS_GT(_clients[C_CLICK].pass, _clients[C_KERNEL].pass))
676 break;
677 #elif BSD_NETISRSCHED
678 break;
679 #endif
680 run_os();
681 } while (0);
682
683 #if CLICK_NS || BSD_NETISRSCHED
684 // Everyone except the NS driver stays in driver() until the driver is
685 // stopped.
686 break;
687 #endif
688 }
689
690 driver_unlock_tasks();
691
692 _driver_entered = false;
693 #if HAVE_ADAPTIVE_SCHEDULER
694 _cur_click_share = 0;
695 #endif
696 #if CLICK_LINUXMODULE
697 _linux_task = 0;
698 #endif
699 #if CLICK_USERLEVEL && HAVE_MULTITHREAD
700 _running_processor = click_invalid_processor();
701 # if HAVE___THREAD_STORAGE_CLASS
702 click_current_thread_id = 0;
703 # endif
704 #endif
705 #if CLICK_NS
706 do {
707 Timestamp t = Timestamp::uninitialized_t();
708 if (active()) {
709 t = Timestamp::now();
710 if (t != _ns_last_active) {
711 _ns_active_iter = 0;
712 _ns_last_active = t;
713 } else if (++_ns_active_iter >= ns_iters_per_time)
714 t += Timestamp::epsilon();
715 } else if (Timestamp next_expiry = timer_set().timer_expiry_steady())
716 t = next_expiry;
717 else
718 break;
719 if (t >= _ns_scheduled && _ns_scheduled.sec() >= 0)
720 break;
721 if (Timestamp::schedule_granularity == Timestamp::usec_per_sec) {
722 t = t.usec_ceil();
723 struct timeval tv = t.timeval();
724 simclick_sim_command(_master->simnode(), SIMCLICK_SCHEDULE, &tv);
725 } else {
726 t = t.nsec_ceil();
727 struct timespec ts = t.timespec();
728 simclick_sim_command(_master->simnode(), SIMCLICK_SCHEDULE, &ts);
729 }
730 _ns_scheduled = t;
731 } while (0);
732 #endif
733 }
734
735
736 void
kill_router(Router * r)737 RouterThread::kill_router(Router *r)
738 {
739 assert(r->dying());
740 lock_tasks();
741 #if HAVE_TASK_HEAP
742 Task *t;
743 for (task_heap_element *tp = _task_heap.end(); tp > _task_heap.begin(); )
744 if ((t = (--tp)->t, t->router() == r)) {
745 task_reheapify_from(tp - _task_heap.begin(), _task_heap.back().t);
746 // must clear _schedpos AFTER task_reheapify_from
747 t->_schedpos = -1;
748 // recheck this slot; have moved a task there
749 _task_heap.pop_back();
750 if (tp < _task_heap.end())
751 tp++;
752 }
753 #else
754 TaskLink *prev = &_task_link;
755 TaskLink *t;
756 for (t = prev->_next; t != &_task_link; t = t->_next)
757 if (static_cast<Task *>(t)->router() == r)
758 t->_prev = 0;
759 else {
760 prev->_next = t;
761 t->_prev = prev;
762 prev = t;
763 }
764 prev->_next = t;
765 t->_prev = prev;
766 #endif
767 click_compiler_fence();
768 if (_pending_head.x)
769 process_pending();
770 unlock_tasks();
771
772 _timers.kill_router(r);
773 #if CLICK_USERLEVEL
774 _selects.kill_router(r);
775 #endif
776 }
777
778 #if CLICK_DEBUG_SCHEDULING
779 String
thread_state_name(int ts)780 RouterThread::thread_state_name(int ts)
781 {
782 switch (ts) {
783 case S_PAUSED: return String::make_stable("paused");
784 case S_BLOCKED: return String::make_stable("blocked");
785 case S_TIMERWAIT: return String::make_stable("timerwait");
786 case S_LOCKSELECT: return String::make_stable("lockselect");
787 case S_LOCKTASKS: return String::make_stable("locktasks");
788 case S_RUNTASK: return String::make_stable("runtask");
789 case S_RUNTIMER: return String::make_stable("runtimer");
790 case S_RUNSIGNAL: return String::make_stable("runsignal");
791 case S_RUNPENDING: return String::make_stable("runpending");
792 case S_RUNSELECT: return String::make_stable("runselect");
793 default: return String(ts);
794 }
795 }
796 #endif
797
798 CLICK_ENDDECLS
799