schedule_work and speedtch.c

Roman Kagan rkagan at mail.ru
Thu Apr 21 03:16:46 EDT 2005


On Sun, Apr 17, 2005 at 11:38:10PM +0400, Roman Kagan wrote:
> On Sun, Apr 17, 2005 at 08:15:25PM +0200, Duncan Sands wrote:
> > Also, with workqueues, we lose the possibility
> > of quickly quitting heavy_init on disconnect by sending a signal...
> 
> Yes this is an important point I've missed.  I need to think it over...

Here's an updated version, which restores this possibility.  It's ugly
though.  So I'm not sure if we should go for it...

Cheers,
  Roman.

 usbatm.h |   10 ++++---
 usbatm.c |   81 ++++++++++++++++++++++++++++-----------------------------------
 2 files changed, 43 insertions(+), 48 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	21 Apr 2005 07:11:09 -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,8 @@ struct usbatm_data {
 	struct semaphore serialize;
 
 	/* heavy init */
-	int thread_pid;
-	struct completion thread_started;
-	struct completion thread_exited;
+	pid_t thread_pid;
+	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	21 Apr 2005 07:11:09 -0000
@@ -999,44 +999,20 @@ static int usbatm_atm_init(struct usbatm
 **  USB  **
 **********/
 
-static int usbatm_do_heavy_init(void *arg)
+static void usbatm_prepare_workq(void *arg)
 {
 	struct usbatm_data *instance = arg;
-	int ret;
 
-	daemonize(instance->driver->driver_name);
+	instance->thread_pid = current->pid;
 	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)
+static void usbatm_heavy_init(void *arg)
 {
-	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);
+	struct usbatm_data *instance = arg;
 
-	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,
@@ -1045,6 +1021,7 @@ int usbatm_usb_probe (struct usb_interfa
 	struct device *dev = &intf->dev;
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	struct usbatm_data *instance;
+	struct work_struct prepare_workq;
 	char *buf;
 	int error = -ENOMEM;
 	int i, length;
@@ -1076,6 +1053,22 @@ int usbatm_usb_probe (struct usb_interfa
 	instance->tx_padding = driver->tx_padding;
 	instance->rx_padding = driver->rx_padding;
 
+	instance->workq = create_singlethread_workqueue(instance->driver_name);
+	if (!instance->workq) {
+		dev_dbg(dev, "%s: failed to create workqueue!\n", __func__);
+		error = -ENOMEM;
+		goto fail_free;
+	}
+
+	INIT_WORK(&prepare_workq, usbatm_prepare_workq, instance);
+	error = queue_work(instance->workq, &prepare_workq);
+	if (error < 0) {
+		dev_dbg(dev, "%s: failed to prepare workqueue!\n", __func__);
+		error = -ENOMEM;
+		goto fail_destroywq;
+	}
+	flush_workqueue(instance->workq);
+
 	buf = instance->description;
 	length = sizeof(instance->description);
 
@@ -1100,8 +1093,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 +1102,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 +1176,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 +1192,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 +1230,10 @@ void usbatm_usb_disconnect(struct usb_in
 
 	usb_set_intfdata(intf, NULL);
 
-	down(&instance->serialize);
-	if (instance->thread_pid >= 0)
+	if (instance->thread_pid > 0)		/* interrupt the workqueue if it sleeps */ 
 		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 +1281,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