LWN.net Logo

Advertisement

f-irc: away with the old irc-client paradigms! The graphical-interface feeling in a terminal. Give it a try!

Advertise here

Some 2.6.12 API changes

The workqueue interface allows kernel code to request that a function be called at a later time, in process context. It can thus be used to arrange for work which cannot be performed immediately, perhaps because the current thread is running in an atomic mode. It is also possible to queue delayed work requests which are guaranteed not to run for a caller-requested delay period.

Sometimes the need arises to cancel tasks which have been queued to a workqueue in a delayed mode. The function which performs this task is:

    int cancel_delayed_work(struct work_struct *work);

This function attempts to intercept the given work before it runs and remove it from the queue. If it is successful, it returns a nonzero value. If, instead, cancel_delayed_work() returns zero, it means that the delayed work request was fired off before the call; it might, in fact, be running on another CPU when the cancel attempt is made. The caller usually needs to know that the work function is not running, so the standard procedure is to call flush_workqueue(), which waits until all tasks currently in the queue are run. After flush_workqueue() returns, the work function is guaranteed not to be running anywhere in the system.

There is one remaining obnoxious detail, however: what if the work function resubmits itself to the workqueue while it is running? In this case, that function could run again when the rest of the kernel least expects it - possibly after the module which contains that function has been removed from the kernel. That is the sort of race condition which gives kernel developers cold sweats. In general, this problem can be avoided by creating a "do not resubmit yourself" flag which is set before calling cancel_delayed_work(), but not all programmers make that effort.

In an attempt to make safe cancellation easier, Arjan van de Ven has added a new function to the workqueue API:

    void cancel_rearming_delayed_work(struct work_struct *work);

The implementation is straightforward; at its core, this function does the following:

	while (!cancel_delayed_work(work))
		flush_workqueue(wq);

In other words, it simply keeps trying until it is able to catch the work request when it is not executing, and, thus, cannot resubmit itself. This approach works because it applies to delayed work - there has to be some time when the work request is sitting in the timer queue waiting to run. Sooner or later, the kernel is sure to catch it during that time and keep it from running again.

The new function has been merged for 2.6.12.

Meanwhile, there are two functions which are used by drivers to send messages to USB peripherals:

    int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
                     void *data, int len, int *actual_length,
                     int timeout);

    int usb_control_msg(struct usb_device *dev, unsigned int pipe,
                        __u8 request, __u8 requesttype,
                        __u16 value, __u16 index,
                        void *data, __u16 size, int timeout);

In 2.6.11 and prior kernels, the timeout value is expressed in jiffies; for 2.6.12, the units of that parameter has been changed to milliseconds. Dozens of patches were merged to bring in-tree drivers up to the new version of the interface, but out-of-tree drivers will need to be changed explicitly. The situation is complicated a bit by the fact that the prototype of the function did not change, so the compiler will not flag callers which have not been updated.

Finally, David Howells has changed the rwsem implementation to use interrupt-disabling spinlocks. This change should be transparent to most callers. Anybody who calls down_read() or down_write() with interrupts already disabled will be in for a surprise, however. There should be no such callers, since those functions can sleep, but one never knows...


(Log in to post comments)

Copyright © 2005, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds