blob: 908abc795012c782891033dee88e02b6db4533cd [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*
2 * Copyright (c) 2008 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <debug.h>
24#include <rand.h>
25#include <app/tests.h>
26#include <kernel/thread.h>
27#include <kernel/mutex.h>
28#include <kernel/event.h>
29
30static int sleep_thread(void *arg)
31{
32 for(;;) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -070033 printf("sleeper %p\n", current_thread);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070034 thread_sleep(rand() % 500);
35 }
36 return 0;
37}
38
39int sleep_test(void)
40{
41 int i;
42 for(i=0; i < 16; i++)
43 thread_resume(thread_create("sleeper", &sleep_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
44 return 0;
45}
46
47static volatile int shared = 0;
48static mutex_t m;
49static volatile int mutex_thread_count = 0;
50
51static int mutex_thread(void *arg)
52{
53 int i;
54 const int iterations = 10000;
55
56 atomic_add(&mutex_thread_count, 1);
57
Travis Geiselbrechteb946052008-09-07 22:32:49 -070058 printf("mutex tester thread %p starting up, will go for %d iterations\n", current_thread, iterations);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070059
60 for (i = 0; i < iterations; i++) {
61 mutex_acquire(&m);
62
63 if (shared != 0)
64 panic("someone else has messed with the shared data\n");
65
66 shared = (int)current_thread;
67 thread_yield();
68 shared = 0;
69
70 mutex_release(&m);
71 thread_yield();
72 }
73 atomic_add(&mutex_thread_count, -1);
74
75 return 0;
76}
77
78static int mutex_timeout_thread(void *arg)
79{
80 mutex_t *timeout_mutex = (mutex_t *)arg;
81 status_t err;
82
Travis Geiselbrechteb946052008-09-07 22:32:49 -070083 printf("mutex_timeout_thread acquiring mutex %p with 1 second timeout\n", timeout_mutex);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070084 err = mutex_acquire_timeout(timeout_mutex, 1000);
Travis Geiselbrechteb946052008-09-07 22:32:49 -070085 printf("mutex_acquire_timeout returns %d\n", err);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070086
87 return err;
88}
89
90static int mutex_zerotimeout_thread(void *arg)
91{
92 mutex_t *timeout_mutex = (mutex_t *)arg;
93 status_t err;
94
Travis Geiselbrechteb946052008-09-07 22:32:49 -070095 printf("mutex_zerotimeout_thread acquiring mutex %p with zero second timeout\n", timeout_mutex);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070096 err = mutex_acquire_timeout(timeout_mutex, 0);
Travis Geiselbrechteb946052008-09-07 22:32:49 -070097 printf("mutex_acquire_timeout returns %d\n", err);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -070098
99 return err;
100}
101
102int mutex_test(void)
103{
104 mutex_init(&m);
105
106 int i;
107 for(i=0; i < 5; i++)
108 thread_resume(thread_create("mutex tester", &mutex_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
109
110 thread_sleep(1000);
111
112 while (mutex_thread_count > 0)
113 thread_yield();
114
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700115 printf("done with simple mutex tests\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700116
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700117 printf("testing mutex timeout\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700118
119 mutex_t timeout_mutex;
120
121 mutex_init(&timeout_mutex);
122 mutex_acquire(&timeout_mutex);
123
124 for (i=0; i < 2; i++)
125 thread_resume(thread_create("mutex timeout tester", &mutex_timeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
126 for (i=0; i < 2; i++)
127 thread_resume(thread_create("mutex timeout tester", &mutex_zerotimeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
128
129 thread_sleep(5000);
130 mutex_release(&timeout_mutex);
131
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700132 printf("done with mutex tests\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700133
134 mutex_destroy(&timeout_mutex);
135
136 return 0;
137}
138
139static event_t e;
140
141static int event_signaller(void *arg)
142{
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700143 printf("event signaller pausing\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700144 thread_sleep(1000);
145
146// for (;;) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700147 printf("signalling event\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700148 event_signal(&e, true);
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700149 printf("done signalling event\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700150 thread_yield();
151// }
152
153 return 0;
154}
155
156static int event_waiter(void *arg)
157{
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700158 printf("event waiter starting\n");
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700159
160 for (;;) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700161 printf("%p: waiting on event...\n", current_thread);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700162 if (event_wait(&e) < 0) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700163 printf("%p: event_wait() returned error\n", current_thread);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700164 return -1;
165 }
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700166 printf("%p: done waiting on event...\n", current_thread);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700167 thread_yield();
168 }
169
170 return 0;
171}
172
173void event_test(void)
174{
175 /* make sure signalling the event wakes up all the threads */
176 event_init(&e, false, 0);
177 thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
178 thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
179 thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
180 thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
181 thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
182 thread_sleep(2000);
183 event_destroy(&e);
184
185 /* make sure signalling the event wakes up precisely one thread */
186 event_init(&e, false, EVENT_FLAG_AUTOUNSIGNAL);
187 thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
188 thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
189 thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
190 thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
191 thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
192 thread_sleep(2000);
193 event_destroy(&e);
194}
195
196static int quantum_tester(void *arg)
197{
198 for (;;) {
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700199 printf("%p: in this thread. rq %d\n", current_thread, current_thread->remaining_quantum);
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700200 }
201 return 0;
202}
203
204void quantum_test(void)
205{
206 thread_resume(thread_create("quantum tester 0", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
207 thread_resume(thread_create("quantum tester 1", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
208 thread_resume(thread_create("quantum tester 2", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
209 thread_resume(thread_create("quantum tester 3", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
210}
211
212static event_t context_switch_event;
213static event_t context_switch_done_event;
214
215static int context_switch_tester(void *arg)
216{
217 int i;
218 uint total_count = 0;
219 const int iter = 100000;
220 int thread_count = (int)arg;
221
222 event_wait(&context_switch_event);
223
Ajay Dudanica0b6a22011-05-18 19:48:32 -0700224 uint count = arch_cycle_count();
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700225 for (i = 0; i < iter; i++) {
226 thread_yield();
227 }
Ajay Dudanica0b6a22011-05-18 19:48:32 -0700228 total_count += arch_cycle_count() - count;
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700229 thread_sleep(1000);
Travis Geiselbrechteb946052008-09-07 22:32:49 -0700230 printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n",
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700231 total_count, iter, total_count / iter, total_count / iter / thread_count);
232
233 event_signal(&context_switch_done_event, true);
234
235 return 0;
236}
237
238void context_switch_test(void)
239{
240 event_init(&context_switch_event, false, 0);
241 event_init(&context_switch_done_event, false, 0);
242
243 thread_resume(thread_create("context switch idle", &context_switch_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
244 thread_sleep(100);
245 event_signal(&context_switch_event, true);
246 event_wait(&context_switch_done_event);
247 thread_sleep(100);
248
249 event_unsignal(&context_switch_event);
250 event_unsignal(&context_switch_done_event);
251 thread_resume(thread_create("context switch 2a", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
252 thread_resume(thread_create("context switch 2b", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
253 thread_sleep(100);
254 event_signal(&context_switch_event, true);
255 event_wait(&context_switch_done_event);
256 thread_sleep(100);
257
258 event_unsignal(&context_switch_event);
259 event_unsignal(&context_switch_done_event);
260 thread_resume(thread_create("context switch 4a", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
261 thread_resume(thread_create("context switch 4b", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
262 thread_resume(thread_create("context switch 4c", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
263 thread_resume(thread_create("context switch 4d", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
264 thread_sleep(100);
265 event_signal(&context_switch_event, true);
266 event_wait(&context_switch_done_event);
267 thread_sleep(100);
268}
269
Travis Geiselbrecht8d529ef2008-09-13 15:13:21 -0700270static volatile int atomic;
271static volatile int atomic_count;
272
273static int atomic_tester(void *arg)
274{
275 int add = (int)arg;
276 int i;
277
278 TRACEF("add %d\n", add);
279
280 for (i=0; i < 1000000; i++) {
281 atomic_add(&atomic, add);
282 }
283
284 int old = atomic_add(&atomic_count, -1);
285 TRACEF("exiting, old count %d\n", old);
286
287 return 0;
288}
289
290static void atomic_test(void)
291{
292 atomic = 0;
293 atomic_count = 8;
294
295 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
296 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
297 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
298 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
299 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
300 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
301 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
302 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
303
304 while (atomic_count > 0) {
305 thread_sleep(1);
306 }
307
308 printf("atomic count == %d (should be zero)\n", atomic);
309}
310
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700311int thread_tests(void)
312{
313 mutex_test();
Travis Geiselbrecht8d529ef2008-09-13 15:13:21 -0700314 event_test();
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700315
316 thread_sleep(200);
317 context_switch_test();
Travis Geiselbrecht8d529ef2008-09-13 15:13:21 -0700318
319 atomic_test();
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -0700320
321 return 0;
322}