diff --git a/sys/kern/subr_workqueue.c b/sys/kern/subr_workqueue.c index df68ee2934b0..4ddcd8d0c178 100644 --- a/sys/kern/subr_workqueue.c +++ b/sys/kern/subr_workqueue.c @@ -1,4 +1,4 @@ -/* $NetBSD: subr_workqueue.c,v 1.4 2006/09/16 11:14:36 yamt Exp $ */ +/* $NetBSD: subr_workqueue.c,v 1.5 2006/09/16 11:15:00 yamt Exp $ */ /*- * Copyright (c)2002, 2005 YAMAMOTO Takashi, @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: subr_workqueue.c,v 1.4 2006/09/16 11:14:36 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_workqueue.c,v 1.5 2006/09/16 11:15:00 yamt Exp $"); #include #include @@ -165,6 +165,56 @@ workqueue_initqueue(struct workqueue *wq) return error; } +struct workqueue_exitargs { + struct work wqe_wk; + struct workqueue_queue *wqe_q; +}; + +static void +workqueue_exit(struct work *wk, void *arg) +{ + struct workqueue_exitargs *wqe = (void *)wk; + struct workqueue_queue *q = wqe->wqe_q; + + /* + * no need to raise ipl because only competition at this point + * is workqueue_finiqueue. + */ + + KASSERT(q->q_worker == curproc); + simple_lock(&q->q_lock); + q->q_worker = NULL; + simple_unlock(&q->q_lock); + wakeup(q); + kthread_exit(0); +} + +static void +workqueue_finiqueue(struct workqueue *wq) +{ + struct workqueue_queue *q = &wq->wq_queue; + struct workqueue_exitargs wqe; + + wq->wq_func = workqueue_exit; + + wqe.wqe_q = q; + KASSERT(SIMPLEQ_EMPTY(&q->q_queue)); + KASSERT(q->q_worker != NULL); + workqueue_lock(wq, q); + SIMPLEQ_INSERT_TAIL(&q->q_queue, &wqe.wqe_wk, wk_entry); + wakeup(q); + while (q->q_worker != NULL) { + int error; + + error = ltsleep(q, wq->wq_prio, "wqfini", 0, &q->q_lock); + if (error) { + panic("%s: %s error=%d", + __func__, wq->wq_name, error); + } + } + workqueue_unlock(wq, q); +} + /* --- */ int @@ -192,6 +242,14 @@ workqueue_create(struct workqueue **wqp, const char *name, return 0; } +void +workqueue_destroy(struct workqueue *wq) +{ + + workqueue_finiqueue(wq); + kmem_free(wq, sizeof(*wq)); +} + void workqueue_enqueue(struct workqueue *wq, struct work *wk) { diff --git a/sys/sys/workqueue.h b/sys/sys/workqueue.h index c7097d4ed3e3..0dc627a11742 100644 --- a/sys/sys/workqueue.h +++ b/sys/sys/workqueue.h @@ -1,4 +1,4 @@ -/* $NetBSD: workqueue.h,v 1.2 2005/12/03 17:10:46 christos Exp $ */ +/* $NetBSD: workqueue.h,v 1.3 2006/09/16 11:15:00 yamt Exp $ */ /*- * Copyright (c)2002, 2005 YAMAMOTO Takashi, @@ -47,6 +47,7 @@ struct workqueue; int workqueue_create(struct workqueue **, const char *, void (*)(struct work *, void *), void *, int, int, int); +void workqueue_destroy(struct workqueue *); void workqueue_enqueue(struct workqueue *, struct work *);