diff options
author | scottl <scottl@FreeBSD.org> | 2006-01-14 01:55:24 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2006-01-14 01:55:24 +0000 |
commit | 645eb22044ffa13d5de0294dc16c9c7aefa7c5b0 (patch) | |
tree | f5229c8522204692d0896701c0159d45163983de /sys/kern/subr_taskqueue.c | |
parent | 275b7c6a54522a88888b37fba8ce842fcb6d83ca (diff) | |
download | FreeBSD-src-645eb22044ffa13d5de0294dc16c9c7aefa7c5b0.zip FreeBSD-src-645eb22044ffa13d5de0294dc16c9c7aefa7c5b0.tar.gz |
Add the following to the taskqueue api:
taskqueue_start_threads(struct taskqueue **, int count, int pri,
const char *name, ...);
This allows the creation of 1 or more threads that will service a single
taskqueue. Also rework the taskqueue_create() API to remove the API change
that was introduced a while back. Creating a taskqueue doesn't rely on
the presence of a process structure, and the proc mechanics are much better
encapsulated in taskqueue_start_threads(). Also clean up the
taskqueue_terminate() and taskqueue_free() functions to safely drain
pending tasks and remove all associated threads.
The TASKQUEUE_DEFINE and TASKQUEUE_DEFINE_THREAD macros have been changed
to use the new API, but drivers compiled against the old definitions will
still work. Thus, recompiling drivers is not a strict requirement.
Diffstat (limited to 'sys/kern/subr_taskqueue.c')
-rw-r--r-- | sys/kern/subr_taskqueue.c | 72 |
1 files changed, 56 insertions, 16 deletions
diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index 3cc8292..72c75a4 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -37,8 +37,10 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/mutex.h> #include <sys/proc.h> +#include <sys/sched.h> #include <sys/taskqueue.h> #include <sys/unistd.h> +#include <machine/stdarg.h> static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); static void *taskqueue_giant_ih; @@ -55,9 +57,13 @@ struct taskqueue { struct task *tq_running; struct mtx tq_mutex; struct proc **tq_pproc; + int tq_pcount; int tq_spin; + int tq_flags; }; +#define TQ_FLAGS_ACTIVE (1 << 0) + static __inline void TQ_LOCK(struct taskqueue *tq) { @@ -100,7 +106,6 @@ SYSINIT(taskqueue_list, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_taskqueue_list, static struct taskqueue * _taskqueue_create(const char *name, int mflags, taskqueue_enqueue_fn enqueue, void *context, - struct proc **pp, int mtxflags, const char *mtxname) { struct taskqueue *queue; @@ -113,8 +118,8 @@ _taskqueue_create(const char *name, int mflags, queue->tq_name = name; queue->tq_enqueue = enqueue; queue->tq_context = context; - queue->tq_pproc = pp; queue->tq_spin = (mtxflags & MTX_SPIN) != 0; + queue->tq_flags |= TQ_FLAGS_ACTIVE; mtx_init(&queue->tq_mutex, mtxname, NULL, mtxflags); mtx_lock(&taskqueue_queues_mutex); @@ -126,10 +131,9 @@ _taskqueue_create(const char *name, int mflags, struct taskqueue * taskqueue_create(const char *name, int mflags, - taskqueue_enqueue_fn enqueue, void *context, - struct proc **pp) + taskqueue_enqueue_fn enqueue, void *context) { - return _taskqueue_create(name, mflags, enqueue, context, pp, + return _taskqueue_create(name, mflags, enqueue, context, MTX_DEF, "taskqueue"); } @@ -139,13 +143,10 @@ taskqueue_create(const char *name, int mflags, static void taskqueue_terminate(struct proc **pp, struct taskqueue *tq) { - struct proc *p; - p = *pp; - *pp = NULL; - if (p) { - wakeup_one(tq); - TQ_SLEEP(tq, p, &tq->tq_mutex, PWAIT, "taskqueue_destroy", 0); + while (tq->tq_pcount > 0) { + wakeup(tq); + TQ_SLEEP(tq, pp, &tq->tq_mutex, PWAIT, "taskqueue_destroy", 0); } } @@ -158,9 +159,11 @@ taskqueue_free(struct taskqueue *queue) mtx_unlock(&taskqueue_queues_mutex); TQ_LOCK(queue); + queue->tq_flags &= ~TQ_FLAGS_ACTIVE; taskqueue_run(queue); taskqueue_terminate(queue->tq_pproc, queue); mtx_destroy(&queue->tq_mutex); + free(queue->tq_pproc, M_TASKQUEUE); free(queue, M_TASKQUEUE); } @@ -306,6 +309,43 @@ taskqueue_swi_giant_run(void *dummy) taskqueue_run(taskqueue_swi_giant); } +int +taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, + const char *name, ...) +{ + va_list ap; + struct taskqueue *tq; + char ktname[MAXCOMLEN]; + int i; + + if (count <= 0) + return (EINVAL); + tq = *tqp; + + if ((tq->tq_pproc = malloc(sizeof(struct proc *) * count, M_TASKQUEUE, + M_NOWAIT | M_ZERO)) == NULL) + return (ENOMEM); + + va_start(ap, name); + vsnprintf(ktname, MAXCOMLEN, name, ap); + va_end(ap); + + for (i = 0; i < count; i++) { + if (count == 1) + kthread_create(taskqueue_thread_loop, tqp, + &tq->tq_pproc[i], 0, 0, ktname); + else + kthread_create(taskqueue_thread_loop, tqp, + &tq->tq_pproc[i], 0, 0, "%s_%d", ktname, i); + mtx_lock_spin(&sched_lock); + sched_prio(FIRST_THREAD_IN_PROC(tq->tq_pproc[i]), pri); + mtx_unlock_spin(&sched_lock); + tq->tq_pcount++; + } + + return (0); +} + void taskqueue_thread_loop(void *arg) { @@ -317,10 +357,11 @@ taskqueue_thread_loop(void *arg) do { taskqueue_run(tq); TQ_SLEEP(tq, tq, &tq->tq_mutex, curthread->td_priority, "-", 0); - } while (*tq->tq_pproc != NULL); + } while ((tq->tq_flags & TQ_FLAGS_ACTIVE) != 0); /* rendezvous with thread that asked us to terminate */ - wakeup_one(tq); + tq->tq_pcount--; + wakeup_one(tq->tq_pproc); TQ_UNLOCK(tq); kthread_exit(0); } @@ -349,10 +390,9 @@ TASKQUEUE_DEFINE_THREAD(thread); struct taskqueue * taskqueue_create_fast(const char *name, int mflags, - taskqueue_enqueue_fn enqueue, void *context, - struct proc **pp) + taskqueue_enqueue_fn enqueue, void *context) { - return _taskqueue_create(name, mflags, enqueue, context, pp, + return _taskqueue_create(name, mflags, enqueue, context, MTX_SPIN, "fast_taskqueue"); } |