Initial import
[openvswitch] / datapath / linux-2.4 / compat-2.4 / rcupdate.c
1 /*
2  * Distributed under the terms of the GNU GPL version 2.
3  */
4
5 #include <linux/module.h>
6 #include <linux/rcupdate.h>
7 #include <linux/sched.h>
8 #include <linux/tqueue.h>
9 #include <linux/smp.h>
10 #include <linux/completion.h>
11
12 #include "compat24.h"
13
14 #ifdef CONFIG_SMP
15 #error "SMP configurations not supported for RCU backport."
16 #endif
17
18 static int default_blimit = 10;
19 static int blimit;
20 static int qhimark = 10000;
21 static int qlowmark = 100;
22
23 static struct rcu_head *head, **tail;
24 static int qlen = 0;
25
26 static struct tq_struct rcu_task;
27
28 /*
29  * Invoke the completed RCU callbacks. They are expected to be in
30  * a per-cpu list.
31  */
32 static void rcu_task_routine(void *unused)
33 {
34         struct rcu_head *list, *next;
35         int count = 0;
36
37         local_irq_disable();
38         list = head;
39         head = NULL;
40         tail = &head;
41         local_irq_enable();
42
43         while (list) {
44                 next = list->next;
45                 prefetch(next);
46                 list->func(list);
47                 list = next;
48                 if (++count >= blimit)
49                         break;
50         }
51
52         local_irq_disable();
53         qlen -= count;
54         local_irq_enable();
55         if (blimit == INT_MAX && qlen <= qlowmark)
56                 blimit = default_blimit;
57
58         if (head)
59                 schedule_task(&rcu_task);
60 }
61
62
63 static inline void force_quiescent_state(void)
64 {
65         current->need_resched = 1;
66 }
67
68 /**
69  * call_rcu - Queue an RCU callback for invocation after a grace period.
70  * @rcu: structure to be used for queueing the RCU updates.
71  * @func: actual update function to be invoked after the grace period
72  *
73  * The update function will be invoked some time after a full grace
74  * period elapses, in other words after all currently executing RCU
75  * read-side critical sections have completed.  RCU read-side critical
76  * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
77  * and may be nested.
78  */
79 void call_rcu(struct rcu_head *rcu, void (*func)(struct rcu_head *rcu))
80 {
81         unsigned long flags;
82
83         /* FIXME?  Following may be mildly expensive, may be worthwhile to
84            optimize common case. */
85         schedule_task(&rcu_task);
86
87         rcu->func = func;
88         rcu->next = NULL;
89         local_irq_save(flags);
90         *tail = rcu;
91         tail = &rcu->next;
92         if (unlikely(++qlen > qhimark)) {
93                 blimit = INT_MAX;
94                 force_quiescent_state();
95         }
96         local_irq_restore(flags);
97 }
98 EXPORT_SYMBOL(call_rcu);
99
100 void rcu_init(void) 
101 {
102         head = NULL;
103         tail = &head;
104         blimit = default_blimit;
105         rcu_task.routine = rcu_task_routine;
106 }
107
108 struct rcu_synchronize {
109         struct rcu_head head;
110         struct completion completion;
111 };
112
113 /* Because of FASTCALL declaration of complete, we use this wrapper */
114 static void wakeme_after_rcu(struct rcu_head  *head)
115 {
116         struct rcu_synchronize *rcu;
117
118         rcu = container_of(head, struct rcu_synchronize, head);
119         complete(&rcu->completion);
120 }
121
122 /**
123  * synchronize_rcu - wait until a grace period has elapsed.
124  *
125  * Control will return to the caller some time after a full grace
126  * period has elapsed, in other words after all currently executing RCU
127  * read-side critical sections have completed.  RCU read-side critical
128  * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
129  * and may be nested.
130  *
131  * If your read-side code is not protected by rcu_read_lock(), do -not-
132  * use synchronize_rcu().
133  */
134 void synchronize_rcu(void)
135 {
136         struct rcu_synchronize rcu;
137
138         init_completion(&rcu.completion);
139         /* Will wake me after RCU finished */
140         call_rcu(&rcu.head, wakeme_after_rcu);
141
142         /* Wait for it */
143         wait_for_completion(&rcu.completion);
144 }
145 EXPORT_SYMBOL(synchronize_rcu);