Date: Mon, 17 Feb 2014 15:24:50 +0000 (UTC) From: Andriy Gapon <avg@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r262063 - in stable/8: share/man/man9 sys/kern sys/sys Message-ID: <201402171524.s1HFOoDg009802@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: avg Date: Mon Feb 17 15:24:49 2014 New Revision: 262063 URL: http://svnweb.freebsd.org/changeset/base/262063 Log: MFC r258713,262062: add taskqueue_drain_all Modified: stable/8/share/man/man9/Makefile stable/8/share/man/man9/taskqueue.9 stable/8/sys/kern/subr_taskqueue.c stable/8/sys/sys/taskqueue.h Directory Properties: stable/8/share/man/man9/ (props changed) stable/8/sys/ (props changed) stable/8/sys/kern/ (props changed) stable/8/sys/sys/ (props changed) Modified: stable/8/share/man/man9/Makefile ============================================================================== --- stable/8/share/man/man9/Makefile Mon Feb 17 15:20:03 2014 (r262062) +++ stable/8/share/man/man9/Makefile Mon Feb 17 15:24:49 2014 (r262063) @@ -1262,19 +1262,22 @@ MLINKS+=sysctl_ctx_init.9 sysctl_ctx_ent sysctl_ctx_init.9 sysctl_ctx_free.9 MLINKS+=taskqueue.9 TASK_INIT.9 \ taskqueue.9 TASK_INITIALIZER.9 \ + taskqueue.9 taskqueue_block.9 \ taskqueue.9 taskqueue_create.9 \ taskqueue.9 taskqueue_create_fast.9 \ taskqueue.9 TASKQUEUE_DECLARE.9 \ taskqueue.9 TASKQUEUE_DEFINE.9 \ taskqueue.9 TASKQUEUE_DEFINE_THREAD.9 \ taskqueue.9 taskqueue_drain.9 \ + taskqueue.9 taskqueue_drain_all.9 \ taskqueue.9 taskqueue_enqueue.9 \ taskqueue.9 taskqueue_enqueue_fast.9 \ taskqueue.9 TASKQUEUE_FAST_DEFINE.9 \ taskqueue.9 TASKQUEUE_FAST_DEFINE_THREAD.9 \ taskqueue.9 taskqueue_free.9 \ taskqueue.9 taskqueue_member.9 \ - taskqueue.9 taskqueue_run.9 + taskqueue.9 taskqueue_run.9 \ + taskqueue.9 taskqueue_unblock.9 MLINKS+=time.9 boottime.9 \ time.9 time_second.9 \ time.9 time_uptime.9 Modified: stable/8/share/man/man9/taskqueue.9 ============================================================================== --- stable/8/share/man/man9/taskqueue.9 Mon Feb 17 15:20:03 2014 (r262062) +++ stable/8/share/man/man9/taskqueue.9 Mon Feb 17 15:24:49 2014 (r262063) @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 18, 2009 +.Dd January 24, 2014 .Dt TASKQUEUE 9 .Os .Sh NAME @@ -69,6 +69,12 @@ struct task { .Fn taskqueue_run_fast "struct taskqueue *queue" .Ft void .Fn taskqueue_drain "struct taskqueue *queue" "struct task *task" +.Ft void +.Fn taskqueue_drain_all "struct taskqueue *queue" +.Ft void +.Fn taskqueue_block "struct taskqueue *queue" +.Ft void +.Fn taskqueue_unblock "struct taskqueue *queue" .Ft int .Fn taskqueue_member "struct taskqueue *queue" "struct thread *td" .Fn TASK_INIT "struct task *task" "int priority" "task_fn_t *func" "void *context" @@ -176,6 +182,73 @@ function is used to wait for the task to There is no guarantee that the task will not be enqueued after call to .Fn taskqueue_drain . +If the caller wants to put the task into a known state, +then before calling +.Fn taskqueue_drain +the caller should use out-of-band means to ensure that the task +would not be enqueued. +For example, if the task is enqueued by an interrupt filter, then +the interrupt could be disabled. +.Pp +The +.Fn taskqueue_drain_all +function is used to wait for all pending and running tasks that +are enqueued on the taskqueue to finish. +The caller must arrange that the tasks are not re-enqueued. +Note that +.Fn taskqueue_drain_all +currently does not handle tasks with delayed enqueueing. +.Pp +The +.Fn taskqueue_block +function blocks the taskqueue. +It prevents any enqueued but not running tasks from being executed. +Future calls to +.Fn taskqueue_enqueue +will enqueue tasks, but the tasks will not be run until +.Fn taskqueue_unblock +is called. +Please note that +.Fn taskqueue_block +does not wait for any currently running tasks to finish. +Thus, the +.Fn taskqueue_block +does not provide a guarantee that +.Fn taskqueue_run +is not running after +.Fn taskqueue_block +returns, but it does provide a guarantee that +.Fn taskqueue_run +will not be called again +until +.Fn taskqueue_unblock +is called. +If the caller requires a guarantee that +.Fn taskqueue_run +is not running, then this must be arranged by the caller. +Note that if +.Fn taskqueue_drain +is called on a task that is enqueued on a taskqueue that is blocked by +.Fn taskqueue_block , +then +.Fn taskqueue_drain +can not return until the taskqueue is unblocked. +This can result in a deadlock if the thread blocked in +.Fn taskqueue_drain +is the thread that is supposed to call +.Fn taskqueue_unblock . +Thus, use of +.Fn taskqueue_drain +after +.Fn taskqueue_block +is discouraged, because the state of the task can not be known in advance. +The same caveat applies to +.Fn taskqueue_drain_all . +.Pp +The +.Fn taskqueue_unblock +function unblocks the previously blocked taskqueue. +All enqueued tasks can be run after this call. .Pp The .Fn taskqueue_member Modified: stable/8/sys/kern/subr_taskqueue.c ============================================================================== --- stable/8/sys/kern/subr_taskqueue.c Mon Feb 17 15:20:03 2014 (r262062) +++ stable/8/sys/kern/subr_taskqueue.c Mon Feb 17 15:24:49 2014 (r262063) @@ -202,6 +202,15 @@ taskqueue_enqueue(struct taskqueue *queu return 0; } +static void +taskqueue_drain_running(struct taskqueue *queue) +{ + + while (!TAILQ_EMPTY(&queue->tq_active)) + TQ_SLEEP(queue, &queue->tq_active, &queue->tq_mutex, + PWAIT, "-", 0); +} + void taskqueue_block(struct taskqueue *queue) { @@ -254,6 +263,8 @@ taskqueue_run_locked(struct taskqueue *q wakeup(task); } TAILQ_REMOVE(&queue->tq_active, &tb, tb_link); + if (TAILQ_EMPTY(&queue->tq_active)) + wakeup(&queue->tq_active); } void @@ -296,6 +307,25 @@ taskqueue_drain(struct taskqueue *queue, } } +void +taskqueue_drain_all(struct taskqueue *queue) +{ + struct task *task; + + if (!queue->tq_spin) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); + + TQ_LOCK(queue); + task = STAILQ_LAST(&queue->tq_queue, task, ta_link); + if (task != NULL) + while (task->ta_pending != 0) + TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0); + taskqueue_drain_running(queue); + KASSERT(STAILQ_EMPTY(&queue->tq_queue), + ("taskqueue queue is not empty after draining")); + TQ_UNLOCK(queue); +} + static void taskqueue_swi_enqueue(void *context) { Modified: stable/8/sys/sys/taskqueue.h ============================================================================== --- stable/8/sys/sys/taskqueue.h Mon Feb 17 15:20:03 2014 (r262062) +++ stable/8/sys/sys/taskqueue.h Mon Feb 17 15:24:49 2014 (r262063) @@ -55,6 +55,7 @@ int taskqueue_start_threads(struct taskq const char *name, ...) __printflike(4, 5); int taskqueue_enqueue(struct taskqueue *queue, struct task *task); void taskqueue_drain(struct taskqueue *queue, struct task *task); +void taskqueue_drain_all(struct taskqueue *queue); void taskqueue_free(struct taskqueue *queue); void taskqueue_run(struct taskqueue *queue); void taskqueue_block(struct taskqueue *queue);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402171524.s1HFOoDg009802>