Click
Loading...
Searching...
No Matches
routerthread.hh
Go to the documentation of this file.
1// -*- c-basic-offset: 4; related-file-name: "../../lib/routerthread.cc" -*-
2#ifndef CLICK_ROUTERTHREAD_HH
3#define CLICK_ROUTERTHREAD_HH
4#include <click/sync.hh>
5#include <click/vector.hh>
6#include <click/timerset.hh>
7#if CLICK_LINUXMODULE
8# include <click/cxxprotect.h>
9CLICK_CXX_PROTECT
10# include <linux/sched.h>
11CLICK_CXX_UNPROTECT
12# include <click/cxxunprotect.h>
13#elif CLICK_BSDMODULE
14# include <click/cxxprotect.h>
15CLICK_CXX_PROTECT
16# include <sys/systm.h>
17CLICK_CXX_UNPROTECT
18# include <click/cxxunprotect.h>
19#elif CLICK_USERLEVEL
20# include <click/selectset.hh>
21#endif
22#if HAVE_CLICK_LOAD
23# include <click/ewma.hh>
24# include <click/multithread.hh>
25#endif
26
27// NB: user must #include <click/task.hh> before <click/routerthread.hh>.
28// We cannot #include <click/task.hh> ourselves because of circular #include
29// dependency.
30CLICK_DECLS
31
32class alignas(CLICK_CACHE_LINE_SIZE) RouterThread { public:
33
34 enum { THREAD_QUIESCENT = -1, THREAD_UNKNOWN = -1000 };
35
36 inline int thread_id() const;
37
38 inline Master *master() const;
39 inline TimerSet &timer_set() { return _timers; }
40 inline const TimerSet &timer_set() const { return _timers; }
41#if CLICK_USERLEVEL
42 inline SelectSet &select_set() { return _selects; }
43 inline const SelectSet &select_set() const { return _selects; }
44#endif
45
46 // Task list functions
47 inline bool active() const;
48 inline Task *task_begin() const;
49 inline Task *task_next(Task *task) const;
50 inline Task *task_end() const;
51 void scheduled_tasks(Router *router, Vector<Task *> &x);
52
53 inline void lock_tasks();
54 inline void unlock_tasks();
55
56 inline void schedule_block_tasks();
57 inline void block_tasks(bool scheduled);
58 inline void unblock_tasks();
59
60 inline bool stop_flag() const;
61
62 inline void mark_driver_entry();
63 void driver();
64
65 void kill_router(Router *router);
66
67#if HAVE_ADAPTIVE_SCHEDULER
68 // min_cpu_share() and max_cpu_share() are expressed on a scale with
69 // Task::MAX_UTILIZATION == 100%.
70 unsigned min_cpu_share() const { return _min_click_share; }
71 unsigned max_cpu_share() const { return _max_click_share; }
72 unsigned cur_cpu_share() const { return _cur_click_share; }
73 void set_cpu_share(unsigned min_share, unsigned max_share);
74#endif
75
76#if HAVE_CLICK_LOAD
77 float load();
78 int load_unscaled();
79 int load_max_scale();
80 unsigned long long load_cycles();
81 unsigned long long useful_kcycles();
82#endif
83
84#if CLICK_LINUXMODULE || CLICK_BSDMODULE
85 bool greedy() const { return _greedy; }
86 void set_greedy(bool g) { _greedy = g; }
87#endif
88
89 inline void wake();
90
91#if CLICK_USERLEVEL
92 inline void run_signals();
93#endif
94
95 enum { S_PAUSED, S_BLOCKED, S_TIMERWAIT,
96 S_LOCKSELECT, S_LOCKTASKS,
97 S_RUNTASK, S_RUNTIMER, S_RUNSIGNAL, S_RUNPENDING, S_RUNSELECT,
98 NSTATES };
99 inline void set_thread_state(int state);
100 inline void set_thread_state_for_blocking(int delay_type);
101#if CLICK_DEBUG_SCHEDULING
102 int thread_state() const { return _thread_state; }
103 static String thread_state_name(int state);
104 uint32_t driver_epoch() const { return _driver_epoch; }
105 uint32_t driver_task_epoch() const { return _driver_task_epoch; }
106 Timestamp task_epoch_time(uint32_t epoch) const;
107# if CLICK_LINUXMODULE
108 struct task_struct *sleeper() const { return _linux_task; }
109# endif
110# if CLICK_DEBUG_SCHEDULING > 1
111 inline Timestamp thread_state_time(int state) const;
112 inline uint64_t thread_state_count(int state) const;
113# endif
114#endif
115
116 private:
117
118#if HAVE_TASK_HEAP
119 struct task_heap_element {
120 unsigned pass;
121 Task *t;
122 task_heap_element() {
123 }
124 task_heap_element(Task *t_)
125 : pass(t_->_pass), t(t_) {
126 }
127 };
128#endif
129
130 // LOCAL STATE GROUP
131 TaskLink _task_link;
132 volatile bool _stop_flag;
133#if HAVE_TASK_HEAP
134 Vector<task_heap_element> _task_heap;
135#endif
136
137 TimerSet _timers;
138#if CLICK_USERLEVEL
139 SelectSet _selects;
140#endif
141
142#if HAVE_ADAPTIVE_SCHEDULER
143 enum { C_CLICK, C_KERNEL, NCLIENTS };
144 struct Client { // top-level stride clients
145 unsigned pass;
146 unsigned stride;
147 int tickets;
148 Client() : pass(0), tickets(0) { }
149 };
150 Client _clients[NCLIENTS];
151 unsigned _global_pass; // global pass
152 unsigned _max_click_share; // maximum allowed Click share of CPU
153 unsigned _min_click_share; // minimum allowed Click share of CPU
154 unsigned _cur_click_share; // current Click share
155 Timestamp _adaptive_restride_timestamp;
156 int _adaptive_restride_iter;
157#endif
158
159#if HAVE_CLICK_LOAD
160 struct LoadState {
161 LoadState() : load(), useful(0),useless(0), all_useful_kcycles(0), last_update(0) {
162
163 }
164 EXPSMOOTH<512,10> load;
165 uint64_t useful;
166 uint64_t useless;
167 uint64_t all_useful_kcycles;
168 click_cycles_t last_update;
169 };
170 click_cycles_t UPDATE_TIME;
172#endif
173
174 // EXTERNAL STATE GROUP
175 Spinlock _task_lock CLICK_ALIGNED(CLICK_CACHE_LINE_SIZE);
176 atomic_uint32_t _task_blocker;
177 atomic_uint32_t _task_blocker_waiting;
178
179 int _idle_dorun;
180 IdleTask* _idletask;
181 Task::Pending _pending_head;
182 Task::Pending *_pending_tail;
183 SpinlockIRQ _pending_lock;
184
185 // SHARED STATE GROUP
186 Master *_master CLICK_ALIGNED(CLICK_CACHE_LINE_SIZE);
187 int _id;
188 bool _driver_entered;
189#if HAVE_MULTITHREAD && !(CLICK_LINUXMODULE || CLICK_MINIOS)
190 click_processor_t _running_processor;
191#endif
192#if CLICK_LINUXMODULE
193 bool _greedy;
194 struct task_struct *_linux_task;
195#endif
196#if CLICK_MINIOS
197 struct thread *_minios_thread;
198#endif
199 public:
200 unsigned _tasks_per_iter;
201 unsigned _iters_per_os;
202 private:
203
204#if CLICK_NS
205 Timestamp _ns_scheduled;
206 Timestamp _ns_last_active;
207 int _ns_active_iter;
208 enum { ns_iters_per_time = 1000 };
209#endif
210
211#if CLICK_BSDMODULE
212 // XXX FreeBSD
213 u_int64_t _old_tsc; /* MARKO - temp. */
214 void *_sleep_ident;
215 int _oticks;
216 bool _greedy;
217#endif
218
219#if CLICK_DEBUG_SCHEDULING
220 int _thread_state;
221 uint32_t _driver_epoch;
222 uint32_t _driver_task_epoch;
223 enum { TASK_EPOCH_BUFSIZ = 32 };
224 uint32_t _task_epoch_first;
225 Timestamp _task_epoch_time[TASK_EPOCH_BUFSIZ];
226# if CLICK_DEBUG_SCHEDULING > 1
227 Timestamp _thread_state_time[NSTATES];
228 uint64_t _thread_state_count[NSTATES];
229 Timestamp _thread_state_timestamp;
230# endif
231#endif
232
233 // called by Master
234 RouterThread(Master *master, int threadno);
236
237 // task requests
238 inline void add_pending();
239#if HAVE_STRIDE_SCHED
240 inline unsigned pass() const {
241# if HAVE_TASK_HEAP
242 return _task_heap.size() ? _task_heap.unchecked_at(0).pass : 0;
243# else
244 return _task_link._next->_pass;
245# endif
246 }
247#endif
248
249 // task running functions
250 void driver_lock_tasks();
251 inline void driver_unlock_tasks() {
252#if ! CLICK_ATOMIC_COMPARE_SWAP
253 assert(_task_blocker.compare_and_swap((uint32_t) -1, 0));
254#else
255 uint32_t val = _task_blocker.compare_swap((uint32_t) -1, 0);
256 (void) val;
257 assert(val == (uint32_t) -1);
258#endif
259 }
260
261 inline bool run_tasks(int ntasks);
262 inline void process_pending();
263 inline bool run_os();
264#if HAVE_ADAPTIVE_SCHEDULER
265 void client_set_tickets(int client, int tickets);
266 inline void client_update_pass(int client, const Timestamp &before);
267#endif
268#if HAVE_TASK_HEAP
269 void task_reheapify_from(int pos, Task*);
270#endif
271 static inline bool running_in_interrupt();
272 inline bool current_thread_is_running() const;
273 inline bool current_thread_is_running_cleanup() const;
274
275 friend class Task;
276 friend class IdleTask;
277 friend class Master;
278#if CLICK_USERLEVEL
279 friend class SelectSet;
280#endif
281
282};
283
284
290inline int
292{
293 return _id;
294}
295
297inline Master*
299{
300 return _master;
301}
302
310inline bool
312{
313 click_compiler_fence();
314#if HAVE_TASK_HEAP
315 return _task_heap.size() != 0 || _pending_head.x;
316#else
317 return _task_link._next != &_task_link || _pending_head.x;
318#endif
319}
320
344inline Task *
346{
347#if HAVE_TASK_HEAP
348 return (_task_heap.size() ? _task_heap.unchecked_at(0).t : 0);
349#else
350 return static_cast<Task *>(_task_link._next);
351#endif
352}
353
363inline Task *
365{
366#if HAVE_TASK_HEAP
367 int p = task->_schedpos + 1;
368 return (p < _task_heap.size() ? _task_heap.unchecked_at(p).t : 0);
369#else
370 return static_cast<Task *>(task->_next);
371#endif
372}
373
380inline Task *
382{
383#if HAVE_TASK_HEAP
384 return 0;
385#else
386 return static_cast<Task *>(const_cast<TaskLink *>(&_task_link));
387#endif
388}
389
390inline bool
391RouterThread::running_in_interrupt()
392{
393#if CLICK_LINUXMODULE
394 return in_interrupt();
395#else
396 return false;
397#endif
398}
399
400inline void
401RouterThread::mark_driver_entry()
402{
403 _driver_entered = true;
404}
405
406inline bool
407RouterThread::current_thread_is_running() const
408{
409#if CLICK_LINUXMODULE
410 return current == _linux_task && !running_in_interrupt();
411#elif CLICK_MINIOS
412 return get_current() == _minios_thread;
413#elif CLICK_USERLEVEL && HAVE_MULTITHREAD && HAVE___THREAD_STORAGE_CLASS
414 return click_current_thread_id == (_id | 0x40000000);
415#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
416 return click_current_processor() == _running_processor;
417#else
418 return true;
419#endif
420}
421
422inline bool
423RouterThread::current_thread_is_running_cleanup() const
424{
425 return current_thread_is_running() || (!_driver_entered && _id >= 0);
426}
427
428inline void
429RouterThread::schedule_block_tasks()
430{
431 assert(!current_thread_is_running());
432 ++_task_blocker_waiting;
433}
434
435inline void
436RouterThread::block_tasks(bool scheduled)
437{
438 assert(!current_thread_is_running() && !running_in_interrupt());
439 if (!scheduled)
440 ++_task_blocker_waiting;
441 while (1) {
442 uint32_t blocker = _task_blocker.value();
443 if ((int32_t) blocker >= 0
444#if ! CLICK_ATOMIC_COMPARE_SWAP
445 && _task_blocker.compare_and_swap(blocker, blocker + 1))
446#else
447 && _task_blocker.compare_swap(blocker, blocker + 1) == blocker)
448#endif
449 break;
450#if CLICK_LINUXMODULE
451 // 3.Nov.2008: Must allow other threads a chance to run. Otherwise,
452 // soft lock is possible: the thread in block_tasks() waits for
453 // RouterThread::_linux_task to complete a task set, but
454 // RouterThread::_linux_task can't run until the thread in
455 // block_tasks() relinquishes the CPU.
456 //
457 // We might be able to avoid schedule() in some cases, but don't
458 // bother to try.
459 schedule();
460#endif
461 }
462 --_task_blocker_waiting;
463}
464
465inline void
466RouterThread::unblock_tasks()
467{
468 assert((int32_t) _task_blocker.value() > 0);
469 --_task_blocker;
470}
471
472inline void
473RouterThread::lock_tasks()
474{
475 assert(!running_in_interrupt());
476 if (unlikely(!current_thread_is_running())) {
477 block_tasks(false);
478 _task_lock.acquire();
479 }
480}
481
482inline void
483RouterThread::unlock_tasks()
484{
485 assert(!running_in_interrupt());
486 if (unlikely(!current_thread_is_running())) {
487 _task_lock.release();
488 unblock_tasks();
489 }
490}
491
492inline void
493RouterThread::wake()
494{
495#if CLICK_LINUXMODULE
496 struct task_struct *task = _linux_task;
497 if (task)
498 wake_up_process(task);
499#elif CLICK_USERLEVEL
500 // see also Master::add_select()
501 if (!current_thread_is_running())
502 _selects.wake_immediate();
503#elif CLICK_BSDMODULE && !BSD_NETISRSCHED
504 if (_sleep_ident)
505 wakeup_one(&_sleep_ident);
506#endif
507}
508
509inline void
510RouterThread::add_pending()
511{
512 wake();
513}
514
515inline bool
516RouterThread::stop_flag() const
517{
518 return _stop_flag;
519}
520
521inline void
522RouterThread::set_thread_state(int state)
523{
524 (void) state;
525#if CLICK_DEBUG_SCHEDULING
526 assert(state >= 0 && state < NSTATES);
527# if CLICK_DEBUG_SCHEDULING > 1
529 if (_thread_state_timestamp)
530 _thread_state_time[_thread_state] += now - _thread_state_timestamp;
531 if (_thread_state != state)
532 ++_thread_state_count[_thread_state];
533 _thread_state_timestamp = now;
534# endif
535 _thread_state = state;
536#endif
537}
538
539inline void
540RouterThread::set_thread_state_for_blocking(int delay_type)
541{
542 if (delay_type < 0)
543 set_thread_state(S_BLOCKED);
544 else
545 set_thread_state(delay_type ? S_TIMERWAIT : S_PAUSED);
546}
547
548#if CLICK_DEBUG_SCHEDULING > 1
549inline Timestamp
550RouterThread::thread_state_time(int state) const
551{
552 assert(state >= 0 && state < NSTATES);
553 return _thread_state_time[state];
554}
555
556inline uint64_t
557RouterThread::thread_state_count(int state) const
558{
559 assert(state >= 0 && state < NSTATES);
560 return _thread_state_count[state];
561}
562#endif
563
564CLICK_ENDDECLS
565#endif
A router configuration.
Definition router.hh:28
A set of Tasks scheduled on the same CPU.
Definition routerthread.hh:32
Task * task_next(Task *task) const
Returns the task following task in the scheduled task list.
Definition routerthread.hh:364
Master * master() const
Returns this thread's associated Master.
Definition routerthread.hh:298
int thread_id() const
Returns this thread's ID.
Definition routerthread.hh:291
Task * task_begin() const
Returns the beginning of the scheduled task list.
Definition routerthread.hh:345
bool active() const
Returns whether any tasks are scheduled.
Definition routerthread.hh:311
Task * task_end() const
Returns the end of the scheduled task list.
Definition routerthread.hh:381
A recursive spinlock for SMP Click threads.
Definition sync.hh:439
A spinlock that disables interrupts.
Definition sync.hh:697
A string of characters.
Definition string.hh:22
Represents a frequently-scheduled computational task.
Definition task.hh:49
Represents a moment or interval in time.
Definition timestamp.hh:125
static Timestamp now()
Return the current system time.
Definition timestamp.hh:958
Vector template.
Definition vector.hh:111
T & unchecked_at(size_type i)
Return a reference to the ith element.
Definition vector.hh:350
size_type size() const
Return the number of elements.
Definition vector.hh:231
A 32-bit integer with support for atomic operations.
Definition atomic.hh:71
bool compare_and_swap(uint32_t expected, uint32_t desired) CLICK_BUILTINS_NONDEPRECATED
Perform a compare-and-swap operation.
Definition atomic.hh:734
Definition multithread.hh:284
Click's classes for supporting exponentially weighted moving averages.
Classes for synchronizing among multiple CPUs, particularly in the Linux kernel.
Click's vector container template.