00001 /* 00002 * tqueue.h --- task queue handling for Linux. 00003 * 00004 * Mostly based on a proposed bottom-half replacement code written by 00005 * Kai Petzke, wpp@marie.physik.tu-berlin.de. 00006 * 00007 * Modified for use in the Linux kernel by Theodore Ts'o, 00008 * tytso@mit.edu. Any bugs are my fault, not Kai's. 00009 * 00010 * The original comment follows below. 00011 */ 00012 00013 #ifndef _LINUX_TQUEUE_H 00014 #define _LINUX_TQUEUE_H 00015 00016 #include <asm/bitops.h> 00017 #include <asm/system.h> 00018 #include <asm/spinlock.h> 00019 00020 /* 00021 * New proposed "bottom half" handlers: 00022 * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de 00023 * 00024 * Advantages: 00025 * - Bottom halfs are implemented as a linked list. You can have as many 00026 * of them, as you want. 00027 * - No more scanning of a bit field is required upon call of a bottom half. 00028 * - Support for chained bottom half lists. The run_task_queue() function can be 00029 * used as a bottom half handler. This is for example useful for bottom 00030 * halfs, which want to be delayed until the next clock tick. 00031 * 00032 * Problems: 00033 * - The queue_task_irq() inline function is only atomic with respect to itself. 00034 * Problems can occur, when queue_task_irq() is called from a normal system 00035 * call, and an interrupt comes in. No problems occur, when queue_task_irq() 00036 * is called from an interrupt or bottom half, and interrupted, as run_task_queue() 00037 * will not be executed/continued before the last interrupt returns. If in 00038 * doubt, use queue_task(), not queue_task_irq(). 00039 * - Bottom halfs are called in the reverse order that they were linked into 00040 * the list. 00041 */ 00042 00043 struct tq_struct { 00044 struct tq_struct *next; /* linked list of active bh's */ 00045 unsigned long sync; /* must be initialized to zero */ 00046 void (*routine)(void *); /* function to call */ 00047 void *data; /* argument to function */ 00048 }; 00049 00050 typedef struct tq_struct * task_queue; 00051 00052 #define DECLARE_TASK_QUEUE(q) task_queue q = NULL 00053 #define TQ_ACTIVE(q) ((q) != NULL) 00054 00055 extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk; 00056 00057 /* 00058 * To implement your own list of active bottom halfs, use the following 00059 * two definitions: 00060 * 00061 * struct tq_struct *my_bh = NULL; 00062 * struct tq_struct run_my_bh = { 00063 * 0, 0, (void (*)(void *)) run_task_queue, &my_bh 00064 * }; 00065 * 00066 * To activate a bottom half on your list, use: 00067 * 00068 * queue_task(tq_pointer, &my_bh); 00069 * 00070 * To run the bottom halfs on your list put them on the immediate list by: 00071 * 00072 * queue_task(&run_my_bh, &tq_immediate); 00073 * 00074 * This allows you to do deferred procession. For example, you could 00075 * have a bottom half list tq_timer, which is marked active by the timer 00076 * interrupt. 00077 */ 00078 00079 extern spinlock_t tqueue_lock; 00080 00081 /* 00082 * Queue a task on a tq. Return non-zero if it was successfully 00083 * added. 00084 */ 00085 extern __inline__ int queue_task(struct tq_struct *bh_pointer, 00086 task_queue *bh_list) 00087 { 00088 int ret = 0; 00089 if (!test_and_set_bit(0,&bh_pointer->sync)) { 00090 unsigned long flags; 00091 spin_lock_irqsave(&tqueue_lock, flags); 00092 bh_pointer->next = *bh_list; 00093 *bh_list = bh_pointer; 00094 spin_unlock_irqrestore(&tqueue_lock, flags); 00095 ret = 1; 00096 } 00097 return ret; 00098 } 00099 00100 00101 /* 00102 * Call all "bottom halfs" on a given list. 00103 */ 00104 extern __inline__ void run_task_queue(task_queue *list) 00105 { 00106 if (*list) { 00107 unsigned long flags; 00108 struct tq_struct *p; 00109 00110 spin_lock_irqsave(&tqueue_lock, flags); 00111 p = *list; 00112 *list = NULL; 00113 spin_unlock_irqrestore(&tqueue_lock, flags); 00114 00115 while (p) { 00116 void *arg; 00117 void (*f) (void *); 00118 struct tq_struct *save_p; 00119 arg = p -> data; 00120 f = p -> routine; 00121 save_p = p; 00122 p = p -> next; 00123 mb(); 00124 save_p -> sync = 0; 00125 (*f)(arg); 00126 } 00127 } 00128 } 00129 00130 #endif /* _LINUX_TQUEUE_H */