Документ взят из кэша поисковой машины. Адрес оригинального документа : http://mavr.sao.ru/hq/sts/linux/doc/porting_to_26/23634.html
Дата изменения: Unknown
Дата индексирования: Fri Dec 28 19:25:53 2007
Кодировка:

Поисковые слова: universe
LWN: Driver porting: the workqueue interface.
LWN.net Logo

 


 
Recent Features

LWN.net Weekly Edition for March 18, 2004

LWN.net Weekly Edition for March 11, 2004

The annotated SCO stock price chart

A grumpy editor's calendar search

LWN.net Weekly Edition for March 4, 2004

Printable page
 

 

Driver porting: the workqueue interface.

This article is part of the LWN Porting Drivers to 2.6 series.
The longstanding task queue interface was removed in 2.5.41; in its place is a new "workqueue" mechanism. Workqueues are very similar to task queues, but there are some important differences. Among other things, each workqueue has one or more dedicated worker threads (one per CPU) associated with it. So all tasks running out of workqueues have a process context, and can thus sleep. Note that access to user space is not possible from code running out of a workqueue; there simply is no user space to access. Drivers can create their own work queues - with their own worker threads - but there is a default queue (for each processor) provided by the kernel that will work in most situations.

Workqueues are created with create_workqueue:

    struct workqueue_struct *create_workqueue(const char *name);
The name of the queue is limited to ten characters; it is only used for generating the "command" for the kernel thread (which can be seen in ps or top).

Tasks to be run out of a workqueue need to be packaged in a struct work_struct structure. This structure may be declared and initialized at compile time as follows:

    DECLARE_WORK(name, void (*function)(void *), void *data);
Here, name is the name of the resulting work_struct structure, function is the function to call to execute the work, and data is a pointer to pass to that function.

To set up a work_struct structure at run time, instead, use the following two macros:

    INIT_WORK(struct work_struct *work, 
              void (*function)(void *), void *data);
    PREPARE_WORK(struct work_struct *work, 
                 void (*function)(void *), void *data);
The difference between the two is that INIT_WORK initializes the linked list pointers within the work_struct structure, while PREPARE_WORK changes only the function and data pointers. INIT_WORK must be used at least once before queueing the work_struct structure, but should not be used if the work_struct might already be in a workqueue.

Actually queueing a job to be executed is simple:

    int queue_work(struct workqueue_struct *queue, 
                   struct work_struct *work);
    int queue_delayed_work(struct workqueue_struct *queue, 
	                   struct work_struct *work,
                           unsigned long delay);
The second form of the call ensures that a minimum delay (in jiffies) passes before the work is actually executed. The return value from both functions is nonzero if the work_struct was actually added to queue (otherwise, it may have already been there and will not be added a second time).

Entries in workqueues are executed at some undefined time in the future, when the associated worker thread is scheduled to run (and after the delay period, if any, has passed). If it is necessary to cancel a delayed task, you can do so with:

    int cancel_delayed_work(struct work_struct *work);
Note that this workqueue entry could actually be executing when cancel_delayed_work() returns; all this function will do is keep it from starting after the call.

To ensure that none of your workqueue entries are running, call:

    void flush_workqueue(struct workqueue_struct *queue);
This would be a good thing to do, for example, in a device driver shutdown routine. Note that if the queue contains work with long delays this call could take a long time to complete. This function will not (as of 2.5.68) wait for any work entries submitted after the call was first made; you should ensure that, for example, any outstanding work queue entries will not resubmit themselves. You should also cancel any delayed entries (with cancel_delayed_work()) first if need be.

Work queues can be destroyed with:

    void destroy_workqueue(struct workqueue_struct *queue);
This operation will flush the queue, then delete it.

Finally, for tasks that do not justify their own workqueue, a "default" work queue (called "events") is defined. work_struct structures can be added to this queue with:

    int schedule_work(struct work_struct *work);
    int schedule_delayed_work(struct work_struct *work, unsigned long delay);
Most users of workqueues can probably use the predefined queue, but one should bear in mind that it is a shared resource. Long delays in the worker function will slow down other users of the queue, and should be avoided. There is a flush_scheduled_work() function which will wait for everything on this queue to be executed. If your module uses the default queue, it should almost certainly call flush_scheduled_work() before allowing itself to be unloaded.

One final note: schedule_work(), schedule_delayed_work() and flush_scheduled_work() are exported to any modules which wish to use them. The other functions (for working with separate workqueues) are exported to GPL-licensed modules only.


Post a comment

  Driver porting: the workqueue interface.
(Posted Jun 17, 2003 21:45 UTC (Tue) by btl) (Post reply)

I'm trying to playing with workqueues... i've trouble on compiling
a little kernel module.

What include files do i need beside linux/workqueue.h?

I can't find where struct workqueue_struct is defined ;(

  Driver porting: the workqueue interface.
(Posted Dec 9, 2003 19:17 UTC (Tue) by bighead) (Post reply)

Its work_struct, not workqueue_struct (if I get what you are asking).

Second you might need the usual, linux/init.h, linux/module.h etc header files. Take a look at http://www.xml.com/ldd/chapter/book/. The book is mainly 2.4 based. You can then see http://lwn.net/Articles/driver-porting/ for differences in 2.4 and 2.6.

Cheers!
Archit

Copyright (©) 2003, Eklektix, Inc.
Linux (®) is a registered trademark of Linus Torvalds
Powered by Rackspace Managed Hosting.