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 <linux/percpu.h>
15 #include <asm/ptrace.h>
17 #if (NR_CPUS > 64 && (BITS_PER_LONG == 32 || NR_CPUS > 32768))
18 #error "fair rwlock needs more bits per long to deal with that many CPUs"
21 #define THREAD_ROFFSET 1UL
22 #define THREAD_RMASK ((NR_CPUS - 1) * THREAD_ROFFSET)
23 #define SOFTIRQ_ROFFSET (THREAD_RMASK + 1)
24 #define SOFTIRQ_RMASK ((NR_CPUS - 1) * SOFTIRQ_ROFFSET)
25 #define HARDIRQ_ROFFSET ((SOFTIRQ_RMASK | THREAD_RMASK) + 1)
26 #define HARDIRQ_RMASK ((NR_CPUS - 1) * HARDIRQ_ROFFSET)
28 #define SUBSCRIBERS_WOFFSET \
29 ((HARDIRQ_RMASK | SOFTIRQ_RMASK | THREAD_RMASK) + 1)
30 #define SUBSCRIBERS_WMASK \
31 ((NR_CPUS - 1) * SUBSCRIBERS_WOFFSET)
32 #define WRITER_MUTEX \
33 ((SUBSCRIBERS_WMASK | HARDIRQ_RMASK | SOFTIRQ_RMASK | THREAD_RMASK) + 1)
34 #define SOFTIRQ_WMASK (WRITER_MUTEX << 1)
35 #define SOFTIRQ_WOFFSET SOFTIRQ_WMASK
36 #define HARDIRQ_WMASK (SOFTIRQ_WMASK << 1)
37 #define HARDIRQ_WOFFSET HARDIRQ_WMASK
42 #define NR_INTERRUPT_READERS 2
44 static int var
[NR_VARS
];
45 static struct task_struct
*reader_threads
[NR_READERS
];
46 static struct task_struct
*writer_threads
[NR_WRITERS
];
47 static struct task_struct
*interrupt_reader
;
49 static struct fair_rwlock frwlock
= {
50 .value
= ATOMIC_LONG_INIT(0),
53 struct proc_dir_entry
*pentry
= NULL
;
55 static int reader_thread(void *data
)
59 unsigned long iter
= 0;
60 cycles_t time1
, time2
, delaymax
= 0;
62 printk("reader_thread/%lu runnning\n", (unsigned long)data
);
65 preempt_disable(); /* for get_cycles accuracy */
67 fair_read_lock(&frwlock
);
69 delaymax
= max(delaymax
, time2
- time1
);
71 for (i
= 1; i
< NR_VARS
; i
++) {
75 "Unequal cur %d/prev %d at i %d, iter %lu "
76 "in thread\n", cur
, prev
, i
, iter
);
78 fair_read_unlock(&frwlock
);
79 preempt_enable(); /* for get_cycles accuracy */
81 } while (!kthread_should_stop());
82 printk("reader_thread/%lu iterations : %lu, "
83 "max contention %llu cycles\n",
84 (unsigned long)data
, iter
, delaymax
);
88 DEFINE_PER_CPU(cycles_t
, int_delaymax
);
90 static void interrupt_reader_ipi(void *data
)
94 cycles_t time1
, time2
;
98 * Skip the ipi caller, not in irq context.
103 delaymax
= &per_cpu(int_delaymax
, smp_processor_id());
104 time1
= get_cycles();
105 fair_read_lock(&frwlock
);
106 time2
= get_cycles();
107 *delaymax
= max(*delaymax
, time2
- time1
);
109 for (i
= 1; i
< NR_VARS
; i
++) {
113 "Unequal cur %d/prev %d at i %d in interrupt\n",
116 fair_read_unlock(&frwlock
);
119 static int interrupt_reader_thread(void *data
)
121 unsigned long iter
= 0;
126 on_each_cpu(interrupt_reader_ipi
, NULL
, 0);
128 } while (!kthread_should_stop());
129 printk("interrupt_reader_thread/%lu iterations : %lu\n",
130 (unsigned long)data
, iter
);
131 for_each_online_cpu(i
) {
132 printk("interrupt readers on CPU %i, "
133 "max contention : %llu cycles\n",
134 i
, per_cpu(int_delaymax
, i
));
139 static int writer_thread(void *data
)
143 unsigned long iter
= 0;
144 cycles_t time1
, time2
, delaymax
= 0;
146 printk("writer_thread/%lu runnning\n", (unsigned long)data
);
149 preempt_disable(); /* for get_cycles accuracy */
150 time1
= get_cycles();
151 fair_write_lock_irq(&frwlock
);
152 //fair_write_lock(&frwlock);
153 time2
= get_cycles();
154 delaymax
= max(delaymax
, time2
- time1
);
155 new = (int)get_cycles();
156 for (i
= 0; i
< NR_VARS
; i
++) {
159 //fair_write_unlock(&frwlock);
160 fair_write_unlock_irq(&frwlock
);
161 preempt_enable(); /* for get_cycles accuracy */
163 } while (!kthread_should_stop());
164 printk("writer_thread/%lu iterations : %lu, "
165 "max contention %llu cycles\n",
166 (unsigned long)data
, iter
, delaymax
);
170 static void fair_rwlock_create(void)
174 for (i
= 0; i
< NR_READERS
; i
++) {
175 printk("starting reader thread %lu\n", i
);
176 reader_threads
[i
] = kthread_run(reader_thread
, (void *)i
,
178 BUG_ON(!reader_threads
[i
]);
181 printk("starting interrupt reader %lu\n", i
);
182 interrupt_reader
= kthread_run(interrupt_reader_thread
, NULL
,
183 "frwlock_interrupt_reader");
185 for (i
= 0; i
< NR_WRITERS
; i
++) {
186 printk("starting writer thread %lu\n", i
);
187 writer_threads
[i
] = kthread_run(writer_thread
, (void *)i
,
189 BUG_ON(!writer_threads
[i
]);
193 static void fair_rwlock_stop(void)
197 for (i
= 0; i
< NR_WRITERS
; i
++) {
198 kthread_stop(writer_threads
[i
]);
201 for (i
= 0; i
< NR_READERS
; i
++) {
202 kthread_stop(reader_threads
[i
]);
205 kthread_stop(interrupt_reader
);
209 static void perform_test(const char *name
, void (*callback
)(void))
211 printk("%s\n", name
);
215 static int my_open(struct inode
*inode
, struct file
*file
)
217 perform_test("fair-rwlock-create", fair_rwlock_create
);
219 perform_test("fair-rwlock-stop", fair_rwlock_stop
);
225 static struct file_operations my_operations
= {
229 int init_module(void)
231 pentry
= create_proc_entry("testfrwlock", 0444, NULL
);
233 pentry
->proc_fops
= &my_operations
;
235 printk("NR_CPUS : %d\n", NR_CPUS
);
236 printk("THREAD_ROFFSET : %lX\n", THREAD_ROFFSET
);
237 printk("THREAD_RMASK : %lX\n", THREAD_RMASK
);
238 printk("SOFTIRQ_ROFFSET : %lX\n", SOFTIRQ_ROFFSET
);
239 printk("SOFTIRQ_RMASK : %lX\n", SOFTIRQ_RMASK
);
240 printk("HARDIRQ_ROFFSET : %lX\n", HARDIRQ_ROFFSET
);
241 printk("HARDIRQ_RMASK : %lX\n", HARDIRQ_RMASK
);
242 printk("SUBSCRIBERS_WOFFSET : %lX\n", SUBSCRIBERS_WOFFSET
);
243 printk("SUBSCRIBERS_WMASK : %lX\n", SUBSCRIBERS_WMASK
);
244 printk("WRITER_MUTEX : %lX\n", WRITER_MUTEX
);
245 printk("SOFTIRQ_WMASK : %lX\n", SOFTIRQ_WMASK
);
246 printk("HARDIRQ_WMASK : %lX\n", HARDIRQ_WMASK
);
251 void cleanup_module(void)
253 remove_proc_entry("testfrwlock", NULL
);
256 MODULE_LICENSE("GPL");
257 MODULE_AUTHOR("Mathieu Desnoyers");
258 MODULE_DESCRIPTION("Fair rwlock test");