Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Nov 2010 19:30:38 +0100
From:      Hans Petter Selasky <hselasky@c2i.net>
To:        freebsd-current@freebsd.org
Cc:        Weongyo Jeong <weongyo.jeong@gmail.com>, Matthew Fleming <mdf356@gmail.com>, freebsd-usb@freebsd.org, freebsd-arch@freebsd.org
Subject:   Re: [RFC] Outline of USB process integration in the kernel taskqueue system
Message-ID:  <201011051930.38530.hselasky@c2i.net>
In-Reply-To: <201011051836.39697.hselasky@c2i.net>
References:  <201011012054.59551.hselasky@c2i.net> <AANLkTimR7MpZ3nyoWqkCR9a=-S6DR_MCNjPA0q5qg3U4@mail.gmail.com> <201011051836.39697.hselasky@c2i.net>

next in thread | previous in thread | raw e-mail | index | archive | help
--Boundary-00=_O1E1M5DxgzaX2zh
Content-Type: Text/Plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Hi,

In the patch attached to this e-mail I included Matthew Fleming's patch 
aswell.


1) I renamed taskqueue_cancel() into taskqueue_stop(), hence that resembles 
the words of the callout and USB API's terminology for doing the same.

2) I turns out I need to have code in subr_taskqueue.c to be able to make the 
operations atomic.

3) I did not update the manpage in this patch. Will do that before a commit.

4) My patch implements separate state keeping in "struct task_pair", which 
avoids having to change any KPI's for now, like suggested by John Baldwin I 
think.

5) In my implementation I hard-coded the priority argument to zero, so that 
enqueuing is fast.

Comments are welcome!

--HPS

--Boundary-00=_O1E1M5DxgzaX2zh
Content-Type: text/x-patch; charset="iso-8859-1";
	name="0001-Implement-taskqueue_pair.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
	filename="0001-Implement-taskqueue_pair.patch"

=== kern/subr_taskqueue.c
==================================================================
--- kern/subr_taskqueue.c	(revision 214796)
+++ kern/subr_taskqueue.c	(local)
@@ -275,6 +275,25 @@
 	return (0);
 }
 
+int
+taskqueue_stop(struct taskqueue *queue, struct task *task)
+{
+	int retval = 0;
+
+	TQ_LOCK(queue);
+
+	if (task->ta_pending != 0) {
+		STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link);
+		task->ta_pending = 0;
+	}
+	if (task_is_running(queue, task))
+		retval = EBUSY;
+
+	TQ_UNLOCK(queue);
+
+	return (retval);
+}
+
 void
 taskqueue_drain(struct taskqueue *queue, struct task *task)
 {
@@ -288,6 +307,113 @@
 	TQ_UNLOCK(queue);
 }
 
+
+int
+taskqueue_pair_enqueue(struct taskqueue *queue, struct task_pair *tp)
+{
+	struct task *task;
+	int retval;
+	int j;
+
+	TQ_LOCK(queue);
+
+	j = 0;
+	if (tp->tp_task[0].ta_pending > 0)
+		j |= 1;
+	if (tp->tp_task[1].ta_pending > 0)
+		j |= 2;
+
+	if (j == 0) {
+		/* No entries are queued. Just pick a last task. */
+		tp->tp_last = 0;
+		/* Re-queue the last queued task. */
+		task = &tp->tp_task[0];
+	} else if (j == 1) {
+		/* There is only one task pending and the other becomes last. */
+		tp->tp_last = 1;
+		/* Re-queue the last queued task. */
+		task = &tp->tp_task[1];
+	} else if (j == 2) {
+		/* There is only one task pending and the other becomes last. */
+		tp->tp_last = 0;
+		/* Re-queue the last queued task. */
+		task = &tp->tp_task[0];
+	} else {
+		/* Re-queue the last queued task. */
+		task = &tp->tp_task[tp->tp_last];
+		STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link);
+	}
+
+	STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link);
+
+	retval = tp->tp_last + 1;
+	/* store the actual order in the pending count */
+	task->ta_pending = retval;
+
+	if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0)
+		queue->tq_enqueue(queue->tq_context);
+	else
+		queue->tq_flags |= TQ_FLAGS_PENDING;
+
+	TQ_UNLOCK(queue);
+
+	return (retval);
+}
+
+int
+taskqueue_pair_stop(struct taskqueue *queue, struct task_pair *tp)
+{
+	struct task *task;
+	int retval = 0;
+
+	TQ_LOCK(queue);
+
+	task = &tp->tp_task[0];
+	if (task->ta_pending != 0) {
+		STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link);
+		task->ta_pending = 0;
+	}
+	if (task_is_running(queue, task))
+		retval = EBUSY;
+
+	task = &tp->tp_task[1];
+	if (task->ta_pending != 0) {
+		STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link);
+		task->ta_pending = 0;
+	}
+	if (task_is_running(queue, task))
+		retval = EBUSY;
+
+	TQ_UNLOCK(queue);
+
+	return (retval);
+}
+
+void
+taskqueue_pair_drain(struct taskqueue *queue, struct task_pair *tp)
+{
+	struct task *task;
+
+	if (!queue->tq_spin)
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__);
+
+	TQ_LOCK(queue);
+top:
+	task = &tp->tp_task[0];
+	if (task->ta_pending != 0 || task_is_running(queue, task)) {
+		TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0);
+		goto top;
+	}
+
+	task = &tp->tp_task[1];
+	if (task->ta_pending != 0 || task_is_running(queue, task)) {
+		TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0);
+		goto top;
+	}
+
+	TQ_UNLOCK(queue);
+}
+
 static void
 taskqueue_swi_enqueue(void *context)
 {
=== sys/_task.h
==================================================================
--- sys/_task.h	(revision 214796)
+++ sys/_task.h	(local)
@@ -51,4 +51,9 @@
 	void	*ta_context;		/* (c) argument for handler */
 };
 
+struct task_pair {
+	struct task tp_task[2];
+	int tp_last;			/* (q) index of last queued task */
+};
+
 #endif /* !_SYS__TASK_H_ */
=== sys/taskqueue.h
==================================================================
--- sys/taskqueue.h	(revision 214796)
+++ sys/taskqueue.h	(local)
@@ -53,7 +53,11 @@
 				    void *context);
 int	taskqueue_start_threads(struct taskqueue **tqp, int count, int pri,
 				const char *name, ...) __printflike(4, 5);
+int	taskqueue_pair_enqueue(struct taskqueue *queue, struct task_pair *tp);
+int	taskqueue_pair_stop(struct taskqueue *queue, struct task_pair *tp);
+void	taskqueue_pair_drain(struct taskqueue *queue, struct task_pair *tp);
 int	taskqueue_enqueue(struct taskqueue *queue, struct task *task);
+int	taskqueue_stop(struct taskqueue *queue, struct task *task);
 void	taskqueue_drain(struct taskqueue *queue, struct task *task);
 void	taskqueue_free(struct taskqueue *queue);
 void	taskqueue_run(struct taskqueue *queue);
@@ -78,6 +82,15 @@
 } while (0)
 
 /*
+ * Initialise a task pair structure.
+ */
+#define TASK_PAIR_INIT(tp, func, context) do {	\
+	TASK_INIT(&(tp)->tp_task[0], 0, func, context);	\
+	TASK_INIT(&(tp)->tp_task[1], 0, func, context);	\
+	(tp)->tp_last = 0; \
+} while (0)
+
+/*
  * Declare a reference to a taskqueue.
  */
 #define TASKQUEUE_DECLARE(name)			\

--Boundary-00=_O1E1M5DxgzaX2zh--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201011051930.38530.hselasky>