summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2007-12-13 05:55:14 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2007-12-13 05:55:14 +0000
commitde974277871a13966b1dcf2d585d07a53e3c204f (patch)
treef47c498297fc61d6f4584595b48bf7b68fe85c97
parent6e41bba807f737eee6ca49985501c08e70c61372 (diff)
use a mutex to protect workq. incidentally, this removes the additional
creation of threads which may have caused multile syswq threads to start. ok dlg
-rw-r--r--sys/kern/kern_workq.c50
1 files changed, 23 insertions, 27 deletions
diff --git a/sys/kern/kern_workq.c b/sys/kern/kern_workq.c
index 258419194fc..226486b2616 100644
--- a/sys/kern/kern_workq.c
+++ b/sys/kern/kern_workq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_workq.c,v 1.5 2007/11/28 13:54:07 tedu Exp $ */
+/* $OpenBSD: kern_workq.c,v 1.6 2007/12/13 05:55:13 tedu Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -24,6 +24,7 @@
#include <sys/queue.h>
#include <sys/kthread.h>
#include <sys/workq.h>
+#include <sys/mutex.h>
struct workq_task {
int wqt_flags;
@@ -43,6 +44,7 @@ struct workq {
const char *wq_name;
SIMPLEQ_HEAD(, workq_task) wq_tasklist;
+ struct mutex wq_mtx;
};
struct pool workq_task_pool;
@@ -64,6 +66,7 @@ workq_init(void)
{
pool_init(&workq_task_pool, sizeof(struct workq_task), 0, 0,
0, "wqtasks", NULL);
+ pool_setipl(&workq_task_pool, IPL_HIGH);
SIMPLEQ_INIT(&workq_syswq.wq_tasklist);
kthread_create_deferred(workq_init_syswq, NULL);
@@ -94,6 +97,7 @@ workq_create(const char *name, int maxqs)
wq->wq_max = maxqs;
wq->wq_name = name;
SIMPLEQ_INIT(&wq->wq_tasklist);
+ mtx_init(&wq->wq_mtx, IPL_HIGH);
/* try to create a thread to guarantee that tasks will be serviced */
kthread_create_deferred(workq_create_thread, wq);
@@ -104,37 +108,32 @@ workq_create(const char *name, int maxqs)
void
workq_destroy(struct workq *wq)
{
- int s;
- s = splhigh();
+ mtx_enter(&wq->wq_mtx);
wq->wq_flags &= ~WQ_F_RUNNING;
while (wq->wq_running != 0) {
wakeup(wq);
- tsleep(&wq->wq_running, PWAIT, "wqdestroy", 0);
+ msleep(&wq->wq_running, &wq->wq_mtx, PWAIT, "wqdestroy", 0);
}
- splx(s);
+ mtx_leave(&wq->wq_mtx);
free(wq, M_DEVBUF);
}
int
-workq_add_task(struct workq *wq, int flags, workq_fn func,
- void *a1, void *a2)
+workq_add_task(struct workq *wq, int flags, workq_fn func, void *a1, void *a2)
{
struct workq_task *wqt;
int wake = 1;
- int s;
if (wq == NULL) {
wq = &workq_syswq;
}
- s = splhigh();
wqt = pool_get(&workq_task_pool, (flags & WQ_WAITOK) ?
PR_WAITOK : PR_NOWAIT);
- splx(s);
if (!wqt)
return (ENOMEM);
@@ -143,13 +142,9 @@ workq_add_task(struct workq *wq, int flags, workq_fn func,
wqt->wqt_arg1 = a1;
wqt->wqt_arg2 = a2;
- s = splhigh();
+ mtx_enter(&wq->wq_mtx);
SIMPLEQ_INSERT_TAIL(&wq->wq_tasklist, wqt, wqt_entry);
- if ((wq->wq_running < wq->wq_max) && (wq->wq_running == wq->wq_busy)) {
- kthread_create_deferred(workq_create_thread, wq);
- wake = 0;
- }
- splx(s);
+ mtx_leave(&wq->wq_mtx);
if (wake)
wakeup_one(wq);
@@ -177,30 +172,31 @@ workq_thread(void *arg)
{
struct workq *wq = arg;
struct workq_task *wqt;
- int s;
- s = splhigh();
+ KERNEL_PROC_UNLOCK(curproc);
+ mtx_enter(&wq->wq_mtx);
while (wq->wq_flags & WQ_F_RUNNING) {
while ((wqt = SIMPLEQ_FIRST(&wq->wq_tasklist)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&wq->wq_tasklist, wqt_entry);
wq->wq_busy++;
- splx(s);
+ mtx_leave(&wq->wq_mtx);
- if (wqt->wqt_flags & WQ_MPSAFE)
- ;
+ if ((wqt->wqt_flags & WQ_MPSAFE) == 0)
+ KERNEL_PROC_LOCK(curproc);
wqt->wqt_func(wqt->wqt_arg1, wqt->wqt_arg2);
- if (wqt->wqt_flags & WQ_MPSAFE)
- ;
+ if ((wqt->wqt_flags & WQ_MPSAFE) == 0)
+ KERNEL_PROC_UNLOCK(curproc);
+ pool_put(&workq_task_pool, wqt);
- s = splhigh();
+ mtx_enter(&wq->wq_mtx);
wq->wq_busy--;
- pool_put(&workq_task_pool, wqt);
}
- tsleep(wq, PWAIT, "bored", 0);
+ msleep(wq, &wq->wq_mtx, PWAIT, "bored", 0);
}
wq->wq_running--;
- splx(s);
+ mtx_leave(&wq->wq_mtx);
wakeup(&wq->wq_running);
+ KERNEL_PROC_LOCK(curproc);
kthread_exit(0);
}