patch-2.4.0-test12 linux/include/linux/tqueue.h

Next file: linux/include/linux/tty.h
Previous file: linux/include/linux/swap.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
@@ -14,6 +14,7 @@
 #define _LINUX_TQUEUE_H
 
 #include <linux/spinlock.h>
+#include <linux/list.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
 
@@ -29,37 +30,33 @@
  *   used as a bottom half handler.  This is for example useful for bottom
  *   halfs, which want to be delayed until the next clock tick.
  *
- * Problems:
- * - The queue_task_irq() inline function is only atomic with respect to itself.
- *   Problems can occur, when queue_task_irq() is called from a normal system
- *   call, and an interrupt comes in.  No problems occur, when queue_task_irq()
- *   is called from an interrupt or bottom half, and interrupted, as run_task_queue()
- *   will not be executed/continued before the last interrupt returns.  If in
- *   doubt, use queue_task(), not queue_task_irq().
+ * Notes:
  * - Bottom halfs are called in the reverse order that they were linked into
  *   the list.
  */
 
 struct tq_struct {
-	struct tq_struct *next;		/* linked list of active bh's */
+	struct list_head list;		/* linked list of active bh's */
 	unsigned long sync;		/* must be initialized to zero */
 	void (*routine)(void *);	/* function to call */
 	void *data;			/* argument to function */
 };
 
-typedef struct tq_struct * task_queue;
+typedef struct list_head task_queue;
 
-#define DECLARE_TASK_QUEUE(q)  task_queue q = NULL
+#define DECLARE_TASK_QUEUE(q)	LIST_HEAD(q)
+#define TQ_ACTIVE(q)		(!list_empty(&q))
 
-extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;
+extern task_queue tq_timer, tq_immediate, tq_disk;
 
 /*
  * To implement your own list of active bottom halfs, use the following
  * two definitions:
  *
- * struct tq_struct *my_bh = NULL;
+ * DECLARE_TASK_QUEUE(my_bh);
  * struct tq_struct run_my_bh = {
- *	0, 0, (void (*)(void *)) run_task_queue, &my_bh
+ * 	routine: (void (*)(void *)) run_task_queue,
+ *	data: &my_bh
  * };
  *
  * To activate a bottom half on your list, use:
@@ -78,18 +75,21 @@
 extern spinlock_t tqueue_lock;
 
 /*
- * queue_task
+ * Queue a task on a tq.  Return non-zero if it was successfully
+ * added.
  */
-static inline void queue_task(struct tq_struct *bh_pointer,
+static inline int queue_task(struct tq_struct *bh_pointer,
 			   task_queue *bh_list)
 {
+	int ret = 0;
 	if (!test_and_set_bit(0,&bh_pointer->sync)) {
 		unsigned long flags;
 		spin_lock_irqsave(&tqueue_lock, flags);
-		bh_pointer->next = *bh_list;
-		*bh_list = bh_pointer;
+		list_add_tail(&bh_pointer->list, bh_list);
 		spin_unlock_irqrestore(&tqueue_lock, flags);
+		ret = 1;
 	}
+	return ret;
 }
 
 /*
@@ -97,28 +97,29 @@
  */
 static inline void run_task_queue(task_queue *list)
 {
-	if (*list) {
+	while (!list_empty(list)) {
 		unsigned long flags;
-		struct tq_struct *p;
+		struct list_head *next;
 
 		spin_lock_irqsave(&tqueue_lock, flags);
-		p = *list;
-		*list = NULL;
-		spin_unlock_irqrestore(&tqueue_lock, flags);
-		
-		while (p) {
+		next = list->next;
+		if (next != list) {
 			void *arg;
 			void (*f) (void *);
-			struct tq_struct *save_p;
-			arg    = p -> data;
-			f      = p -> routine;
-			save_p = p;
-			p      = p -> next;
-			smp_mb();
-			save_p -> sync = 0;
+			struct tq_struct *p;
+
+			list_del(next);
+			p = list_entry(next, struct tq_struct, list);
+			arg = p->data;
+			f = p->routine;
+			p->sync = 0;
+			spin_unlock_irqrestore(&tqueue_lock, flags);
+
 			if (f)
-				(*f)(arg);
+				f(arg);
+			continue;
 		}
+		spin_unlock_irqrestore(&tqueue_lock, flags);
 	}
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)