Bottom Halves and Deferring Work
Bottom Halves
The job of bottom halves is to perform any interrupt-related work not performed by the interrupt handler. In an ideal world, this is nearly all the work because you want the
interrupt handler to perform as little work (and in turn be as fast) as possible. By offloading as much work as possible to the bottom half, the interrupt handler can return control of the system to whatever it interrupted as quickly as possible.
A World of Bottom Halves
The Original “Bottom Half” --> Task Queues --> Softirqs and Tasklets
Softirqs
Softirqs are a set of statically defined bottom halves that can run simultaneously on any processor; even two of the same type can run concurrently.Tasklets, which have an awful and confusing name,2 are flexible, dynamically created bottom halves built on top of softirqs.Two different tasklets can run concurrently on different processors, but two of the same type of tasklet cannot run simultaneously.Thus, tasklets are a good trade-off between performance and ease of use.
Tasklets
Tasklets are a bottom-half mechanism built on top of softirqs.As mentioned, they have nothing to do with tasks.Tasklets are similar in nature and behavior to softirqs; however, they have a simpler interface and relaxed locking rules.
ksoftirqd
Softirq (and thus tasklet) processing is aided by a set of per-processor kernel threads.These kernel threads help in the processing of softirqs when the system is overwhelmed with softirqs.
The first solution is simply to keep processing softirqs as they come in and to recheck and reprocess any pending softirqs before returning.
The second solution is not to handle reactivated softirqs. On return from interrupt, the kernel merely looks at all pending softirqs and executes them as normal.
In designing softirqs, the kernel developers realized that some sort of compromise was needed.The solution ultimately implemented in the kernel is to not immediately process
reactivated softirqs. Instead, if the number of softirqs grows excessive, the kernel wakes up a family of kernel threads to handle the load.The kernel threads run with the lowest possible priority (nice value of 19), which ensures they do not run in lieu of anything important.
Work Queues
Work queues are a different form of deferring work from what we have looked at so far. Work queues defer work into a kernel thread—this bottom half always runs in process context.Thus, code deferred to a work queue has all the usual benefits of process context. Most important, work queues are schedulable and can therefore sleep.
Each worker thread is represented by the cpu_workqueue_struct structure.The workqueue_struct structure represents all the worker threads of a given type.
Which Bottom Half Should I Use?
In short, normal driver writers have two choices. First, do you need a schedulable entity to perform your deferred work—fundamentally, do you need to sleep for any reason? Then work queues are your only option. Otherwise, tasklets are preferred. Only if scalability becomes a concern do you investigate softirqs.
Locking Between the Bottom Halves