blob: 0469c2d09ad9ad8146006816bb103ca842e3ab99 [file] [log] [blame]
Dennis Huang6d037712014-04-22 19:20:59 -07001/*
2 * Copyright (c) 2008-2012 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 <err.h>
26#include <app/tests.h>
27#include <kernel/thread.h>
28#include <kernel/mutex.h>
29#include <kernel/semaphore.h>
30#include <kernel/event.h>
31#include <platform.h>
32
33static int sleep_thread(void *arg)
34{
35 for(;;) {
36 printf("sleeper %p\n", current_thread);
37 thread_sleep(rand() % 500);
38 }
39 return 0;
40}
41
42int sleep_test(void)
43{
44 int i;
45 for(i=0; i < 16; i++)
46 thread_resume(thread_create("sleeper", &sleep_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
47 return 0;
48}
49
50static semaphore_t sem;
51static const int sem_total_its = 10000;
52static const int sem_thread_max_its = 1000;
53static const int sem_start_value = 10;
54static int sem_remaining_its = 0;
55static int sem_threads = 0;
56static mutex_t sem_test_mutex;
57
58static int semaphore_producer()
59{
60 printf("semaphore producer %p starting up, running for %d iterations\n", current_thread, sem_total_its);
61
62 for (int x = 0; x < sem_total_its; x++) {
63 sem_post(&sem);
64 }
65
66 return 0;
67}
68
69static int semaphore_consumer()
70{
71 unsigned int iterations = 0;
72
73 mutex_acquire(&sem_test_mutex);
74 if (sem_remaining_its >= sem_thread_max_its) {
75 iterations = rand();
76 iterations %= sem_thread_max_its;
77 } else {
78 iterations = sem_remaining_its;
79 }
80 sem_remaining_its -= iterations;
81 mutex_release(&sem_test_mutex);
82
83 printf("semaphore consumer %p starting up, running for %u iterations\n", current_thread, iterations);
84 for (unsigned int x = 0; x < iterations; x++)
85 sem_wait(&sem);
86 printf("semaphore consumer %p done\n", current_thread);
87 atomic_add(&sem_threads, -1);
88 return 0;
89}
90
91static int semaphore_test()
92{
93 sem_init(&sem, sem_start_value);
94 mutex_init(&sem_test_mutex);
95
96 sem_remaining_its = sem_total_its;
97 while (1) {
98 mutex_acquire(&sem_test_mutex);
99 if (sem_remaining_its) {
100 thread_resume(thread_create("semaphore consumer", &semaphore_consumer, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
101 atomic_add(&sem_threads, 1);
102 } else {
103 mutex_release(&sem_test_mutex);
104 break;
105 }
106 mutex_release(&sem_test_mutex);
107 }
108
109 thread_resume(thread_create("semaphore producer", &semaphore_producer, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
110
111 while (sem_threads)
112 thread_yield();
113
114 if (sem.count == sem_start_value)
115 printf("semaphore tests successfully complete\n");
116 else
117 printf("semaphore tests failed: %d != %d\n", sem.count, sem_start_value);
118
119 sem_destroy(&sem);
120 mutex_destroy(&sem_test_mutex);
121
122 return 0;
123}
124
125
126static volatile int shared = 0;
127static mutex_t m;
128static volatile int mutex_thread_count = 0;
129
130static int mutex_thread(void *arg)
131{
132 int i;
133 const int iterations = 10000;
134
135 atomic_add(&mutex_thread_count, 1);
136
137 printf("mutex tester thread %p starting up, will go for %d iterations\n", current_thread, iterations);
138
139 for (i = 0; i < iterations; i++) {
140 mutex_acquire(&m);
141
142 if (shared != 0)
143 panic("someone else has messed with the shared data\n");
144
145 shared = (int)current_thread;
146 thread_yield();
147 shared = 0;
148
149 mutex_release(&m);
150 thread_yield();
151 }
152 atomic_add(&mutex_thread_count, -1);
153
154 return 0;
155}
156
157static int mutex_timeout_thread(void *arg)
158{
159 mutex_t *timeout_mutex = (mutex_t *)arg;
160 status_t err;
161
162 printf("mutex_timeout_thread acquiring mutex %p with 1 second timeout\n", timeout_mutex);
163 err = mutex_acquire_timeout(timeout_mutex, 1000);
164 if (err == ERR_TIMED_OUT)
165 printf("mutex_acquire_timeout returns with TIMEOUT\n");
166 else
167 printf("mutex_acquire_timeout returns %d\n", err);
168
169 return err;
170}
171
172static int mutex_zerotimeout_thread(void *arg)
173{
174 mutex_t *timeout_mutex = (mutex_t *)arg;
175 status_t err;
176
177 printf("mutex_zerotimeout_thread acquiring mutex %p with zero second timeout\n", timeout_mutex);
178 err = mutex_acquire_timeout(timeout_mutex, 0);
179 if (err == ERR_TIMED_OUT)
180 printf("mutex_acquire_timeout returns with TIMEOUT\n");
181 else
182 printf("mutex_acquire_timeout returns %d\n", err);
183
184 return err;
185}
186
187int mutex_test(void)
188{
189 mutex_init(&m);
190
191 int i;
192 for(i=0; i < 5; i++)
193 thread_resume(thread_create("mutex tester", &mutex_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
194
195 thread_sleep(1000);
196
197 while (mutex_thread_count > 0)
198 thread_yield();
199
200 printf("done with simple mutex tests\n");
201
202 printf("testing mutex timeout\n");
203
204 mutex_t timeout_mutex;
205
206 mutex_init(&timeout_mutex);
207 mutex_acquire(&timeout_mutex);
208
209 for (i=0; i < 2; i++)
210 thread_resume(thread_create("mutex timeout tester", &mutex_timeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
211 for (i=0; i < 2; i++)
212 thread_resume(thread_create("mutex timeout tester", &mutex_zerotimeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
213
214 thread_sleep(5000);
215 mutex_release(&timeout_mutex);
216
217 printf("done with mutex tests\n");
218
219 mutex_destroy(&timeout_mutex);
220
221 return 0;
222}
223
224static event_t e;
225
226static int event_signaller(void *arg)
227{
228 printf("event signaller pausing\n");
229 thread_sleep(1000);
230
231// for (;;) {
232 printf("signalling event\n");
233 event_signal(&e, true);
234 printf("done signalling event\n");
235 thread_yield();
236// }
237
238 return 0;
239}
240
241static int event_waiter(void *arg)
242{
243 int count = (int)arg;
244
245 printf("event waiter starting\n");
246
247 while (count > 0) {
248 printf("%p: waiting on event...\n", current_thread);
249 if (event_wait(&e) < 0) {
250 printf("%p: event_wait() returned error\n", current_thread);
251 return -1;
252 }
253 printf("%p: done waiting on event...\n", current_thread);
254 thread_yield();
255 count--;
256 }
257
258 return 0;
259}
260
261void event_test(void)
262{
263 printf("event tests starting\n");
264
265 /* make sure signalling the event wakes up all the threads */
266 event_init(&e, false, 0);
267 thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
268 thread_resume(thread_create("event waiter 0", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
269 thread_resume(thread_create("event waiter 1", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
270 thread_resume(thread_create("event waiter 2", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
271 thread_resume(thread_create("event waiter 3", &event_waiter, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
272 thread_sleep(2000);
273 printf("destroying event\n");
274 event_destroy(&e);
275 thread_sleep(1000);
276
277 /* make sure signalling the event wakes up precisely one thread */
278 event_init(&e, false, EVENT_FLAG_AUTOUNSIGNAL);
279 thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
280 thread_resume(thread_create("event waiter 0", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
281 thread_resume(thread_create("event waiter 1", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
282 thread_resume(thread_create("event waiter 2", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
283 thread_resume(thread_create("event waiter 3", &event_waiter, (void *)99, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
284 thread_sleep(2000);
285 event_destroy(&e);
286
287 printf("event tests done\n");
288}
289
290static int quantum_tester(void *arg)
291{
292 for (;;) {
293 printf("%p: in this thread. rq %d\n", current_thread, current_thread->remaining_quantum);
294 }
295 return 0;
296}
297
298void quantum_test(void)
299{
300 thread_resume(thread_create("quantum tester 0", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
301 thread_resume(thread_create("quantum tester 1", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
302 thread_resume(thread_create("quantum tester 2", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
303 thread_resume(thread_create("quantum tester 3", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
304}
305
306static event_t context_switch_event;
307static event_t context_switch_done_event;
308
309static int context_switch_tester(void *arg)
310{
311 int i;
312 uint total_count = 0;
313 const int iter = 100000;
314 int thread_count = (int)arg;
315
316 event_wait(&context_switch_event);
317
318 uint count = arch_cycle_count();
319 for (i = 0; i < iter; i++) {
320 thread_yield();
321 }
322 total_count += arch_cycle_count() - count;
323 thread_sleep(1000);
324 printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n",
325 total_count, iter, total_count / iter, total_count / iter / thread_count);
326
327 event_signal(&context_switch_done_event, true);
328
329 return 0;
330}
331
332void context_switch_test(void)
333{
334 event_init(&context_switch_event, false, 0);
335 event_init(&context_switch_done_event, false, 0);
336
337 thread_resume(thread_create("context switch idle", &context_switch_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
338 thread_sleep(100);
339 event_signal(&context_switch_event, true);
340 event_wait(&context_switch_done_event);
341 thread_sleep(100);
342
343 event_unsignal(&context_switch_event);
344 event_unsignal(&context_switch_done_event);
345 thread_resume(thread_create("context switch 2a", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
346 thread_resume(thread_create("context switch 2b", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
347 thread_sleep(100);
348 event_signal(&context_switch_event, true);
349 event_wait(&context_switch_done_event);
350 thread_sleep(100);
351
352 event_unsignal(&context_switch_event);
353 event_unsignal(&context_switch_done_event);
354 thread_resume(thread_create("context switch 4a", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
355 thread_resume(thread_create("context switch 4b", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
356 thread_resume(thread_create("context switch 4c", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
357 thread_resume(thread_create("context switch 4d", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
358 thread_sleep(100);
359 event_signal(&context_switch_event, true);
360 event_wait(&context_switch_done_event);
361 thread_sleep(100);
362}
363
364static volatile int atomic;
365static volatile int atomic_count;
366
367static int atomic_tester(void *arg)
368{
369 int add = (int)arg;
370 int i;
371
372 TRACEF("add %d\n", add);
373
374 for (i=0; i < 1000000; i++) {
375 atomic_add(&atomic, add);
376 }
377
378 int old = atomic_add(&atomic_count, -1);
379 TRACEF("exiting, old count %d\n", old);
380
381 return 0;
382}
383
384static void atomic_test(void)
385{
386 atomic = 0;
387 atomic_count = 8;
388
389 printf("testing atomic routines\n");
390
391 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
392 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
393 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
394 thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
395 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
396 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
397 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
398 thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
399
400 while (atomic_count > 0) {
401 thread_sleep(1);
402 }
403
404 printf("atomic count == %d (should be zero)\n", atomic);
405}
406
407static volatile int preempt_count;
408
409static int preempt_tester(void *arg)
410{
411#define COUNT (8*1024*1024)
412
413 int i;
414 for (i = 0; i < COUNT; i++)
415 __asm__ volatile("nop");
416
417 printf("exiting ts %lld\n", current_time_hires());
418
419 atomic_add(&preempt_count, -1);
420
421 return 0;
422}
423
424static void preempt_test(void)
425{
426 printf("testing preemption\n");
427
428 preempt_count = 5;
429
430 int i;
431 for (i = 0; i < preempt_count; i++)
432 thread_resume(thread_create("preempt tester", &preempt_tester, NULL, LOW_PRIORITY, DEFAULT_STACK_SIZE));
433
434 while (preempt_count > 0) {
435 thread_sleep(1000);
436 }
437
438 printf("done with preempt test, above time stamps should be very close\n");
439}
440
441int thread_tests(void)
442{
443 mutex_test();
444 semaphore_test();
445 event_test();
446
447 atomic_test();
448
449 thread_sleep(200);
450 context_switch_test();
451
452 preempt_test();
453
454 return 0;
455}