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