1 /*****************************************************************************/ 2 // Copyright 2002-2008 Adobe Systems Incorporated 3 // All Rights Reserved. 4 // 5 // NOTICE: Adobe permits you to use, modify, and distribute this file in 6 // accordance with the terms of the Adobe license agreement accompanying it. 7 /*****************************************************************************/ 8 9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pthread.cpp#2 $ */ 10 /* $DateTime: 2012/07/31 22:04:34 $ */ 11 /* $Change: 840853 $ */ 12 /* $Author: tknoll $ */ 13 14 #include "dng_pthread.h" 15 16 /*****************************************************************************/ 17 18 #if qDNGThreadSafe 19 20 /*****************************************************************************/ 21 22 #include "dng_assertions.h" 23 24 /*****************************************************************************/ 25 26 #if qWinOS 27 28 #pragma warning(disable : 4786) 29 30 // Nothing in this file requires Unicode, 31 // However, CreateSemaphore has a path parameter 32 // (which is NULL always in this code) and thus 33 // does not work on Win98 if UNICODE is defined. 34 // So we force it off here. 35 36 #undef UNICODE 37 #undef _UNICODE 38 39 #include <windows.h> 40 #include <process.h> 41 #include <errno.h> 42 #include <memory> 43 #include <new> 44 #include <map> 45 46 #else 47 48 #include <sys/time.h> 49 50 #endif 51 52 /*****************************************************************************/ 53 54 #if qWinOS 55 56 /*****************************************************************************/ 57 58 namespace { 59 struct waiter { 60 struct waiter *prev; 61 struct waiter *next; 62 HANDLE semaphore; 63 bool chosen_by_signal; 64 }; 65 } 66 67 /*****************************************************************************/ 68 69 struct dng_pthread_mutex_impl 70 { 71 CRITICAL_SECTION lock; 72 73 dng_pthread_mutex_impl() { ::InitializeCriticalSection(&lock); } 74 ~dng_pthread_mutex_impl() { ::DeleteCriticalSection(&lock); } 75 void Lock() { ::EnterCriticalSection(&lock); } 76 void Unlock() { ::LeaveCriticalSection(&lock); } 77 private: 78 dng_pthread_mutex_impl &operator=(const dng_pthread_mutex_impl &) { } 79 dng_pthread_mutex_impl(const dng_pthread_mutex_impl &) { } 80 }; 81 82 /*****************************************************************************/ 83 84 struct dng_pthread_cond_impl 85 { 86 dng_pthread_mutex_impl lock; // Mutual exclusion on next two variables 87 waiter *head_waiter; // List of threads waiting on this condition 88 waiter *tail_waiter; // Used to get FIFO, rather than LIFO, behavior for pthread_cond_signal 89 unsigned int broadcast_generation; // Used as sort of a separator on broadcasts 90 // saves having to walk the waiters list setting 91 // each one's "chosen_by_signal" flag while the condition is locked 92 93 dng_pthread_cond_impl() : head_waiter(NULL), tail_waiter(NULL), broadcast_generation(0) { } 94 ~dng_pthread_cond_impl() { } ; 95 96 // Non copyable 97 private: 98 dng_pthread_cond_impl &operator=(const dng_pthread_cond_impl &) { } 99 dng_pthread_cond_impl(const dng_pthread_cond_impl &) { } 100 101 }; 102 103 /*****************************************************************************/ 104 105 namespace 106 { 107 108 struct ScopedLock 109 { 110 dng_pthread_mutex_impl *mutex; 111 112 ScopedLock(dng_pthread_mutex_impl *arg) : mutex(arg) 113 { 114 mutex->Lock(); 115 } 116 ScopedLock(dng_pthread_mutex_impl &arg) : mutex(&arg) 117 { 118 mutex->Lock(); 119 } 120 ~ScopedLock() 121 { 122 mutex->Unlock(); 123 } 124 private: 125 ScopedLock &operator=(const ScopedLock &) { } 126 ScopedLock(const ScopedLock &) { } 127 }; 128 129 dng_pthread_mutex_impl validationLock; 130 131 void ValidateMutex(dng_pthread_mutex_t *mutex) 132 { 133 if (*mutex != DNG_PTHREAD_MUTEX_INITIALIZER) 134 return; 135 136 ScopedLock lock(validationLock); 137 138 if (*mutex == DNG_PTHREAD_MUTEX_INITIALIZER) 139 dng_pthread_mutex_init(mutex, NULL); 140 } 141 142 void ValidateCond(dng_pthread_cond_t *cond) 143 { 144 if (*cond != DNG_PTHREAD_COND_INITIALIZER) 145 return; 146 147 ScopedLock lock(validationLock); 148 149 if (*cond == DNG_PTHREAD_COND_INITIALIZER) 150 dng_pthread_cond_init(cond, NULL); 151 } 152 153 DWORD thread_wait_sema_TLS_index; 154 bool thread_wait_sema_inited = false; 155 dng_pthread_once_t once_thread_TLS = DNG_PTHREAD_ONCE_INIT; 156 157 void init_thread_TLS() 158 { 159 thread_wait_sema_TLS_index = ::TlsAlloc(); 160 thread_wait_sema_inited = true; 161 } 162 163 void finalize_thread_TLS() 164 { 165 if (thread_wait_sema_inited) 166 { 167 ::TlsFree(thread_wait_sema_TLS_index); 168 thread_wait_sema_inited = false; 169 } 170 } 171 172 dng_pthread_mutex_impl primaryHandleMapLock; 173 174 typedef std::map<DWORD, std::pair<HANDLE, void **> > ThreadMapType; 175 176 // A map to make sure handles are freed and to allow returning a pointer sized result 177 // even on 64-bit Windows. 178 ThreadMapType primaryHandleMap; 179 180 HANDLE GetThreadSemaphore() 181 { 182 dng_pthread_once(&once_thread_TLS, init_thread_TLS); 183 184 HANDLE semaphore = ::TlsGetValue(thread_wait_sema_TLS_index); 185 if (semaphore == NULL) 186 { 187 semaphore = ::CreateSemaphore(NULL, 0, 1, NULL); 188 ::TlsSetValue(thread_wait_sema_TLS_index, semaphore); 189 } 190 191 return semaphore; 192 } 193 194 void FreeThreadSemaphore() 195 { 196 if (thread_wait_sema_inited) 197 { 198 HANDLE semaphore = (HANDLE)::TlsGetValue(thread_wait_sema_TLS_index); 199 200 if (semaphore != NULL) 201 { 202 ::TlsSetValue(thread_wait_sema_TLS_index, NULL); 203 ::CloseHandle(semaphore); 204 } 205 } 206 } 207 208 struct trampoline_args 209 { 210 void *(*func)(void *); 211 void *arg; 212 }; 213 214 // This trampoline takes care of the return type being different 215 // between pthreads thread funcs and Windows C lib thread funcs 216 unsigned __stdcall trampoline(void *arg_arg) 217 { 218 trampoline_args *args_ptr = (trampoline_args *)arg_arg; 219 trampoline_args args = *args_ptr; 220 221 delete args_ptr; 222 223 GetThreadSemaphore(); 224 225 void *result = args.func(args.arg); 226 227 { 228 ScopedLock lockMap(primaryHandleMapLock); 229 230 ThreadMapType::iterator iter = primaryHandleMap.find(pthread_self()); 231 if (iter != primaryHandleMap.end()) 232 *iter->second.second = result; 233 } 234 235 FreeThreadSemaphore(); 236 237 return S_OK; 238 } 239 240 } 241 242 /*****************************************************************************/ 243 244 extern "C" { 245 246 /*****************************************************************************/ 247 248 struct dng_pthread_attr_impl 249 { 250 size_t stacksize; 251 }; 252 253 /*****************************************************************************/ 254 255 int dng_pthread_attr_init(pthread_attr_t *attr) 256 { 257 dng_pthread_attr_impl *newAttrs; 258 259 newAttrs = new (std::nothrow) dng_pthread_attr_impl; 260 if (newAttrs == NULL) 261 return -1; // ENOMEM; 262 263 newAttrs->stacksize = 0; 264 265 *attr = newAttrs; 266 267 return 0; 268 } 269 270 /*****************************************************************************/ 271 272 int dng_pthread_attr_destroy(pthread_attr_t *attr) 273 { 274 if (*attr == NULL) 275 return -1; // EINVAL 276 277 delete *attr; 278 279 *attr = NULL; 280 281 return 0; 282 } 283 284 /*****************************************************************************/ 285 286 int dng_pthread_attr_setstacksize(dng_pthread_attr_t *attr, size_t stacksize) 287 { 288 if (attr == NULL || (*attr) == NULL) 289 return -1; // EINVAL 290 291 (*attr)->stacksize = stacksize; 292 293 return 0; 294 } 295 296 /*****************************************************************************/ 297 298 int dng_pthread_attr_getstacksize(const dng_pthread_attr_t *attr, size_t *stacksize) 299 { 300 if (attr == NULL || (*attr) == NULL || stacksize == NULL) 301 return -1; // EINVAL 302 303 *stacksize = (*attr)->stacksize; 304 305 return 0; 306 } 307 308 /*****************************************************************************/ 309 310 int dng_pthread_create(dng_pthread_t *thread, const pthread_attr_t *attrs, void * (*func)(void *), void *arg) 311 { 312 try 313 { 314 uintptr_t result; 315 unsigned threadID; 316 std::auto_ptr<trampoline_args> args(new (std::nothrow) trampoline_args); 317 std::auto_ptr<void *> resultHolder(new (std::nothrow) (void *)); 318 319 if (args.get() == NULL || resultHolder.get () == NULL) 320 return -1; // ENOMEM 321 322 args->func = func; 323 args->arg = arg; 324 325 size_t stacksize = 0; 326 327 if (attrs != NULL) 328 dng_pthread_attr_getstacksize (attrs, &stacksize); 329 330 { 331 ScopedLock lockMap(primaryHandleMapLock); 332 333 result = _beginthreadex(NULL, (unsigned)stacksize, trampoline, args.get(), 0, &threadID); 334 if (result == NULL) 335 return -1; // ENOMEM 336 args.release(); 337 338 std::pair<DWORD, std::pair<HANDLE, void **> > newMapEntry(threadID, 339 std::pair<HANDLE, void **>((HANDLE)result, resultHolder.get ())); 340 std::pair<ThreadMapType::iterator, bool> insertion = primaryHandleMap.insert(newMapEntry); 341 342 // If there is a handle open on the thread, its ID should not be reused so assert that an insertion was made. 343 DNG_ASSERT(insertion.second, "pthread emulation logic error"); 344 } 345 346 347 resultHolder.release (); 348 349 *thread = (dng_pthread_t)threadID; 350 return 0; 351 } 352 catch (const std::bad_alloc &) 353 { 354 return -1; 355 } 356 } 357 358 /*****************************************************************************/ 359 360 int dng_pthread_detach(dng_pthread_t thread) 361 { 362 HANDLE primaryHandle; 363 void **resultHolder = NULL; 364 365 { 366 ScopedLock lockMap(primaryHandleMapLock); 367 368 ThreadMapType::iterator iter = primaryHandleMap.find(thread); 369 if (iter == primaryHandleMap.end()) 370 return -1; 371 372 primaryHandle = iter->second.first; 373 374 // A join is waiting on the thread. 375 if (primaryHandle == NULL) 376 return -1; 377 378 resultHolder = iter->second.second; 379 380 primaryHandleMap.erase(iter); 381 } 382 383 delete resultHolder; 384 385 if (!::CloseHandle(primaryHandle)) 386 return -1; 387 388 return 0; 389 } 390 391 /*****************************************************************************/ 392 393 int dng_pthread_join(dng_pthread_t thread, void **result) 394 { 395 bool found = false; 396 HANDLE primaryHandle = NULL; 397 void **resultHolder = NULL; 398 399 ThreadMapType::iterator iter; 400 401 { 402 ScopedLock lockMap(primaryHandleMapLock); 403 404 iter = primaryHandleMap.find(thread); 405 found = iter != primaryHandleMap.end(); 406 if (found) 407 { 408 primaryHandle = iter->second.first; 409 resultHolder = iter->second.second; 410 411 // Set HANDLE to NULL to force any later join or detach to fail. 412 iter->second.first = NULL; 413 } 414 } 415 416 // This case can happens when joining a thread not created with pthread_create, 417 // which is a bad idea, but it gets mapped to doing the join, but always returns NULL. 418 if (!found) 419 primaryHandle = ::OpenThread(SYNCHRONIZE|THREAD_QUERY_INFORMATION, FALSE, thread); 420 421 if (primaryHandle == NULL) 422 return -1; 423 424 DWORD err; 425 if (::WaitForSingleObject(primaryHandle, INFINITE) != WAIT_OBJECT_0) 426 { 427 err = ::GetLastError(); 428 return -1; 429 } 430 431 { 432 ScopedLock lockMap(primaryHandleMapLock); 433 434 if (iter != primaryHandleMap.end()) 435 primaryHandleMap.erase(iter); 436 } 437 438 ::CloseHandle(primaryHandle); 439 if (result != NULL && resultHolder != NULL) 440 *result = *resultHolder; 441 442 delete resultHolder; 443 444 return 0; 445 } 446 447 /*****************************************************************************/ 448 449 dng_pthread_t dng_pthread_self() 450 { 451 return (dng_pthread_t)::GetCurrentThreadId(); 452 } 453 454 /*****************************************************************************/ 455 456 void dng_pthread_exit(void *result) 457 { 458 { 459 ScopedLock lockMap(primaryHandleMapLock); 460 461 ThreadMapType::iterator iter = primaryHandleMap.find(pthread_self()); 462 if (iter != primaryHandleMap.end()) 463 *iter->second.second = result; 464 } 465 466 FreeThreadSemaphore(); 467 468 _endthreadex(S_OK); 469 } 470 471 /*****************************************************************************/ 472 473 int dng_pthread_mutex_init(dng_pthread_mutex_t *mutex, void * /* attrs */) 474 { 475 dng_pthread_mutex_t result; 476 try { 477 result = new(dng_pthread_mutex_impl); 478 } catch (const std::bad_alloc &) 479 { 480 return -1; 481 } 482 483 if (result == NULL) 484 return -1; 485 *mutex = result; 486 return 0; 487 } 488 489 /*****************************************************************************/ 490 491 int dng_pthread_mutex_destroy(dng_pthread_mutex_t *mutex) 492 { 493 if (*mutex == DNG_PTHREAD_MUTEX_INITIALIZER) 494 { 495 *mutex = NULL; 496 return 0; 497 } 498 499 delete *mutex; 500 *mutex = NULL; 501 return 0; 502 } 503 504 /*****************************************************************************/ 505 506 int dng_pthread_cond_init(dng_pthread_cond_t *cond, void * /* attrs */) 507 { 508 dng_pthread_cond_t result; 509 try { 510 result = new(dng_pthread_cond_impl); 511 } catch (const std::bad_alloc &) 512 { 513 return -1; 514 } 515 516 if (result == NULL) 517 return -1; 518 *cond = result; 519 return 0; 520 } 521 522 /*****************************************************************************/ 523 524 int dng_pthread_cond_destroy(dng_pthread_cond_t *cond) 525 { 526 if (*cond == DNG_PTHREAD_COND_INITIALIZER) 527 { 528 *cond = NULL; 529 return 0; 530 } 531 532 delete *cond; 533 *cond = NULL; 534 return 0; 535 } 536 537 /*****************************************************************************/ 538 539 int dng_pthread_mutexattr_init(dng_pthread_mutexattr_t* mutexattr) 540 { 541 return 0; 542 } 543 544 /*****************************************************************************/ 545 546 int dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t* mutexattr, int type) 547 { 548 return 0; 549 } 550 551 /*****************************************************************************/ 552 553 int dng_pthread_mutex_lock(dng_pthread_mutex_t *mutex) 554 { 555 ValidateMutex(mutex); 556 (*mutex)->Lock(); 557 return 0; 558 } 559 560 /*****************************************************************************/ 561 562 int dng_pthread_mutex_unlock(dng_pthread_mutex_t *mutex) 563 { 564 ValidateMutex(mutex); 565 (*mutex)->Unlock(); 566 return 0; 567 } 568 569 /*****************************************************************************/ 570 571 static int cond_wait_internal(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, int timeout_milliseconds) 572 { 573 dng_pthread_cond_impl &real_cond = **cond; 574 dng_pthread_mutex_impl &real_mutex = **mutex; 575 576 waiter this_wait; 577 HANDLE semaphore = GetThreadSemaphore(); 578 int my_generation; // The broadcast generation this waiter is in 579 580 { 581 this_wait.next = NULL; 582 this_wait.semaphore = semaphore; 583 this_wait.chosen_by_signal = 0; 584 585 ScopedLock lock1(real_cond.lock); 586 587 // Add this waiter to the end of the list. 588 this_wait.prev = real_cond.tail_waiter; 589 if (real_cond.tail_waiter != NULL) 590 real_cond.tail_waiter->next = &this_wait; 591 real_cond.tail_waiter = &this_wait; 592 593 // If the list was empty, set the head of the list to this waiter. 594 if (real_cond.head_waiter == NULL) 595 real_cond.head_waiter = &this_wait; 596 597 // Note which broadcast generation this waiter belongs to. 598 my_generation = real_cond.broadcast_generation; 599 } 600 601 real_mutex.Unlock(); 602 603 DWORD result = ::WaitForSingleObject(semaphore, timeout_milliseconds); 604 605 if (result == WAIT_TIMEOUT) 606 { 607 // If the wait timed out, this thread is likely still on the waiters list 608 // of the condition. However, there is a race in that the thread may have been 609 // signaled or broadcast between when WaitForSingleObject decided 610 // we had timed out and this code running. 611 612 bool mustConsumeSemaphore = false; 613 { 614 ScopedLock lock2(real_cond.lock); 615 616 bool chosen_by_signal = this_wait.chosen_by_signal; 617 bool chosen_by_broadcast = my_generation != real_cond.broadcast_generation; 618 619 if (chosen_by_signal || chosen_by_broadcast) 620 mustConsumeSemaphore = true; 621 else 622 { 623 // Still on waiters list. Remove this waiter from list. 624 if (this_wait.next != NULL) 625 this_wait.next->prev = this_wait.prev; 626 else 627 real_cond.tail_waiter = this_wait.prev; 628 629 if (this_wait.prev != NULL) 630 this_wait.prev->next = this_wait.next; 631 else 632 real_cond.head_waiter = this_wait.next; 633 } 634 } 635 636 if (mustConsumeSemaphore) 637 { 638 ::WaitForSingleObject(semaphore, INFINITE); 639 result = WAIT_OBJECT_0; 640 } 641 } 642 else 643 DNG_ASSERT (result == WAIT_OBJECT_0, "pthread emulation logic error"); 644 645 // reacquire the mutex 646 real_mutex.Lock(); 647 648 return (result == WAIT_TIMEOUT) ? DNG_ETIMEDOUT : 0; 649 } 650 651 /*****************************************************************************/ 652 653 int dng_pthread_cond_wait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex) 654 { 655 ValidateCond(cond); 656 657 return cond_wait_internal(cond, mutex, INFINITE); 658 } 659 660 /*****************************************************************************/ 661 662 int dng_pthread_cond_timedwait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, struct dng_timespec *latest_time) 663 { 664 ValidateCond(cond); 665 666 struct dng_timespec sys_timespec; 667 668 dng_pthread_now (&sys_timespec); 669 670 __int64 sys_time = (__int64)sys_timespec.tv_sec * 1000000000 + sys_timespec.tv_nsec; 671 __int64 lock_time = (__int64)latest_time->tv_sec * 1000000000 + latest_time->tv_nsec; 672 673 int wait_millisecs = (int)((lock_time - sys_time + 500000) / 1000000); 674 675 if (wait_millisecs < 0) 676 wait_millisecs = 0; 677 678 return cond_wait_internal(cond, mutex, wait_millisecs); 679 } 680 681 /*****************************************************************************/ 682 683 int dng_pthread_cond_signal(dng_pthread_cond_t *cond) 684 { 685 ValidateCond(cond); 686 687 waiter *first; 688 dng_pthread_cond_impl &real_cond = **cond; 689 690 { 691 ScopedLock lock(real_cond.lock); 692 693 first = real_cond.head_waiter; 694 if (first != NULL) 695 { 696 if (first->next != NULL) 697 first->next->prev = NULL; 698 else 699 real_cond.tail_waiter = NULL; // Or first->prev, which is always NULL in this case 700 701 first->chosen_by_signal = true; 702 703 real_cond.head_waiter = first->next; 704 } 705 } 706 707 if (first != NULL) 708 ::ReleaseSemaphore(first->semaphore, 1, NULL); 709 710 return 0; 711 } 712 713 /*****************************************************************************/ 714 715 int dng_pthread_cond_broadcast(dng_pthread_cond_t *cond) 716 { 717 ValidateCond(cond); 718 719 waiter *first; 720 dng_pthread_cond_impl &real_cond = **cond; 721 722 { 723 ScopedLock lock(real_cond.lock); 724 725 first = real_cond.head_waiter; 726 real_cond.head_waiter = NULL; 727 real_cond.tail_waiter = NULL; 728 729 real_cond.broadcast_generation++; 730 } 731 732 while (first != NULL) 733 { 734 waiter *next = first->next; 735 ::ReleaseSemaphore(first->semaphore, 1, NULL); 736 first = next; 737 } 738 739 return 0; 740 } 741 742 /*****************************************************************************/ 743 744 int dng_pthread_once(dng_pthread_once_t *once, void (*init_func)()) 745 { 746 if (once == NULL || init_func == NULL) 747 return EINVAL; 748 749 if (once->inited) 750 return 0; 751 752 if (::InterlockedIncrement(&once->semaphore) == 0) 753 { 754 init_func(); 755 once->inited = 1; 756 } 757 else 758 { 759 while (!once->inited) 760 Sleep(0); 761 } 762 763 return 0; 764 } 765 766 /*****************************************************************************/ 767 768 int dng_pthread_key_create(dng_pthread_key_t * key, void (*destructor) (void *)) 769 { 770 if (destructor != NULL) 771 return -1; 772 773 DWORD result = ::TlsAlloc(); 774 if (result == TLS_OUT_OF_INDEXES) 775 return -1; 776 *key = (unsigned long)result; 777 return 0; 778 } 779 780 /*****************************************************************************/ 781 782 int dng_pthread_key_delete(dng_pthread_key_t key) 783 { 784 if (::TlsFree((DWORD)key)) 785 return 0; 786 return -1; 787 } 788 789 /*****************************************************************************/ 790 791 int dng_pthread_setspecific(dng_pthread_key_t key, const void *value) 792 { 793 if (::TlsSetValue((DWORD)key, const_cast<void *>(value))) 794 return 0; 795 return -1; 796 } 797 798 /*****************************************************************************/ 799 800 void *dng_pthread_getspecific(dng_pthread_key_t key) 801 { 802 return ::TlsGetValue((DWORD)key); 803 } 804 805 /*****************************************************************************/ 806 807 namespace { 808 struct rw_waiter { 809 struct rw_waiter *prev; 810 struct rw_waiter *next; 811 HANDLE semaphore; 812 bool is_writer; 813 }; 814 } 815 816 struct dng_pthread_rwlock_impl 817 { 818 dng_pthread_mutex_impl mutex; 819 820 rw_waiter *head_waiter; 821 rw_waiter *tail_waiter; 822 823 unsigned long readers_active; 824 unsigned long writers_waiting; 825 bool writer_active; 826 827 dng_pthread_cond_impl read_wait; 828 dng_pthread_cond_impl write_wait; 829 830 dng_pthread_rwlock_impl () 831 : mutex () 832 , head_waiter (NULL) 833 , tail_waiter (NULL) 834 , readers_active (0) 835 , writers_waiting (0) 836 , read_wait () 837 , write_wait () 838 , writer_active (false) 839 { 840 } 841 842 ~dng_pthread_rwlock_impl () 843 { 844 } 845 846 void WakeHeadWaiter () 847 { 848 HANDLE semaphore = head_waiter->semaphore; 849 850 head_waiter = head_waiter->next; 851 if (head_waiter == NULL) 852 tail_waiter = NULL; 853 854 ::ReleaseSemaphore(semaphore, 1, NULL); 855 } 856 857 }; 858 859 /*****************************************************************************/ 860 861 int dng_pthread_rwlock_init(dng_pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attrs) 862 { 863 dng_pthread_rwlock_impl *newRWLock; 864 865 newRWLock = new (std::nothrow) dng_pthread_rwlock_impl; 866 if (newRWLock == NULL) 867 return -1; // ENOMEM; 868 869 *rwlock = newRWLock; 870 871 return 0; 872 } 873 874 /*****************************************************************************/ 875 876 int dng_pthread_rwlock_destroy(dng_pthread_rwlock_t *rwlock) 877 { 878 dng_pthread_rwlock_impl &real_rwlock = **rwlock; 879 880 { 881 ScopedLock lock (real_rwlock.mutex); 882 883 if (real_rwlock.head_waiter != NULL || 884 real_rwlock.readers_active != 0 || 885 real_rwlock.writers_waiting != 0 || 886 real_rwlock.writer_active) 887 return -1; // EBUSY 888 } 889 890 delete *rwlock; 891 *rwlock = NULL; 892 return 0; 893 } 894 895 /*****************************************************************************/ 896 897 #define CHECK_RWLOCK_STATE(real_rwlock) \ 898 DNG_ASSERT (!real_rwlock.writer_active || real_rwlock.readers_active == 0, "dng_pthread_rwlock_t logic error") 899 900 /*****************************************************************************/ 901 902 int dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t *rwlock) 903 { 904 dng_pthread_rwlock_impl &real_rwlock = **rwlock; 905 906 struct rw_waiter this_wait; 907 bool doWait = false;; 908 int result = 0; 909 HANDLE semaphore=NULL; 910 911 { 912 913 ScopedLock lock (real_rwlock.mutex); 914 915 CHECK_RWLOCK_STATE (real_rwlock); 916 917 if (real_rwlock.writers_waiting > 0 || real_rwlock.writer_active) 918 { 919 semaphore = GetThreadSemaphore(); 920 921 this_wait.next = NULL; 922 this_wait.semaphore = semaphore; 923 this_wait.is_writer = false; 924 925 // Add this waiter to the end of the list. 926 this_wait.prev = real_rwlock.tail_waiter; 927 if (real_rwlock.tail_waiter != NULL) 928 real_rwlock.tail_waiter->next = &this_wait; 929 real_rwlock.tail_waiter = &this_wait; 930 931 // If the list was empty, set the head of the list to this waiter. 932 if (real_rwlock.head_waiter == NULL) 933 real_rwlock.head_waiter = &this_wait; 934 935 doWait = true; 936 } 937 else 938 real_rwlock.readers_active++; 939 } 940 941 if (result == 0 && doWait) 942 result = (WaitForSingleObject(semaphore, INFINITE) == WAIT_OBJECT_0) ? 0 : -1; 943 944 return result; 945 } 946 947 /*****************************************************************************/ 948 949 int dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t *rwlock) 950 { 951 dng_pthread_rwlock_impl &real_rwlock = **rwlock; 952 953 ScopedLock lock (real_rwlock.mutex); 954 955 CHECK_RWLOCK_STATE (real_rwlock); 956 957 if (real_rwlock.writers_waiting == 0 && !real_rwlock.writer_active) 958 { 959 real_rwlock.readers_active++; 960 return 0; 961 } 962 963 return -1; 964 } 965 966 /*****************************************************************************/ 967 968 int dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t *rwlock) 969 { 970 dng_pthread_rwlock_impl &real_rwlock = **rwlock; 971 972 ScopedLock lock (real_rwlock.mutex); 973 974 CHECK_RWLOCK_STATE (real_rwlock); 975 976 if (real_rwlock.readers_active == 0 && 977 real_rwlock.writers_waiting == 0 && 978 !real_rwlock.writer_active) 979 { 980 real_rwlock.writer_active = true; 981 return 0; 982 } 983 984 return -1; 985 } 986 987 /*****************************************************************************/ 988 989 int dng_pthread_rwlock_unlock(dng_pthread_rwlock_t *rwlock) 990 { 991 dng_pthread_rwlock_impl &real_rwlock = **rwlock; 992 993 int result = 0; 994 995 ScopedLock lock (real_rwlock.mutex); 996 997 CHECK_RWLOCK_STATE (real_rwlock); 998 999 if (real_rwlock.readers_active > 0) 1000 --real_rwlock.readers_active; 1001 else 1002 real_rwlock.writer_active = false; 1003 1004 while (real_rwlock.head_waiter != NULL) 1005 { 1006 if (real_rwlock.head_waiter->is_writer) 1007 { 1008 if (real_rwlock.readers_active == 0) 1009 { 1010 real_rwlock.writers_waiting--; 1011 real_rwlock.writer_active = true; 1012 real_rwlock.WakeHeadWaiter (); 1013 } 1014 1015 break; 1016 } 1017 else 1018 { 1019 ++real_rwlock.readers_active; 1020 real_rwlock.WakeHeadWaiter (); 1021 } 1022 } 1023 1024 return result; 1025 } 1026 1027 /*****************************************************************************/ 1028 1029 int dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t *rwlock) 1030 { 1031 dng_pthread_rwlock_impl &real_rwlock = **rwlock; 1032 1033 int result = 0; 1034 struct rw_waiter this_wait; 1035 HANDLE semaphore=NULL; 1036 bool doWait = false; 1037 1038 { 1039 ScopedLock lock (real_rwlock.mutex); 1040 1041 CHECK_RWLOCK_STATE (real_rwlock); 1042 1043 if (real_rwlock.readers_active || 1044 real_rwlock.writers_waiting || 1045 real_rwlock.writer_active) 1046 { 1047 semaphore = GetThreadSemaphore(); 1048 1049 this_wait.next = NULL; 1050 this_wait.semaphore = semaphore; 1051 this_wait.is_writer = true; 1052 1053 // Add this waiter to the end of the list. 1054 this_wait.prev = real_rwlock.tail_waiter; 1055 if (real_rwlock.tail_waiter != NULL) 1056 real_rwlock.tail_waiter->next = &this_wait; 1057 real_rwlock.tail_waiter = &this_wait; 1058 1059 // If the list was empty, set the head of the list to this waiter. 1060 if (real_rwlock.head_waiter == NULL) 1061 real_rwlock.head_waiter = &this_wait; 1062 1063 real_rwlock.writers_waiting++; 1064 1065 doWait = true; 1066 } 1067 else 1068 real_rwlock.writer_active = true; 1069 } 1070 1071 if (result == 0 && doWait) 1072 result = (WaitForSingleObject(semaphore, INFINITE) == WAIT_OBJECT_0) ? 0 : -1; 1073 1074 return result; 1075 } 1076 1077 /*****************************************************************************/ 1078 1079 void dng_pthread_disassociate() 1080 { 1081 FreeThreadSemaphore(); 1082 } 1083 1084 void dng_pthread_terminate() 1085 { 1086 finalize_thread_TLS(); 1087 } 1088 1089 /*****************************************************************************/ 1090 1091 } // extern "C" 1092 1093 /*****************************************************************************/ 1094 1095 #endif 1096 1097 /*****************************************************************************/ 1098 1099 int dng_pthread_now (struct timespec *now) 1100 { 1101 1102 if (now == NULL) 1103 return -1; // EINVAL 1104 1105 #if qWinOS 1106 1107 FILETIME ft; 1108 ::GetSystemTimeAsFileTime(&ft); 1109 1110 __int64 sys_time = ((__int64)ft.dwHighDateTime << 32) + ft.dwLowDateTime; 1111 1112 #define SecsFrom1601To1970 11644473600 1113 1114 sys_time -= SecsFrom1601To1970 * 10000000LL; 1115 1116 sys_time *= 100; // Convert from 100ns to 1ns units 1117 1118 now->tv_sec = (long)(sys_time / 1000000000); 1119 now->tv_nsec = (long)(sys_time % 1000000000); 1120 1121 #else 1122 1123 struct timeval tv; 1124 1125 if (gettimeofday (&tv, NULL) != 0) 1126 return errno; 1127 1128 now->tv_sec = tv.tv_sec; 1129 now->tv_nsec = tv.tv_usec * 1000; 1130 1131 #endif 1132 1133 return 0; 1134 1135 } 1136 1137 /*****************************************************************************/ 1138 1139 #endif // qDNGThreadSafe 1140 1141 /*****************************************************************************/ 1142