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