freebsd_network: Use MTX_SPIN for fast taskqueues instead of a direct spinlock.
This commit is contained in:
@@ -31,7 +31,6 @@ struct taskqueue {
|
|||||||
taskqueue_enqueue_fn tq_enqueue;
|
taskqueue_enqueue_fn tq_enqueue;
|
||||||
void *tq_arg;
|
void *tq_arg;
|
||||||
int tq_fast;
|
int tq_fast;
|
||||||
spinlock tq_spinlock;
|
|
||||||
sem_id tq_sem;
|
sem_id tq_sem;
|
||||||
thread_id *tq_threads;
|
thread_id *tq_threads;
|
||||||
thread_id tq_thread_storage;
|
thread_id tq_thread_storage;
|
||||||
@@ -56,7 +55,7 @@ _taskqueue_create(const char *name, int mflags, int fast,
|
|||||||
tq->tq_fast = fast;
|
tq->tq_fast = fast;
|
||||||
|
|
||||||
if (fast) {
|
if (fast) {
|
||||||
B_INITIALIZE_SPINLOCK(&tq->tq_spinlock);
|
mtx_init(&tq->tq_mutex, name, NULL, MTX_SPIN);
|
||||||
} else {
|
} else {
|
||||||
mtx_init(&tq->tq_mutex, name, NULL, MTX_DEF);
|
mtx_init(&tq->tq_mutex, name, NULL, MTX_DEF);
|
||||||
}
|
}
|
||||||
@@ -77,11 +76,10 @@ _taskqueue_create(const char *name, int mflags, int fast,
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tq_lock(struct taskqueue *taskQueue, cpu_status *status)
|
tq_lock(struct taskqueue *taskQueue)
|
||||||
{
|
{
|
||||||
if (taskQueue->tq_fast) {
|
if (taskQueue->tq_fast) {
|
||||||
*status = disable_interrupts();
|
mtx_lock_spin(&taskQueue->tq_mutex);
|
||||||
acquire_spinlock(&taskQueue->tq_spinlock);
|
|
||||||
} else {
|
} else {
|
||||||
mtx_lock(&taskQueue->tq_mutex);
|
mtx_lock(&taskQueue->tq_mutex);
|
||||||
}
|
}
|
||||||
@@ -89,11 +87,10 @@ tq_lock(struct taskqueue *taskQueue, cpu_status *status)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tq_unlock(struct taskqueue *taskQueue, cpu_status status)
|
tq_unlock(struct taskqueue *taskQueue)
|
||||||
{
|
{
|
||||||
if (taskQueue->tq_fast) {
|
if (taskQueue->tq_fast) {
|
||||||
release_spinlock(&taskQueue->tq_spinlock);
|
mtx_unlock_spin(&taskQueue->tq_mutex);
|
||||||
restore_interrupts(status);
|
|
||||||
} else {
|
} else {
|
||||||
mtx_unlock(&taskQueue->tq_mutex);
|
mtx_unlock(&taskQueue->tq_mutex);
|
||||||
}
|
}
|
||||||
@@ -112,20 +109,19 @@ static int32
|
|||||||
tq_handle_thread(void *data)
|
tq_handle_thread(void *data)
|
||||||
{
|
{
|
||||||
struct taskqueue *tq = data;
|
struct taskqueue *tq = data;
|
||||||
cpu_status cpu_state;
|
|
||||||
struct task *t;
|
struct task *t;
|
||||||
int pending;
|
int pending;
|
||||||
sem_id sem;
|
sem_id sem;
|
||||||
|
|
||||||
/* just a synchronization point */
|
/* just a synchronization point */
|
||||||
tq_lock(tq, &cpu_state);
|
tq_lock(tq);
|
||||||
sem = tq->tq_sem;
|
sem = tq->tq_sem;
|
||||||
tq_unlock(tq, cpu_state);
|
tq_unlock(tq);
|
||||||
|
|
||||||
while (acquire_sem(sem) == B_NO_ERROR) {
|
while (acquire_sem(sem) == B_NO_ERROR) {
|
||||||
tq_lock(tq, &cpu_state);
|
tq_lock(tq);
|
||||||
t = list_remove_head_item(&tq->tq_list);
|
t = list_remove_head_item(&tq->tq_list);
|
||||||
tq_unlock(tq, cpu_state);
|
tq_unlock(tq);
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
continue;
|
continue;
|
||||||
pending = t->ta_pending;
|
pending = t->ta_pending;
|
||||||
@@ -200,7 +196,6 @@ taskqueue_start_threads(struct taskqueue **taskQueue, int count, int priority,
|
|||||||
* the TQ is 'fast', locking the TQ disables interrupts... and then
|
* the TQ is 'fast', locking the TQ disables interrupts... and then
|
||||||
* we can't create semaphores, threads and bananas. */
|
* we can't create semaphores, threads and bananas. */
|
||||||
|
|
||||||
/* cpu_status state; */
|
|
||||||
char name[64];
|
char name[64];
|
||||||
int result;
|
int result;
|
||||||
va_list vl;
|
va_list vl;
|
||||||
@@ -209,9 +204,9 @@ taskqueue_start_threads(struct taskqueue **taskQueue, int count, int priority,
|
|||||||
vsnprintf(name, sizeof(name), format, vl);
|
vsnprintf(name, sizeof(name), format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
|
||||||
/*tq_lock(*tqp, &state);*/
|
/*tq_lock(*tqp);*/
|
||||||
result = _taskqueue_start_threads(taskQueue, count, priority, name);
|
result = _taskqueue_start_threads(taskQueue, count, priority, name);
|
||||||
/*tq_unlock(*tqp, state);*/
|
/*tq_unlock(*tqp);*/
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -220,10 +215,8 @@ taskqueue_start_threads(struct taskqueue **taskQueue, int count, int priority,
|
|||||||
void
|
void
|
||||||
taskqueue_free(struct taskqueue *taskQueue)
|
taskqueue_free(struct taskqueue *taskQueue)
|
||||||
{
|
{
|
||||||
if (taskQueue == NULL) {
|
if (taskQueue == NULL)
|
||||||
printf("taskqueue_free called with NULL taskqueue\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* lock and drain list? */
|
/* lock and drain list? */
|
||||||
taskQueue->tq_flags &= ~TQ_FLAGS_ACTIVE;
|
taskQueue->tq_flags &= ~TQ_FLAGS_ACTIVE;
|
||||||
@@ -250,20 +243,16 @@ taskqueue_free(struct taskqueue *taskQueue)
|
|||||||
void
|
void
|
||||||
taskqueue_drain(struct taskqueue *taskQueue, struct task *task)
|
taskqueue_drain(struct taskqueue *taskQueue, struct task *task)
|
||||||
{
|
{
|
||||||
cpu_status status;
|
if (taskQueue == NULL)
|
||||||
|
|
||||||
if (taskQueue == NULL) {
|
|
||||||
printf("taskqueue_drain called with NULL taskqueue\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
tq_lock(taskQueue, &status);
|
tq_lock(taskQueue);
|
||||||
while (task->ta_pending != 0) {
|
while (task->ta_pending != 0) {
|
||||||
tq_unlock(taskQueue, status);
|
tq_unlock(taskQueue);
|
||||||
snooze(0);
|
snooze(0);
|
||||||
tq_lock(taskQueue, &status);
|
tq_lock(taskQueue);
|
||||||
}
|
}
|
||||||
tq_unlock(taskQueue, status);
|
tq_unlock(taskQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -271,15 +260,14 @@ void
|
|||||||
taskqueue_drain_timeout(struct taskqueue *queue,
|
taskqueue_drain_timeout(struct taskqueue *queue,
|
||||||
struct timeout_task *timeout_task)
|
struct timeout_task *timeout_task)
|
||||||
{
|
{
|
||||||
cpu_status status;
|
|
||||||
/*
|
/*
|
||||||
* Set flag to prevent timer from re-starting during drain:
|
* Set flag to prevent timer from re-starting during drain:
|
||||||
*/
|
*/
|
||||||
tq_lock(queue, &status);
|
tq_lock(queue);
|
||||||
KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
|
KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
|
||||||
("Drain already in progress"));
|
("Drain already in progress"));
|
||||||
timeout_task->f |= DT_DRAIN_IN_PROGRESS;
|
timeout_task->f |= DT_DRAIN_IN_PROGRESS;
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
|
|
||||||
callout_drain(&timeout_task->c);
|
callout_drain(&timeout_task->c);
|
||||||
taskqueue_drain(queue, &timeout_task->t);
|
taskqueue_drain(queue, &timeout_task->t);
|
||||||
@@ -287,9 +275,9 @@ taskqueue_drain_timeout(struct taskqueue *queue,
|
|||||||
/*
|
/*
|
||||||
* Clear flag to allow timer to re-start:
|
* Clear flag to allow timer to re-start:
|
||||||
*/
|
*/
|
||||||
tq_lock(queue, &status);
|
tq_lock(queue);
|
||||||
timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
|
timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -316,8 +304,7 @@ taskqueue_drain_all(struct taskqueue *taskQueue)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
taskqueue_enqueue_locked(struct taskqueue *taskQueue, struct task *task,
|
taskqueue_enqueue_locked(struct taskqueue *taskQueue, struct task *task)
|
||||||
cpu_status status)
|
|
||||||
{
|
{
|
||||||
/* we don't really support priorities */
|
/* we don't really support priorities */
|
||||||
if (task->ta_pending) {
|
if (task->ta_pending) {
|
||||||
@@ -330,17 +317,15 @@ taskqueue_enqueue_locked(struct taskqueue *taskQueue, struct task *task,
|
|||||||
else
|
else
|
||||||
taskQueue->tq_flags |= TQ_FLAGS_PENDING;
|
taskQueue->tq_flags |= TQ_FLAGS_PENDING;
|
||||||
}
|
}
|
||||||
tq_unlock(taskQueue, status);
|
tq_unlock(taskQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
taskqueue_enqueue(struct taskqueue *taskQueue, struct task *task)
|
taskqueue_enqueue(struct taskqueue *taskQueue, struct task *task)
|
||||||
{
|
{
|
||||||
cpu_status status;
|
tq_lock(taskQueue);
|
||||||
|
taskqueue_enqueue_locked(taskQueue, task);
|
||||||
tq_lock(taskQueue, &status);
|
|
||||||
taskqueue_enqueue_locked(taskQueue, task, status);
|
|
||||||
/* The lock is released inside. */
|
/* The lock is released inside. */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -352,8 +337,6 @@ taskqueue_timeout_func(void *arg)
|
|||||||
{
|
{
|
||||||
struct taskqueue *queue;
|
struct taskqueue *queue;
|
||||||
struct timeout_task *timeout_task;
|
struct timeout_task *timeout_task;
|
||||||
cpu_status status;
|
|
||||||
// dummy, as we should never get here on a spin taskqueue
|
|
||||||
|
|
||||||
timeout_task = arg;
|
timeout_task = arg;
|
||||||
queue = timeout_task->q;
|
queue = timeout_task->q;
|
||||||
@@ -361,7 +344,7 @@ taskqueue_timeout_func(void *arg)
|
|||||||
("stray timeout ('%s')", timeout_task->q->tq_name));
|
("stray timeout ('%s')", timeout_task->q->tq_name));
|
||||||
timeout_task->f &= ~DT_CALLOUT_ARMED;
|
timeout_task->f &= ~DT_CALLOUT_ARMED;
|
||||||
queue->tq_callouts--;
|
queue->tq_callouts--;
|
||||||
taskqueue_enqueue_locked(timeout_task->q, &timeout_task->t, status);
|
taskqueue_enqueue_locked(timeout_task->q, &timeout_task->t);
|
||||||
/* The lock is released inside. */
|
/* The lock is released inside. */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,19 +354,18 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
|
|||||||
struct timeout_task *ttask, int _ticks)
|
struct timeout_task *ttask, int _ticks)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
cpu_status status;
|
|
||||||
|
|
||||||
tq_lock(queue, &status);
|
tq_lock(queue);
|
||||||
KASSERT(ttask->q == NULL || ttask->q == queue,
|
KASSERT(ttask->q == NULL || ttask->q == queue,
|
||||||
("Migrated queue"));
|
("Migrated queue"));
|
||||||
ttask->q = queue;
|
ttask->q = queue;
|
||||||
res = ttask->t.ta_pending;
|
res = ttask->t.ta_pending;
|
||||||
if (ttask->f & DT_DRAIN_IN_PROGRESS) {
|
if (ttask->f & DT_DRAIN_IN_PROGRESS) {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
res = -1;
|
res = -1;
|
||||||
} else if (_ticks == 0) {
|
} else if (_ticks == 0) {
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
taskqueue_enqueue(queue, &ttask->t);
|
taskqueue_enqueue(queue, &ttask->t);
|
||||||
} else {
|
} else {
|
||||||
if ((ttask->f & DT_CALLOUT_ARMED) != 0) {
|
if ((ttask->f & DT_CALLOUT_ARMED) != 0) {
|
||||||
@@ -394,7 +376,7 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
|
|||||||
if (_ticks < 0)
|
if (_ticks < 0)
|
||||||
_ticks = -_ticks; /* Ignore overflow. */
|
_ticks = -_ticks; /* Ignore overflow. */
|
||||||
}
|
}
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
if (_ticks > 0) {
|
if (_ticks > 0) {
|
||||||
callout_reset(&ttask->c, _ticks,
|
callout_reset(&ttask->c, _ticks,
|
||||||
taskqueue_timeout_func, ttask);
|
taskqueue_timeout_func, ttask);
|
||||||
@@ -421,11 +403,10 @@ int
|
|||||||
taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp)
|
taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
cpu_status status;
|
|
||||||
|
|
||||||
tq_lock(queue, &status);
|
tq_lock(queue);
|
||||||
error = taskqueue_cancel_locked(queue, task, pendp);
|
error = taskqueue_cancel_locked(queue, task, pendp);
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@@ -437,16 +418,15 @@ taskqueue_cancel_timeout(struct taskqueue *queue,
|
|||||||
{
|
{
|
||||||
u_int pending, pending1;
|
u_int pending, pending1;
|
||||||
int error;
|
int error;
|
||||||
cpu_status status;
|
|
||||||
|
|
||||||
tq_lock(queue, &status);
|
tq_lock(queue);
|
||||||
pending = !!(callout_stop(&timeout_task->c) > 0);
|
pending = !!(callout_stop(&timeout_task->c) > 0);
|
||||||
error = taskqueue_cancel_locked(queue, &timeout_task->t, &pending1);
|
error = taskqueue_cancel_locked(queue, &timeout_task->t, &pending1);
|
||||||
if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
|
if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
|
||||||
timeout_task->f &= ~DT_CALLOUT_ARMED;
|
timeout_task->f &= ~DT_CALLOUT_ARMED;
|
||||||
queue->tq_callouts--;
|
queue->tq_callouts--;
|
||||||
}
|
}
|
||||||
tq_unlock(queue, status);
|
tq_unlock(queue);
|
||||||
|
|
||||||
if (pendp != NULL)
|
if (pendp != NULL)
|
||||||
*pendp = pending + pending1;
|
*pendp = pending + pending1;
|
||||||
@@ -579,24 +559,20 @@ uninit_taskqueues()
|
|||||||
void
|
void
|
||||||
taskqueue_block(struct taskqueue *taskQueue)
|
taskqueue_block(struct taskqueue *taskQueue)
|
||||||
{
|
{
|
||||||
cpu_status status;
|
tq_lock(taskQueue);
|
||||||
|
|
||||||
tq_lock(taskQueue, &status);
|
|
||||||
taskQueue->tq_flags |= TQ_FLAGS_BLOCKED;
|
taskQueue->tq_flags |= TQ_FLAGS_BLOCKED;
|
||||||
tq_unlock(taskQueue, status);
|
tq_unlock(taskQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
taskqueue_unblock(struct taskqueue *taskQueue)
|
taskqueue_unblock(struct taskqueue *taskQueue)
|
||||||
{
|
{
|
||||||
cpu_status status;
|
tq_lock(taskQueue);
|
||||||
|
|
||||||
tq_lock(taskQueue, &status);
|
|
||||||
taskQueue->tq_flags &= ~TQ_FLAGS_BLOCKED;
|
taskQueue->tq_flags &= ~TQ_FLAGS_BLOCKED;
|
||||||
if (taskQueue->tq_flags & TQ_FLAGS_PENDING) {
|
if (taskQueue->tq_flags & TQ_FLAGS_PENDING) {
|
||||||
taskQueue->tq_flags &= ~TQ_FLAGS_PENDING;
|
taskQueue->tq_flags &= ~TQ_FLAGS_PENDING;
|
||||||
taskQueue->tq_enqueue(taskQueue->tq_arg);
|
taskQueue->tq_enqueue(taskQueue->tq_arg);
|
||||||
}
|
}
|
||||||
tq_unlock(taskQueue, status);
|
tq_unlock(taskQueue);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user