(time units) - jiffies (1 jiffy = 1 "heartbeat") - "jiffies" is a global variable (delaying/sleeping) - ndelay, udelay, mdelay (busy waiting) - msleep, ssleep (sleeping) (deferred work methods) wait queues - declare wait queue - task 1 will wait on the wait queue (i.e. worker kernel thread) - task 2 will notify the wait queue to wake up (i.e. interrupt handler) - wait_event_timeout(waitqueue, time_in_jiffies) - HZ is defined to 1 second of jiffies - example of 5 seconds: wait_event_timeout(wq, 5 * HZ) - example of 0.01 seconds: wait_event_timeout(wq, HZ / 100) scheduling - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(time_in_jiffies); - give the cpu to someone else - I want the cpu back at time_in_jiffies (as a maximum) timers - add_timer, mod_timer, del_timer, timer_pending - specify a function callback and private data (with add_timer) - specify a delay when it should be called (with add_timer, specified in jiffies) - softirq context (this is atomic!) - run on whatever cpu called add_timer - in_softirq() - hrtimer: net/can/bcm.c:970 hrtimer_init / hrtimer_start / hrtimer_cancel - jiffie: drivers/pcmcia/soc_common.c:802 timer_setup / mod_timer / del_timer_sync - ndelay, udelay, mdelay (busy waiting) - msleep, ssleep (sleeping) tasklets - tasklets run atomically in a run-to-complete fashion, but HW interrupts are enabled! - tasklet_enable, tasklet_disable, tasklet_schedule, tasklet_kill - specify a function callback and private data (with tasklet creation) - runs on whatever cpu called tasklet_schedule - softirq context (this is atomic!) -> scheduled function isn't allowed to use sleep - serialized with itself - https://linux-kernel-labs.github.io/master/labs/deferred_work.html#tasklets - drivers/firewire/ohci.c:993 tasklet_init / tasklet_kill / tasklet_disable / tasklet_schedule workqueues - schedule a function to be executed in a different context - PREPARE_WORK, queue_work, queue_work_delayed (in jiffies), cancel_delayed_work, flush_workqueue - specify a function callback and private data (with PREPARE_WORK) - runs on whatever cpu called queue_work (unless WQ_UNBOUND is used, then runs on any cpu) - execution can be delayed (queue_work_delayed) - runs in a kernel thread - can use shared/system workqueues (you do not need to create your own) - serialized with itself - scheduled function can use sleep - Documentation/core-api/workqueue.rst - include/linux/workqueue.h - net/rfkill/core.c: INIT_WORK - schedule_work, cancel_work_sync INIT_DELAYED_WORK - queue_delayed_work, cancel_delayed_work_sync delayed* enables to specify delay while queuing schedule_ vs. queue_ : schedule_* uses a global queue, queue_* requires us to specify a specific queue threaded interrupt handlers - useful for handling interrupts in a non-atomic context completions - Documentation/scheduler/completion.txt - wait_for_completion() is not usable in atomic, preempt_disabled or irq_off situations, use try_wait_for_completion() there - fs/btrfs/qgroup.c:3288: init_completion / wait_for_completion / complete_all done in rescan_worker