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