]>
Commit | Line | Data |
---|---|---|
552cc11b | 1 | /* |
de42bf35 | 2 | * Copyright (C) 2013 Tobias Brunner |
552cc11b MW |
3 | * Copyright (C) 2008 Martin Willi |
4 | * Hochschule fuer Technik Rapperswil | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | */ | |
16 | ||
95e99150 TB |
17 | #include "test_suite.h" |
18 | ||
855747ea | 19 | #include <unistd.h> |
f23fd4c5 MW |
20 | |
21 | #include <threading/thread.h> | |
de42bf35 | 22 | #include <threading/mutex.h> |
f23fd4c5 | 23 | #include <threading/condvar.h> |
dac31fe1 | 24 | #include <threading/rwlock.h> |
f644b9e8 | 25 | #include <threading/rwlock_condvar.h> |
b1bfe595 | 26 | #include <threading/spinlock.h> |
ffab2e0c | 27 | #include <threading/semaphore.h> |
0b00e63e | 28 | #include <threading/thread_value.h> |
552cc11b | 29 | |
de42bf35 TB |
30 | /******************************************************************************* |
31 | * recursive mutex test | |
32 | */ | |
552cc11b | 33 | |
de42bf35 TB |
34 | #define THREADS 20 |
35 | ||
f23fd4c5 MW |
36 | /** |
37 | * Thread barrier data | |
38 | */ | |
39 | typedef struct { | |
40 | mutex_t *mutex; | |
41 | condvar_t *cond; | |
42 | int count; | |
43 | int current; | |
44 | bool active; | |
45 | } barrier_t; | |
46 | ||
47 | /** | |
48 | * Create a thread barrier for count threads | |
49 | */ | |
50 | static barrier_t* barrier_create(int count) | |
51 | { | |
52 | barrier_t *this; | |
552cc11b | 53 | |
f23fd4c5 MW |
54 | INIT(this, |
55 | .mutex = mutex_create(MUTEX_TYPE_DEFAULT), | |
56 | .cond = condvar_create(CONDVAR_TYPE_DEFAULT), | |
57 | .count = count, | |
58 | ); | |
59 | ||
60 | return this; | |
61 | } | |
62 | ||
63 | /** | |
64 | * Destroy a thread barrier | |
65 | */ | |
66 | static void barrier_destroy(barrier_t *this) | |
67 | { | |
68 | this->mutex->destroy(this->mutex); | |
69 | this->cond->destroy(this->cond); | |
70 | free(this); | |
71 | } | |
552cc11b | 72 | |
f23fd4c5 MW |
73 | /** |
74 | * Wait to have configured number of threads in barrier | |
75 | */ | |
76 | static bool barrier_wait(barrier_t *this) | |
77 | { | |
78 | bool winner = FALSE; | |
79 | ||
80 | this->mutex->lock(this->mutex); | |
81 | if (!this->active) | |
82 | { /* first, reset */ | |
83 | this->active = TRUE; | |
84 | this->current = 0; | |
85 | } | |
86 | ||
87 | this->current++; | |
88 | while (this->current < this->count) | |
89 | { | |
90 | this->cond->wait(this->cond, this->mutex); | |
91 | } | |
92 | if (this->active) | |
93 | { /* first, win */ | |
94 | winner = TRUE; | |
95 | this->active = FALSE; | |
96 | } | |
97 | this->mutex->unlock(this->mutex); | |
98 | this->cond->broadcast(this->cond); | |
99 | sched_yield(); | |
100 | ||
101 | return winner; | |
102 | } | |
103 | ||
104 | /** | |
105 | * Barrier for some tests | |
106 | */ | |
107 | static barrier_t *barrier; | |
552cc11b | 108 | |
13183a74 MW |
109 | /** |
110 | * A mutex for tests requiring one | |
111 | */ | |
112 | static mutex_t *mutex; | |
113 | ||
114 | /** | |
115 | * A condvar for tests requiring one | |
116 | */ | |
117 | static condvar_t *condvar; | |
118 | ||
119 | /** | |
120 | * A counter for signaling | |
121 | */ | |
122 | static int sigcount; | |
123 | ||
de42bf35 | 124 | static void *mutex_run(void *data) |
552cc11b | 125 | { |
13183a74 | 126 | int locked = 0; |
552cc11b MW |
127 | int i; |
128 | ||
129 | /* wait for all threads before getting in action */ | |
f23fd4c5 | 130 | barrier_wait(barrier); |
552cc11b MW |
131 | |
132 | for (i = 0; i < 100; i++) | |
133 | { | |
134 | mutex->lock(mutex); | |
135 | mutex->lock(mutex); | |
136 | mutex->lock(mutex); | |
f23fd4c5 | 137 | locked++; |
552cc11b | 138 | sched_yield(); |
f23fd4c5 | 139 | if (locked > 1) |
552cc11b | 140 | { |
de42bf35 | 141 | fail("two threads locked the mutex concurrently"); |
7daf5226 | 142 | } |
f23fd4c5 | 143 | locked--; |
552cc11b MW |
144 | mutex->unlock(mutex); |
145 | mutex->unlock(mutex); | |
146 | mutex->unlock(mutex); | |
147 | } | |
148 | return NULL; | |
149 | } | |
150 | ||
de42bf35 | 151 | START_TEST(test_mutex) |
552cc11b | 152 | { |
f23fd4c5 | 153 | thread_t *threads[THREADS]; |
de42bf35 | 154 | int i; |
7daf5226 | 155 | |
f23fd4c5 | 156 | barrier = barrier_create(THREADS); |
3901937d | 157 | mutex = mutex_create(MUTEX_TYPE_RECURSIVE); |
7daf5226 | 158 | |
552cc11b MW |
159 | for (i = 0; i < 10; i++) |
160 | { | |
161 | mutex->lock(mutex); | |
162 | mutex->unlock(mutex); | |
163 | } | |
164 | for (i = 0; i < 10; i++) | |
165 | { | |
166 | mutex->lock(mutex); | |
167 | } | |
168 | for (i = 0; i < 10; i++) | |
169 | { | |
170 | mutex->unlock(mutex); | |
171 | } | |
7daf5226 | 172 | |
552cc11b MW |
173 | for (i = 0; i < THREADS; i++) |
174 | { | |
13183a74 | 175 | threads[i] = thread_create(mutex_run, NULL); |
552cc11b MW |
176 | } |
177 | for (i = 0; i < THREADS; i++) | |
178 | { | |
f23fd4c5 | 179 | threads[i]->join(threads[i]); |
552cc11b | 180 | } |
7daf5226 | 181 | |
552cc11b | 182 | mutex->destroy(mutex); |
f23fd4c5 | 183 | barrier_destroy(barrier); |
552cc11b | 184 | } |
de42bf35 | 185 | END_TEST |
552cc11b | 186 | |
b1bfe595 MW |
187 | /** |
188 | * Spinlock for testing | |
189 | */ | |
190 | static spinlock_t *spinlock; | |
191 | ||
192 | static void *spinlock_run(void *data) | |
193 | { | |
194 | int i, *locked = (int*)data; | |
195 | ||
196 | barrier_wait(barrier); | |
197 | ||
198 | for (i = 0; i < 1000; i++) | |
199 | { | |
200 | spinlock->lock(spinlock); | |
201 | (*locked)++; | |
202 | ck_assert_int_eq(*locked, 1); | |
203 | (*locked)--; | |
204 | spinlock->unlock(spinlock); | |
205 | } | |
206 | return NULL; | |
207 | } | |
208 | ||
209 | START_TEST(test_spinlock) | |
210 | { | |
211 | thread_t *threads[THREADS]; | |
212 | int i, locked = 0; | |
213 | ||
214 | barrier = barrier_create(THREADS); | |
215 | spinlock = spinlock_create(); | |
216 | ||
217 | for (i = 0; i < THREADS; i++) | |
218 | { | |
219 | threads[i] = thread_create(spinlock_run, &locked); | |
220 | } | |
221 | for (i = 0; i < THREADS; i++) | |
222 | { | |
223 | threads[i]->join(threads[i]); | |
224 | } | |
225 | ||
226 | spinlock->destroy(spinlock); | |
227 | barrier_destroy(barrier); | |
228 | } | |
229 | END_TEST | |
230 | ||
13183a74 MW |
231 | static void *condvar_run(void *data) |
232 | { | |
233 | mutex->lock(mutex); | |
234 | sigcount++; | |
235 | condvar->signal(condvar); | |
236 | mutex->unlock(mutex); | |
237 | return NULL; | |
238 | } | |
239 | ||
240 | START_TEST(test_condvar) | |
241 | { | |
242 | thread_t *threads[THREADS]; | |
243 | int i; | |
244 | ||
245 | mutex = mutex_create(MUTEX_TYPE_DEFAULT); | |
246 | condvar = condvar_create(CONDVAR_TYPE_DEFAULT); | |
247 | sigcount = 0; | |
248 | ||
249 | for (i = 0; i < THREADS; i++) | |
250 | { | |
251 | threads[i] = thread_create(condvar_run, NULL); | |
252 | } | |
253 | ||
254 | mutex->lock(mutex); | |
255 | while (sigcount < THREADS) | |
256 | { | |
257 | condvar->wait(condvar, mutex); | |
258 | } | |
259 | mutex->unlock(mutex); | |
260 | ||
261 | for (i = 0; i < THREADS; i++) | |
262 | { | |
263 | threads[i]->join(threads[i]); | |
264 | } | |
265 | ||
266 | mutex->destroy(mutex); | |
267 | condvar->destroy(condvar); | |
268 | } | |
269 | END_TEST | |
270 | ||
b7db393d MW |
271 | static void *condvar_recursive_run(void *data) |
272 | { | |
273 | mutex->lock(mutex); | |
274 | mutex->lock(mutex); | |
275 | mutex->lock(mutex); | |
276 | sigcount++; | |
277 | condvar->signal(condvar); | |
278 | mutex->unlock(mutex); | |
279 | mutex->unlock(mutex); | |
280 | mutex->unlock(mutex); | |
281 | return NULL; | |
282 | } | |
283 | ||
284 | START_TEST(test_condvar_recursive) | |
285 | { | |
286 | thread_t *threads[THREADS]; | |
287 | int i; | |
288 | ||
289 | mutex = mutex_create(MUTEX_TYPE_RECURSIVE); | |
290 | condvar = condvar_create(CONDVAR_TYPE_DEFAULT); | |
291 | sigcount = 0; | |
292 | ||
293 | mutex->lock(mutex); | |
294 | ||
295 | for (i = 0; i < THREADS; i++) | |
296 | { | |
297 | threads[i] = thread_create(condvar_recursive_run, NULL); | |
298 | } | |
299 | ||
300 | mutex->lock(mutex); | |
301 | mutex->lock(mutex); | |
302 | while (sigcount < THREADS) | |
303 | { | |
304 | condvar->wait(condvar, mutex); | |
305 | } | |
306 | mutex->unlock(mutex); | |
307 | mutex->unlock(mutex); | |
308 | mutex->unlock(mutex); | |
309 | ||
310 | for (i = 0; i < THREADS; i++) | |
311 | { | |
312 | threads[i]->join(threads[i]); | |
313 | } | |
314 | ||
315 | mutex->destroy(mutex); | |
316 | condvar->destroy(condvar); | |
317 | } | |
318 | END_TEST | |
319 | ||
9a0a891e MW |
320 | static void *condvar_run_broad(void *data) |
321 | { | |
322 | mutex->lock(mutex); | |
323 | while (sigcount < 0) | |
324 | { | |
325 | condvar->wait(condvar, mutex); | |
326 | } | |
327 | mutex->unlock(mutex); | |
328 | return NULL; | |
329 | } | |
330 | ||
331 | START_TEST(test_condvar_broad) | |
332 | { | |
333 | thread_t *threads[THREADS]; | |
334 | int i; | |
335 | ||
336 | mutex = mutex_create(MUTEX_TYPE_DEFAULT); | |
337 | condvar = condvar_create(CONDVAR_TYPE_DEFAULT); | |
338 | sigcount = 0; | |
339 | ||
340 | for (i = 0; i < THREADS; i++) | |
341 | { | |
342 | threads[i] = thread_create(condvar_run_broad, NULL); | |
343 | } | |
344 | ||
345 | sched_yield(); | |
346 | ||
347 | mutex->lock(mutex); | |
348 | sigcount = 1; | |
349 | condvar->broadcast(condvar); | |
350 | mutex->unlock(mutex); | |
351 | ||
352 | for (i = 0; i < THREADS; i++) | |
353 | { | |
354 | threads[i]->join(threads[i]); | |
355 | } | |
356 | ||
357 | mutex->destroy(mutex); | |
358 | condvar->destroy(condvar); | |
359 | } | |
360 | END_TEST | |
361 | ||
31f9f777 MW |
362 | START_TEST(test_condvar_timed) |
363 | { | |
364 | thread_t *thread; | |
365 | timeval_t start, end, diff = { .tv_usec = 50000 }; | |
366 | ||
367 | mutex = mutex_create(MUTEX_TYPE_DEFAULT); | |
368 | condvar = condvar_create(CONDVAR_TYPE_DEFAULT); | |
369 | sigcount = 0; | |
370 | ||
371 | mutex->lock(mutex); | |
372 | while (TRUE) | |
373 | { | |
374 | time_monotonic(&start); | |
375 | if (condvar->timed_wait(condvar, mutex, diff.tv_usec / 1000)) | |
376 | { | |
377 | break; | |
378 | } | |
379 | } | |
380 | time_monotonic(&end); | |
381 | mutex->unlock(mutex); | |
382 | timersub(&end, &start, &end); | |
383 | ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u", | |
384 | end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec); | |
385 | ||
386 | thread = thread_create(condvar_run, NULL); | |
387 | ||
388 | mutex->lock(mutex); | |
389 | while (sigcount == 0) | |
390 | { | |
391 | ck_assert(!condvar->timed_wait(condvar, mutex, 1000)); | |
392 | } | |
393 | mutex->unlock(mutex); | |
394 | ||
395 | thread->join(thread); | |
396 | mutex->destroy(mutex); | |
397 | condvar->destroy(condvar); | |
398 | } | |
399 | END_TEST | |
400 | ||
8699a32b MW |
401 | START_TEST(test_condvar_timed_abs) |
402 | { | |
403 | thread_t *thread; | |
404 | timeval_t start, end, abso, diff = { .tv_usec = 50000 }; | |
405 | ||
406 | mutex = mutex_create(MUTEX_TYPE_DEFAULT); | |
407 | condvar = condvar_create(CONDVAR_TYPE_DEFAULT); | |
408 | sigcount = 0; | |
409 | ||
410 | mutex->lock(mutex); | |
411 | while (TRUE) | |
412 | { | |
413 | time_monotonic(&start); | |
414 | timeradd(&start, &diff, &abso); | |
415 | if (condvar->timed_wait_abs(condvar, mutex, abso)) | |
416 | { | |
417 | break; | |
418 | } | |
419 | } | |
420 | time_monotonic(&end); | |
421 | mutex->unlock(mutex); | |
422 | ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u", | |
423 | end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec); | |
424 | ||
425 | thread = thread_create(condvar_run, NULL); | |
426 | ||
427 | time_monotonic(&start); | |
428 | diff.tv_sec = 1; | |
429 | timeradd(&start, &diff, &abso); | |
430 | mutex->lock(mutex); | |
431 | while (sigcount == 0) | |
432 | { | |
433 | ck_assert(!condvar->timed_wait_abs(condvar, mutex, abso)); | |
434 | } | |
435 | mutex->unlock(mutex); | |
436 | ||
437 | thread->join(thread); | |
438 | mutex->destroy(mutex); | |
439 | condvar->destroy(condvar); | |
440 | } | |
441 | END_TEST | |
442 | ||
8b25b5c3 MW |
443 | static void *condvar_cancel_run(void *data) |
444 | { | |
445 | thread_cancelability(FALSE); | |
446 | ||
447 | mutex->lock(mutex); | |
448 | ||
449 | sigcount++; | |
450 | condvar->broadcast(condvar); | |
451 | ||
452 | thread_cleanup_push((void*)mutex->unlock, mutex); | |
453 | thread_cancelability(TRUE); | |
454 | while (TRUE) | |
455 | { | |
456 | condvar->wait(condvar, mutex); | |
457 | } | |
458 | thread_cleanup_pop(TRUE); | |
459 | ||
460 | return NULL; | |
461 | } | |
462 | ||
463 | START_TEST(test_condvar_cancel) | |
464 | { | |
465 | thread_t *threads[THREADS]; | |
466 | int i; | |
467 | ||
468 | mutex = mutex_create(MUTEX_TYPE_DEFAULT); | |
469 | condvar = condvar_create(CONDVAR_TYPE_DEFAULT); | |
470 | sigcount = 0; | |
471 | ||
472 | for (i = 0; i < THREADS; i++) | |
473 | { | |
474 | threads[i] = thread_create(condvar_cancel_run, NULL); | |
475 | } | |
476 | ||
477 | /* wait for all threads */ | |
478 | mutex->lock(mutex); | |
479 | while (sigcount < THREADS) | |
480 | { | |
481 | condvar->wait(condvar, mutex); | |
482 | } | |
483 | mutex->unlock(mutex); | |
484 | ||
485 | for (i = 0; i < THREADS; i++) | |
486 | { | |
487 | threads[i]->cancel(threads[i]); | |
488 | } | |
489 | for (i = 0; i < THREADS; i++) | |
490 | { | |
491 | threads[i]->join(threads[i]); | |
492 | } | |
493 | ||
494 | mutex->destroy(mutex); | |
495 | condvar->destroy(condvar); | |
496 | } | |
497 | END_TEST | |
498 | ||
dac31fe1 MW |
499 | /** |
500 | * RWlock for different tests | |
501 | */ | |
502 | static rwlock_t *rwlock; | |
503 | ||
504 | static void *rwlock_run(refcount_t *refs) | |
505 | { | |
506 | rwlock->read_lock(rwlock); | |
507 | ref_get(refs); | |
508 | sched_yield(); | |
509 | ignore_result(ref_put(refs)); | |
510 | rwlock->unlock(rwlock); | |
511 | ||
512 | if (rwlock->try_write_lock(rwlock)) | |
513 | { | |
514 | ck_assert_int_eq(*refs, 0); | |
515 | sched_yield(); | |
516 | rwlock->unlock(rwlock); | |
517 | } | |
518 | ||
519 | rwlock->write_lock(rwlock); | |
520 | ck_assert_int_eq(*refs, 0); | |
521 | sched_yield(); | |
522 | rwlock->unlock(rwlock); | |
523 | ||
524 | rwlock->read_lock(rwlock); | |
525 | rwlock->read_lock(rwlock); | |
526 | ref_get(refs); | |
527 | sched_yield(); | |
528 | ignore_result(ref_put(refs)); | |
529 | rwlock->unlock(rwlock); | |
530 | rwlock->unlock(rwlock); | |
531 | ||
532 | return NULL; | |
533 | } | |
534 | ||
535 | START_TEST(test_rwlock) | |
536 | { | |
537 | thread_t *threads[THREADS]; | |
538 | refcount_t refs = 0; | |
539 | int i; | |
540 | ||
541 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
542 | ||
543 | for (i = 0; i < THREADS; i++) | |
544 | { | |
545 | threads[i] = thread_create((void*)rwlock_run, &refs); | |
546 | } | |
547 | for (i = 0; i < THREADS; i++) | |
548 | { | |
549 | threads[i]->join(threads[i]); | |
550 | } | |
551 | ||
552 | rwlock->destroy(rwlock); | |
553 | } | |
554 | END_TEST | |
555 | ||
6a3f0467 MW |
556 | static void *rwlock_try_run(void *param) |
557 | { | |
558 | if (rwlock->try_write_lock(rwlock)) | |
559 | { | |
560 | rwlock->unlock(rwlock); | |
561 | return param; | |
562 | } | |
563 | return NULL; | |
564 | } | |
565 | ||
566 | START_TEST(test_rwlock_try) | |
567 | { | |
568 | uintptr_t magic = 0xcafebabe; | |
569 | thread_t *thread; | |
570 | ||
571 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
572 | ||
573 | thread = thread_create(rwlock_try_run, (void*)magic); | |
574 | ck_assert_int_eq((uintptr_t)thread->join(thread), magic); | |
575 | ||
576 | rwlock->read_lock(rwlock); | |
577 | thread = thread_create(rwlock_try_run, (void*)magic); | |
578 | ck_assert(thread->join(thread) == NULL); | |
579 | rwlock->unlock(rwlock); | |
580 | ||
581 | rwlock->read_lock(rwlock); | |
582 | rwlock->read_lock(rwlock); | |
583 | rwlock->read_lock(rwlock); | |
584 | thread = thread_create(rwlock_try_run, (void*)magic); | |
585 | ck_assert(thread->join(thread) == NULL); | |
586 | rwlock->unlock(rwlock); | |
587 | rwlock->unlock(rwlock); | |
588 | rwlock->unlock(rwlock); | |
589 | ||
590 | rwlock->write_lock(rwlock); | |
591 | thread = thread_create(rwlock_try_run, (void*)magic); | |
592 | ck_assert(thread->join(thread) == NULL); | |
593 | rwlock->unlock(rwlock); | |
594 | ||
595 | rwlock->destroy(rwlock); | |
596 | } | |
597 | END_TEST | |
598 | ||
f644b9e8 MW |
599 | /** |
600 | * Rwlock condvar | |
601 | */ | |
602 | static rwlock_condvar_t *rwcond; | |
603 | ||
604 | static void *rwlock_condvar_run(void *data) | |
605 | { | |
606 | rwlock->write_lock(rwlock); | |
607 | sigcount++; | |
608 | rwcond->signal(rwcond); | |
609 | rwlock->unlock(rwlock); | |
610 | return NULL; | |
611 | } | |
612 | ||
613 | START_TEST(test_rwlock_condvar) | |
614 | { | |
615 | thread_t *threads[THREADS]; | |
616 | int i; | |
617 | ||
618 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
619 | rwcond = rwlock_condvar_create(); | |
620 | sigcount = 0; | |
621 | ||
622 | for (i = 0; i < THREADS; i++) | |
623 | { | |
624 | threads[i] = thread_create(rwlock_condvar_run, NULL); | |
625 | } | |
626 | ||
627 | rwlock->write_lock(rwlock); | |
628 | while (sigcount < THREADS) | |
629 | { | |
630 | rwcond->wait(rwcond, rwlock); | |
631 | } | |
632 | rwlock->unlock(rwlock); | |
633 | ||
634 | for (i = 0; i < THREADS; i++) | |
635 | { | |
636 | threads[i]->join(threads[i]); | |
637 | } | |
638 | ||
639 | rwlock->destroy(rwlock); | |
640 | rwcond->destroy(rwcond); | |
641 | } | |
642 | END_TEST | |
643 | ||
1032f52d MW |
644 | static void *rwlock_condvar_run_broad(void *data) |
645 | { | |
646 | rwlock->write_lock(rwlock); | |
647 | while (sigcount < 0) | |
648 | { | |
649 | rwcond->wait(rwcond, rwlock); | |
650 | } | |
651 | rwlock->unlock(rwlock); | |
652 | return NULL; | |
653 | } | |
654 | ||
655 | START_TEST(test_rwlock_condvar_broad) | |
656 | { | |
657 | thread_t *threads[THREADS]; | |
658 | int i; | |
659 | ||
660 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
661 | rwcond = rwlock_condvar_create(); | |
662 | sigcount = 0; | |
663 | ||
664 | for (i = 0; i < THREADS; i++) | |
665 | { | |
666 | threads[i] = thread_create(rwlock_condvar_run_broad, NULL); | |
667 | } | |
668 | ||
669 | sched_yield(); | |
670 | ||
671 | rwlock->write_lock(rwlock); | |
672 | sigcount = 1; | |
673 | rwcond->broadcast(rwcond); | |
674 | rwlock->unlock(rwlock); | |
675 | ||
676 | for (i = 0; i < THREADS; i++) | |
677 | { | |
678 | threads[i]->join(threads[i]); | |
679 | } | |
680 | ||
681 | rwlock->destroy(rwlock); | |
682 | rwcond->destroy(rwcond); | |
683 | } | |
684 | END_TEST | |
685 | ||
af19213c MW |
686 | START_TEST(test_rwlock_condvar_timed) |
687 | { | |
688 | thread_t *thread; | |
689 | timeval_t start, end, diff = { .tv_usec = 50000 }; | |
690 | ||
691 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
692 | rwcond = rwlock_condvar_create(); | |
693 | sigcount = 0; | |
694 | ||
695 | rwlock->write_lock(rwlock); | |
696 | while (TRUE) | |
697 | { | |
698 | time_monotonic(&start); | |
699 | if (rwcond->timed_wait(rwcond, rwlock, diff.tv_usec / 1000)) | |
700 | { | |
701 | break; | |
702 | } | |
703 | } | |
704 | rwlock->unlock(rwlock); | |
705 | time_monotonic(&end); | |
706 | timersub(&end, &start, &end); | |
707 | ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u", | |
708 | end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec); | |
709 | ||
710 | thread = thread_create(rwlock_condvar_run, NULL); | |
711 | ||
712 | rwlock->write_lock(rwlock); | |
713 | while (sigcount == 0) | |
714 | { | |
715 | ck_assert(!rwcond->timed_wait(rwcond, rwlock, 1000)); | |
716 | } | |
717 | rwlock->unlock(rwlock); | |
718 | ||
719 | thread->join(thread); | |
720 | rwlock->destroy(rwlock); | |
721 | rwcond->destroy(rwcond); | |
722 | } | |
723 | END_TEST | |
724 | ||
b92c173b MW |
725 | START_TEST(test_rwlock_condvar_timed_abs) |
726 | { | |
727 | thread_t *thread; | |
728 | timeval_t start, end, abso, diff = { .tv_usec = 50000 }; | |
729 | ||
730 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
731 | rwcond = rwlock_condvar_create(); | |
732 | sigcount = 0; | |
733 | ||
734 | rwlock->write_lock(rwlock); | |
735 | while (TRUE) | |
736 | { | |
737 | time_monotonic(&start); | |
738 | timeradd(&start, &diff, &abso); | |
739 | if (rwcond->timed_wait_abs(rwcond, rwlock, abso)) | |
740 | { | |
741 | break; | |
742 | } | |
743 | } | |
744 | rwlock->unlock(rwlock); | |
745 | time_monotonic(&end); | |
746 | ck_assert_msg(timercmp(&end, &abso, >), "end: %u.%u, abso: %u.%u", | |
747 | end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec); | |
748 | ||
749 | thread = thread_create(rwlock_condvar_run, NULL); | |
750 | ||
751 | time_monotonic(&start); | |
752 | diff.tv_sec = 1; | |
753 | timeradd(&start, &diff, &abso); | |
754 | rwlock->write_lock(rwlock); | |
755 | while (sigcount == 0) | |
756 | { | |
757 | ck_assert(!rwcond->timed_wait_abs(rwcond, rwlock, abso)); | |
758 | } | |
759 | rwlock->unlock(rwlock); | |
760 | ||
761 | thread->join(thread); | |
762 | rwlock->destroy(rwlock); | |
763 | rwcond->destroy(rwcond); | |
764 | } | |
765 | END_TEST | |
766 | ||
478dc025 MW |
767 | static void *rwlock_condvar_cancel_run(void *data) |
768 | { | |
769 | thread_cancelability(FALSE); | |
770 | ||
771 | rwlock->write_lock(rwlock); | |
772 | ||
773 | sigcount++; | |
774 | rwcond->broadcast(rwcond); | |
775 | ||
776 | thread_cleanup_push((void*)rwlock->unlock, rwlock); | |
777 | thread_cancelability(TRUE); | |
778 | while (TRUE) | |
779 | { | |
780 | rwcond->wait(rwcond, rwlock); | |
781 | } | |
782 | thread_cleanup_pop(TRUE); | |
783 | ||
784 | return NULL; | |
785 | } | |
786 | ||
787 | START_TEST(test_rwlock_condvar_cancel) | |
788 | { | |
789 | thread_t *threads[THREADS]; | |
790 | int i; | |
791 | ||
792 | rwlock = rwlock_create(RWLOCK_TYPE_DEFAULT); | |
793 | rwcond = rwlock_condvar_create(); | |
794 | sigcount = 0; | |
795 | ||
796 | for (i = 0; i < THREADS; i++) | |
797 | { | |
798 | threads[i] = thread_create(rwlock_condvar_cancel_run, NULL); | |
799 | } | |
800 | ||
801 | /* wait for all threads */ | |
802 | rwlock->write_lock(rwlock); | |
803 | while (sigcount < THREADS) | |
804 | { | |
805 | rwcond->wait(rwcond, rwlock); | |
806 | } | |
807 | rwlock->unlock(rwlock); | |
808 | ||
809 | for (i = 0; i < THREADS; i++) | |
810 | { | |
811 | threads[i]->cancel(threads[i]); | |
812 | } | |
813 | for (i = 0; i < THREADS; i++) | |
814 | { | |
815 | threads[i]->join(threads[i]); | |
816 | } | |
817 | ||
818 | rwlock->destroy(rwlock); | |
819 | rwcond->destroy(rwcond); | |
820 | } | |
821 | END_TEST | |
822 | ||
ffab2e0c MW |
823 | /** |
824 | * Semaphore for different tests | |
825 | */ | |
826 | static semaphore_t *semaphore; | |
827 | ||
828 | static void *semaphore_run(void *data) | |
829 | { | |
830 | semaphore->post(semaphore); | |
831 | return NULL; | |
832 | } | |
833 | ||
834 | START_TEST(test_semaphore) | |
835 | { | |
836 | thread_t *threads[THREADS]; | |
837 | int i, initial = 5; | |
838 | ||
839 | semaphore = semaphore_create(initial); | |
840 | ||
841 | for (i = 0; i < THREADS; i++) | |
842 | { | |
843 | threads[i] = thread_create(semaphore_run, NULL); | |
844 | } | |
845 | for (i = 0; i < THREADS + initial; i++) | |
846 | { | |
847 | semaphore->wait(semaphore); | |
848 | } | |
849 | for (i = 0; i < THREADS; i++) | |
850 | { | |
851 | threads[i]->join(threads[i]); | |
852 | } | |
853 | ||
854 | semaphore->destroy(semaphore); | |
855 | } | |
856 | END_TEST | |
857 | ||
a14935ea MW |
858 | START_TEST(test_semaphore_timed) |
859 | { | |
860 | thread_t *thread; | |
861 | timeval_t start, end, diff = { .tv_usec = 50000 }; | |
862 | ||
863 | semaphore = semaphore_create(0); | |
864 | ||
865 | time_monotonic(&start); | |
866 | ck_assert(semaphore->timed_wait(semaphore, diff.tv_usec / 1000)); | |
867 | time_monotonic(&end); | |
868 | timersub(&end, &start, &end); | |
869 | ck_assert_msg(timercmp(&end, &diff, >), "end: %u.%u, diff: %u.%u", | |
870 | end.tv_sec, end.tv_usec, diff.tv_sec, diff.tv_usec); | |
871 | ||
872 | thread = thread_create(semaphore_run, NULL); | |
873 | ||
874 | ck_assert(!semaphore->timed_wait(semaphore, 1000)); | |
875 | ||
876 | thread->join(thread); | |
877 | semaphore->destroy(semaphore); | |
878 | } | |
879 | END_TEST | |
880 | ||
fae1b852 MW |
881 | START_TEST(test_semaphore_timed_abs) |
882 | { | |
883 | thread_t *thread; | |
884 | timeval_t start, end, abso, diff = { .tv_usec = 50000 }; | |
885 | ||
886 | semaphore = semaphore_create(0); | |
887 | ||
888 | time_monotonic(&start); | |
889 | timeradd(&start, &diff, &abso); | |
890 | ck_assert(semaphore->timed_wait_abs(semaphore, abso)); | |
891 | time_monotonic(&end); | |
892 | ck_assert_msg(timercmp(&end, &abso, >), "end: %u.%u, abso: %u.%u", | |
893 | end.tv_sec, end.tv_usec, abso.tv_sec, abso.tv_usec); | |
894 | ||
895 | thread = thread_create(semaphore_run, NULL); | |
896 | ||
897 | time_monotonic(&start); | |
898 | diff.tv_sec = 1; | |
899 | timeradd(&start, &diff, &abso); | |
900 | ck_assert(!semaphore->timed_wait_abs(semaphore, abso)); | |
901 | ||
902 | thread->join(thread); | |
903 | semaphore->destroy(semaphore); | |
904 | } | |
905 | END_TEST | |
906 | ||
a4cbda35 MW |
907 | static void *semaphore_cancel_run(void *data) |
908 | { | |
909 | refcount_t *ready = (refcount_t*)data; | |
910 | ||
911 | thread_cancelability(FALSE); | |
912 | ref_get(ready); | |
913 | ||
914 | thread_cancelability(TRUE); | |
915 | semaphore->wait(semaphore); | |
916 | ||
917 | ck_assert(FALSE); | |
918 | return NULL; | |
919 | } | |
920 | ||
921 | START_TEST(test_semaphore_cancel) | |
922 | { | |
923 | thread_t *threads[THREADS]; | |
924 | refcount_t ready = 0; | |
925 | int i; | |
926 | ||
927 | semaphore = semaphore_create(0); | |
928 | ||
929 | for (i = 0; i < THREADS; i++) | |
930 | { | |
931 | threads[i] = thread_create(semaphore_cancel_run, &ready); | |
932 | } | |
933 | while (ready < THREADS) | |
934 | { | |
935 | sched_yield(); | |
936 | } | |
937 | for (i = 0; i < THREADS; i++) | |
938 | { | |
939 | threads[i]->cancel(threads[i]); | |
940 | } | |
941 | for (i = 0; i < THREADS; i++) | |
942 | { | |
943 | threads[i]->join(threads[i]); | |
944 | } | |
945 | ||
946 | semaphore->destroy(semaphore); | |
947 | } | |
948 | END_TEST | |
949 | ||
5d4a882f MW |
950 | static void *join_run(void *data) |
951 | { | |
952 | /* force some context switches */ | |
953 | sched_yield(); | |
954 | return (void*)((uintptr_t)data + THREADS); | |
955 | } | |
956 | ||
957 | START_TEST(test_join) | |
958 | { | |
959 | thread_t *threads[THREADS]; | |
960 | int i; | |
961 | ||
962 | for (i = 0; i < THREADS; i++) | |
963 | { | |
964 | threads[i] = thread_create(join_run, (void*)(uintptr_t)i); | |
965 | } | |
966 | for (i = 0; i < THREADS; i++) | |
967 | { | |
968 | ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS); | |
969 | } | |
970 | } | |
971 | END_TEST | |
972 | ||
c320c611 MW |
973 | static void *exit_join_run(void *data) |
974 | { | |
975 | sched_yield(); | |
976 | thread_exit((void*)((uintptr_t)data + THREADS)); | |
977 | /* not reached */ | |
978 | ck_assert(FALSE); | |
979 | return NULL; | |
980 | } | |
981 | ||
982 | START_TEST(test_join_exit) | |
983 | { | |
984 | thread_t *threads[THREADS]; | |
985 | int i; | |
986 | ||
987 | for (i = 0; i < THREADS; i++) | |
988 | { | |
989 | threads[i] = thread_create(exit_join_run, (void*)(uintptr_t)i); | |
990 | } | |
991 | for (i = 0; i < THREADS; i++) | |
992 | { | |
993 | ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + THREADS); | |
994 | } | |
995 | } | |
996 | END_TEST | |
997 | ||
274e6beb MW |
998 | static void *detach_run(void *data) |
999 | { | |
1000 | refcount_t *running = (refcount_t*)data; | |
1001 | ||
1002 | ignore_result(ref_put(running)); | |
1003 | return NULL; | |
1004 | } | |
1005 | ||
1006 | START_TEST(test_detach) | |
1007 | { | |
1008 | thread_t *threads[THREADS]; | |
1009 | int i; | |
1010 | refcount_t running = 0; | |
1011 | ||
1012 | for (i = 0; i < THREADS; i++) | |
1013 | { | |
1014 | ref_get(&running); | |
1015 | threads[i] = thread_create(detach_run, &running); | |
1016 | } | |
1017 | for (i = 0; i < THREADS; i++) | |
1018 | { | |
1019 | threads[i]->detach(threads[i]); | |
1020 | } | |
1021 | while (running > 0) | |
1022 | { | |
1023 | sched_yield(); | |
1024 | } | |
1025 | /* no checks done here, but we check that thread state gets cleaned | |
c6f886ce TB |
1026 | * up with leak detective. give the threads time to clean up. */ |
1027 | usleep(10000); | |
274e6beb MW |
1028 | } |
1029 | END_TEST | |
1030 | ||
c320c611 MW |
1031 | static void *detach_exit_run(void *data) |
1032 | { | |
1033 | refcount_t *running = (refcount_t*)data; | |
1034 | ||
1035 | ignore_result(ref_put(running)); | |
1036 | thread_exit(NULL); | |
1037 | /* not reached */ | |
1038 | ck_assert(FALSE); | |
1039 | return NULL; | |
1040 | } | |
1041 | ||
1042 | START_TEST(test_detach_exit) | |
1043 | { | |
1044 | thread_t *threads[THREADS]; | |
1045 | int i; | |
1046 | refcount_t running = 0; | |
1047 | ||
1048 | for (i = 0; i < THREADS; i++) | |
1049 | { | |
1050 | ref_get(&running); | |
1051 | threads[i] = thread_create(detach_exit_run, &running); | |
1052 | } | |
1053 | for (i = 0; i < THREADS; i++) | |
1054 | { | |
1055 | threads[i]->detach(threads[i]); | |
1056 | } | |
1057 | while (running > 0) | |
1058 | { | |
1059 | sched_yield(); | |
1060 | } | |
1061 | /* no checks done here, but we check that thread state gets cleaned | |
c6f886ce TB |
1062 | * up with leak detective. give the threads time to clean up. */ |
1063 | usleep(10000); | |
c320c611 MW |
1064 | } |
1065 | END_TEST | |
1066 | ||
855747ea MW |
1067 | static void *cancel_run(void *data) |
1068 | { | |
1069 | /* default cancellability should be TRUE, so don't change it */ | |
1070 | while (TRUE) | |
1071 | { | |
1072 | sleep(10); | |
1073 | } | |
1074 | return NULL; | |
1075 | } | |
1076 | ||
1077 | START_TEST(test_cancel) | |
1078 | { | |
1079 | thread_t *threads[THREADS]; | |
1080 | int i; | |
1081 | ||
1082 | for (i = 0; i < THREADS; i++) | |
1083 | { | |
1084 | threads[i] = thread_create(cancel_run, NULL); | |
1085 | } | |
1086 | for (i = 0; i < THREADS; i++) | |
1087 | { | |
1088 | threads[i]->cancel(threads[i]); | |
1089 | } | |
1090 | for (i = 0; i < THREADS; i++) | |
1091 | { | |
1092 | threads[i]->join(threads[i]); | |
1093 | } | |
1094 | } | |
1095 | END_TEST | |
1096 | ||
49e6848b MW |
1097 | static void *cancel_onoff_run(void *data) |
1098 | { | |
1099 | bool *cancellable = (bool*)data; | |
1100 | ||
1101 | thread_cancelability(FALSE); | |
1102 | *cancellable = FALSE; | |
1103 | ||
1104 | /* we should not get cancelled here */ | |
1105 | usleep(50000); | |
1106 | ||
1107 | *cancellable = TRUE; | |
1108 | thread_cancelability(TRUE); | |
1109 | ||
1110 | /* but here */ | |
1111 | while (TRUE) | |
1112 | { | |
1113 | sleep(10); | |
1114 | } | |
1115 | return NULL; | |
1116 | } | |
1117 | ||
1118 | START_TEST(test_cancel_onoff) | |
1119 | { | |
1120 | thread_t *threads[THREADS]; | |
1121 | bool cancellable[THREADS]; | |
1122 | int i; | |
1123 | ||
1124 | for (i = 0; i < THREADS; i++) | |
1125 | { | |
1126 | cancellable[i] = TRUE; | |
1127 | threads[i] = thread_create(cancel_onoff_run, &cancellable[i]); | |
1128 | } | |
1129 | for (i = 0; i < THREADS; i++) | |
1130 | { | |
1131 | /* wait until thread has cleared its cancellability */ | |
1132 | while (cancellable[i]) | |
1133 | { | |
1134 | sched_yield(); | |
1135 | } | |
1136 | threads[i]->cancel(threads[i]); | |
1137 | } | |
1138 | for (i = 0; i < THREADS; i++) | |
1139 | { | |
1140 | threads[i]->join(threads[i]); | |
1141 | ck_assert(cancellable[i]); | |
1142 | } | |
1143 | } | |
1144 | END_TEST | |
1145 | ||
e5b34086 MW |
1146 | static void *cancel_point_run(void *data) |
1147 | { | |
1148 | thread_cancelability(FALSE); | |
1149 | while (TRUE) | |
1150 | { | |
1151 | /* implicitly enables cancellability */ | |
1152 | thread_cancellation_point(); | |
1153 | } | |
1154 | return NULL; | |
1155 | } | |
1156 | ||
1157 | START_TEST(test_cancel_point) | |
1158 | { | |
1159 | thread_t *threads[THREADS]; | |
1160 | int i; | |
1161 | ||
1162 | for (i = 0; i < THREADS; i++) | |
1163 | { | |
1164 | threads[i] = thread_create(cancel_point_run, NULL); | |
1165 | } | |
1166 | sched_yield(); | |
1167 | for (i = 0; i < THREADS; i++) | |
1168 | { | |
1169 | threads[i]->cancel(threads[i]); | |
1170 | } | |
1171 | for (i = 0; i < THREADS; i++) | |
1172 | { | |
1173 | threads[i]->join(threads[i]); | |
1174 | } | |
1175 | } | |
1176 | END_TEST | |
1177 | ||
4aec0c55 MW |
1178 | static void cleanup1(void *data) |
1179 | { | |
1180 | uintptr_t *value = (uintptr_t*)data; | |
1181 | ||
1182 | ck_assert_int_eq(*value, 1); | |
1183 | (*value)++; | |
1184 | } | |
1185 | ||
1186 | static void cleanup2(void *data) | |
1187 | { | |
1188 | uintptr_t *value = (uintptr_t*)data; | |
1189 | ||
1190 | ck_assert_int_eq(*value, 2); | |
1191 | (*value)++; | |
1192 | } | |
1193 | ||
1194 | static void cleanup3(void *data) | |
1195 | { | |
1196 | uintptr_t *value = (uintptr_t*)data; | |
1197 | ||
1198 | ck_assert_int_eq(*value, 3); | |
1199 | (*value)++; | |
1200 | } | |
1201 | ||
1202 | static void *cleanup_run(void *data) | |
1203 | { | |
1204 | thread_cleanup_push(cleanup3, data); | |
1205 | thread_cleanup_push(cleanup2, data); | |
1206 | thread_cleanup_push(cleanup1, data); | |
1207 | return NULL; | |
1208 | } | |
1209 | ||
1210 | START_TEST(test_cleanup) | |
1211 | { | |
1212 | thread_t *threads[THREADS]; | |
1213 | uintptr_t values[THREADS]; | |
1214 | int i; | |
1215 | ||
1216 | for (i = 0; i < THREADS; i++) | |
1217 | { | |
1218 | values[i] = 1; | |
1219 | threads[i] = thread_create(cleanup_run, &values[i]); | |
1220 | } | |
1221 | for (i = 0; i < THREADS; i++) | |
1222 | { | |
1223 | threads[i]->join(threads[i]); | |
1224 | ck_assert_int_eq(values[i], 4); | |
1225 | } | |
1226 | } | |
1227 | END_TEST | |
1228 | ||
1229 | static void *cleanup_exit_run(void *data) | |
1230 | { | |
1231 | thread_cleanup_push(cleanup3, data); | |
1232 | thread_cleanup_push(cleanup2, data); | |
1233 | thread_cleanup_push(cleanup1, data); | |
1234 | thread_exit(NULL); | |
1235 | ck_assert(FALSE); | |
1236 | return NULL; | |
1237 | } | |
1238 | ||
1239 | START_TEST(test_cleanup_exit) | |
1240 | { | |
1241 | thread_t *threads[THREADS]; | |
1242 | uintptr_t values[THREADS]; | |
1243 | int i; | |
1244 | ||
1245 | for (i = 0; i < THREADS; i++) | |
1246 | { | |
1247 | values[i] = 1; | |
1248 | threads[i] = thread_create(cleanup_exit_run, &values[i]); | |
1249 | } | |
1250 | for (i = 0; i < THREADS; i++) | |
1251 | { | |
1252 | threads[i]->join(threads[i]); | |
1253 | ck_assert_int_eq(values[i], 4); | |
1254 | } | |
1255 | } | |
1256 | END_TEST | |
1257 | ||
1258 | static void *cleanup_cancel_run(void *data) | |
1259 | { | |
1260 | thread_cancelability(FALSE); | |
1261 | ||
b9dfeb5d TB |
1262 | barrier_wait(barrier); |
1263 | ||
4aec0c55 MW |
1264 | thread_cleanup_push(cleanup3, data); |
1265 | thread_cleanup_push(cleanup2, data); | |
1266 | thread_cleanup_push(cleanup1, data); | |
1267 | ||
1268 | thread_cancelability(TRUE); | |
1269 | ||
1270 | while (TRUE) | |
1271 | { | |
1272 | sleep(1); | |
1273 | } | |
1274 | return NULL; | |
1275 | } | |
1276 | ||
1277 | START_TEST(test_cleanup_cancel) | |
1278 | { | |
1279 | thread_t *threads[THREADS]; | |
1280 | uintptr_t values[THREADS]; | |
1281 | int i; | |
1282 | ||
b9dfeb5d | 1283 | barrier = barrier_create(THREADS+1); |
4aec0c55 MW |
1284 | for (i = 0; i < THREADS; i++) |
1285 | { | |
1286 | values[i] = 1; | |
1287 | threads[i] = thread_create(cleanup_cancel_run, &values[i]); | |
1288 | } | |
b9dfeb5d | 1289 | barrier_wait(barrier); |
4aec0c55 MW |
1290 | for (i = 0; i < THREADS; i++) |
1291 | { | |
1292 | threads[i]->cancel(threads[i]); | |
1293 | } | |
1294 | for (i = 0; i < THREADS; i++) | |
1295 | { | |
1296 | threads[i]->join(threads[i]); | |
1297 | ck_assert_int_eq(values[i], 4); | |
1298 | } | |
b9dfeb5d | 1299 | barrier_destroy(barrier); |
4aec0c55 MW |
1300 | } |
1301 | END_TEST | |
1302 | ||
fd26b7ff MW |
1303 | static void *cleanup_pop_run(void *data) |
1304 | { | |
1305 | thread_cleanup_push(cleanup3, data); | |
1306 | thread_cleanup_push(cleanup2, data); | |
1307 | thread_cleanup_push(cleanup1, data); | |
1308 | ||
1309 | thread_cleanup_push(cleanup2, data); | |
1310 | thread_cleanup_pop(FALSE); | |
1311 | ||
1312 | thread_cleanup_pop(TRUE); | |
1313 | return NULL; | |
1314 | } | |
1315 | ||
1316 | START_TEST(test_cleanup_pop) | |
1317 | { | |
1318 | thread_t *threads[THREADS]; | |
1319 | uintptr_t values[THREADS]; | |
1320 | int i; | |
1321 | ||
1322 | for (i = 0; i < THREADS; i++) | |
1323 | { | |
1324 | values[i] = 1; | |
1325 | threads[i] = thread_create(cleanup_pop_run, &values[i]); | |
1326 | } | |
1327 | for (i = 0; i < THREADS; i++) | |
1328 | { | |
1329 | threads[i]->join(threads[i]); | |
1330 | ck_assert_int_eq(values[i], 4); | |
1331 | } | |
1332 | } | |
1333 | END_TEST | |
1334 | ||
0b00e63e MW |
1335 | static thread_value_t *tls[10]; |
1336 | ||
1337 | static void *tls_run(void *data) | |
1338 | { | |
1339 | uintptr_t value = (uintptr_t)data; | |
1340 | int i, j; | |
1341 | ||
1342 | for (i = 0; i < countof(tls); i++) | |
1343 | { | |
1344 | ck_assert(tls[i]->get(tls[i]) == NULL); | |
1345 | } | |
1346 | for (i = 0; i < countof(tls); i++) | |
1347 | { | |
1348 | tls[i]->set(tls[i], (void*)(value * i)); | |
1349 | } | |
1350 | for (j = 0; j < 1000; j++) | |
1351 | { | |
1352 | for (i = 0; i < countof(tls); i++) | |
1353 | { | |
1354 | tls[i]->set(tls[i], (void*)(value * i)); | |
1355 | ck_assert(tls[i]->get(tls[i]) == (void*)(value * i)); | |
1356 | } | |
1357 | sched_yield(); | |
1358 | } | |
1359 | for (i = 0; i < countof(tls); i++) | |
1360 | { | |
1361 | ck_assert(tls[i]->get(tls[i]) == (void*)(value * i)); | |
1362 | } | |
1363 | return (void*)(value + 1); | |
1364 | } | |
1365 | ||
1366 | START_TEST(test_tls) | |
1367 | { | |
1368 | thread_t *threads[THREADS]; | |
1369 | int i; | |
1370 | ||
1371 | for (i = 0; i < countof(tls); i++) | |
1372 | { | |
1373 | tls[i] = thread_value_create(NULL); | |
1374 | } | |
1375 | for (i = 0; i < THREADS; i++) | |
1376 | { | |
1377 | threads[i] = thread_create(tls_run, (void*)(uintptr_t)i); | |
1378 | } | |
1379 | ||
1380 | ck_assert_int_eq((uintptr_t)tls_run((void*)(uintptr_t)(THREADS + 1)), | |
1381 | THREADS + 2); | |
1382 | ||
1383 | for (i = 0; i < THREADS; i++) | |
1384 | { | |
1385 | ck_assert_int_eq((uintptr_t)threads[i]->join(threads[i]), i + 1); | |
1386 | } | |
1387 | for (i = 0; i < countof(tls); i++) | |
1388 | { | |
1389 | tls[i]->destroy(tls[i]); | |
1390 | } | |
1391 | } | |
1392 | END_TEST | |
1393 | ||
21df9851 MW |
1394 | static void tls_cleanup(void *data) |
1395 | { | |
1396 | uintptr_t *value = (uintptr_t*)data; | |
1397 | ||
1398 | (*value)--; | |
1399 | } | |
1400 | ||
1401 | static void *tls_cleanup_run(void *data) | |
1402 | { | |
1403 | int i; | |
1404 | ||
1405 | for (i = 0; i < countof(tls); i++) | |
1406 | { | |
1407 | tls[i]->set(tls[i], data); | |
1408 | } | |
1409 | return NULL; | |
1410 | } | |
1411 | ||
1412 | START_TEST(test_tls_cleanup) | |
1413 | { | |
1414 | thread_t *threads[THREADS]; | |
1415 | uintptr_t values[THREADS], main_value = countof(tls); | |
1416 | int i; | |
1417 | ||
1418 | for (i = 0; i < countof(tls); i++) | |
1419 | { | |
1420 | tls[i] = thread_value_create(tls_cleanup); | |
1421 | } | |
1422 | for (i = 0; i < THREADS; i++) | |
1423 | { | |
1424 | values[i] = countof(tls); | |
1425 | threads[i] = thread_create(tls_cleanup_run, &values[i]); | |
1426 | } | |
1427 | ||
1428 | tls_cleanup_run(&main_value); | |
1429 | ||
1430 | for (i = 0; i < THREADS; i++) | |
1431 | { | |
1432 | threads[i]->join(threads[i]); | |
1433 | ck_assert_int_eq(values[i], 0); | |
1434 | } | |
1435 | for (i = 0; i < countof(tls); i++) | |
1436 | { | |
1437 | tls[i]->destroy(tls[i]); | |
1438 | } | |
1439 | ck_assert_int_eq(main_value, 0); | |
1440 | } | |
1441 | END_TEST | |
1442 | ||
de42bf35 TB |
1443 | Suite *threading_suite_create() |
1444 | { | |
1445 | Suite *s; | |
1446 | TCase *tc; | |
1447 | ||
1448 | s = suite_create("threading"); | |
1449 | ||
1450 | tc = tcase_create("recursive mutex"); | |
1451 | tcase_add_test(tc, test_mutex); | |
1452 | suite_add_tcase(s, tc); | |
1453 | ||
b1bfe595 MW |
1454 | tc = tcase_create("spinlock"); |
1455 | tcase_add_test(tc, test_spinlock); | |
1456 | suite_add_tcase(s, tc); | |
1457 | ||
13183a74 MW |
1458 | tc = tcase_create("condvar"); |
1459 | tcase_add_test(tc, test_condvar); | |
b7db393d | 1460 | tcase_add_test(tc, test_condvar_recursive); |
9a0a891e | 1461 | tcase_add_test(tc, test_condvar_broad); |
31f9f777 | 1462 | tcase_add_test(tc, test_condvar_timed); |
8699a32b | 1463 | tcase_add_test(tc, test_condvar_timed_abs); |
8b25b5c3 | 1464 | tcase_add_test(tc, test_condvar_cancel); |
13183a74 MW |
1465 | suite_add_tcase(s, tc); |
1466 | ||
dac31fe1 MW |
1467 | tc = tcase_create("rwlock"); |
1468 | tcase_add_test(tc, test_rwlock); | |
6a3f0467 | 1469 | tcase_add_test(tc, test_rwlock_try); |
dac31fe1 MW |
1470 | suite_add_tcase(s, tc); |
1471 | ||
f644b9e8 MW |
1472 | tc = tcase_create("rwlock condvar"); |
1473 | tcase_add_test(tc, test_rwlock_condvar); | |
1032f52d | 1474 | tcase_add_test(tc, test_rwlock_condvar_broad); |
af19213c | 1475 | tcase_add_test(tc, test_rwlock_condvar_timed); |
b92c173b | 1476 | tcase_add_test(tc, test_rwlock_condvar_timed_abs); |
478dc025 | 1477 | tcase_add_test(tc, test_rwlock_condvar_cancel); |
f644b9e8 MW |
1478 | suite_add_tcase(s, tc); |
1479 | ||
ffab2e0c MW |
1480 | tc = tcase_create("semaphore"); |
1481 | tcase_add_test(tc, test_semaphore); | |
a14935ea | 1482 | tcase_add_test(tc, test_semaphore_timed); |
fae1b852 | 1483 | tcase_add_test(tc, test_semaphore_timed_abs); |
a4cbda35 | 1484 | tcase_add_test(tc, test_semaphore_cancel); |
ffab2e0c MW |
1485 | suite_add_tcase(s, tc); |
1486 | ||
5d4a882f MW |
1487 | tc = tcase_create("thread joining"); |
1488 | tcase_add_test(tc, test_join); | |
c320c611 | 1489 | tcase_add_test(tc, test_join_exit); |
5d4a882f MW |
1490 | suite_add_tcase(s, tc); |
1491 | ||
274e6beb MW |
1492 | tc = tcase_create("thread detaching"); |
1493 | tcase_add_test(tc, test_detach); | |
c320c611 | 1494 | tcase_add_test(tc, test_detach_exit); |
274e6beb MW |
1495 | suite_add_tcase(s, tc); |
1496 | ||
855747ea MW |
1497 | tc = tcase_create("thread cancellation"); |
1498 | tcase_add_test(tc, test_cancel); | |
49e6848b | 1499 | tcase_add_test(tc, test_cancel_onoff); |
e5b34086 | 1500 | tcase_add_test(tc, test_cancel_point); |
855747ea MW |
1501 | suite_add_tcase(s, tc); |
1502 | ||
4aec0c55 MW |
1503 | tc = tcase_create("thread cleanup"); |
1504 | tcase_add_test(tc, test_cleanup); | |
1505 | tcase_add_test(tc, test_cleanup_exit); | |
1506 | tcase_add_test(tc, test_cleanup_cancel); | |
fd26b7ff | 1507 | tcase_add_test(tc, test_cleanup_pop); |
4aec0c55 MW |
1508 | suite_add_tcase(s, tc); |
1509 | ||
0b00e63e MW |
1510 | tc = tcase_create("thread local storage"); |
1511 | tcase_add_test(tc, test_tls); | |
21df9851 | 1512 | tcase_add_test(tc, test_tls_cleanup); |
0b00e63e MW |
1513 | suite_add_tcase(s, tc); |
1514 | ||
de42bf35 TB |
1515 | return s; |
1516 | } |