1 /*-------------------------------------------------------------------------
2 * drawElements Thread Library
3 * ---------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Thread library tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deThreadTest.h"
25 #include "deThread.h"
26 #include "deMutex.h"
27 #include "deSemaphore.h"
28 #include "deMemory.h"
29 #include "deRandom.h"
30 #include "deAtomic.h"
31 #include "deThreadLocal.h"
32 #include "deSingleton.h"
33 #include "deMemPool.h"
34 #include "dePoolArray.h"
35
threadTestThr1(void * arg)36 static void threadTestThr1(void *arg)
37 {
38 int32_t val = *((int32_t *)arg);
39 DE_TEST_ASSERT(val == 123);
40 }
41
threadTestThr2(void * arg)42 static void threadTestThr2(void *arg)
43 {
44 DE_UNREF(arg);
45 deSleep(100);
46 }
47
48 typedef struct ThreadData3_s
49 {
50 uint8_t bytes[16];
51 } ThreadData3;
52
threadTestThr3(void * arg)53 static void threadTestThr3(void *arg)
54 {
55 ThreadData3 *data = (ThreadData3 *)arg;
56 int ndx;
57
58 for (ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(data->bytes); ndx++)
59 DE_TEST_ASSERT(data->bytes[ndx] == 0);
60
61 for (ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(data->bytes); ndx++)
62 data->bytes[ndx] = 0xff;
63 }
64
threadTestThr4(void * arg)65 static void threadTestThr4(void *arg)
66 {
67 deThreadLocal tls = *(deThreadLocal *)arg;
68 deThreadLocal_set(tls, DE_NULL);
69 }
70
71 #if defined(DE_THREAD_LOCAL)
72
73 static DE_THREAD_LOCAL int tls_testVar = 123;
74
tlsTestThr(void * arg)75 static void tlsTestThr(void *arg)
76 {
77 DE_UNREF(arg);
78 DE_TEST_ASSERT(tls_testVar == 123);
79 tls_testVar = 104;
80 DE_TEST_ASSERT(tls_testVar == 104);
81 }
82
83 #endif
84
deThread_selfTest(void)85 void deThread_selfTest(void)
86 {
87 /* Test sleep & yield. */
88 deSleep(0);
89 deSleep(100);
90 deYield();
91
92 /* Thread test 1. */
93 {
94 int32_t val = 123;
95 bool ret;
96 deThread thread = deThread_create(threadTestThr1, &val, DE_NULL);
97 DE_TEST_ASSERT(thread);
98
99 ret = deThread_join(thread);
100 DE_TEST_ASSERT(ret);
101
102 deThread_destroy(thread);
103 }
104
105 /* Thread test 2. */
106 {
107 deThread thread = deThread_create(threadTestThr2, DE_NULL, DE_NULL);
108 int32_t ret;
109 DE_TEST_ASSERT(thread);
110
111 ret = deThread_join(thread);
112 DE_TEST_ASSERT(ret);
113
114 deThread_destroy(thread);
115 }
116
117 /* Thread test 3. */
118 {
119 ThreadData3 data;
120 deThread thread;
121 bool ret;
122 int ndx;
123
124 deMemset(&data, 0, sizeof(ThreadData3));
125
126 thread = deThread_create(threadTestThr3, &data, DE_NULL);
127 DE_TEST_ASSERT(thread);
128
129 ret = deThread_join(thread);
130 DE_TEST_ASSERT(ret);
131
132 for (ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(data.bytes); ndx++)
133 DE_TEST_ASSERT(data.bytes[ndx] == 0xff);
134
135 deThread_destroy(thread);
136 }
137
138 /* Test tls. */
139 {
140 deThreadLocal tls;
141 deThread thread;
142
143 tls = deThreadLocal_create();
144 DE_TEST_ASSERT(tls);
145
146 deThreadLocal_set(tls, (void *)(uintptr_t)0xff);
147
148 thread = deThread_create(threadTestThr4, &tls, DE_NULL);
149 deThread_join(thread);
150 deThread_destroy(thread);
151
152 DE_TEST_ASSERT((uintptr_t)deThreadLocal_get(tls) == 0xff);
153 deThreadLocal_destroy(tls);
154 }
155
156 #if defined(DE_THREAD_LOCAL)
157 {
158 deThread thread;
159
160 DE_TEST_ASSERT(tls_testVar == 123);
161 tls_testVar = 1;
162 DE_TEST_ASSERT(tls_testVar == 1);
163
164 thread = deThread_create(tlsTestThr, DE_NULL, DE_NULL);
165 deThread_join(thread);
166 deThread_destroy(thread);
167
168 DE_TEST_ASSERT(tls_testVar == 1);
169 tls_testVar = 123;
170 }
171 #endif
172 }
173
mutexTestThr1(void * arg)174 static void mutexTestThr1(void *arg)
175 {
176 deMutex mutex = *((deMutex *)arg);
177
178 deMutex_lock(mutex);
179 deMutex_unlock(mutex);
180 }
181
182 typedef struct MutexData2_s
183 {
184 deMutex mutex;
185 int32_t counter;
186 int32_t counter2;
187 int32_t maxVal;
188 } MutexData2;
189
mutexTestThr2(void * arg)190 static void mutexTestThr2(void *arg)
191 {
192 MutexData2 *data = (MutexData2 *)arg;
193 int32_t numIncremented = 0;
194
195 for (;;)
196 {
197 int32_t localCounter;
198 deMutex_lock(data->mutex);
199
200 if (data->counter >= data->maxVal)
201 {
202 deMutex_unlock(data->mutex);
203 break;
204 }
205
206 localCounter = data->counter;
207 deYield();
208
209 DE_TEST_ASSERT(localCounter == data->counter);
210 localCounter += 1;
211 data->counter = localCounter;
212
213 deMutex_unlock(data->mutex);
214
215 numIncremented++;
216 }
217
218 deMutex_lock(data->mutex);
219 data->counter2 += numIncremented;
220 deMutex_unlock(data->mutex);
221 }
222
mutexTestThr3(void * arg)223 void mutexTestThr3(void *arg)
224 {
225 deMutex mutex = *((deMutex *)arg);
226 bool ret;
227
228 ret = deMutex_tryLock(mutex);
229 DE_TEST_ASSERT(!ret);
230 }
231
deMutex_selfTest(void)232 void deMutex_selfTest(void)
233 {
234 /* Default mutex from single thread. */
235 {
236 deMutex mutex = deMutex_create(DE_NULL);
237 bool ret;
238 DE_TEST_ASSERT(mutex);
239
240 deMutex_lock(mutex);
241 deMutex_unlock(mutex);
242
243 /* Should succeed. */
244 ret = deMutex_tryLock(mutex);
245 DE_TEST_ASSERT(ret);
246 deMutex_unlock(mutex);
247
248 deMutex_destroy(mutex);
249 }
250
251 /* Recursive mutex. */
252 {
253 deMutexAttributes attrs;
254 deMutex mutex;
255 int ndx;
256 int numLocks = 10;
257
258 deMemset(&attrs, 0, sizeof(attrs));
259
260 attrs.flags = DE_MUTEX_RECURSIVE;
261
262 mutex = deMutex_create(&attrs);
263 DE_TEST_ASSERT(mutex);
264
265 for (ndx = 0; ndx < numLocks; ndx++)
266 deMutex_lock(mutex);
267
268 for (ndx = 0; ndx < numLocks; ndx++)
269 deMutex_unlock(mutex);
270
271 deMutex_destroy(mutex);
272 }
273
274 /* Mutex and threads. */
275 {
276 deMutex mutex;
277 deThread thread;
278
279 mutex = deMutex_create(DE_NULL);
280 DE_TEST_ASSERT(mutex);
281
282 deMutex_lock(mutex);
283
284 thread = deThread_create(mutexTestThr1, &mutex, DE_NULL);
285 DE_TEST_ASSERT(thread);
286
287 deSleep(100);
288 deMutex_unlock(mutex);
289
290 deMutex_lock(mutex);
291 deMutex_unlock(mutex);
292
293 deThread_join(thread);
294
295 deThread_destroy(thread);
296 deMutex_destroy(mutex);
297 }
298
299 /* A bit more complex mutex test. */
300 {
301 MutexData2 data;
302 deThread threads[2];
303 int ndx;
304
305 data.mutex = deMutex_create(DE_NULL);
306 DE_TEST_ASSERT(data.mutex);
307
308 data.counter = 0;
309 data.counter2 = 0;
310 data.maxVal = 1000;
311
312 deMutex_lock(data.mutex);
313
314 for (ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(threads); ndx++)
315 {
316 threads[ndx] = deThread_create(mutexTestThr2, &data, DE_NULL);
317 DE_TEST_ASSERT(threads[ndx]);
318 }
319
320 deMutex_unlock(data.mutex);
321
322 for (ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(threads); ndx++)
323 {
324 bool ret = deThread_join(threads[ndx]);
325 DE_TEST_ASSERT(ret);
326 deThread_destroy(threads[ndx]);
327 }
328
329 DE_TEST_ASSERT(data.counter == data.counter2);
330 DE_TEST_ASSERT(data.maxVal == data.counter);
331
332 deMutex_destroy(data.mutex);
333 }
334
335 /* tryLock() deadlock test. */
336 {
337 deThread thread;
338 deMutex mutex = deMutex_create(DE_NULL);
339 bool ret;
340 DE_TEST_ASSERT(mutex);
341
342 deMutex_lock(mutex);
343
344 thread = deThread_create(mutexTestThr3, &mutex, DE_NULL);
345 DE_TEST_ASSERT(mutex);
346
347 ret = deThread_join(thread);
348 DE_TEST_ASSERT(ret);
349
350 deMutex_unlock(mutex);
351 deMutex_destroy(mutex);
352 deThread_destroy(thread);
353 }
354 }
355
356 typedef struct TestBuffer_s
357 {
358 uint32_t buffer[32];
359 deSemaphore empty;
360 deSemaphore fill;
361
362 uint32_t producerHash;
363 uint32_t consumerHash;
364 } TestBuffer;
365
producerThread(void * arg)366 void producerThread(void *arg)
367 {
368 TestBuffer *buffer = (TestBuffer *)arg;
369 deRandom random;
370 int ndx;
371 int numToProduce = 10000;
372 int writePos = 0;
373
374 deRandom_init(&random, 123);
375
376 for (ndx = 0; ndx <= numToProduce; ndx++)
377 {
378 uint32_t val;
379
380 if (ndx == numToProduce)
381 {
382 val = 0u; /* End. */
383 }
384 else
385 {
386 val = deRandom_getUint32(&random);
387 val = val ? val : 1u;
388 }
389
390 deSemaphore_decrement(buffer->empty);
391
392 buffer->buffer[writePos] = val;
393 writePos = (writePos + 1) % DE_LENGTH_OF_ARRAY(buffer->buffer);
394
395 deSemaphore_increment(buffer->fill);
396
397 buffer->producerHash ^= val;
398 }
399 }
400
consumerThread(void * arg)401 void consumerThread(void *arg)
402 {
403 TestBuffer *buffer = (TestBuffer *)arg;
404 int readPos = 0;
405
406 for (;;)
407 {
408 int32_t val;
409
410 deSemaphore_decrement(buffer->fill);
411
412 val = buffer->buffer[readPos];
413 readPos = (readPos + 1) % DE_LENGTH_OF_ARRAY(buffer->buffer);
414
415 deSemaphore_increment(buffer->empty);
416
417 buffer->consumerHash ^= val;
418
419 if (val == 0)
420 break;
421 }
422 }
423
deSemaphore_selfTest(void)424 void deSemaphore_selfTest(void)
425 {
426 /* Basic test. */
427 {
428 deSemaphore semaphore = deSemaphore_create(1, DE_NULL);
429 DE_TEST_ASSERT(semaphore);
430
431 deSemaphore_increment(semaphore);
432 deSemaphore_decrement(semaphore);
433 deSemaphore_decrement(semaphore);
434
435 deSemaphore_destroy(semaphore);
436 }
437
438 /* Producer-consumer test. */
439 {
440 TestBuffer testBuffer;
441 deThread producer;
442 deThread consumer;
443 bool ret;
444
445 deMemset(&testBuffer, 0, sizeof(testBuffer));
446
447 testBuffer.empty = deSemaphore_create(DE_LENGTH_OF_ARRAY(testBuffer.buffer), DE_NULL);
448 testBuffer.fill = deSemaphore_create(0, DE_NULL);
449
450 DE_TEST_ASSERT(testBuffer.empty && testBuffer.fill);
451
452 consumer = deThread_create(consumerThread, &testBuffer, DE_NULL);
453 producer = deThread_create(producerThread, &testBuffer, DE_NULL);
454
455 DE_TEST_ASSERT(consumer && producer);
456
457 ret = deThread_join(consumer) && deThread_join(producer);
458 DE_TEST_ASSERT(ret);
459
460 deThread_destroy(producer);
461 deThread_destroy(consumer);
462
463 deSemaphore_destroy(testBuffer.empty);
464 deSemaphore_destroy(testBuffer.fill);
465 DE_TEST_ASSERT(testBuffer.producerHash == testBuffer.consumerHash);
466 }
467 }
468
deAtomic_selfTest(void)469 void deAtomic_selfTest(void)
470 {
471 /* Single-threaded tests. */
472 {
473 volatile int32_t a = 11;
474 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == 12);
475 DE_TEST_ASSERT(a == 12);
476 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == 13);
477 DE_TEST_ASSERT(a == 13);
478
479 a = -2;
480 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == -1);
481 DE_TEST_ASSERT(a == -1);
482 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == 0);
483 DE_TEST_ASSERT(a == 0);
484
485 a = 11;
486 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == 10);
487 DE_TEST_ASSERT(a == 10);
488 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == 9);
489 DE_TEST_ASSERT(a == 9);
490
491 a = 0;
492 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == -1);
493 DE_TEST_ASSERT(a == -1);
494 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == -2);
495 DE_TEST_ASSERT(a == -2);
496
497 a = 0x7fffffff;
498 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == (int)0x80000000);
499 DE_TEST_ASSERT(a == (int)0x80000000);
500 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == (int)0x7fffffff);
501 DE_TEST_ASSERT(a == 0x7fffffff);
502 }
503
504 {
505 volatile uint32_t a = 11;
506 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 12);
507 DE_TEST_ASSERT(a == 12);
508 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 13);
509 DE_TEST_ASSERT(a == 13);
510
511 a = 0x7fffffff;
512 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 0x80000000);
513 DE_TEST_ASSERT(a == 0x80000000);
514 DE_TEST_ASSERT(deAtomicDecrementUint32(&a) == 0x7fffffff);
515 DE_TEST_ASSERT(a == 0x7fffffff);
516
517 a = 0xfffffffe;
518 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 0xffffffff);
519 DE_TEST_ASSERT(a == 0xffffffff);
520 DE_TEST_ASSERT(deAtomicDecrementUint32(&a) == 0xfffffffe);
521 DE_TEST_ASSERT(a == 0xfffffffe);
522 }
523
524 {
525 volatile uint32_t p;
526
527 p = 0;
528 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 0, 1) == 0);
529 DE_TEST_ASSERT(p == 1);
530
531 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 0, 2) == 1);
532 DE_TEST_ASSERT(p == 1);
533
534 p = 7;
535 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 6, 8) == 7);
536 DE_TEST_ASSERT(p == 7);
537
538 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 7, 8) == 7);
539 DE_TEST_ASSERT(p == 8);
540 }
541
542 #if (DE_PTR_SIZE == 8)
543 {
544 volatile int64_t a = 11;
545 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == 12);
546 DE_TEST_ASSERT(a == 12);
547 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == 13);
548 DE_TEST_ASSERT(a == 13);
549
550 a = -2;
551 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == -1);
552 DE_TEST_ASSERT(a == -1);
553 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == 0);
554 DE_TEST_ASSERT(a == 0);
555
556 a = 11;
557 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == 10);
558 DE_TEST_ASSERT(a == 10);
559 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == 9);
560 DE_TEST_ASSERT(a == 9);
561
562 a = 0;
563 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == -1);
564 DE_TEST_ASSERT(a == -1);
565 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == -2);
566 DE_TEST_ASSERT(a == -2);
567
568 a = (int64_t)((1ull << 63) - 1ull);
569 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == (int64_t)(1ull << 63));
570 DE_TEST_ASSERT(a == (int64_t)(1ull << 63));
571 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == (int64_t)((1ull << 63) - 1));
572 DE_TEST_ASSERT(a == (int64_t)((1ull << 63) - 1));
573 }
574 #endif /* (DE_PTR_SIZE == 8) */
575
576 /* \todo [2012-10-26 pyry] Implement multi-threaded tests. */
577 }
578
579 /* Singleton self-test. */
580
581 DE_DECLARE_POOL_ARRAY(deThreadArray, deThread);
582
583 static volatile deSingletonState s_testSingleton = DE_SINGLETON_STATE_NOT_INITIALIZED;
584 static volatile int s_testSingletonInitCount = 0;
585 static bool s_testSingletonInitialized = false;
586 static volatile bool s_singletonInitLock = false;
587
waitForSingletonInitLock(void)588 static void waitForSingletonInitLock(void)
589 {
590 for (;;)
591 {
592 deMemoryReadWriteFence();
593
594 if (s_singletonInitLock)
595 break;
596 }
597 }
598
initTestSingleton(void * arg)599 static void initTestSingleton(void *arg)
600 {
601 int initTimeMs = *(const int *)arg;
602
603 if (initTimeMs >= 0)
604 deSleep((uint32_t)initTimeMs);
605
606 deAtomicIncrement32(&s_testSingletonInitCount);
607 s_testSingletonInitialized = true;
608 }
609
singletonTestThread(void * arg)610 static void singletonTestThread(void *arg)
611 {
612 waitForSingletonInitLock();
613
614 deInitSingleton(&s_testSingleton, initTestSingleton, arg);
615 DE_TEST_ASSERT(s_testSingletonInitialized);
616 }
617
resetTestState(void)618 static void resetTestState(void)
619 {
620 s_testSingleton = DE_SINGLETON_STATE_NOT_INITIALIZED;
621 s_testSingletonInitCount = 0;
622 s_testSingletonInitialized = false;
623 s_singletonInitLock = false;
624 }
625
runSingletonThreadedTest(int numThreads,int initTimeMs)626 static void runSingletonThreadedTest(int numThreads, int initTimeMs)
627 {
628 deMemPool *tmpPool = deMemPool_createRoot(DE_NULL, 0);
629 deThreadArray *threads = tmpPool ? deThreadArray_create(tmpPool) : DE_NULL;
630 int threadNdx;
631
632 resetTestState();
633
634 for (threadNdx = 0; threadNdx < numThreads; threadNdx++)
635 {
636 deThread thread = deThread_create(singletonTestThread, &initTimeMs, DE_NULL);
637 DE_TEST_ASSERT(thread);
638 DE_TEST_ASSERT(deThreadArray_pushBack(threads, thread));
639 }
640
641 /* All threads created - let them do initialization. */
642 deMemoryReadWriteFence();
643 s_singletonInitLock = true;
644 deMemoryReadWriteFence();
645
646 for (threadNdx = 0; threadNdx < numThreads; threadNdx++)
647 {
648 deThread thread = deThreadArray_get(threads, threadNdx);
649 DE_TEST_ASSERT(deThread_join(thread));
650 deThread_destroy(thread);
651 }
652
653 /* Verify results. */
654 DE_TEST_ASSERT(s_testSingletonInitialized);
655 DE_TEST_ASSERT(s_testSingletonInitCount == 1);
656
657 deMemPool_destroy(tmpPool);
658 }
659
deSingleton_selfTest(void)660 void deSingleton_selfTest(void)
661 {
662 const struct
663 {
664 int numThreads;
665 int initTimeMs;
666 int repeatCount;
667 } cases[] = {/* #threads time #repeat */
668 {1, -1, 5}, {1, 1, 5}, {2, -1, 20}, {2, 1, 20}, {4, -1, 20}, {4, 1, 20}, {4, 5, 20}};
669 int caseNdx;
670
671 for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
672 {
673 int numThreads = cases[caseNdx].numThreads;
674 int initTimeMs = cases[caseNdx].initTimeMs;
675 int repeatCount = cases[caseNdx].repeatCount;
676 int subCaseNdx;
677
678 for (subCaseNdx = 0; subCaseNdx < repeatCount; subCaseNdx++)
679 runSingletonThreadedTest(numThreads, initTimeMs);
680 }
681 }
682