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 deInt32 buffer[32];
359 deSemaphore empty;
360 deSemaphore fill;
361
362 deInt32 producerSum;
363 deInt32 consumerSum;
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 deInt32 val;
379
380 if (ndx == numToProduce)
381 {
382 val = 0; /* End. */
383 }
384 else
385 {
386 val = (deInt32)deRandom_getUint32(&random);
387 val = val ? val : 1;
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->producerSum += 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->consumerSum += 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.producerSum == testBuffer.consumerSum);
467 }
468 }
469
deAtomic_selfTest(void)470 void deAtomic_selfTest (void)
471 {
472 /* Single-threaded tests. */
473 {
474 volatile int a = 11;
475 DE_TEST_ASSERT(deAtomicIncrement32(&a) == 12);
476 DE_TEST_ASSERT(a == 12);
477 DE_TEST_ASSERT(deAtomicIncrement32(&a) == 13);
478 DE_TEST_ASSERT(a == 13);
479
480 DE_TEST_ASSERT(deAtomicDecrement32(&a) == 12);
481 DE_TEST_ASSERT(a == 12);
482 DE_TEST_ASSERT(deAtomicDecrement32(&a) == 11);
483 DE_TEST_ASSERT(a == 11);
484 }
485
486 {
487 volatile deUint32 p;
488
489 p = 0;
490 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 0, 1) == 0);
491 DE_TEST_ASSERT(p == 1);
492
493 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 0, 2) == 1);
494 DE_TEST_ASSERT(p == 1);
495
496 p = 7;
497 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 6, 8) == 7);
498 DE_TEST_ASSERT(p == 7);
499
500 DE_TEST_ASSERT(deAtomicCompareExchange32(&p, 7, 8) == 7);
501 DE_TEST_ASSERT(p == 8);
502 }
503
504 /* \todo [2012-10-26 pyry] Implement multi-threaded tests. */
505 }
506
507 /* Singleton self-test. */
508
509 DE_DECLARE_POOL_ARRAY(deThreadArray, deThread);
510
511 static volatile deSingletonState s_testSingleton = DE_SINGLETON_STATE_NOT_INITIALIZED;
512 static volatile int s_testSingletonInitCount = 0;
513 static deBool s_testSingletonInitialized = DE_FALSE;
514 static volatile deBool s_singletonInitLock = DE_FALSE;
515
waitForSingletonInitLock(void)516 static void waitForSingletonInitLock (void)
517 {
518 for (;;)
519 {
520 deMemoryReadWriteFence();
521
522 if (s_singletonInitLock)
523 break;
524 }
525 }
526
initTestSingleton(void * arg)527 static void initTestSingleton (void* arg)
528 {
529 int initTimeMs = *(const int*)arg;
530
531 if (initTimeMs >= 0)
532 deSleep((deUint32)initTimeMs);
533
534 deAtomicIncrement32(&s_testSingletonInitCount);
535 s_testSingletonInitialized = DE_TRUE;
536 }
537
singletonTestThread(void * arg)538 static void singletonTestThread (void* arg)
539 {
540 waitForSingletonInitLock();
541
542 deInitSingleton(&s_testSingleton, initTestSingleton, arg);
543 DE_TEST_ASSERT(s_testSingletonInitialized);
544 }
545
resetTestState(void)546 static void resetTestState (void)
547 {
548 s_testSingleton = DE_SINGLETON_STATE_NOT_INITIALIZED;
549 s_testSingletonInitCount = 0;
550 s_testSingletonInitialized = DE_FALSE;
551 s_singletonInitLock = DE_FALSE;
552 }
553
runSingletonThreadedTest(int numThreads,int initTimeMs)554 static void runSingletonThreadedTest (int numThreads, int initTimeMs)
555 {
556 deMemPool* tmpPool = deMemPool_createRoot(DE_NULL, 0);
557 deThreadArray* threads = tmpPool ? deThreadArray_create(tmpPool) : DE_NULL;
558 int threadNdx;
559
560 resetTestState();
561
562 for (threadNdx = 0; threadNdx < numThreads; threadNdx++)
563 {
564 deThread thread = deThread_create(singletonTestThread, &initTimeMs, DE_NULL);
565 DE_TEST_ASSERT(thread);
566 DE_TEST_ASSERT(deThreadArray_pushBack(threads, thread));
567 }
568
569 /* All threads created - let them do initialization. */
570 deMemoryReadWriteFence();
571 s_singletonInitLock = DE_TRUE;
572 deMemoryReadWriteFence();
573
574 for (threadNdx = 0; threadNdx < numThreads; threadNdx++)
575 {
576 deThread thread = deThreadArray_get(threads, threadNdx);
577 DE_TEST_ASSERT(deThread_join(thread));
578 deThread_destroy(thread);
579 }
580
581 /* Verify results. */
582 DE_TEST_ASSERT(s_testSingletonInitialized);
583 DE_TEST_ASSERT(s_testSingletonInitCount == 1);
584
585 deMemPool_destroy(tmpPool);
586 }
587
deSingleton_selfTest(void)588 void deSingleton_selfTest (void)
589 {
590 const struct
591 {
592 int numThreads;
593 int initTimeMs;
594 int repeatCount;
595 } cases[] =
596 {
597 /* #threads time #repeat */
598 { 1, -1, 5 },
599 { 1, 1, 5 },
600 { 2, -1, 20 },
601 { 2, 1, 20 },
602 { 4, -1, 20 },
603 { 4, 1, 20 },
604 { 4, 5, 20 }
605 };
606 int caseNdx;
607
608 for (caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); caseNdx++)
609 {
610 int numThreads = cases[caseNdx].numThreads;
611 int initTimeMs = cases[caseNdx].initTimeMs;
612 int repeatCount = cases[caseNdx].repeatCount;
613 int subCaseNdx;
614
615 for (subCaseNdx = 0; subCaseNdx < repeatCount; subCaseNdx++)
616 runSingletonThreadedTest(numThreads, initTimeMs);
617 }
618 }
619