Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/subr_gtaskqueue.c
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/gtaskqueue.h> | #include <sys/gtaskqueue.h> | ||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
static MALLOC_DEFINE(M_GTASKQUEUE, "gtaskqueue", "Group Task Queues"); | static MALLOC_DEFINE(M_GTASKQUEUE, "gtaskqueue", "Group Task Queues"); | ||||
static void gtaskqueue_thread_enqueue(void *); | static void gtaskqueue_thread_enqueue(void *); | ||||
static void gtaskqueue_thread_loop(void *arg); | static void gtaskqueue_thread_loop(void *arg); | ||||
static int task_is_running(struct gtaskqueue *queue, struct gtask *gtask); | |||||
static void gtaskqueue_drain_locked(struct gtaskqueue *queue, struct gtask *gtask); | |||||
TASKQGROUP_DEFINE(softirq, mp_ncpus, 1); | TASKQGROUP_DEFINE(softirq, mp_ncpus, 1); | ||||
TASKQGROUP_DEFINE(config, 1, 1); | TASKQGROUP_DEFINE(config, 1, 1); | ||||
struct gtaskqueue_busy { | struct gtaskqueue_busy { | ||||
struct gtask *tb_running; | struct gtask *tb_running; | ||||
TAILQ_ENTRY(gtaskqueue_busy) tb_link; | TAILQ_ENTRY(gtaskqueue_busy) tb_link; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | gtaskqueue_free(struct gtaskqueue *queue) | ||||
KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?")); | KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?")); | ||||
KASSERT(queue->tq_callouts == 0, ("Armed timeout tasks")); | KASSERT(queue->tq_callouts == 0, ("Armed timeout tasks")); | ||||
mtx_destroy(&queue->tq_mutex); | mtx_destroy(&queue->tq_mutex); | ||||
free(queue->tq_threads, M_GTASKQUEUE); | free(queue->tq_threads, M_GTASKQUEUE); | ||||
free(queue->tq_name, M_GTASKQUEUE); | free(queue->tq_name, M_GTASKQUEUE); | ||||
free(queue, M_GTASKQUEUE); | free(queue, M_GTASKQUEUE); | ||||
} | } | ||||
/* | |||||
* Wait for all to complete, then prevent it from being enqueued | |||||
*/ | |||||
void | |||||
grouptask_block(struct grouptask *grouptask) | |||||
{ | |||||
struct gtaskqueue *queue = grouptask->gt_taskqueue; | |||||
struct gtask *gtask = &grouptask->gt_task; | |||||
#ifdef INVARIANTS | |||||
if (queue == NULL) { | |||||
gtask_dump(gtask); | |||||
panic("queue == NULL"); | |||||
} | |||||
#endif | |||||
TQ_LOCK(queue); | |||||
gtask->ta_flags |= TASK_NOENQUEUE; | |||||
gtaskqueue_drain_locked(queue, gtask); | |||||
TQ_UNLOCK(queue); | |||||
} | |||||
void | |||||
grouptask_unblock(struct grouptask *grouptask) | |||||
{ | |||||
struct gtaskqueue *queue = grouptask->gt_taskqueue; | |||||
struct gtask *gtask = &grouptask->gt_task; | |||||
#ifdef INVARIANTS | |||||
if (queue == NULL) { | |||||
gtask_dump(gtask); | |||||
panic("queue == NULL"); | |||||
} | |||||
#endif | |||||
TQ_LOCK(queue); | |||||
gtask->ta_flags &= ~TASK_NOENQUEUE; | |||||
TQ_UNLOCK(queue); | |||||
} | |||||
int | int | ||||
grouptaskqueue_enqueue(struct gtaskqueue *queue, struct gtask *gtask) | grouptaskqueue_enqueue(struct gtaskqueue *queue, struct gtask *gtask) | ||||
{ | { | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (queue == NULL) { | if (queue == NULL) { | ||||
gtask_dump(gtask); | gtask_dump(gtask); | ||||
panic("queue == NULL"); | panic("queue == NULL"); | ||||
} | } | ||||
#endif | #endif | ||||
TQ_LOCK(queue); | TQ_LOCK(queue); | ||||
if (gtask->ta_flags & TASK_ENQUEUED) { | if (gtask->ta_flags & TASK_ENQUEUED) { | ||||
TQ_UNLOCK(queue); | TQ_UNLOCK(queue); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (gtask->ta_flags & TASK_NOENQUEUE) { | |||||
TQ_UNLOCK(queue); | |||||
return (EAGAIN); | |||||
} | |||||
STAILQ_INSERT_TAIL(&queue->tq_queue, gtask, ta_link); | STAILQ_INSERT_TAIL(&queue->tq_queue, gtask, ta_link); | ||||
gtask->ta_flags |= TASK_ENQUEUED; | gtask->ta_flags |= TASK_ENQUEUED; | ||||
TQ_UNLOCK(queue); | TQ_UNLOCK(queue); | ||||
if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0) | if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0) | ||||
queue->tq_enqueue(queue->tq_context); | queue->tq_enqueue(queue->tq_context); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | gtaskqueue_cancel(struct gtaskqueue *queue, struct gtask *gtask) | ||||
TQ_LOCK(queue); | TQ_LOCK(queue); | ||||
error = gtaskqueue_cancel_locked(queue, gtask); | error = gtaskqueue_cancel_locked(queue, gtask); | ||||
TQ_UNLOCK(queue); | TQ_UNLOCK(queue); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | |||||
gtaskqueue_drain_locked(struct gtaskqueue *queue, struct gtask *gtask) | |||||
{ | |||||
while ((gtask->ta_flags & TASK_ENQUEUED) || task_is_running(queue, gtask)) | |||||
TQ_SLEEP(queue, gtask, &queue->tq_mutex, PWAIT, "-", 0); | |||||
} | |||||
void | void | ||||
gtaskqueue_drain(struct gtaskqueue *queue, struct gtask *gtask) | gtaskqueue_drain(struct gtaskqueue *queue, struct gtask *gtask) | ||||
{ | { | ||||
if (!queue->tq_spin) | if (!queue->tq_spin) | ||||
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); | WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); | ||||
TQ_LOCK(queue); | TQ_LOCK(queue); | ||||
while ((gtask->ta_flags & TASK_ENQUEUED) || task_is_running(queue, gtask)) | gtaskqueue_drain_locked(queue, gtask); | ||||
TQ_SLEEP(queue, gtask, &queue->tq_mutex, PWAIT, "-", 0); | |||||
TQ_UNLOCK(queue); | TQ_UNLOCK(queue); | ||||
} | } | ||||
void | void | ||||
gtaskqueue_drain_all(struct gtaskqueue *queue) | gtaskqueue_drain_all(struct gtaskqueue *queue) | ||||
{ | { | ||||
if (!queue->tq_spin) | if (!queue->tq_spin) | ||||
▲ Show 20 Lines • Show All 399 Lines • ▼ Show 20 Lines | taskqgroup_attach_cpu_deferred(struct taskqgroup *qgroup, struct grouptask *gtask) | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
taskqgroup_detach(struct taskqgroup *qgroup, struct grouptask *gtask) | taskqgroup_detach(struct taskqgroup *qgroup, struct grouptask *gtask) | ||||
{ | { | ||||
int i; | int i; | ||||
grouptask_block(gtask); | |||||
mtx_lock(&qgroup->tqg_lock); | mtx_lock(&qgroup->tqg_lock); | ||||
for (i = 0; i < qgroup->tqg_cnt; i++) | for (i = 0; i < qgroup->tqg_cnt; i++) | ||||
if (qgroup->tqg_queue[i].tgc_taskq == gtask->gt_taskqueue) | if (qgroup->tqg_queue[i].tgc_taskq == gtask->gt_taskqueue) | ||||
break; | break; | ||||
if (i == qgroup->tqg_cnt) | if (i == qgroup->tqg_cnt) | ||||
panic("taskqgroup_detach: task %s not in group\n", gtask->gt_name); | panic("taskqgroup_detach: task %s not in group\n", gtask->gt_name); | ||||
qgroup->tqg_queue[i].tgc_cnt--; | qgroup->tqg_queue[i].tgc_cnt--; | ||||
LIST_REMOVE(gtask, gt_list); | LIST_REMOVE(gtask, gt_list); | ||||
mtx_unlock(&qgroup->tqg_lock); | mtx_unlock(&qgroup->tqg_lock); | ||||
gtask->gt_taskqueue = NULL; | gtask->gt_taskqueue = NULL; | ||||
gtask->gt_task.ta_flags &= ~TASK_NOENQUEUE; | |||||
} | } | ||||
static void | static void | ||||
taskqgroup_binder(void *ctx) | taskqgroup_binder(void *ctx) | ||||
{ | { | ||||
struct taskq_bind_task *gtask = (struct taskq_bind_task *)ctx; | struct taskq_bind_task *gtask = (struct taskq_bind_task *)ctx; | ||||
cpuset_t mask; | cpuset_t mask; | ||||
int error; | int error; | ||||
▲ Show 20 Lines • Show All 190 Lines • Show Last 20 Lines |