summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2019-06-23 12:56:11 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2019-06-23 12:56:11 +0000
commitae7cad33495c99a6d11a82c999947dc9e3df78f7 (patch)
treef89c810fbe80b96621e01c05a2ad0d90cf713850 /sys/kern
parent5a7996f8224a39f7cbcce2755f46572678dea144 (diff)
Make taskq_barrier(9) work for multi-threaded task queues.
ok visa@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_task.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/sys/kern/kern_task.c b/sys/kern/kern_task.c
index 74f3ea4ab18..c553caca8ec 100644
--- a/sys/kern/kern_task.c
+++ b/sys/kern/kern_task.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_task.c,v 1.25 2019/04/28 04:20:40 dlg Exp $ */
+/* $OpenBSD: kern_task.c,v 1.26 2019/06/23 12:56:10 kettenis Exp $ */
/*
* Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
@@ -43,6 +43,7 @@ struct taskq {
TQ_S_DESTROYED
} tq_state;
unsigned int tq_running;
+ unsigned int tq_waiting;
unsigned int tq_nthreads;
unsigned int tq_flags;
const char *tq_name;
@@ -59,6 +60,7 @@ static const char taskq_sys_name[] = "systq";
struct taskq taskq_sys = {
TQ_S_CREATED,
0,
+ 0,
1,
0,
taskq_sys_name,
@@ -77,6 +79,7 @@ static const char taskq_sys_mp_name[] = "systqmp";
struct taskq taskq_sys_mp = {
TQ_S_CREATED,
0,
+ 0,
1,
TASKQ_MPSAFE,
taskq_sys_mp_name,
@@ -122,6 +125,7 @@ taskq_create(const char *name, unsigned int nthreads, int ipl,
tq->tq_state = TQ_S_CREATED;
tq->tq_running = 0;
+ tq->tq_waiting = 0;
tq->tq_nthreads = nthreads;
tq->tq_name = name;
tq->tq_flags = flags;
@@ -223,6 +227,7 @@ taskq_barrier(struct taskq *tq)
WITNESS_CHECKORDER(&tq->tq_lock_object, LOP_NEWORDER, NULL);
+ SET(t.t_flags, TASK_BARRIER);
task_add(tq, &t);
cond_wait(&c, "tqbar");
}
@@ -238,6 +243,7 @@ taskq_del_barrier(struct taskq *tq, struct task *del)
if (task_del(tq, del))
return;
+ SET(t.t_flags, TASK_BARRIER);
task_add(tq, &t);
cond_wait(&c, "tqbar");
}
@@ -304,13 +310,30 @@ taskq_next_work(struct taskq *tq, struct task *work)
struct task *next;
mtx_enter(&tq->tq_mtx);
+retry:
while ((next = TAILQ_FIRST(&tq->tq_worklist)) == NULL) {
if (tq->tq_state != TQ_S_RUNNING) {
mtx_leave(&tq->tq_mtx);
return (0);
}
+ tq->tq_waiting++;
msleep(tq, &tq->tq_mtx, PWAIT, "bored", 0);
+ tq->tq_waiting--;
+ }
+
+ if (ISSET(next->t_flags, TASK_BARRIER)) {
+ /*
+ * Make sure all other threads are sleeping before we
+ * proceed and run the barrier task.
+ */
+ if (++tq->tq_waiting == tq->tq_nthreads) {
+ tq->tq_waiting--;
+ } else {
+ msleep(tq, &tq->tq_mtx, PWAIT, "tqblk", 0);
+ tq->tq_waiting--;
+ goto retry;
+ }
}
TAILQ_REMOVE(&tq->tq_worklist, next, t_entry);