Click
Loading...
Searching...
No Matches
task.hh
Go to the documentation of this file.
1// -*- c-basic-offset: 4; related-file-name: "../../lib/task.cc" -*-
2#ifndef CLICK_TASK_HH
3#define CLICK_TASK_HH
4#include <click/element.hh>
5#include <click/sync.hh>
6#if HAVE_MULTITHREAD
7# include <click/atomic.hh>
8# include <click/ewma.hh>
9#endif
10CLICK_DECLS
11
12#if CLICK_BSDMODULE
13# include <click/cxxprotect.h>
14CLICK_CXX_PROTECT
15# include <sys/lock.h>
16# include <sys/mutex.h>
17CLICK_CXX_UNPROTECT
18# include <click/cxxunprotect.h>
19#else
20#define GIANT_REQUIRED
21#endif
22
23#define PASS_GT(a, b) ((int)(a - b) > 0)
24
25typedef bool (*TaskCallback)(Task *, void *);
26typedef TaskCallback TaskHook CLICK_DEPRECATED;
27class RouterThread;
28class TaskList;
29class Master;
30
31struct TaskLink {
32#if !HAVE_TASK_HEAP
33 TaskLink *_prev;
34 TaskLink *_next;
35#endif
36#if HAVE_STRIDE_SCHED
37 unsigned _pass;
38#endif
39 TaskLink() {
40#if !HAVE_TASK_HEAP
41 _prev = _next = 0;
42#endif
43#if HAVE_STRIDE_SCHED
44 _pass = 0;
45#endif
46 }
47};
48
49class Task : private TaskLink { public:
50
51#if HAVE_STRIDE_SCHED
52 enum { STRIDE1 = 1U<<16, MAX_STRIDE = 1U<<31 };
53 enum { MAX_TICKETS = 1<<15, DEFAULT_TICKETS = 1<<10 };
54#endif
55#if HAVE_ADAPTIVE_SCHEDULER
56 enum { MAX_UTILIZATION = 1000 };
57#endif
58
75 inline Task(TaskCallback f, void *user_data, int tid = -2);
76
86 inline Task(Element *e);
87
91 ~Task();
92
93
98 inline TaskCallback callback() const {
99 return _hook;
100 }
101
103 inline void *user_data() const {
104 return _thunk;
105 }
106
108 inline Element *element() const {
109 return _owner;
110 }
111
112
114 inline bool initialized() const;
115
123 inline int home_thread_id() const;
124
132 inline RouterThread *thread() const;
133
135 inline Router *router() const {
136 return _owner->router();
137 }
138
140 Master *master() const;
141
142
159 void initialize(Element *owner, bool schedule);
160
169 void initialize(Router *router, bool schedule);
170
171
179 inline bool scheduled() const {
180 return _status.is_scheduled;
181 }
182
183
190 inline void unschedule() {
191 _status.is_scheduled = false;
192 }
193
197 void unschedule_notify(Element* e);
198
206 inline void reschedule() {
207 _status.is_scheduled = true;
208 click_fence();
209 if (_pending_nextptr.x < 2)
210 complete_schedule(0);
211 }
212
216 void reschedule_notify(Element* e);
217
248 inline void fast_reschedule() {
249 _status.is_scheduled = true;
250 }
251
252
260 inline void strong_unschedule() {
261 _status.is_scheduled = false;
262 _status.is_strong_unscheduled = true;
263 }
264
271 inline void strong_reschedule() {
272 _status.is_strong_unscheduled = false;
273 reschedule();
274 }
275
276
285 void move_thread(int new_thread_id);
286
287
288#if HAVE_STRIDE_SCHED
289 inline int tickets() const;
290 inline void set_tickets(int n);
291 inline void adjust_tickets(int delta);
292#endif
293
294 inline bool fire();
295
296#if HAVE_ADAPTIVE_SCHEDULER
297 inline unsigned runs() const;
298 inline unsigned work_done() const;
299 inline unsigned utilization() const;
300 inline void clear_runs();
301#endif
302#if HAVE_TASK_STATS
303 inline int cycles() const;
304 inline unsigned cycle_runs() const;
305 inline void update_cycles(unsigned c);
306#endif
307
309 inline TaskCallback hook() const CLICK_DEPRECATED;
310 inline void *thunk() const CLICK_DEPRECATED;
313 private:
314
315#if HAVE_TASK_HEAP
316 int _schedpos;
317#endif
318
319#if HAVE_STRIDE_SCHED
320 unsigned _stride;
321 int _tickets;
322#endif
323
324 union Status {
325 struct {
326 int16_t home_thread_id;
327 uint8_t is_scheduled;
328 uint8_t is_strong_unscheduled;
329 };
330 uint32_t status;
331 } _status;
332
333 TaskCallback _hook;
334 void *_thunk;
335
336#if HAVE_ADAPTIVE_SCHEDULER
337 unsigned _runs;
338 unsigned _work_done;
339#endif
340#if HAVE_TASK_STATS
341 DirectEWMA _cycles;
342 unsigned _cycle_runs;
343#endif
344
345 RouterThread *_thread;
346
347 Element *_owner;
348
349 union Pending {
350 Task *t;
351 uintptr_t x;
352 };
353 Pending _pending_nextptr;
354
355 Task(const Task &x);
356 Task &operator=(const Task &x);
357 void cleanup();
358
359#if CLICK_DEBUG_SCHEDULING
360 public:
361#endif
362 inline bool on_scheduled_list() const;
363 inline bool on_pending_list() const {
364 return _pending_nextptr.x != 0;
365 }
366 inline bool needs_cleanup() const;
367#if CLICK_DEBUG_SCHEDULING
368 private:
369#endif
370
371 void add_pending(bool always);
372 void process_pending(RouterThread* thread);
373
374 void complete_schedule(RouterThread* process_pending_thread);
375 inline void remove_from_scheduled_list();
376
377 static bool error_hook(Task *task, void *user_data);
378
379 friend class RouterThread;
380 friend class Master;
381};
382
383
384// need RouterThread's definition for inline functions
385CLICK_ENDDECLS
386#include <click/routerthread.hh>
387CLICK_DECLS
388
389
390inline
391Task::Task(TaskCallback f, void *user_data, int tid)
392 :
393#if HAVE_TASK_HEAP
394 _schedpos(-1),
395#endif
396#if HAVE_STRIDE_SCHED
397 _stride(0), _tickets(-1),
398#endif
399 _hook(f), _thunk(user_data),
400#if HAVE_ADAPTIVE_SCHEDULER
401 _runs(0), _work_done(0),
402#endif
403#if HAVE_TASK_STATS
404 _cycle_runs(0),
405#endif
406 _thread(0), _owner(0)
407{
408 _status.home_thread_id = tid;
409 _status.is_scheduled = _status.is_strong_unscheduled = false;
410 _pending_nextptr.x = 0;
411}
412
413inline
415 :
416#if HAVE_TASK_HEAP
417 _schedpos(-1),
418#endif
419#if HAVE_STRIDE_SCHED
420 _stride(0), _tickets(-1),
421#endif
422 _hook(0), _thunk(e),
423#if HAVE_ADAPTIVE_SCHEDULER
424 _runs(0), _work_done(0),
425#endif
426#if HAVE_TASK_STATS
427 _cycle_runs(0),
428#endif
429 _thread(0), _owner(0)
430{
431 _status.home_thread_id = -2;
432 _status.is_scheduled = _status.is_strong_unscheduled = false;
433 _pending_nextptr.x = 0;
434}
435
436inline bool
438{
439 return _owner != 0;
440}
441
442inline bool
443Task::on_scheduled_list() const
444{
445#if HAVE_TASK_HEAP
446 return _schedpos >= 0;
447#else
448 return _prev != 0;
449#endif
450}
451
452inline bool
453Task::needs_cleanup() const
454{
455#if HAVE_TASK_HEAP
456 int a;
457 uintptr_t b;
458 do {
459 a = _schedpos;
460 b = _pending_nextptr.x;
461 click_fence();
462 } while (a != _schedpos || b != _pending_nextptr.x);
463 return a >= 0 || b != 0;
464#else
465 TaskLink* a;
466 uintptr_t b;
467 do {
468 a = _prev;
469 b = _pending_nextptr.x;
470 click_fence();
471 } while (a != _prev || b != _pending_nextptr.x);
472 return a != 0 || b != 0;
473#endif
474}
475
479inline TaskCallback
480Task::hook() const
481{
482 return _hook;
483}
484
487inline void *
488Task::thunk() const
489{
490 return _thunk;
491}
494inline int
496{
497 return _status.home_thread_id;
498}
499
500inline RouterThread *
502{
503 return _thread;
504}
505
506inline void
507Task::remove_from_scheduled_list()
508{
509 if (on_scheduled_list()) {
510#if HAVE_TASK_HEAP
511 Task *back = _thread->_task_heap.back().t;
512 _thread->_task_heap.pop_back();
513 if (_thread->_task_heap.size() > 0)
514 _thread->task_reheapify_from(_schedpos, back);
515 click_fence();
516 _schedpos = -1;
517#else
518 _next->_prev = _prev;
519 _prev->_next = _next;
520 _next = 0;
521 click_fence();
522 _prev = 0;
523#endif
524 }
525}
526
527#if HAVE_STRIDE_SCHED
528
536inline int
538{
539 return _tickets;
540}
541
549inline void
551{
552 if (n > MAX_TICKETS)
553 n = MAX_TICKETS;
554 else if (n < 1)
555 n = 1;
556 _tickets = n;
557 _stride = STRIDE1 / n;
558 assert(_stride < MAX_STRIDE);
559}
560
568inline void
570{
571 set_tickets(_tickets + delta);
572}
573
574#endif /* HAVE_STRIDE_SCHED */
575
576
582inline bool
584{
585#if CLICK_STATS >= 2
586 click_cycles_t start_cycles = click_get_cycles(),
587 start_child_cycles = _owner->_child_cycles;
588#endif
589#if HAVE_TASK_STATS
590 _cycle_runs++;
591#endif
592 bool work_done;
593 if (!_hook)
594 work_done = ((Element*)_thunk)->run_task(this);
595 else
596 work_done = _hook(this, _thunk);
597#if HAVE_ADAPTIVE_SCHEDULER
598 ++_runs;
599 _work_done += work_done;
600#endif
601#if CLICK_STATS >= 2
602 click_cycles_t all_delta = click_get_cycles() - start_cycles,
603 own_delta = all_delta - (_owner->_child_cycles - start_child_cycles);
604 _owner->_task_calls += 1;
605 _owner->_task_own_cycles += own_delta;
606#endif
607 return work_done;
608}
609
610#if HAVE_ADAPTIVE_SCHEDULER
611inline unsigned
612Task::runs() const
613{
614 return _runs;
615}
616
617inline unsigned
618Task::work_done() const
619{
620 return _work_done;
621}
622
623inline unsigned
624Task::utilization() const
625{
626 return (_runs ? (MAX_UTILIZATION * _work_done) / _runs : 0);
627}
628
629inline void
630Task::clear_runs()
631{
632 _runs = _work_done = 0;
633}
634#endif
635
636#if HAVE_TASK_STATS
637inline int
638Task::cycles() const
639{
640 return _cycles.unscaled_average();
641}
642
643inline unsigned
644Task::cycle_runs() const
645{
646 return _cycle_runs;
647}
648
649inline void
650Task::update_cycles(unsigned c)
651{
652 _cycles.update(c);
653 _cycle_runs = 0;
654}
655#endif
656
657CLICK_ENDDECLS
658#endif
An atomic 32-bit integer.
Base class for Click elements.
Definition element.hh:42
virtual bool run_task(Task *task)
Run the element's task.
Definition element.cc:3267
Router * router() const
Return the element's router.
Definition element.hh:515
A router configuration.
Definition router.hh:28
A set of Tasks scheduled on the same CPU.
Definition routerthread.hh:32
Represents a frequently-scheduled computational task.
Definition task.hh:49
int home_thread_id() const
Return the task's home thread ID.
Definition task.hh:495
void unschedule_notify(Element *e)
Unschedule the task, sending a notification.
Definition task.cc:147
void set_tickets(int n)
Set the task's ticket count.
Definition task.hh:550
void adjust_tickets(int delta)
Add delta to the Task's ticket count.
Definition task.hh:569
Master * master() const
Return the master where this task will be scheduled.
Definition task.cc:133
void move_thread(int new_thread_id)
Move the Task to a new home thread.
Definition task.cc:379
bool fire()
Fire the task by calling its callback function.
Definition task.hh:583
void reschedule()
Reschedule the task.
Definition task.hh:206
~Task()
Destroy a task.
Definition task.cc:126
bool scheduled() const
Return true iff the task is currently scheduled to run.
Definition task.hh:179
void strong_reschedule()
Reschedule the Task, undoing a prior strong_unschedule().
Definition task.hh:271
Element * element() const
Return the task's owning element.
Definition task.hh:108
bool initialized() const
Return true iff the task has been initialize()d.
Definition task.hh:437
void reschedule_notify(Element *e)
Reschedule the task, sending thread migration messages.
Definition task.cc:140
void * user_data() const
Return the task callback function's user data.
Definition task.hh:103
int tickets() const
Return the task's number of tickets.
Definition task.hh:537
Task(TaskCallback f, void *user_data, int tid=-2)
Construct a task that calls f with user_data argument.
Definition task.hh:391
void initialize(Element *owner, bool schedule)
Initialize the Task, and optionally schedule it.
Definition task.cc:283
void strong_unschedule()
Unschedule the Task until strong_reschedule().
Definition task.hh:260
RouterThread * thread() const
Return the thread on which this task is currently scheduled, or would be scheduled.
Definition task.hh:501
void unschedule()
Unschedule the task.
Definition task.hh:190
TaskCallback callback() const
Return the task's callback function.
Definition task.hh:98
void fast_reschedule()
Reschedule a task from the task's callback function.
Definition task.hh:248
Router * router() const
Return the router to which this task belongs.
Definition task.hh:135
Click's Element class.
Click's classes for supporting exponentially weighted moving averages.
DirectEWMAX< FixedEWMAXParameters< 4, 10 > > DirectEWMA
A DirectEWMAX with stability shift 4 (alpha 1/16), scaling factor 10 (10 bits of fraction),...
Definition ewma.hh:265
The RouterThread class implementing the Click driver loop.
Classes for synchronizing among multiple CPUs, particularly in the Linux kernel.