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