diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/kern/subr_taskqueue.c | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2 |
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/kern/subr_taskqueue.c')
-rw-r--r-- | freebsd/sys/kern/subr_taskqueue.c | 201 |
1 files changed, 161 insertions, 40 deletions
diff --git a/freebsd/sys/kern/subr_taskqueue.c b/freebsd/sys/kern/subr_taskqueue.c index be19c5b4..867b0e6b 100644 --- a/freebsd/sys/kern/subr_taskqueue.c +++ b/freebsd/sys/kern/subr_taskqueue.c @@ -68,34 +68,52 @@ struct taskqueue { int tq_spin; #endif /* __rtems__ */ int tq_flags; + int tq_callouts; }; #define TQ_FLAGS_ACTIVE (1 << 0) #define TQ_FLAGS_BLOCKED (1 << 1) #define TQ_FLAGS_PENDING (1 << 2) -static void taskqueue_run_locked(struct taskqueue *); +#define DT_CALLOUT_ARMED (1 << 0) -static __inline void -TQ_LOCK(struct taskqueue *tq) -{ #ifndef __rtems__ - if (tq->tq_spin) - mtx_lock_spin(&tq->tq_mutex); - else +#define TQ_LOCK(tq) \ + do { \ + if ((tq)->tq_spin) \ + mtx_lock_spin(&(tq)->tq_mutex); \ + else \ + mtx_lock(&(tq)->tq_mutex); \ + } while (0) + +#define TQ_UNLOCK(tq) \ + do { \ + if ((tq)->tq_spin) \ + mtx_unlock_spin(&(tq)->tq_mutex); \ + else \ + mtx_unlock(&(tq)->tq_mutex); \ + } while (0) +#else /* __rtems__ */ +#define TQ_LOCK(tq) \ + do { \ + mtx_lock(&(tq)->tq_mutex); \ + } while (0) + +#define TQ_UNLOCK(tq) \ + do { \ + mtx_unlock(&(tq)->tq_mutex); \ + } while (0) #endif /* __rtems__ */ - mtx_lock(&tq->tq_mutex); -} -static __inline void -TQ_UNLOCK(struct taskqueue *tq) +void +_timeout_task_init(struct taskqueue *queue, struct timeout_task *timeout_task, + int priority, task_fn_t func, void *context) { -#ifndef __rtems__ - if (tq->tq_spin) - mtx_unlock_spin(&tq->tq_mutex); - else -#endif /* __rtems__ */ - mtx_unlock(&tq->tq_mutex); + + TASK_INIT(&timeout_task->t, priority, func, context); + callout_init_mtx(&timeout_task->c, &queue->tq_mutex, 0); + timeout_task->q = queue; + timeout_task->f = 0; } static __inline int @@ -153,7 +171,7 @@ static void taskqueue_terminate(struct thread **pp, struct taskqueue *tq) { - while (tq->tq_tcount > 0) { + while (tq->tq_tcount > 0 || tq->tq_callouts > 0) { wakeup(tq); TQ_SLEEP(tq, pp, &tq->tq_mutex, PWAIT, "taskqueue_destroy", 0); } @@ -165,30 +183,27 @@ taskqueue_free(struct taskqueue *queue) TQ_LOCK(queue); queue->tq_flags &= ~TQ_FLAGS_ACTIVE; - taskqueue_run_locked(queue); taskqueue_terminate(queue->tq_threads, queue); KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?")); + KASSERT(queue->tq_callouts == 0, ("Armed timeout tasks")); mtx_destroy(&queue->tq_mutex); free(queue->tq_threads, M_TASKQUEUE); free(queue, M_TASKQUEUE); } -int -taskqueue_enqueue(struct taskqueue *queue, struct task *task) +static int +taskqueue_enqueue_locked(struct taskqueue *queue, struct task *task) { struct task *ins; struct task *prev; - TQ_LOCK(queue); - /* * Count multiple enqueues. */ if (task->ta_pending) { if (task->ta_pending < USHRT_MAX) task->ta_pending++; - TQ_UNLOCK(queue); - return 0; + return (0); } /* @@ -216,9 +231,64 @@ taskqueue_enqueue(struct taskqueue *queue, struct task *task) else queue->tq_flags |= TQ_FLAGS_PENDING; + return (0); +} +int +taskqueue_enqueue(struct taskqueue *queue, struct task *task) +{ + int res; + + TQ_LOCK(queue); + res = taskqueue_enqueue_locked(queue, task); TQ_UNLOCK(queue); - return 0; + return (res); +} + +static void +taskqueue_timeout_func(void *arg) +{ + struct taskqueue *queue; + struct timeout_task *timeout_task; + + 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_locked(timeout_task->q, &timeout_task->t); +} + +int +taskqueue_enqueue_timeout(struct taskqueue *queue, + struct timeout_task *timeout_task, int ticks) +{ + int res; + + TQ_LOCK(queue); + KASSERT(timeout_task->q == NULL || timeout_task->q == queue, + ("Migrated queue")); + KASSERT(!queue->tq_spin, ("Timeout for spin-queue")); + timeout_task->q = queue; + res = timeout_task->t.ta_pending; + if (ticks == 0) { + taskqueue_enqueue_locked(queue, &timeout_task->t); + } else { + if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) { + res++; + } else { + queue->tq_callouts++; + timeout_task->f |= DT_CALLOUT_ARMED; + if (ticks < 0) + ticks = -ticks; /* Ignore overflow. */ + } + if (ticks > 0) { + callout_reset(&timeout_task->c, ticks, + taskqueue_timeout_func, timeout_task); + } + } + TQ_UNLOCK(queue); + return (res); } void @@ -297,26 +367,76 @@ task_is_running(struct taskqueue *queue, struct task *task) return (0); } +static int +taskqueue_cancel_locked(struct taskqueue *queue, struct task *task, + u_int *pendp) +{ + + if (task->ta_pending > 0) + STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link); + if (pendp != NULL) + *pendp = task->ta_pending; + task->ta_pending = 0; + return (task_is_running(queue, task) ? EBUSY : 0); +} + +int +taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp) +{ + u_int pending; + int error; + + TQ_LOCK(queue); + pending = task->ta_pending; + error = taskqueue_cancel_locked(queue, task, pendp); + TQ_UNLOCK(queue); + + return (error); +} + +int +taskqueue_cancel_timeout(struct taskqueue *queue, + struct timeout_task *timeout_task, u_int *pendp) +{ + u_int pending, pending1; + int error; + + TQ_LOCK(queue); + pending = !!callout_stop(&timeout_task->c); + error = taskqueue_cancel_locked(queue, &timeout_task->t, &pending1); + if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) { + timeout_task->f &= ~DT_CALLOUT_ARMED; + queue->tq_callouts--; + } + TQ_UNLOCK(queue); + + if (pendp != NULL) + *pendp = pending + pending1; + return (error); +} + void taskqueue_drain(struct taskqueue *queue, struct task *task) { -#ifndef __rtems__ - if (queue->tq_spin) { /* XXX */ - mtx_lock_spin(&queue->tq_mutex); - while (task->ta_pending != 0 || task_is_running(queue, task)) - msleep_spin(task, &queue->tq_mutex, "-", 0); - mtx_unlock_spin(&queue->tq_mutex); - } else { -#endif /* __rtems__ */ - WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); - mtx_lock(&queue->tq_mutex); - while (task->ta_pending != 0 || task_is_running(queue, task)) - msleep(task, &queue->tq_mutex, PWAIT, "-", 0); - mtx_unlock(&queue->tq_mutex); #ifndef __rtems__ - } + if (!queue->tq_spin) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); #endif /* __rtems__ */ + + TQ_LOCK(queue); + while (task->ta_pending != 0 || task_is_running(queue, task)) + TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0); + TQ_UNLOCK(queue); +} + +void +taskqueue_drain_timeout(struct taskqueue *queue, + struct timeout_task *timeout_task) +{ + + callout_drain(&timeout_task->c); + taskqueue_drain(queue, &timeout_task->t); } static void @@ -423,6 +543,7 @@ taskqueue_thread_loop(void *arg) break; TQ_SLEEP(tq, tq, &tq->tq_mutex, 0, "-", 0); } + taskqueue_run_locked(tq); /* rendezvous with thread that asked us to terminate */ tq->tq_tcount--; |