diff options
authorMatthew D Fleming <mdf@FreeBSD.org>2010-11-08 20:56:31 +0000
committerMatthew D Fleming <mdf@FreeBSD.org>2010-11-08 20:56:31 +0000
commitf46276a9b0dd5274905bff812f58edc1c17571d3 (patch)
parent75ba301116c07a74dfdc5fc9643f4a251407f2bc (diff)
Add a taskqueue_cancel(9) to cancel a pending task without waiting for
it to run as taskqueue_drain(9) does. Requested by: hselasky Original code: jeff Reviewed by: jhb MFC after: 2 weeks
Notes: svn path=/head/; revision=215011
4 files changed, 48 insertions, 0 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index e6a490a9d98a..ecb1dff57610 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1212,6 +1212,7 @@ MLINKS+=sysctl_ctx_init.9 sysctl_ctx_entry_add.9 \
sysctl_ctx_init.9 sysctl_ctx_entry_find.9 \
sysctl_ctx_init.9 sysctl_ctx_free.9
MLINKS+=taskqueue.9 TASK_INIT.9 \
+ taskqueue.9 taskqueue_cancel.9 \
taskqueue.9 taskqueue_create.9 \
taskqueue.9 taskqueue_create_fast.9 \
taskqueue.9 TASKQUEUE_DECLARE.9 \
diff --git a/share/man/man9/taskqueue.9 b/share/man/man9/taskqueue.9
index d5e096af3ad6..168ca70b0485 100644
--- a/share/man/man9/taskqueue.9
+++ b/share/man/man9/taskqueue.9
@@ -63,6 +63,8 @@ struct task {
.Fn taskqueue_enqueue "struct taskqueue *queue" "struct task *task"
.Ft int
.Fn taskqueue_enqueue_fast "struct taskqueue *queue" "struct task *task"
+.Ft int
+.Fn taskqueue_cancel "struct taskqueue *queue" "struct task *task" "u_int *pendp"
.Ft void
.Fn taskqueue_drain "struct taskqueue *queue" "struct task *task"
.Ft int
@@ -162,6 +164,31 @@ is called on the task pointer passed to
.Fn taskqueue_enqueue .
+.Fn taskqueue_cancel
+function is used to cancel a task.
+.Va ta_pending
+count is cleared, and the old value returned in the reference
+.Fa pendp ,
+if it is non- Dv NULL .
+If the task is currently running,
+is returned, otherwise 0.
+To implement a blocking
+.Fn taskqueue_cancel
+that waits for a running task to finish, it could look like:
+.Bd -literal -offset indent
+while (taskqueue_cancel(tq, task, NULL) != 0)
+ taskqueue_drain(tq, task);
+Note that, as with
+.Fn taskqueue_drain ,
+the caller is responsible for ensuring that the task is not re-enqueued
+after being canceled.
.Fn taskqueue_drain
function is used to wait for the task to finish.
There is no guarantee that the task will not be
diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c
index fd6dd4f54885..d31d668a4242 100644
--- a/sys/kern/subr_taskqueue.c
+++ b/sys/kern/subr_taskqueue.c
@@ -275,6 +275,24 @@ task_is_running(struct taskqueue *queue, struct task *task)
return (0);
+taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp)
+ u_int pending;
+ int error;
+ TQ_LOCK(queue);
+ if ((pending = task->ta_pending) > 0)
+ STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link);
+ task->ta_pending = 0;
+ error = task_is_running(queue, task) ? EBUSY : 0;
+ TQ_UNLOCK(queue);
+ if (pendp != NULL)
+ *pendp = pending;
+ return (error);
taskqueue_drain(struct taskqueue *queue, struct task *task)
diff --git a/sys/sys/taskqueue.h b/sys/sys/taskqueue.h
index bf2e4ee31d0d..c7a7b16023a8 100644
--- a/sys/sys/taskqueue.h
+++ b/sys/sys/taskqueue.h
@@ -54,6 +54,8 @@ struct taskqueue *taskqueue_create(const char *name, int mflags,
int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
const char *name, ...) __printflike(4, 5);
int taskqueue_enqueue(struct taskqueue *queue, struct task *task);
+int taskqueue_cancel(struct taskqueue *queue, struct task *task,
+ u_int *pendp);
void taskqueue_drain(struct taskqueue *queue, struct task *task);
void taskqueue_free(struct taskqueue *queue);
void taskqueue_run(struct taskqueue *queue);