Deferrable functions in linux is a mechanism to delay the execution of any piece of code later in the kernel context. Can be implemented using Tasklet and work queues
3. Deferrable function
• Mechanism for supporting the delayed execution of any function in
Interrupt handlers (Interrupt context)
• Interrupt Context
– Kernel enters Interrupt context when hardware interrupt received
– Kernel enters Process/Kernel context from Interrupt context after
servicing the hardware interrupt
– Execution of tasks in Interrupt context should be minimized
• Why - Majority of Interrupts are disabled, therefore latency to handle other
interrupts will be increased
• Solution: Move execution of not urgent function (piece of code) into process
context (Deferrable function)
• Add deferrable functions in Interrupt Handlers
• Deferrable functions: can be executed in process context
– Tasklet
– Work queues
12/6/2013
Raj Kumar Rampelli
3
4. Top Half Vs Bottom Half
Top Half
Bottom Half
Processing of tasks in Interrupt Handler
(Interrupt context)
Processing of tasks in Kernel context
Interrupts are disabled
Interrupts are not disabled
Add Deferrable functions for delayed
execution
Handles Deferrable functions
Processing time should be less
-NA-
Uses Tasklets and work queue APIs for deferrable mechanism
12/6/2013
Raj Kumar Rampelli
4
5. Tasklet: To schedule the work (function) to run later point of time
so that reducing the amount of work done in interrupt handlers.
Tasklet Initialization APIs
Usage
void tasklet_function (unsigned
long data);
Deferrable function i.e. actual Task
DECLARE_TASKLET
(tasklet_name,
tasklet_function, tasklet_data);
• Initializes the tasklet structure (tasklet_struct)
with passing argument list
• Tasklets are enabled by default
• Next step: Schedule the task
DECLARE_TASKLET_DISABLED
(tasklet_name,
tasklet_function, tasklet_data);
• Initializes the tasklet structure
• Tasklets are disabled
• Next step: Enable Tasklet before schedule the
task
void tasklet_init(struct
tasklet_struct *, void (*func)
(unsigned long), unsigned long
data);
• Initializes the tasklet structure (tasklet_struct)
with passing argument list
12/6/2013
Raj Kumar Rampelli
5
6. Tasklet (contd.)
Tasklet Enable/Disable APIs
Usage
void tasklet_enable (struct tasklet_struct *);
/* Enable normal priority scheduling */
void tasklet_disable (struct tasklet_struct *);
/* returns after disabling the tasklet */
void tasklet_hi_enable (struct tasklet_struct *); /* Enabling High priority scheduling */
void tasklet_disable_nosync (struct
tasklet_struct *);
12/6/2013
/* May returns before termination i.e.
no synchronization with disabling of
tasklet */
Raj Kumar Rampelli
6
7. Tasklet (contd.)
Tasklet Schedule APIs
Usage
void tasklet_schedule (struct tasklet_struct *);
/* Normal priority scheduling */
void tasklet_hi_schedule (struct tasklet_struct *);
/* Higher priority scheduling */
CPU maintains the normal and high priority softirq vectors lists (normal priority vector
list and high priority vector list) where these functions are queued.
If the function is higher priority function then it is en-queued in higher priority softirq
vector list and similar case for normal priority functions.
Kill a Tasklet
Usage
void tasklet_kill (struct tasklet_struct *);
/* Kill a tasklet */
void tasklet_hi_kill (struct tasklet_struct *);
/* Kill the tasklet and ensure they
would never run */
12/6/2013
Raj Kumar Rampelli
7
8. Work queue
• Added in linux kernel 2.6 version
• Use two data structures
– struct workqueue_struct
• Work is queued here in Interrupt context
• The same work is executed in Kernel context
– struct work_struct
• Identifies the work and deferrable function
• Kernel threads named "events/X" will extract work from the core work
queue and activates the work's handler function.
Tasklet
Added in linux kernel 2.3
version
In 2.6 kernel version
Sleep in Handler function
Not possible
12/6/2013
Work queue
Possible.
Latency is less
Raj Kumar Rampelli
More compared to Tasklet
8
9. Work queue APIs
Create and destroy work queue structure
Usage
struct workqueue_struct
*create_workqueue(name);
/* Creates core workqueue */
void destroy_workqueue(struct
workqueue_struct *);
/* Destroy the workqueue */
Initialization of work structure
Usage
INIT_WORK(work, function);
/* Initializes the work structure with
function handler */
INIT_DELAYED_WORK(work, function);
/* Add any delay before adding this work
INIT_DELAYED_WORK_DEFERRABLE(work, into work queue structure */
function);
12/6/2013
Raj Kumar Rampelli
9
10. Work queue APIs (contd.)
•
Add work on to work queue
– int queue_work (struct workqueue_struct *wq, struct work_struct *work);
– /* specify the CPU on which the handler should run */
int queue_work_on (int cpu, struct workqueue_struct *wq, struct work_struct *work);
– /* Queue specified work on to specified work queue after delay */
int queue_delayed_work (struct workqueue_struct *wq, struct delayed_work *work, unsigned
long delay);
– int queue_delayed_work_on (int cpu, struct workqueue_struct *wq, struct delayed_work
*work), unsigned long delay);
•
The below functions doesn't require workqueue structure defined. Since, they
uses kernel-global work queue. So, no need to pass workqueue_struct in the
argument list.
–
–
–
–
12/6/2013
int schedule_work (struct work_struct *):
int schedule_work_on (int cpu, struct work_struct *):
int scheduled_delayed_work (struct delayed_work *, unsigned long delay);
int scheduled_delayed_work_on (int cpu, struct delayed_work *, unsigned long delay);
Raj Kumar Rampelli
10
11. Work queue APIs (contd.)
• Cancel work
/* terminate work in the queue, which is not already executing in the handler */
int cancel_work_sync (struct work_struct *);
int cancel_delayed_work_sync (struct delayed_work *);
• Flush work
Below functions are used to flush the work and works in the specified workqueue.
/* Flush a particular work and block until it is completed */
int flush_work (struct work_struct *);
/* Flush all works in given workqueue and block until it is completed */
int flush_workqueue (struct workqueue_struct *);
/* Flush kernel-global work queue */
void flush_scheduled_work (void);
• Status of work
We can use below two functions to know whether the given work is pending i.e. its handler function is
not yet started.
work_pending(work);
delayed_work_pending (work);
12/6/2013
Raj Kumar Rampelli
11
12. Conclusion
• Reduce the execution time in Interrupt context by using deferrable
function mechanism
• Top Half: Processing of tasks in Interrupt Handler (Interrupt
context)
• Bottom Half: Processing of tasks in Kernel/Process context
• Two type of deferrable functions
– Tasklet
– Work queue
• Aim: To schedule the work/function (not urgent piece of code) in
interrupt handler to run later point of time (in bottom half) so that
reducing the amount of work done in interrupt handlers.
• Tasklet and Work queue both do the above task using their own set
of APIs
• For more details visit: www.practicepeople.blogspot.com
12/6/2013
Raj Kumar Rampelli
12