svn commit: r215191 - stable/7/sys/kern
Matthew D Fleming
mdf at FreeBSD.org
Fri Nov 12 18:10:27 UTC 2010
Author: mdf
Date: Fri Nov 12 18:10:27 2010
New Revision: 215191
URL: http://svn.freebsd.org/changeset/base/215191
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/7/sys/kern/subr_taskqueue.c
Modified: stable/7/sys/kern/subr_taskqueue.c
==============================================================================
--- stable/7/sys/kern/subr_taskqueue.c Fri Nov 12 18:09:06 2010 (r215190)
+++ stable/7/sys/kern/subr_taskqueue.c Fri Nov 12 18:10:27 2010 (r215191)
@@ -48,13 +48,18 @@ static void *taskqueue_ih;
static STAILQ_HEAD(taskqueue_list, taskqueue) taskqueue_queues;
static struct mtx taskqueue_queues_mutex;
+struct taskqueue_busy {
+ struct task *tb_running;
+ TAILQ_ENTRY(taskqueue_busy) tb_link;
+};
+
struct taskqueue {
STAILQ_ENTRY(taskqueue) tq_link;
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 proc **tq_pproc;
int tq_pcount;
@@ -66,6 +71,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)
{
@@ -117,6 +124,7 @@ _taskqueue_create(const char *name, int
return 0;
STAILQ_INIT(&queue->tq_queue);
+ TAILQ_INIT(&queue->tq_active);
queue->tq_name = name;
queue->tq_enqueue = enqueue;
queue->tq_context = context;
@@ -162,8 +170,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_pproc, queue);
+ KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?"));
mtx_destroy(&queue->tq_mutex);
free(queue->tq_pproc, M_TASKQUEUE);
free(queue, M_TASKQUEUE);
@@ -258,15 +267,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
@@ -276,22 +287,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
@@ -299,14 +326,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);
}
@@ -398,7 +425,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);
TQ_SLEEP(tq, tq, &tq->tq_mutex, 0, "-", 0);
}
More information about the svn-src-stable
mailing list