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