Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/subr_taskqueue.c
Show All 36 Lines | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/kthread.h> | #include <sys/kthread.h> | ||||
#include <sys/libkern.h> | #include <sys/libkern.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/epoch.h> | |||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); | static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); | ||||
static void *taskqueue_giant_ih; | static void *taskqueue_giant_ih; | ||||
▲ Show 20 Lines • Show All 313 Lines • ▼ Show 20 Lines | taskqueue_drain_tq_queue(struct taskqueue *queue) | ||||
/* | /* | ||||
* Enqueue our barrier after all current tasks, but with | * Enqueue our barrier after all current tasks, but with | ||||
* the highest priority so that newly queued tasks cannot | * the highest priority so that newly queued tasks cannot | ||||
* pass it. Because of the high priority, we can not use | * pass it. Because of the high priority, we can not use | ||||
* taskqueue_enqueue_locked directly (which drops the lock | * taskqueue_enqueue_locked directly (which drops the lock | ||||
* anyway) so just insert it at tail while we have the | * anyway) so just insert it at tail while we have the | ||||
* queue lock. | * queue lock. | ||||
*/ | */ | ||||
TASK_INIT(&t_barrier, USHRT_MAX, taskqueue_task_nop_fn, &t_barrier); | TASK_INIT(&t_barrier, UCHAR_MAX, taskqueue_task_nop_fn, &t_barrier); | ||||
STAILQ_INSERT_TAIL(&queue->tq_queue, &t_barrier, ta_link); | STAILQ_INSERT_TAIL(&queue->tq_queue, &t_barrier, ta_link); | ||||
queue->tq_hint = &t_barrier; | queue->tq_hint = &t_barrier; | ||||
t_barrier.ta_pending = 1; | t_barrier.ta_pending = 1; | ||||
/* | /* | ||||
* Once the barrier has executed, all previously queued tasks | * Once the barrier has executed, all previously queued tasks | ||||
* have completed or are currently executing. | * have completed or are currently executing. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | taskqueue_unblock(struct taskqueue *queue) | ||||
if (!STAILQ_EMPTY(&queue->tq_queue)) | if (!STAILQ_EMPTY(&queue->tq_queue)) | ||||
queue->tq_enqueue(queue->tq_context); | queue->tq_enqueue(queue->tq_context); | ||||
TQ_UNLOCK(queue); | TQ_UNLOCK(queue); | ||||
} | } | ||||
static void | static void | ||||
taskqueue_run_locked(struct taskqueue *queue) | taskqueue_run_locked(struct taskqueue *queue) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct taskqueue_busy tb; | struct taskqueue_busy tb; | ||||
struct task *task; | struct task *task; | ||||
bool in_net_epoch; | |||||
int pending; | int pending; | ||||
KASSERT(queue != NULL, ("tq is NULL")); | KASSERT(queue != NULL, ("tq is NULL")); | ||||
TQ_ASSERT_LOCKED(queue); | TQ_ASSERT_LOCKED(queue); | ||||
tb.tb_running = NULL; | tb.tb_running = NULL; | ||||
LIST_INSERT_HEAD(&queue->tq_active, &tb, tb_link); | LIST_INSERT_HEAD(&queue->tq_active, &tb, tb_link); | ||||
in_net_epoch = false; | |||||
while ((task = STAILQ_FIRST(&queue->tq_queue)) != NULL) { | while ((task = STAILQ_FIRST(&queue->tq_queue)) != NULL) { | ||||
STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); | STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); | ||||
if (queue->tq_hint == task) | if (queue->tq_hint == task) | ||||
queue->tq_hint = NULL; | queue->tq_hint = NULL; | ||||
pending = task->ta_pending; | pending = task->ta_pending; | ||||
task->ta_pending = 0; | task->ta_pending = 0; | ||||
tb.tb_running = task; | tb.tb_running = task; | ||||
tb.tb_seq = ++queue->tq_seq; | tb.tb_seq = ++queue->tq_seq; | ||||
TQ_UNLOCK(queue); | TQ_UNLOCK(queue); | ||||
KASSERT(task->ta_func != NULL, ("task->ta_func is NULL")); | KASSERT(task->ta_func != NULL, ("task->ta_func is NULL")); | ||||
if (!in_net_epoch && TASK_IS_NET(task)) { | |||||
in_net_epoch = true; | |||||
NET_EPOCH_ENTER(et); | |||||
} else if (in_net_epoch && !TASK_IS_NET(task)) { | |||||
NET_EPOCH_EXIT(et); | |||||
in_net_epoch = false; | |||||
} | |||||
task->ta_func(task->ta_context, pending); | task->ta_func(task->ta_context, pending); | ||||
TQ_LOCK(queue); | TQ_LOCK(queue); | ||||
wakeup(task); | wakeup(task); | ||||
} | } | ||||
if (in_net_epoch) | |||||
NET_EPOCH_EXIT(et); | |||||
LIST_REMOVE(&tb, tb_link); | LIST_REMOVE(&tb, tb_link); | ||||
} | } | ||||
void | void | ||||
taskqueue_run(struct taskqueue *queue) | taskqueue_run(struct taskqueue *queue) | ||||
{ | { | ||||
TQ_LOCK(queue); | TQ_LOCK(queue); | ||||
▲ Show 20 Lines • Show All 392 Lines • Show Last 20 Lines |