Home | History | Annotate | Download | only in dethread
      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 	deUint32		buffer[32];
    359 	deSemaphore		empty;
    360 	deSemaphore		fill;
    361 
    362 	deUint32		producerHash;
    363 	deUint32		consumerHash;
    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 		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 
    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 
    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 
    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 
    589 static void waitForSingletonInitLock (void)
    590 {
    591 	for (;;)
    592 	{
    593 		deMemoryReadWriteFence();
    594 
    595 		if (s_singletonInitLock)
    596 			break;
    597 	}
    598 }
    599 
    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 
    611 static void singletonTestThread (void* arg)
    612 {
    613 	waitForSingletonInitLock();
    614 
    615 	deInitSingleton(&s_testSingleton, initTestSingleton, arg);
    616 	DE_TEST_ASSERT(s_testSingletonInitialized);
    617 }
    618 
    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 
    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 
    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