summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/subr_taskqueue.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/kern/subr_taskqueue.c
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-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.c201
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--;