svn commit: r215190 - stable/8/sys/kern
Matthew D Fleming
mdf at FreeBSD.org
Fri Nov 12 18:09:06 UTC 2010
Author: mdf
Date: Fri Nov 12 18:09:06 2010
New Revision: 215190
URL: http://svn.freebsd.org/changeset/base/215190
Log:
MFC r213813. This is a direct commit because the diff is against
several non-MFC'd changes.
Use a safer mechanism for determining if a task is currently running,
that does not rely on the lifetime of pointers being the same. This
also restores the task KBI.
Modified:
stable/8/sys/kern/subr_taskqueue.c
Modified: stable/8/sys/kern/subr_taskqueue.c
==============================================================================
--- stable/8/sys/kern/subr_taskqueue.c Fri Nov 12 17:20:18 2010 (r215189)
+++ stable/8/sys/kern/subr_taskqueue.c Fri Nov 12 18:09:06 2010 (r215190)
@@ -46,12 +46,17 @@ static MALLOC_DEFINE(M_TASKQUEUE, "taskq
static void *taskqueue_giant_ih;
static void *taskqueue_ih;
+struct taskqueue_busy {
+ struct task *tb_running;
+ TAILQ_ENTRY(taskqueue_busy) tb_link;
+};
+
struct taskqueue {
STAILQ_HEAD(, task) tq_queue;
const char *tq_name;
taskqueue_enqueue_fn tq_enqueue;
void *tq_context;
- struct task *tq_running;
+ TAILQ_HEAD(, taskqueue_busy) tq_active;
struct mtx tq_mutex;
struct thread **tq_threads;
int tq_tcount;
@@ -63,6 +68,8 @@ struct taskqueue {
#define TQ_FLAGS_BLOCKED (1 << 1)
#define TQ_FLAGS_PENDING (1 << 2)
+static void taskqueue_run_locked(struct taskqueue *);
+
static __inline void
TQ_LOCK(struct taskqueue *tq)
{
@@ -102,6 +109,7 @@ _taskqueue_create(const char *name, int
return NULL;
STAILQ_INIT(&queue->tq_queue);
+ TAILQ_INIT(&queue->tq_active);
queue->tq_name = name;
queue->tq_enqueue = enqueue;
queue->tq_context = context;
@@ -139,8 +147,9 @@ taskqueue_free(struct taskqueue *queue)
TQ_LOCK(queue);
queue->tq_flags &= ~TQ_FLAGS_ACTIVE;
- taskqueue_run(queue);
+ taskqueue_run_locked(queue);
taskqueue_terminate(queue->tq_threads, queue);
+ KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?"));
mtx_destroy(&queue->tq_mutex);
free(queue->tq_threads, M_TASKQUEUE);
free(queue, M_TASKQUEUE);
@@ -215,15 +224,17 @@ taskqueue_unblock(struct taskqueue *queu
TQ_UNLOCK(queue);
}
-void
-taskqueue_run(struct taskqueue *queue)
+static void
+taskqueue_run_locked(struct taskqueue *queue)
{
+ struct taskqueue_busy tb;
struct task *task;
- int owned, pending;
+ int pending;
+
+ mtx_assert(&queue->tq_mutex, MA_OWNED);
+ tb.tb_running = NULL;
+ TAILQ_INSERT_TAIL(&queue->tq_active, &tb, tb_link);
- owned = mtx_owned(&queue->tq_mutex);
- if (!owned)
- TQ_LOCK(queue);
while (STAILQ_FIRST(&queue->tq_queue)) {
/*
* Carefully remove the first task from the queue and
@@ -233,22 +244,38 @@ taskqueue_run(struct taskqueue *queue)
STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link);
pending = task->ta_pending;
task->ta_pending = 0;
- queue->tq_running = task;
+ tb.tb_running = task;
TQ_UNLOCK(queue);
task->ta_func(task->ta_context, pending);
TQ_LOCK(queue);
- queue->tq_running = NULL;
+ tb.tb_running = NULL;
wakeup(task);
}
+ TAILQ_REMOVE(&queue->tq_active, &tb, tb_link);
+}
- /*
- * For compatibility, unlock on return if the queue was not locked
- * on entry, although this opens a race window.
- */
- if (!owned)
- TQ_UNLOCK(queue);
+void
+taskqueue_run(struct taskqueue *queue)
+{
+
+ TQ_LOCK(queue);
+ taskqueue_run_locked(queue);
+ TQ_UNLOCK(queue);
+}
+
+static int
+task_is_running(struct taskqueue *queue, struct task *task)
+{
+ struct taskqueue_busy *tb;
+
+ mtx_assert(&queue->tq_mutex, MA_OWNED);
+ TAILQ_FOREACH(tb, &queue->tq_active, tb_link) {
+ if (tb->tb_running == task)
+ return (1);
+ }
+ return (0);
}
void
@@ -256,14 +283,14 @@ taskqueue_drain(struct taskqueue *queue,
{
if (queue->tq_spin) { /* XXX */
mtx_lock_spin(&queue->tq_mutex);
- while (task->ta_pending != 0 || task == queue->tq_running)
+ while (task->ta_pending != 0 || task_is_running(queue, task))
msleep_spin(task, &queue->tq_mutex, "-", 0);
mtx_unlock_spin(&queue->tq_mutex);
} else {
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__);
mtx_lock(&queue->tq_mutex);
- while (task->ta_pending != 0 || task == queue->tq_running)
+ while (task->ta_pending != 0 || task_is_running(queue, task))
msleep(task, &queue->tq_mutex, PWAIT, "-", 0);
mtx_unlock(&queue->tq_mutex);
}
@@ -357,7 +384,7 @@ taskqueue_thread_loop(void *arg)
tq = *tqp;
TQ_LOCK(tq);
while ((tq->tq_flags & TQ_FLAGS_ACTIVE) != 0) {
- taskqueue_run(tq);
+ taskqueue_run_locked(tq);
/*
* Because taskqueue_run() can drop tq_mutex, we need to
* check if the TQ_FLAGS_ACTIVE flag wasn't removed in the
More information about the svn-src-stable-8
mailing list