Creating dedicated workqueues

Timing of the execution of work items scheduled onto the global workqueue is not predictable: one long-running work item can always cause indefinite delays for the rest. Alternatively, the workqueue framework allows the allocation of dedicated workqueues, which can be owned by a kernel subsystem or a service. Interface APIs used to create and schedule work into these queues provide control flags, through which owners can set special attributes such as CPU locality, concurrency limits, and priority, which have an influence on the execution of work items queued.

A new workqueue can be set up through a call to alloc_workqueue(); the following excerpt taken from <fs/nfs/inode.c> shows sample usage:

   struct workqueue_struct *wq;
   ...
   wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM, 0);

This call takes three arguments: the first is a string constant to name the workqueue. The second argument is the bitfield of flags, and the third an integer called max_active. The last two are used to specify control attributes of the queue. On success, this function returns the address of the workqueue descriptor.

The following is a list of flag options:

  • WQ_UNBOUND: Workqueues created with this flag are managed by kworker-pools that are not bound to any specific CPU. This causes all work items scheduled to this queue to run on any available processor. Work items in this queue are executed as soon as possible by kworker pools.
  • WQ_FREEZABLE: A workqueue of this type is freezable, which means that it is affected by system suspend operations. During suspend, all current work items are drained and no new work item can run until the system is unfreezed or resumed.
  • WQ_MEM_RECLAIM: This flag is used to mark a workqueue that contains work items involved in memory reclaim paths. This causes the framework to ensure that there is always a worker thread available to run work items on this queue.
  • WQ_HIGHPRI: This flag is used to mark a workqueue as high priority. Work items in high-priority workqueues have a higher precedence over normal ones, in that these are executed by a high-priority pool of kworker threads. The kernel maintains a dedicated pool of high-priority kworker threads for each CPU, which are distinct from normal kworker pools.
  • WQ_CPU_INTENSIVE: This flag marks work items on this workqueue to be CPU intensive. This helps the system scheduler to regulate the execution of work items that are expected to hog the CPU for long intervals. This means runnable CPU-intensive work items will not prevent other work items in the same kworker-pool from starting. A runnable non-CPU-intensive work item can always delay the execution of work items marked as CPU intensive. This flag is meaningless for an unbound wq.
  • WQ_POWER_EFFICIENT: Workqueues marked with this flag are per-CPU by default, but become unbound if the system was booted with the workqueue.power_efficient kernel param set. Per-CPU workqueues that are identified to contribute significantly to power consumption are identified and marked with this flag, and enabling the power_efficient mode leads to noticeable power savings at the cost of a slight performance penalty.

The final argument max_active is an integer, which must specify the count of work items that can be executed simultaneously from this workqueue on any given CPU.

Once a dedicated workqueue is set up, work items can be scheduled through any of the following calls:

bool queue_work(struct workqueue_struct *wq, struct work_struct *work);

wq is a pointer to a queue; it enqueues the specified work item on the local CPU, but does not guarantee execution on local processor. This call returns true if the given work item is successfully queued, and false if the given work item is already scheduled.

Alternatively, callers can enqueue a work item bound to a specific CPU with a call to:

bool queue_work_on(int cpu,struct workqueue_struct *wq,struct work_struct
*work);

Once a work item is enqueued into a workqueue of the specified cpu, it returns true if the given work item is successfully queued and false if the given work item is already found in the queue.

Similar to shared workqueue APIs, delayed scheduling options also are available for dedicated workqueues. The following calls are to be used for delayed scheduling of work items:

bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq, struct                                                                                                                                                        delayed_work *dwork,unsigned long delay);

bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay

Both calls delay scheduling of the given work until the timeout specified by the delay has elapsed, with the exception that queue_delayed_work_on() enqueues the given work item on the specified CPU and guarantees its execution on it. Note that if the delay specified is zero and the workqueue is idle, then the given work item is scheduled for immediate execution.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.144.197