diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2007-12-13 05:55:14 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2007-12-13 05:55:14 +0000 |
commit | de974277871a13966b1dcf2d585d07a53e3c204f (patch) | |
tree | f47c498297fc61d6f4584595b48bf7b68fe85c97 | |
parent | 6e41bba807f737eee6ca49985501c08e70c61372 (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.c | 50 |
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); } |