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