summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2008-10-30 23:55:23 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2008-10-30 23:55:23 +0000
commitb8538b7800104ea39fddfc4d633fd94b9edfdedd (patch)
tree61d1c64ca28f9f04e6cbd27fb425697f9eb0d10d /sys/kern
parent9f5cf30a93400bfeddfa4ffab6084a13200fd88e (diff)
reintroduce mutexes to workqs for locking.
tested by many on many archs including several alpha test. ok tedu@ go for it deraadt@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_workq.c106
1 files changed, 61 insertions, 45 deletions
diff --git a/sys/kern/kern_workq.c b/sys/kern/kern_workq.c
index 8aec163d494..b4a62f68d4d 100644
--- a/sys/kern/kern_workq.c
+++ b/sys/kern/kern_workq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_workq.c,v 1.8 2008/10/27 02:13:34 dlg Exp $ */
+/* $OpenBSD: kern_workq.c,v 1.9 2008/10/30 23:55:22 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -22,6 +22,7 @@
#include <sys/malloc.h>
#include <sys/pool.h>
#include <sys/queue.h>
+#include <sys/mutex.h>
#include <sys/kthread.h>
#include <sys/workq.h>
@@ -38,10 +39,10 @@ struct workq {
int wq_flags;
#define WQ_F_RUNNING (1<<0)
int wq_running;
- int wq_busy;
int wq_max;
const char *wq_name;
+ struct mutex wq_mtx;
SIMPLEQ_HEAD(, workq_task) wq_tasklist;
};
@@ -49,22 +50,24 @@ struct pool workq_task_pool;
struct workq workq_syswq = {
WQ_F_RUNNING,
0,
- 0,
1,
"syswq"
};
-void workq_init(void); /* called in init_main.c */
-void workq_init_syswq(void *);
-void workq_create_thread(void *);
-void workq_thread(void *);
+void workq_init(void); /* called in init_main.c */
+void workq_init_syswq(void *);
+void workq_create_thread(void *);
+struct workq_task * workq_next_task(struct workq *);
+void workq_thread(void *);
void
workq_init(void)
{
pool_init(&workq_task_pool, sizeof(struct workq_task), 0, 0,
0, "wqtasks", NULL);
+ pool_setipl(&workq_task_pool, IPL_HIGH);
+ mtx_init(&workq_syswq.wq_mtx, IPL_HIGH);
SIMPLEQ_INIT(&workq_syswq.wq_tasklist);
kthread_create_deferred(workq_init_syswq, NULL);
}
@@ -72,15 +75,17 @@ workq_init(void)
void
workq_init_syswq(void *arg)
{
+ mtx_enter(&workq_syswq.wq_mtx);
if (kthread_create(workq_thread, &workq_syswq, NULL, "%s",
workq_syswq.wq_name) != 0)
panic("unable to create system work queue thread");
workq_syswq.wq_running++;
+ mtx_leave(&workq_syswq.wq_mtx);
}
struct workq *
-workq_create(const char *name, int maxqs)
+workq_create(const char *name, int maxqs, int ipl)
{
struct workq *wq;
@@ -90,9 +95,10 @@ workq_create(const char *name, int maxqs)
wq->wq_flags = WQ_F_RUNNING;
wq->wq_running = 0;
- wq->wq_busy = 0;
wq->wq_max = maxqs;
wq->wq_name = name;
+
+ mtx_init(&wq->wq_mtx, ipl);
SIMPLEQ_INIT(&wq->wq_tasklist);
/* try to create a thread to guarantee that tasks will be serviced */
@@ -104,17 +110,15 @@ 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);
}
@@ -123,16 +127,12 @@ int
workq_add_task(struct workq *wq, int flags, workq_fn func, void *a1, void *a2)
{
struct workq_task *wqt;
- int s;
- if (wq == NULL) {
+ 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);
@@ -141,9 +141,9 @@ workq_add_task(struct workq *wq, int flags, workq_fn func, void *a1, void *a2)
wqt->wqt_arg1 = a1;
wqt->wqt_arg2 = a2;
- s = splhigh();
+ mtx_enter(&wq->wq_mtx);
SIMPLEQ_INSERT_TAIL(&wq->wq_tasklist, wqt, wqt_entry);
- splx(s);
+ mtx_leave(&wq->wq_mtx);
wakeup_one(wq);
@@ -154,43 +154,59 @@ void
workq_create_thread(void *arg)
{
struct workq *wq = arg;
+ int i;
int rv;
- rv = kthread_create(workq_thread, wq, NULL, "%s", wq->wq_name);
- if (rv != 0) {
- printf("unable to create \"%s\" workq thread\n", wq->wq_name);
- return;
+ mtx_enter(&wq->wq_mtx);
+ for (i = wq->wq_running; i < wq->wq_max; i++) {
+ rv = kthread_create(workq_thread, wq, NULL, "%s", wq->wq_name);
+ if (rv != 0) {
+ printf("unable to create thread for \"%s\" workq\n",
+ wq->wq_name);
+ break;
+ }
+ wq->wq_running++;
}
-
- wq->wq_running++;
+ mtx_leave(&wq->wq_mtx);
}
-void
-workq_thread(void *arg)
+
+struct workq_task *
+workq_next_task(struct workq *wq)
{
- struct workq *wq = arg;
struct workq_task *wqt;
- int s;
- s = splhigh();
- while (wq->wq_flags & WQ_F_RUNNING) {
- while ((wqt = SIMPLEQ_FIRST(&wq->wq_tasklist)) != NULL) {
+ mtx_enter(&wq->wq_mtx);
+
+ for (;;) {
+ wqt = SIMPLEQ_FIRST(&wq->wq_tasklist);
+ if (wqt != NULL) {
SIMPLEQ_REMOVE_HEAD(&wq->wq_tasklist, wqt_entry);
- wq->wq_busy++;
- splx(s);
+ break;
+ } else if (wq->wq_flags & WQ_F_RUNNING)
+ msleep(wq, &wq->wq_mtx, PWAIT, "bored", 0);
+ else {
+ if (--wq->wq_running == 0);
+ wakeup_one(&wq->wq_running);
+ break;
+ }
+ }
- wqt->wqt_func(wqt->wqt_arg1, wqt->wqt_arg2);
+ mtx_leave(&wq->wq_mtx);
- s = splhigh();
- pool_put(&workq_task_pool, wqt);
+ return (wqt);
+}
- wq->wq_busy--;
- }
- tsleep(wq, PWAIT, "bored", 0);
+void
+workq_thread(void *arg)
+{
+ struct workq *wq = arg;
+ struct workq_task *wqt;
+
+ while ((wqt = workq_next_task(wq)) != NULL) {
+ wqt->wqt_func(wqt->wqt_arg1, wqt->wqt_arg2);
+ pool_put(&workq_task_pool, wqt);
}
- wq->wq_running--;
- splx(s);
- wakeup(&wq->wq_running);
kthread_exit(0);
}