f0a36bb1 |
1 | /* test-fair-rwlock.c |
2 | * |
3 | */ |
4 | |
5 | #include <linux/module.h> |
6 | #include <linux/proc_fs.h> |
7 | #include <linux/sched.h> |
8 | #include <linux/timex.h> |
9 | #include <linux/fair-rwlock.h> |
10 | #include <linux/kthread.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/hardirq.h> |
13 | #include <linux/module.h> |
14 | #include <asm/ptrace.h> |
15 | |
16 | #if (NR_CPUS > 512 && (BITS_PER_LONG == 32 || NR_CPUS > 1048576)) |
17 | #error "fair rwlock needs more bits per long to deal with that many CPUs" |
18 | #endif |
19 | |
20 | #define THREAD_ROFFSET 1UL |
21 | #define THREAD_RMASK ((NR_CPUS - 1) * THREAD_ROFFSET) |
22 | #define SOFTIRQ_ROFFSET (THREAD_RMASK + 1) |
23 | #define SOFTIRQ_RMASK ((NR_CPUS - 1) * SOFTIRQ_ROFFSET) |
24 | #define HARDIRQ_ROFFSET ((SOFTIRQ_RMASK | THREAD_RMASK) + 1) |
25 | #define HARDIRQ_RMASK ((NR_CPUS - 1) * HARDIRQ_ROFFSET) |
26 | |
27 | #define THREAD_WMASK (1UL << (BITS_PER_LONG - 3)) |
28 | #define SOFTIRQ_WMASK (1UL << (BITS_PER_LONG - 2)) |
29 | #define HARDIRQ_WMASK (1UL << (BITS_PER_LONG - 1)) |
30 | |
31 | |
32 | #define NR_VARS 100 |
33 | #define NR_WRITERS 3 |
34 | #define NR_READERS 6 |
35 | #define NR_INTERRUPT_READERS 2 |
36 | |
37 | static int var[NR_VARS]; |
38 | static struct task_struct *reader_threads[NR_READERS]; |
39 | static struct task_struct *writer_threads[NR_WRITERS]; |
40 | static struct task_struct *interrupt_reader; |
41 | |
42 | static struct fair_rwlock frwlock = { |
43 | .value = ATOMIC_LONG_INIT(0), |
44 | .wlock = __SPIN_LOCK_UNLOCKED(&frwlock.wlock), |
45 | }; |
46 | |
47 | struct proc_dir_entry *pentry = NULL; |
48 | |
49 | static int reader_thread(void *data) |
50 | { |
51 | int i; |
52 | int prev, cur; |
53 | unsigned long iter = 0; |
54 | |
55 | printk("reader_thread/%lu runnning\n", (unsigned long)data); |
56 | do { |
57 | iter++; |
58 | fair_read_lock(&frwlock); |
59 | prev = var[0]; |
60 | for (i = 1; i < NR_VARS; i++) { |
61 | cur = var[i]; |
62 | if (cur != prev) |
63 | printk(KERN_ALERT |
64 | "Unequal cur %d/prev %d at i %d, iter %lu " |
65 | "in thread\n", cur, prev, i, iter); |
66 | } |
67 | fair_read_unlock(&frwlock); |
68 | //msleep(100); |
69 | } while (!kthread_should_stop()); |
70 | printk("reader_thread/%lu iterations : %lu\n", |
71 | (unsigned long)data, iter); |
72 | return 0; |
73 | } |
74 | |
75 | static void interrupt_reader_ipi(void *data) |
76 | { |
77 | int i; |
78 | int prev, cur; |
79 | |
80 | fair_read_lock(&frwlock); |
81 | prev = var[0]; |
82 | for (i = 1; i < NR_VARS; i++) { |
83 | cur = var[i]; |
84 | if (cur != prev) |
85 | printk(KERN_ALERT |
86 | "Unequal cur %d/prev %d at i %d in interrupt\n", |
87 | cur, prev, i); |
88 | } |
89 | fair_read_unlock(&frwlock); |
90 | } |
91 | |
92 | static int interrupt_reader_thread(void *data) |
93 | { |
94 | unsigned long iter = 0; |
95 | do { |
96 | iter++; |
97 | on_each_cpu(interrupt_reader_ipi, NULL, 0); |
98 | msleep(100); |
99 | } while (!kthread_should_stop()); |
100 | printk("interrupt_reader_thread/%lu iterations : %lu\n", |
101 | (unsigned long)data, iter); |
102 | return 0; |
103 | } |
104 | |
105 | static int writer_thread(void *data) |
106 | { |
107 | int i; |
108 | int new; |
109 | unsigned long iter = 0; |
110 | |
111 | printk("writer_thread/%lu runnning\n", (unsigned long)data); |
112 | do { |
113 | iter++; |
114 | fair_write_lock_irq(&frwlock); |
115 | //fair_write_lock(&frwlock); |
116 | new = (int)get_cycles(); |
117 | for (i = 0; i < NR_VARS; i++) { |
118 | var[i] = new; |
119 | } |
120 | //fair_write_unlock(&frwlock); |
121 | fair_write_unlock_irq(&frwlock); |
122 | //msleep(100); |
123 | } while (!kthread_should_stop()); |
124 | printk("writer_thread/%lu iterations : %lu\n", |
125 | (unsigned long)data, iter); |
126 | return 0; |
127 | } |
128 | |
129 | static void fair_rwlock_create(void) |
130 | { |
131 | unsigned long i; |
132 | |
133 | for (i = 0; i < NR_READERS; i++) { |
134 | printk("starting reader thread %lu\n", i); |
135 | reader_threads[i] = kthread_run(reader_thread, (void *)i, |
136 | "frwlock_reader"); |
137 | BUG_ON(!reader_threads[i]); |
138 | } |
139 | |
140 | printk("starting interrupt reader %lu\n", i); |
141 | interrupt_reader = kthread_run(interrupt_reader_thread, NULL, |
142 | "frwlock_interrupt_reader"); |
143 | |
144 | for (i = 0; i < NR_WRITERS; i++) { |
145 | printk("starting writer thread %lu\n", i); |
146 | writer_threads[i] = kthread_run(writer_thread, (void *)i, |
147 | "frwlock_writer"); |
148 | BUG_ON(!writer_threads[i]); |
149 | } |
150 | } |
151 | |
152 | static void fair_rwlock_stop(void) |
153 | { |
154 | unsigned long i; |
155 | |
156 | for (i = 0; i < NR_READERS; i++) { |
157 | kthread_stop(reader_threads[i]); |
158 | } |
159 | |
160 | //kthread_stop(interrupt_reader); |
161 | |
162 | for (i = 0; i < NR_WRITERS; i++) { |
163 | kthread_stop(writer_threads[i]); |
164 | } |
165 | } |
166 | |
167 | |
168 | static void perform_test(const char *name, void (*callback)(void)) |
169 | { |
170 | printk("%s\n", name); |
171 | callback(); |
172 | } |
173 | |
174 | static int my_open(struct inode *inode, struct file *file) |
175 | { |
176 | perform_test("fair-rwlock-create", fair_rwlock_create); |
177 | ssleep(30); |
178 | perform_test("fair-rwlock-stop", fair_rwlock_stop); |
179 | |
180 | return -EPERM; |
181 | } |
182 | |
183 | |
184 | static struct file_operations my_operations = { |
185 | .open = my_open, |
186 | }; |
187 | |
188 | int init_module(void) |
189 | { |
190 | pentry = create_proc_entry("testfrwlock", 0444, NULL); |
191 | if (pentry) |
192 | pentry->proc_fops = &my_operations; |
193 | |
194 | printk("NR_CPUS : %d\n", NR_CPUS); |
195 | printk("THREAD_ROFFSET : %lX\n", THREAD_ROFFSET); |
196 | printk("THREAD_RMASK : %lX\n", THREAD_RMASK); |
197 | printk("THREAD_WMASK : %lX\n", THREAD_WMASK); |
198 | printk("SOFTIRQ_ROFFSET : %lX\n", SOFTIRQ_ROFFSET); |
199 | printk("SOFTIRQ_RMASK : %lX\n", SOFTIRQ_RMASK); |
200 | printk("SOFTIRQ_WMASK : %lX\n", SOFTIRQ_WMASK); |
201 | printk("HARDIRQ_ROFFSET : %lX\n", HARDIRQ_ROFFSET); |
202 | printk("HARDIRQ_RMASK : %lX\n", HARDIRQ_RMASK); |
203 | printk("HARDIRQ_WMASK : %lX\n", HARDIRQ_WMASK); |
204 | |
205 | return 0; |
206 | } |
207 | |
208 | void cleanup_module(void) |
209 | { |
210 | remove_proc_entry("testfrwlock", NULL); |
211 | } |
212 | |
213 | MODULE_LICENSE("GPL"); |
214 | MODULE_AUTHOR("Mathieu Desnoyers"); |
215 | MODULE_DESCRIPTION("Fair rwlock test"); |