Commit 3820421b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ISDN kernelcapi notifier workqueue re-structured

From: Armin Schindler <armin@melware.de>

Use the notifier workqueue in a cleaner way.
parent 9bab8e3c
/* $Id: kcapi.c,v 1.1.2.5 2004/03/15 12:32:31 armin Exp $ /* $Id: kcapi.c,v 1.1.2.6 2004/03/16 08:00:08 armin Exp $
* *
* Kernel CAPI 2.0 Module * Kernel CAPI 2.0 Module
* *
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <linux/b1lli.h> #include <linux/b1lli.h>
#endif #endif
static char *revision = "$Revision: 1.1.2.5 $"; static char *revision = "$Revision: 1.1.2.6 $";
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
...@@ -45,7 +45,7 @@ MODULE_PARM(showcapimsgs, "i"); ...@@ -45,7 +45,7 @@ MODULE_PARM(showcapimsgs, "i");
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
struct capi_notifier { struct capi_notifier {
struct capi_notifier *next; struct work_struct work;
unsigned int cmd; unsigned int cmd;
u32 controller; u32 controller;
u16 applid; u16 applid;
...@@ -69,7 +69,6 @@ struct capi_ctr *capi_cards[CAPI_MAXCONTR]; ...@@ -69,7 +69,6 @@ struct capi_ctr *capi_cards[CAPI_MAXCONTR];
static int ncards; static int ncards;
static struct sk_buff_head recv_queue; static struct sk_buff_head recv_queue;
static struct work_struct tq_state_notify;
static struct work_struct tq_recv_notify; static struct work_struct tq_recv_notify;
/* -------- controller ref counting -------------------------------------- */ /* -------- controller ref counting -------------------------------------- */
...@@ -161,79 +160,6 @@ static void release_appl(struct capi_ctr *card, u16 applid) ...@@ -161,79 +160,6 @@ static void release_appl(struct capi_ctr *card, u16 applid)
capi_ctr_put(card); capi_ctr_put(card);
} }
/* -------- Notifier handling --------------------------------- */
static struct capi_notifier_list{
struct capi_notifier *head;
struct capi_notifier *tail;
} notifier_list;
static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;
static inline void notify_enqueue(struct capi_notifier *np)
{
struct capi_notifier_list *q = &notifier_list;
unsigned long flags;
spin_lock_irqsave(&notifier_lock, flags);
if (q->tail) {
q->tail->next = np;
q->tail = np;
} else {
q->head = q->tail = np;
}
spin_unlock_irqrestore(&notifier_lock, flags);
}
static inline struct capi_notifier *notify_dequeue(void)
{
struct capi_notifier_list *q = &notifier_list;
struct capi_notifier *np = 0;
unsigned long flags;
spin_lock_irqsave(&notifier_lock, flags);
if (q->head) {
np = q->head;
if ((q->head = np->next) == 0)
q->tail = 0;
np->next = 0;
}
spin_unlock_irqrestore(&notifier_lock, flags);
return np;
}
static int notify_push(unsigned int cmd, u32 controller,
u16 applid, u32 ncci)
{
struct capi_notifier *np;
if (!try_module_get(THIS_MODULE)) {
printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__);
return -1;
}
np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
if (!np) {
module_put(THIS_MODULE);
return -1;
}
memset(np, 0, sizeof(struct capi_notifier));
np->cmd = cmd;
np->controller = controller;
np->applid = applid;
np->ncci = ncci;
notify_enqueue(np);
/*
* The notifier will result in adding/deleteing
* of devices. Devices can only removed in
* user process, not in bh.
*/
__module_get(THIS_MODULE);
if (schedule_work(&tq_state_notify) == 0)
module_put(THIS_MODULE);
return 0;
}
/* -------- KCI_CONTRUP --------------------------------------- */ /* -------- KCI_CONTRUP --------------------------------------- */
static void notify_up(u32 contr) static void notify_up(u32 contr)
...@@ -271,31 +197,43 @@ static void notify_down(u32 contr) ...@@ -271,31 +197,43 @@ static void notify_down(u32 contr)
} }
} }
/* ------------------------------------------------------------ */ static void notify_handler(void *data)
static inline void notify_doit(struct capi_notifier *np)
{ {
struct capi_notifier *np = data;
switch (np->cmd) { switch (np->cmd) {
case KCI_CONTRUP: case KCI_CONTRUP:
notify_up(np->controller); notify_up(np->controller);
break; break;
case KCI_CONTRDOWN: case KCI_CONTRDOWN:
notify_down(np->controller); notify_down(np->controller);
break; break;
} }
kfree(np);
} }
static void notify_handler(void *dummy) /*
* The notifier will result in adding/deleteing of devices. Devices can
* only removed in user process, not in bh.
*/
static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
{ {
struct capi_notifier *np; struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
while ((np = notify_dequeue()) != 0) { if (!np)
notify_doit(np); return -ENOMEM;
kfree(np);
module_put(THIS_MODULE); INIT_WORK(&np->work, notify_handler, np);
} np->cmd = cmd;
module_put(THIS_MODULE); np->controller = controller;
np->applid = applid;
np->ncci = ncci;
schedule_work(&np->work);
return 0;
} }
/* -------- Receiver ------------------------------------------ */ /* -------- Receiver ------------------------------------------ */
...@@ -989,7 +927,6 @@ static int __init kcapi_init(void) ...@@ -989,7 +927,6 @@ static int __init kcapi_init(void)
skb_queue_head_init(&recv_queue); skb_queue_head_init(&recv_queue);
INIT_WORK(&tq_state_notify, notify_handler, NULL);
INIT_WORK(&tq_recv_notify, recv_handler, NULL); INIT_WORK(&tq_recv_notify, recv_handler, NULL);
kcapi_proc_init(); kcapi_proc_init();
...@@ -1009,6 +946,9 @@ static int __init kcapi_init(void) ...@@ -1009,6 +946,9 @@ static int __init kcapi_init(void)
static void __exit kcapi_exit(void) static void __exit kcapi_exit(void)
{ {
kcapi_proc_exit(); kcapi_proc_exit();
/* make sure all notifiers are finished */
flush_scheduled_work();
} }
module_init(kcapi_init); module_init(kcapi_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment