Deferred Work
August 5, 2022 ยท View on GitHub
Reference: https://linux-kernel-labs.github.io/refs/heads/master/labs/deferred_work.html
- Deferred work is a class of kernel facilities that allow to schedule code to be executed at a later timer
- Summarizing we have two categories:
- Running in interrupt context, also known as bottom-half (BH): Softirqs, Tasklets, Timers
- Running in process context: Workqueues, Kernel Threads. Kernel Threads are not strictly speaking deferred work in themselves, but are used to complement deferred work mechanisms
- When running in interrupt context we have the following restrictions:
- Can't transfer data from or to user space (they don't execute in the context of a process)
- Can't sleep (e.g., call
wait_event, allocate memory withoutGFP_ATOMIC, acquire semaphores or mutexes, etc.) - Can't call
schedule
Types of deferred work
Softirqs
- Can't be used by device drivers, reserved for various kernel subsystems
- They run in interrupt context, so they can't call blocking functions
Tasklets
- They run in interrupt context, so they can't call blocking functions
- Are used to schedule some action to be executed later, but can't be used to schedule at a specific time
Timers
- They run in interrupt context, so they can't call blocking functions
- Used to schedule a function to execute a specific time
- Unit of time is jiffies
Workqueues
- Used to schedule actions to run in process context
- Can be either scheduled at a specific time, or not (
work_structvsdelayed_work)
Kernel Threads
- Basically a thread that runs only in kernel mode, and has no user address space or other user attributes
- Used to run kernel code in process context
- Used with work queues
- They are not technically deferred work
Synchronization
- When synchronizing code running in process context and interrupt context, we need to use special locking primitives:
- In interrupt context, we can use the usual spinlock operations (
spin_lock,spin_unlock) - In process context, we have to disable bottom-half handlers in the current processor besides acquiring a lock. This can be done with
spin_lock_bhandspin_unlock_bh
- In interrupt context, we can use the usual spinlock operations (
- This is necessary to avoid creating a deadlock if we acquire a lock in process context, but then a BH handler that also has to acquire the lock is scheduled in the same CPU (for example, because a timer fires, etc.)