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