1 /* 2 * tqueue.h --- task queue handling for Linux. 3 * 4 * Mostly based on a proposed bottom-half replacement code written by 5 * Kai Petzke, wpp@marie.physik.tu-berlin.de. 6 * 7 * Modified for use in the Linux kernel by Theodore Ts'o, 8 * tytso@mit.edu. Any bugs are my fault, not Kai's. 9 * 10 * The original comment follows below. 11 */ 12 13 #ifndef _LINUX_TQUEUE_H 14 #define _LINUX_TQUEUE_H 15 16 #include <asm/bitops.h> 17 #include <asm/system.h> 18 19 /* 20 * New proposed "bottom half" handlers: 21 * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de 22 * 23 * Advantages: 24 * - Bottom halfs are implemented as a linked list. You can have as many 25 * of them, as you want. 26 * - No more scanning of a bit field is required upon call of a bottom half. 27 * - Support for chained bottom half lists. The run_task_queue() function can be 28 * used as a bottom half handler. This is for example useful for bottom 29 * halfs, which want to be delayed until the next clock tick. 30 * 31 * Problems: 32 * - The queue_task_irq() inline function is only atomic with respect to itself. 33 * Problems can occur, when queue_task_irq() is called from a normal system 34 * call, and an interrupt comes in. No problems occur, when queue_task_irq() 35 * is called from an interrupt or bottom half, and interrupted, as run_task_queue() 36 * will not be executed/continued before the last interrupt returns. If in 37 * doubt, use queue_task(), not queue_task_irq(). 38 * - Bottom halfs are called in the reverse order that they were linked into 39 * the list. 40 */ 41 42 struct tq_struct { 43 struct tq_struct *next; /* linked list of active bh's */ 44 int sync; /* must be initialized to zero */ 45 void (*routine)(void *); /* function to call */ 46 void *data; /* argument to function */ 47 }; 48 49 typedef struct tq_struct * task_queue; 50 51 #define DECLARE_TASK_QUEUE(q) task_queue q = NULL 52 53 extern task_queue tq_timer, tq_immediate, tq_scheduler; 54 55 /* 56 * To implement your own list of active bottom halfs, use the following 57 * two definitions: 58 * 59 * struct tq_struct *my_bh = NULL; 60 * struct tq_struct run_my_bh = { 61 * 0, 0, (void *)(void *) run_task_queue, &my_bh 62 * }; 63 * 64 * To activate a bottom half on your list, use: 65 * 66 * queue_task(tq_pointer, &my_bh); 67 * 68 * To run the bottom halfs on your list put them on the immediate list by: 69 * 70 * queue_task(&run_my_bh, &tq_immediate); 71 * 72 * This allows you to do deferred procession. For example, you could 73 * have a bottom half list tq_timer, which is marked active by the timer 74 * interrupt. 75 */ 76 77 /* 78 * queue_task_irq: put the bottom half handler "bh_pointer" on the list 79 * "bh_list". You may call this function only from an interrupt 80 * handler or a bottom half handler. 81 */ 82 extern __inline__ void queue_task_irq(struct tq_struct *bh_pointer, /* */ 83 task_queue *bh_list) 84 { 85 if (!set_bit(0,&bh_pointer->sync)) { 86 bh_pointer->next = *bh_list; 87 *bh_list = bh_pointer; 88 } 89 } 90 91 /* 92 * queue_task_irq_off: put the bottom half handler "bh_pointer" on the list 93 * "bh_list". You may call this function only when interrupts are off. 94 */ 95 extern __inline__ void queue_task_irq_off(struct tq_struct *bh_pointer, /* */ 96 task_queue *bh_list) 97 { 98 if (!(bh_pointer->sync & 1)) { 99 bh_pointer->sync = 1; 100 bh_pointer->next = *bh_list; 101 *bh_list = bh_pointer; 102 } 103 } 104 105 106 /* 107 * queue_task: as queue_task_irq, but can be called from anywhere. 108 */ 109 extern __inline__ void queue_task(struct tq_struct *bh_pointer, /* */ 110 task_queue *bh_list) 111 { 112 if (!set_bit(0,&bh_pointer->sync)) { 113 unsigned long flags; 114 save_flags(flags); 115 cli(); 116 bh_pointer->next = *bh_list; 117 *bh_list = bh_pointer; 118 restore_flags(flags); 119 } 120 } 121 122 /* 123 * Call all "bottom halfs" on a given list. 124 */ 125 extern __inline__ void run_task_queue(task_queue *list) /* */ 126 { 127 struct tq_struct *p; 128 129 p = xchg(list,NULL); 130 while (p) { 131 void *arg; 132 void (*f) (void *); 133 struct tq_struct *save_p; 134 arg = p -> data; 135 f = p -> routine; 136 save_p = p; 137 p = p -> next; 138 save_p -> sync = 0; 139 (*f)(arg); 140 } 141 } 142 143 #endif /* _LINUX_TQUEUE_H */