freebsd11_network: Properly implement CALLOUT_RETURNUNLOCKED.

Fixes a double-lock situation in the Atheros driver. We really should
implement FreeBSD's MTX_SPIN instead of relying on cpu_status here...
This commit is contained in:
Augustin Cavalier 2018-07-11 19:03:27 -04:00
parent 3248de3de4
commit 09ddf9b9f3
2 changed files with 23 additions and 7 deletions

View File

@ -1,6 +1,7 @@
/*
* Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
* Copyright 2018, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*/
@ -66,7 +67,8 @@ callout_thread(void* /*data*/)
c->c_func(c->c_arg);
if (mutex != NULL)
if (mutex != NULL
&& (c->c_flags & CALLOUT_RETURNUNLOCKED) == 0)
mtx_unlock(mutex);
mutex_lock(&sLock);

View File

@ -293,11 +293,10 @@ taskqueue_drain_timeout(struct taskqueue *queue,
}
int
taskqueue_enqueue(struct taskqueue *taskQueue, struct task *task)
static void
taskqueue_enqueue_locked(struct taskqueue *taskQueue, struct task *task,
cpu_status status)
{
cpu_status status;
tq_lock(taskQueue, &status);
/* we don't really support priorities */
if (task->ta_pending) {
task->ta_pending++;
@ -310,6 +309,18 @@ taskqueue_enqueue(struct taskqueue *taskQueue, struct task *task)
taskQueue->tq_flags |= TQ_FLAGS_PENDING;
}
tq_unlock(taskQueue, status);
}
int
taskqueue_enqueue(struct taskqueue *taskQueue, struct task *task)
{
cpu_status status;
tq_lock(taskQueue, &status);
taskqueue_enqueue_locked(taskQueue, task, status);
/* The lock is released inside. */
return 0;
}
@ -319,13 +330,16 @@ taskqueue_timeout_func(void *arg)
{
struct taskqueue *queue;
struct timeout_task *timeout_task;
cpu_status status;
// dummy, as we should never get here on a spin taskqueue
timeout_task = arg;
queue = timeout_task->q;
KASSERT((timeout_task->f & DT_CALLOUT_ARMED) != 0, ("Stray timeout"));
timeout_task->f &= ~DT_CALLOUT_ARMED;
queue->tq_callouts--;
taskqueue_enqueue(timeout_task->q, &timeout_task->t);
taskqueue_enqueue_locked(timeout_task->q, &timeout_task->t, status);
/* The lock is released inside. */
}