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