Work Queues

Work queues are a further means of deferring actions until later. Because they are executed in the user context by means of daemons, the functions can sleep as long as they like — it does not matter at all to the kernel. During the development of 2.5, work queues were designed as a replacement for the keventd mechanism formerly used.

Each work queue has an array with as many entries as there are processors in the system. Each entry lists tasks to be performed at a later time.

For each work queue, the kernel generates a new kernel daemon in whose context the deferred tasks are performed using the wait queue mechanism just described.

A new wait queue is generated by invoking one of the functions create_workqueue or create_workqueue_singlethread. While the first one creates a worker thread on all CPUs, the latter one just creates a single thread on the first CPU of the system. Both functions use_create_workqueue_key internally19:

kernel/workqueue.c struct workqueue_struct *_create_workqueue(const char *name, int singlethread)

The name argument indicates the name under which the generated daemon is shown in the process list. If singlethread is set to 0, a thread is created on every CPU of the system, otherwise just on the first one.

All tasks pushed onto wait queues must be packed into instances of the work_struct structure in which the following elements are important in the view of the work queue user:


struct work_struct;

typedef void (*work_func_t)(struct work_struct *work);

struct work_struct {

atomic_long_t data; struct list_head entry; work_func_t func;

entry is used as usual to group several work_struct instances in a linked list. func is a pointer to the function to be deferred. It is supplied with a pointer to the instance of work_struct that was used to submit the work. This allows the worker function to obtain the data element that can point to arbitrary data associated with the work_struct.

19Another variant, create_freezable_workqueue, is available to create work queues that are friendly toward system hibernation. Since I do not discuss any mechanisms related to power management, I will also not discuss this alternative any further. Also note that the prototype of __create_workqueue is simplified and does not contain parameters related to lock depth management and power management.

Why does the kernel use atomic_long_t as the data type for a pointer to some arbitrary data, and not void * as usual? In fact, former kernel versions defined work_struct as follows:

Continue reading here: Info

Was this article helpful?

0 0