thread_tests.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  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. static int sleep_thread(void *arg)
  30. {
  31. for(;;) {
  32. printf("sleeper %p\n", current_thread);
  33. thread_sleep(rand() % 500);
  34. }
  35. return 0;
  36. }
  37. int sleep_test(void)
  38. {
  39. int i;
  40. for(i=0; i < 16; i++)
  41. thread_resume(thread_create("sleeper", &sleep_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  42. return 0;
  43. }
  44. static volatile int shared = 0;
  45. static mutex_t m;
  46. static volatile int mutex_thread_count = 0;
  47. static int mutex_thread(void *arg)
  48. {
  49. int i;
  50. const int iterations = 10000;
  51. atomic_add(&mutex_thread_count, 1);
  52. printf("mutex tester thread %p starting up, will go for %d iterations\n", current_thread, iterations);
  53. for (i = 0; i < iterations; i++) {
  54. mutex_acquire(&m);
  55. if (shared != 0)
  56. panic("someone else has messed with the shared data\n");
  57. shared = (int)current_thread;
  58. thread_yield();
  59. shared = 0;
  60. mutex_release(&m);
  61. thread_yield();
  62. }
  63. atomic_add(&mutex_thread_count, -1);
  64. return 0;
  65. }
  66. static int mutex_timeout_thread(void *arg)
  67. {
  68. mutex_t *timeout_mutex = (mutex_t *)arg;
  69. status_t err;
  70. printf("mutex_timeout_thread acquiring mutex %p with 1 second timeout\n", timeout_mutex);
  71. err = mutex_acquire_timeout(timeout_mutex, 1000);
  72. printf("mutex_acquire_timeout returns %d\n", err);
  73. return err;
  74. }
  75. static int mutex_zerotimeout_thread(void *arg)
  76. {
  77. mutex_t *timeout_mutex = (mutex_t *)arg;
  78. status_t err;
  79. printf("mutex_zerotimeout_thread acquiring mutex %p with zero second timeout\n", timeout_mutex);
  80. err = mutex_acquire_timeout(timeout_mutex, 0);
  81. printf("mutex_acquire_timeout returns %d\n", err);
  82. return err;
  83. }
  84. int mutex_test(void)
  85. {
  86. mutex_init(&m);
  87. int i;
  88. for(i=0; i < 5; i++)
  89. thread_resume(thread_create("mutex tester", &mutex_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  90. thread_sleep(1000);
  91. while (mutex_thread_count > 0)
  92. thread_yield();
  93. printf("done with simple mutex tests\n");
  94. printf("testing mutex timeout\n");
  95. mutex_t timeout_mutex;
  96. mutex_init(&timeout_mutex);
  97. mutex_acquire(&timeout_mutex);
  98. for (i=0; i < 2; i++)
  99. thread_resume(thread_create("mutex timeout tester", &mutex_timeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  100. for (i=0; i < 2; i++)
  101. thread_resume(thread_create("mutex timeout tester", &mutex_zerotimeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  102. thread_sleep(5000);
  103. mutex_release(&timeout_mutex);
  104. printf("done with mutex tests\n");
  105. mutex_destroy(&timeout_mutex);
  106. return 0;
  107. }
  108. static event_t e;
  109. static int event_signaller(void *arg)
  110. {
  111. printf("event signaller pausing\n");
  112. thread_sleep(1000);
  113. // for (;;) {
  114. printf("signalling event\n");
  115. event_signal(&e, true);
  116. printf("done signalling event\n");
  117. thread_yield();
  118. // }
  119. return 0;
  120. }
  121. static int event_waiter(void *arg)
  122. {
  123. printf("event waiter starting\n");
  124. for (;;) {
  125. printf("%p: waiting on event...\n", current_thread);
  126. if (event_wait(&e) < 0) {
  127. printf("%p: event_wait() returned error\n", current_thread);
  128. return -1;
  129. }
  130. printf("%p: done waiting on event...\n", current_thread);
  131. thread_yield();
  132. }
  133. return 0;
  134. }
  135. void event_test(void)
  136. {
  137. /* make sure signalling the event wakes up all the threads */
  138. event_init(&e, false, 0);
  139. thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  140. thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  141. thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  142. thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  143. thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  144. thread_sleep(2000);
  145. event_destroy(&e);
  146. /* make sure signalling the event wakes up precisely one thread */
  147. event_init(&e, false, EVENT_FLAG_AUTOUNSIGNAL);
  148. thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  149. thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  150. thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  151. thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  152. thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  153. thread_sleep(2000);
  154. event_destroy(&e);
  155. }
  156. static int quantum_tester(void *arg)
  157. {
  158. for (;;) {
  159. printf("%p: in this thread. rq %d\n", current_thread, current_thread->remaining_quantum);
  160. }
  161. return 0;
  162. }
  163. void quantum_test(void)
  164. {
  165. thread_resume(thread_create("quantum tester 0", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  166. thread_resume(thread_create("quantum tester 1", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  167. thread_resume(thread_create("quantum tester 2", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  168. thread_resume(thread_create("quantum tester 3", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  169. }
  170. static event_t context_switch_event;
  171. static event_t context_switch_done_event;
  172. static int context_switch_tester(void *arg)
  173. {
  174. int i;
  175. uint total_count = 0;
  176. const int iter = 100000;
  177. int thread_count = (int)arg;
  178. event_wait(&context_switch_event);
  179. uint count = arch_cycle_count();
  180. for (i = 0; i < iter; i++) {
  181. thread_yield();
  182. }
  183. total_count += arch_cycle_count() - count;
  184. thread_sleep(1000);
  185. printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n",
  186. total_count, iter, total_count / iter, total_count / iter / thread_count);
  187. event_signal(&context_switch_done_event, true);
  188. return 0;
  189. }
  190. void context_switch_test(void)
  191. {
  192. event_init(&context_switch_event, false, 0);
  193. event_init(&context_switch_done_event, false, 0);
  194. thread_resume(thread_create("context switch idle", &context_switch_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  195. thread_sleep(100);
  196. event_signal(&context_switch_event, true);
  197. event_wait(&context_switch_done_event);
  198. thread_sleep(100);
  199. event_unsignal(&context_switch_event);
  200. event_unsignal(&context_switch_done_event);
  201. thread_resume(thread_create("context switch 2a", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  202. thread_resume(thread_create("context switch 2b", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  203. thread_sleep(100);
  204. event_signal(&context_switch_event, true);
  205. event_wait(&context_switch_done_event);
  206. thread_sleep(100);
  207. event_unsignal(&context_switch_event);
  208. event_unsignal(&context_switch_done_event);
  209. thread_resume(thread_create("context switch 4a", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  210. thread_resume(thread_create("context switch 4b", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  211. thread_resume(thread_create("context switch 4c", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  212. thread_resume(thread_create("context switch 4d", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
  213. thread_sleep(100);
  214. event_signal(&context_switch_event, true);
  215. event_wait(&context_switch_done_event);
  216. thread_sleep(100);
  217. }
  218. static volatile int atomic;
  219. static volatile int atomic_count;
  220. static int atomic_tester(void *arg)
  221. {
  222. int add = (int)arg;
  223. int i;
  224. TRACEF("add %d\n", add);
  225. for (i=0; i < 1000000; i++) {
  226. atomic_add(&atomic, add);
  227. }
  228. int old = atomic_add(&atomic_count, -1);
  229. TRACEF("exiting, old count %d\n", old);
  230. return 0;
  231. }
  232. static void atomic_test(void)
  233. {
  234. atomic = 0;
  235. atomic_count = 8;
  236. thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  237. thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  238. thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  239. thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  240. thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  241. thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  242. thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  243. thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
  244. while (atomic_count > 0) {
  245. thread_sleep(1);
  246. }
  247. printf("atomic count == %d (should be zero)\n", atomic);
  248. }
  249. int thread_tests(void)
  250. {
  251. mutex_test();
  252. event_test();
  253. thread_sleep(200);
  254. context_switch_test();
  255. atomic_test();
  256. return 0;
  257. }