Linux Bottom Halves:-
There are 3 types of bottom halves
1. Soft IRQ
2. Task let
3. Work queues
A set of 32 statically defined bottom halves that can run simultaneously on any processor. Even 2 of the same type can run concurrently. These are used when performance critical and must be registered statically at compile time.
Soft IRQ are restricted for statically built kernel services. i.e services implemented as kernel modules can not use soft IRQs, only the driver built along with kernel only can use soft IRQs.
Step-1: Declare Soft IRQ.
modify Soft IRQ enum in kernel source "include/linux/interrupt.h"
MY_SOFTIRQ, ----> Your soft IRQ also to be added like this
Step-2: Implement the soft IRQ function and register the function
register the above function using "open_softirq(softirq name/id,function)"
Step-3: Schedule the Soft IRQ for execution using "raise_softirq(softirq name/id)"
Soft IRQ Scheduling:
Soft IRQ may execute under any of the following context
1. In the context of "do_irq( )" after termination of ISR routine with interrupt lines enabled and process scheduler disabled.
2. In the context of "spin_unlock_bh( )"
3. Soft IRQs may also run in the context of dedicated per CPU kernel thread "ksoftirqd"
Kernel imposes a restriction on the usage of Soft IRQ since they are concurrent and may cause latency problems if used by all drivers. The restriction is maximum of 32 Soft IRQs are allowed. As the Soft IRQs are concurrent, kernel will maintain a counter. If this counter reaches 20, the kernel thread "ksoftirqd" will terminate the process of executing Soft IRQs and enables the process scheduler as process/CPU scheduler will be disabled when Soft IRQs executes.
Tasklets are interrupt context bottom halves that are executed serially. The tasklets are extension to SoftIRQ framework.
Step-1: Create an instance of "tasklet_struct" and initialize with an address of bottom half routione.
name: tasklet_struct instance; function: bottom half function; data: arguments to bottom half function
void taskletfunc(unsigned long data);
Same as DECLARE_TASKLET but it creates the tasklet in disabled state, if we want to use we need to enable it and schedule it.
void tasklet_disable(struct tasklet_struct *t);
void tasklet_enable(struct tasklet_struct *t);
Step-2: Schedule tasklet
void tasklet_schedule(struct tasklet_struct *t); ----> normal priority
void tasklet_hi_schedule(struct tasklet_struct *t); ------> high priority
Tasklet execution policy:
1. Once scheduled , a tasklet is guaranteed to execute once after that
2. An already scheduled but not yet executed tasklet can be re-scheduled but will be executed only once
3. Once a tasklet starts running, it can be re-scheduled to run again later
4. Tasklets never be concurrent
5. Different tasklets can run simultaneously on different CPUs
work queues are process context bottom halves executed by kernel threads when system is idle.
Step-1: Create an instance of type "struct work" and assign it with address of bottom half routine
DECLARE_WORK(struct work *wq,(work_func_t)wq_func);
wq_func ----> bottom half function
Step-2: Schedule work queue using "schedule_work" routine
->Kernel thread called "events" executes pending work objects.
->As it runs in process context (events) it can have any code. As it can be pre-empted if other process wants CPU time.
-> "CPU scheduler is not disabled while work queues execution