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 deInt32 val = *((deInt32*)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 deUint8 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 deInt32 val = 123;
95 deBool 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 deInt32 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 deBool 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*)(deUintptr)0xff);
147
148 thread = deThread_create(threadTestThr4, &tls, DE_NULL);
149 deThread_join(thread);
150 deThread_destroy(thread);
151
152 DE_TEST_ASSERT((deUintptr)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 deInt32 counter;
186 deInt32 counter2;
187 deInt32 maxVal;
188 } MutexData2;
189
mutexTestThr2(void * arg)190 static void mutexTestThr2 (void* arg)
191 {
192 MutexData2* data = (MutexData2*)arg;
193 deInt32 numIncremented = 0;
194
195 for (;;)
196 {
197 deInt32 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 deBool 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 deBool 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 deBool 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 deBool 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 deUint32 buffer[32];
359 deSemaphore empty;
360 deSemaphore fill;
361
362 deUint32 producerHash;
363 deUint32 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 deUint32 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 deInt32 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 deBool 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) &&
458 deThread_join(producer);
459 DE_TEST_ASSERT(ret);
460
461 deThread_destroy(producer);
462 deThread_destroy(consumer);
463
464 deSemaphore_destroy(testBuffer.empty);
465 deSemaphore_destroy(testBuffer.fill);
466 DE_TEST_ASSERT(testBuffer.producerHash == testBuffer.consumerHash);
467 }
468 }
469
deAtomic_selfTest(void)470 void deAtomic_selfTest (void)
471 {
472 /* Single-threaded tests. */
473 {
474 volatile deInt32 a = 11;
475 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == 12);
476 DE_TEST_ASSERT(a == 12);
477 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == 13);
478 DE_TEST_ASSERT(a == 13);
479
480 a = -2;
481 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == -1);
482 DE_TEST_ASSERT(a == -1);
483 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == 0);
484 DE_TEST_ASSERT(a == 0);
485
486 a = 11;
487 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == 10);
488 DE_TEST_ASSERT(a == 10);
489 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == 9);
490 DE_TEST_ASSERT(a == 9);
491
492 a = 0;
493 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == -1);
494 DE_TEST_ASSERT(a == -1);
495 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == -2);
496 DE_TEST_ASSERT(a == -2);
497
498 a = 0x7fffffff;
499 DE_TEST_ASSERT(deAtomicIncrementInt32(&a) == (int)0x80000000);
500 DE_TEST_ASSERT(a == (int)0x80000000);
501 DE_TEST_ASSERT(deAtomicDecrementInt32(&a) == (int)0x7fffffff);
502 DE_TEST_ASSERT(a == 0x7fffffff);
503 }
504
505 {
506 volatile deUint32 a = 11;
507 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 12);
508 DE_TEST_ASSERT(a == 12);
509 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 13);
510 DE_TEST_ASSERT(a == 13);
511
512 a = 0x7fffffff;
513 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 0x80000000);
514 DE_TEST_ASSERT(a == 0x80000000);
515 DE_TEST_ASSERT(deAtomicDecrementUint32(&a) == 0x7fffffff);
516 DE_TEST_ASSERT(a == 0x7fffffff);
517
518 a = 0xfffffffe;
519 DE_TEST_ASSERT(deAtomicIncrementUint32(&a) == 0xffffffff);
520 DE_TEST_ASSERT(a == 0xffffffff);
521 DE_TEST_ASSERT(deAtomicDecrementUint32(&a) == 0xfffffffe);
522 DE_TEST_ASSERT(a == 0xfffffffe);
523 }
524
525 {
526 volatile deUint32 p;
527
528 p = 0;
529 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 0, 1) == 0);
530 DE_TEST_ASSERT(p == 1);
531
532 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 0, 2) == 1);
533 DE_TEST_ASSERT(p == 1);
534
535 p = 7;
536 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 6, 8) == 7);
537 DE_TEST_ASSERT(p == 7);
538
539 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 7, 8) == 7);
540 DE_TEST_ASSERT(p == 8);
541 }
542
543 #if (DE_PTR_SIZE == 8)
544 {
545 volatile deInt64 a = 11;
546 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == 12);
547 DE_TEST_ASSERT(a == 12);
548 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == 13);
549 DE_TEST_ASSERT(a == 13);
550
551 a = -2;
552 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == -1);
553 DE_TEST_ASSERT(a == -1);
554 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == 0);
555 DE_TEST_ASSERT(a == 0);
556
557 a = 11;
558 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == 10);
559 DE_TEST_ASSERT(a == 10);
560 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == 9);
561 DE_TEST_ASSERT(a == 9);
562
563 a = 0;
564 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == -1);
565 DE_TEST_ASSERT(a == -1);
566 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == -2);
567 DE_TEST_ASSERT(a == -2);
568
569 a = (deInt64)((1ull << 63) - 1ull);
570 DE_TEST_ASSERT(deAtomicIncrementInt64(&a) == (deInt64)(1ull << 63));
571 DE_TEST_ASSERT(a == (deInt64)(1ull << 63));
572 DE_TEST_ASSERT(deAtomicDecrementInt64(&a) == (deInt64)((1ull << 63) - 1));
573 DE_TEST_ASSERT(a == (deInt64)((1ull << 63) - 1));
574 }
575 #endif /* (DE_PTR_SIZE == 8) */
576
577 /* \todo [2012-10-26 pyry] Implement multi-threaded tests. */
578 }
579
580 /* Singleton self-test. */
581
582 DE_DECLARE_POOL_ARRAY(deThreadArray, deThread);
583
584 static volatile deSingletonState s_testSingleton = DE_SINGLETON_STATE_NOT_INITIALIZED;
585 static volatile int s_testSingletonInitCount = 0;
586 static deBool s_testSingletonInitialized = DE_FALSE;
587 static volatile deBool s_singletonInitLock = DE_FALSE;
588
waitForSingletonInitLock(void)589 static void waitForSingletonInitLock (void)
590 {
591 for (;;)
592 {
593 deMemoryReadWriteFence();
594
595 if (s_singletonInitLock)
596 break;
597 }
598 }
599
initTestSingleton(void * arg)600 static void initTestSingleton (void* arg)
601 {
602 int initTimeMs = *(const int*)arg;
603
604 if (initTimeMs >= 0)
605 deSleep((deUint32)initTimeMs);
606
607 deAtomicIncrement32(&s_testSingletonInitCount);
608 s_testSingletonInitialized = DE_TRUE;
609 }
610
singletonTestThread(void * arg)611 static void singletonTestThread (void* arg)
612 {
613 waitForSingletonInitLock();
614
615 deInitSingleton(&s_testSingleton, initTestSingleton, arg);
616 DE_TEST_ASSERT(s_testSingletonInitialized);
617 }
618
resetTestState(void)619 static void resetTestState (void)
620 {
621 s_testSingleton = DE_SINGLETON_STATE_NOT_INITIALIZED;
622 s_testSingletonInitCount = 0;
623 s_testSingletonInitialized = DE_FALSE;
624 s_singletonInitLock = DE_FALSE;
625 }
626
runSingletonThreadedTest(int numThreads,int initTimeMs)627 static void runSingletonThreadedTest (int numThreads, int initTimeMs)
628 {
629 deMemPool* tmpPool = deMemPool_createRoot(DE_NULL, 0);
630 deThreadArray* threads = tmpPool ? deThreadArray_create(tmpPool) : DE_NULL;
631 int threadNdx;
632
633 resetTestState();
634
635 for (threadNdx = 0; threadNdx < numThreads; threadNdx++)
636 {
637 deThread thread = deThread_create(singletonTestThread, &initTimeMs, DE_NULL);
638 DE_TEST_ASSERT(thread);
639 DE_TEST_ASSERT(deThreadArray_pushBack(threads, thread));
640 }
641
642 /* All threads created - let them do initialization. */
643 deMemoryReadWriteFence();
644 s_singletonInitLock = DE_TRUE;
645 deMemoryReadWriteFence();
646
647 for (threadNdx = 0; threadNdx < numThreads; threadNdx++)
648 {
649 deThread thread = deThreadArray_get(threads, threadNdx);
650 DE_TEST_ASSERT(deThread_join(thread));
651 deThread_destroy(thread);
652 }
653
654 /* Verify results. */
655 DE_TEST_ASSERT(s_testSingletonInitialized);
656 DE_TEST_ASSERT(s_testSingletonInitCount == 1);
657
658 deMemPool_destroy(tmpPool);
659 }
660
deSingleton_selfTest(void)661 void deSingleton_selfTest (void)
662 {
663 const struct
664 {
665 int numThreads;
666 int initTimeMs;
667 int repeatCount;
668 } cases[] =
669 {
670 /* #threads time #repeat */
671 { 1, -1, 5 },
672 { 1, 1, 5 },
673 { 2, -1, 20 },
674 { 2, 1, 20 },
675 { 4, -1, 20 },
676 { 4, 1, 20 },
677 { 4, 5, 20 }
678 };
679 int caseNdx;
680
681 for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
682 {
683 int numThreads = cases[caseNdx].numThreads;
684 int initTimeMs = cases[caseNdx].initTimeMs;
685 int repeatCount = cases[caseNdx].repeatCount;
686 int subCaseNdx;
687
688 for (subCaseNdx = 0; subCaseNdx < repeatCount; subCaseNdx++)
689 runSingletonThreadedTest(numThreads, initTimeMs);
690 }
691 }
692