First version
[3rdparty/ote_partner/tlk.git] / app / tests / thread_tests.c
1 /*
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
33 static 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
42 int 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
50 static semaphore_t sem;
51 static const int sem_total_its = 10000;
52 static const int sem_thread_max_its = 1000;
53 static const int sem_start_value = 10;
54 static int sem_remaining_its = 0;
55 static int sem_threads = 0;
56 static mutex_t sem_test_mutex;
57
58 static 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
69 static 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
91 static 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
126 static volatile int shared = 0;
127 static mutex_t m;
128 static volatile int mutex_thread_count = 0;
129
130 static 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
157 static 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
172 static 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
187 int 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
224 static event_t e;
225
226 static 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
241 static 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
261 void 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
290 static 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
298 void 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
306 static event_t context_switch_event;
307 static event_t context_switch_done_event;
308
309 static 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
332 void 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
364 static volatile int atomic;
365 static volatile int atomic_count;
366
367 static 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
384 static 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
407 static volatile int preempt_count;
408
409 static 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
424 static 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
441 int 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 }