Linux Kernel Tutorials - Workqueues

In last chapter we discussed about tasklets and softirqs. In this chapter we will discuss one other type of bottom half work queues which is little different from tasklets and softirqs.

Work queues are different from of differing work from what we have discussed till now. work queues use kernel thread to handle the deferred work. This bottom half runs in process context. It means you can have all the advantages of process context. Which means work queues can be scheduled and sleep.

Because of this specialty of work queues we can easily choose between work queses and tasklets/softirqs. If your work needs to sleep then only way left is to defer the work by using work queues . But if your work need not to sleep then better to go for tasklets/softirq.

If your work required to allocate large amount of memory, obtaining a semaphore or performing some block i/o operations then work queues is the only way to defer your work.

Implementing Work queues

As we discussed work queues use kernel thread to handle the deferred work. work queues provide an interface for creating a kernel thread and defer your work on that thread. Work queues subsystem also provide some default kernel thread which is called worker thread . You can use these kernel thread to defer your work instead of creating new kernel thread for each work. work queue provide one default worker thread per processor . worker thread is named as events/n where n is the serial number of thread.

for example If your system has only one processor then you will have events/0 as worker thread. But if your system is dual processor you will have events/0 and events/1 as worker threads.

You always have option to create a new kernel thread dedicated exclusively to serve your work. but if your work doesn’t have some special need for new kernel thread then usage of default kernel thread is recommended. If your work needs large amount of processing then better to go for new thread.

data structure for worker thread

workqueue_struct structure is used to represent worker thread .

struct workqueue_struct {

struct cpu_workqueue_struct cpu_wq[NR_CPUS];

struct list_head list;

const char *name;

int singlethread;

int freezeable;

int rt;

};

This structure defined in kernel/workqueue.c which contains an array of cpu_workqueue_struct , one per processor.

cpu_workqueue_struct is also defined in kernel/workqueue.c

.

Data Structure for work

worker threads are just like normal kernel thread which runs worker_thread() function. After initial setup this function enters into infinite loop and goes to sleep. when there is new addition of work on the queue , thread is awakened and work is processed.

struct work_struct {

atomic_long_t data;

struct list_head entry;

work_func_t func;

#ifdef CONFIG_LOCKDEP

struct lockdep_map lockdep_map;

#endif

};

above structure is used to represent work. which is defined in <linux/workqueue.h>

one link list of these work is maintained for their respective worker thread .

Using work queues

First we will be using default worker thread for deferring our work

First step is to create the work . We can create a work statically as well as dynamically

creating a work statically

DECLARE_WORK(name, void (*func)(void *), void *data);

creating a work at run time

DECLARE_WORK(name, void (*func)(void *), void *data);

Work queue handler

Work queue handler is a function which will be executed whenever worker thread will get chance for execution. Below is the prototype for the work queue handler

void work_handler(void *data)

worker thread executes this function to process the defer work.

Scheduling work

after creating the work we can schedule it . If you want to schedule it on default worker thread then you can simply use

schedule_work(&work);

this work will run as soon as worker thread on current processor get chance to run.

You can also put some delay in execution of work by using

schedule_delay_work(&work,delay)

Flushing work

you can flush a given workqueue by using

void flush_scheduled_work(void);

If your work has certain requirement of creating own workqueue then you can create it by using below function

struct workqueue_struct *create_workqueue(const char *name);

you can schedule your work on new workqueue by using below function

int queue_work(struct workqueue_struct *wq, struct work_struct *work)

 

adana elektrikci

', 'auto'); ga('send', 'pageview');