Date: Mon, 17 Feb 2014 15:32:08 +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-10@freebsd.org Subject: svn commit: r262065 - in stable/10: share/man/man9 sys/kern sys/sys Message-ID: <201402171532.s1HFW8w7013373@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: avg Date: Mon Feb 17 15:32:08 2014 New Revision: 262065 URL: http://svnweb.freebsd.org/changeset/base/262065 Log: MFC r258713,262062: add taskqueue_drain_all Modified: stable/10/share/man/man9/Makefile stable/10/share/man/man9/taskqueue.9 stable/10/sys/kern/subr_taskqueue.c stable/10/sys/sys/taskqueue.h Directory Properties: stable/10/ (props changed) Modified: stable/10/share/man/man9/Makefile ============================================================================== --- stable/10/share/man/man9/Makefile Mon Feb 17 15:29:46 2014 (r262064) +++ stable/10/share/man/man9/Makefile Mon Feb 17 15:32:08 2014 (r262065) @@ -1336,6 +1336,7 @@ MLINKS+=sysctl_ctx_init.9 sysctl_ctx_ent MLINKS+=SYSINIT.9 SYSUNINIT.9 MLINKS+=taskqueue.9 TASK_INIT.9 \ taskqueue.9 TASK_INITIALIZER.9 \ + taskqueue.9 taskqueue_block.9 \ taskqueue.9 taskqueue_cancel.9 \ taskqueue.9 taskqueue_create.9 \ taskqueue.9 taskqueue_create_fast.9 \ @@ -1343,13 +1344,15 @@ MLINKS+=taskqueue.9 TASK_INIT.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/10/share/man/man9/taskqueue.9 ============================================================================== --- stable/10/share/man/man9/taskqueue.9 Mon Feb 17 15:29:46 2014 (r262064) +++ stable/10/share/man/man9/taskqueue.9 Mon Feb 17 15:32:08 2014 (r262065) @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 4, 2012 +.Dd January 24, 2014 .Dt TASKQUEUE 9 .Os .Sh NAME @@ -86,6 +86,12 @@ struct timeout_task; .Fn taskqueue_drain "struct taskqueue *queue" "struct task *task" .Ft void .Fn taskqueue_drain_timeout "struct taskqueue *queue" "struct timeout_task *timeout_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" .Ft void @@ -255,6 +261,73 @@ function is used to wait for the schedul 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/10/sys/kern/subr_taskqueue.c ============================================================================== --- stable/10/sys/kern/subr_taskqueue.c Mon Feb 17 15:29:46 2014 (r262064) +++ stable/10/sys/kern/subr_taskqueue.c Mon Feb 17 15:32:08 2014 (r262065) @@ -285,6 +285,15 @@ taskqueue_enqueue_timeout(struct taskque return (res); } +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) { @@ -337,6 +346,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 @@ -421,6 +432,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); +} + +void taskqueue_drain_timeout(struct taskqueue *queue, struct timeout_task *timeout_task) { Modified: stable/10/sys/sys/taskqueue.h ============================================================================== --- stable/10/sys/sys/taskqueue.h Mon Feb 17 15:29:46 2014 (r262064) +++ stable/10/sys/sys/taskqueue.h Mon Feb 17 15:32:08 2014 (r262065) @@ -81,6 +81,7 @@ int taskqueue_cancel_timeout(struct task void taskqueue_drain(struct taskqueue *queue, struct task *task); void taskqueue_drain_timeout(struct taskqueue *queue, struct timeout_task *timeout_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?201402171532.s1HFW8w7013373>