schedule_work and speedtch.c
Roman Kagan
rkagan at mail.ru
Sun Apr 17 12:56:08 EDT 2005
On Sat, Apr 16, 2005 at 11:57:19PM +0400, Roman Kagan wrote:
> On Sat, Apr 16, 2005 at 09:30:08PM +0200, Duncan Sands wrote:
> > In that case, maybe we could use the workqueue for heavy_init too.
>
> I like this idea. It'll make handling of heavy_init even easier.
OK so how about the patch below? It changes the heavy_init stuff to use
a workqueue. The subdrivers can also use it for status polling, it's a
matter of replacing schedule_work() by queue_work() and
flush_scheduled_work() by flash_workqueue().
Cheers,
Roman.
usbatm.h | 9 ++++---
usbatm.c | 74 +++++++++++++++++++--------------------------------------------
2 files changed, 28 insertions(+), 55 deletions(-)
Index: usbatm.h
===================================================================
RCS file: /home/cvs/usbatm/usbatm.h,v
retrieving revision 1.13
diff -u -p -r1.13 usbatm.h
--- usbatm.h 14 Apr 2005 10:20:26 -0000 1.13
+++ usbatm.h 17 Apr 2005 16:52:03 -0000
@@ -38,11 +38,11 @@
#include <asm/semaphore.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
-#include <linux/completion.h>
#include <linux/device.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/usb.h>
+#include <linux/workqueue.h>
#ifdef DEBUG
#define UDSL_ASSERT(x) BUG_ON(!(x))
@@ -197,6 +197,9 @@ struct usbatm_data {
/* ATM device */
struct atm_dev *atm_dev;
+ /* workqueue for deferred tasks: heavy_init, status poll, etc. */
+ struct workqueue_struct *workq;
+
/********************************
* private fields - do not use *
********************************/
@@ -205,9 +208,7 @@ struct usbatm_data {
struct semaphore serialize;
/* heavy init */
- int thread_pid;
- struct completion thread_started;
- struct completion thread_exited;
+ struct work_struct heavy_init_work;
/* ATM device */
struct list_head vcc_list;
Index: usbatm.c
===================================================================
RCS file: /home/cvs/usbatm/usbatm.c,v
retrieving revision 1.19
diff -u -p -r1.19 usbatm.c
--- usbatm.c 15 Apr 2005 08:49:51 -0000 1.19
+++ usbatm.c 17 Apr 2005 16:52:04 -0000
@@ -999,44 +999,12 @@ static int usbatm_atm_init(struct usbatm
** USB **
**********/
-static int usbatm_do_heavy_init(void *arg)
+static void usbatm_heavy_init(void *arg)
{
struct usbatm_data *instance = arg;
- int ret;
- daemonize(instance->driver->driver_name);
- allow_signal(SIGTERM);
-
- complete(&instance->thread_started);
-
- ret = instance->driver->heavy_init(instance, instance->usb_intf);
-
- if (!ret)
- ret = usbatm_atm_init(instance);
-
- down(&instance->serialize);
- instance->thread_pid = -1;
- up(&instance->serialize);
-
- complete_and_exit(&instance->thread_exited, ret);
-}
-
-static int usbatm_heavy_init(struct usbatm_data *instance)
-{
- int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
-
- if (ret < 0) {
- usb_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
- return ret;
- }
-
- down(&instance->serialize);
- instance->thread_pid = ret;
- up(&instance->serialize);
-
- wait_for_completion(&instance->thread_started);
-
- return 0;
+ if (!instance->driver->heavy_init(instance, instance->usb_intf))
+ usbatm_atm_init(instance);
}
int usbatm_usb_probe (struct usb_interface *intf, const struct usb_device_id *id,
@@ -1076,6 +1044,13 @@ int usbatm_usb_probe (struct usb_interfa
instance->tx_padding = driver->tx_padding;
instance->rx_padding = driver->rx_padding;
+ instance->workq = create_workqueue(instance->driver_name);
+ if (!instance->workq) {
+ dev_dbg(dev, "%s: failed to create workqueue!\n", __func__);
+ error = -ENOMEM;
+ goto fail_free;
+ }
+
buf = instance->description;
length = sizeof(instance->description);
@@ -1100,8 +1075,8 @@ int usbatm_usb_probe (struct usb_interfa
bind:
need_heavy = 1;
if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) {
- dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error);
- goto fail_free;
+ dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error);
+ goto fail_destroywq;
}
/* private fields */
@@ -1109,9 +1084,7 @@ int usbatm_usb_probe (struct usb_interfa
kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */
init_MUTEX(&instance->serialize);
- instance->thread_pid = -1;
- init_completion(&instance->thread_started);
- init_completion(&instance->thread_exited);
+ INIT_WORK(&instance->heavy_init_work, usbatm_heavy_init, instance);
INIT_LIST_HEAD(&instance->vcc_list);
@@ -1185,12 +1158,10 @@ int usbatm_usb_probe (struct usb_interfa
list_add(&buf->list, &instance->spare_send_buffers);
}
- if (need_heavy && driver->heavy_init) {
- error = usbatm_heavy_init(instance);
- } else {
- complete(&instance->thread_exited); /* pretend that heavy_init was run */
+ if (need_heavy && driver->heavy_init)
+ error = queue_work(instance->workq, &instance->heavy_init_work);
+ else
error = usbatm_atm_init(instance);
- }
if (error < 0)
goto fail_unbind;
@@ -1203,6 +1174,10 @@ int usbatm_usb_probe (struct usb_interfa
fail_unbind:
if (instance->driver->unbind)
instance->driver->unbind(instance, intf);
+
+ fail_destroywq:
+ destroy_workqueue(instance->workq);
+
fail_free:
for (i = 0; i < num_snd_bufs; i++)
kfree(instance->send_buffers[i].base);
@@ -1237,12 +1212,7 @@ void usbatm_usb_disconnect(struct usb_in
usb_set_intfdata(intf, NULL);
- down(&instance->serialize);
- if (instance->thread_pid >= 0)
- kill_proc(instance->thread_pid, SIGTERM, 1);
- up(&instance->serialize);
-
- wait_for_completion(&instance->thread_exited);
+ flush_workqueue(instance->workq); /* flush wq but preserve it for driver->unbind */
tasklet_disable(&instance->receive_tasklet);
tasklet_disable(&instance->send_tasklet);
@@ -1290,6 +1260,8 @@ void usbatm_usb_disconnect(struct usb_in
for (i = 0; i < num_snd_bufs; i++)
kfree(instance->send_buffers[i].base);
+ destroy_workqueue(instance->workq);
+
/* ATM finalize */
if (instance->atm_dev)
shutdown_atm_dev(instance->atm_dev);
More information about the Usbatm
mailing list