2af44dedf9ed86878dfc20203448141f1978ddf4
[platform/upstream/VK-GL-CTS.git] / framework / delibs / dethread / deThreadTest.c
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
36 static void threadTestThr1 (void* arg)
37 {
38         deInt32 val = *((deInt32*)arg);
39         DE_TEST_ASSERT(val == 123);
40 }
41
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
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
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
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
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
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
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
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
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
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
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
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
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
516 static void waitForSingletonInitLock (void)
517 {
518         for (;;)
519         {
520                 deMemoryReadWriteFence();
521
522                 if (s_singletonInitLock)
523                         break;
524         }
525 }
526
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
538 static void singletonTestThread (void* arg)
539 {
540         waitForSingletonInitLock();
541
542         deInitSingleton(&s_testSingleton, initTestSingleton, arg);
543         DE_TEST_ASSERT(s_testSingletonInitialized);
544 }
545
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
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
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 }