summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_taskqueue.c
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2006-01-14 01:55:24 +0000
committerscottl <scottl@FreeBSD.org>2006-01-14 01:55:24 +0000
commit645eb22044ffa13d5de0294dc16c9c7aefa7c5b0 (patch)
treef5229c8522204692d0896701c0159d45163983de /sys/kern/subr_taskqueue.c
parent275b7c6a54522a88888b37fba8ce842fcb6d83ca (diff)
downloadFreeBSD-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.c72
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");
}
OpenPOWER on IntegriCloud