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 <linux/spinlock.h> 17#include <linux/list.h> 18#include <asm/bitops.h> 19#include <asm/system.h> 20 21/* 22 * New proposed "bottom half" handlers: 23 * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de 24 * 25 * Advantages: 26 * - Bottom halfs are implemented as a linked list. You can have as many 27 * of them, as you want. 28 * - No more scanning of a bit field is required upon call of a bottom half. 29 * - Support for chained bottom half lists. The run_task_queue() function can be 30 * used as a bottom half handler. This is for example useful for bottom 31 * halfs, which want to be delayed until the next clock tick. 32 * 33 * Notes: 34 * - Bottom halfs are called in the reverse order that they were linked into 35 * the list. 36 */ 37 38struct tq_struct { 39 struct list_head list; /* linked list of active bh's */ 40 unsigned long sync; /* must be initialized to zero */ 41 void (*routine)(void *); /* function to call */ 42 void *data; /* argument to function */ 43}; 44 45/* 46 * Emit code to initialise a tq_struct's routine and data pointers 47 */ 48#define PREPARE_TQUEUE(_tq, _routine, _data) \ 49 do { \ 50 (_tq)->routine = _routine; \ 51 (_tq)->data = _data; \ 52 } while (0) 53 54/* 55 * Emit code to initialise all of a tq_struct 56 */ 57#define INIT_TQUEUE(_tq, _routine, _data) \ 58 do { \ 59 INIT_LIST_HEAD(&(_tq)->list); \ 60 (_tq)->sync = 0; \ 61 PREPARE_TQUEUE((_tq), (_routine), (_data)); \ 62 } while (0) 63 64typedef struct list_head task_queue; 65 66#define DECLARE_TASK_QUEUE(q) LIST_HEAD(q) 67#define TQ_ACTIVE(q) (!list_empty(&q)) 68 69extern task_queue tq_timer, tq_immediate, tq_disk; 70 71/* 72 * To implement your own list of active bottom halfs, use the following 73 * two definitions: 74 * 75 * DECLARE_TASK_QUEUE(my_tqueue); 76 * struct tq_struct my_task = { 77 * routine: (void (*)(void *)) my_routine, 78 * data: &my_data 79 * }; 80 * 81 * To activate a bottom half on a list, use: 82 * 83 * queue_task(&my_task, &my_tqueue); 84 * 85 * To later run the queued tasks use 86 * 87 * run_task_queue(&my_tqueue); 88 * 89 * This allows you to do deferred processing. For example, you could 90 * have a task queue called tq_timer, which is executed within the timer 91 * interrupt. 92 */ 93 94extern spinlock_t tqueue_lock; 95 96/* 97 * Queue a task on a tq. Return non-zero if it was successfully 98 * added. 99 */ 100static inline int queue_task(struct tq_struct *bh_pointer, task_queue *bh_list) 101{ 102 int ret = 0; 103 if (!test_and_set_bit(0,&bh_pointer->sync)) { 104 unsigned long flags; 105 spin_lock_irqsave(&tqueue_lock, flags); 106 list_add_tail(&bh_pointer->list, bh_list); 107 spin_unlock_irqrestore(&tqueue_lock, flags); 108 ret = 1; 109 } 110 return ret; 111} 112 113/* 114 * Call all "bottom halfs" on a given list. 115 */ 116 117extern void __run_task_queue(task_queue *list); 118 119static inline void run_task_queue(task_queue *list) 120{ 121 if (TQ_ACTIVE(*list)) 122 __run_task_queue(list); 123} 124 125#endif /* _LINUX_TQUEUE_H */ 126

