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 58namespace { 59 struct waiter { 60 struct waiter *prev; 61 struct waiter *next; 62 HANDLE semaphore; 63 bool chosen_by_signal; 64 }; 65} 66 67/*****************************************************************************/ 68 69struct 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); } 77private: 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 84struct 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 97private: 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 105namespace 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 244extern "C" { 245 246/*****************************************************************************/ 247 248struct dng_pthread_attr_impl 249 { 250 size_t stacksize; 251 }; 252 253/*****************************************************************************/ 254 255int 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 272int 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 286int 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 298int 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 310int 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 360int 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 393int 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 449dng_pthread_t dng_pthread_self() 450{ 451 return (dng_pthread_t)::GetCurrentThreadId(); 452} 453 454/*****************************************************************************/ 455 456void 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 473int 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 491int 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 506int 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 524int 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 539int dng_pthread_mutexattr_init(dng_pthread_mutexattr_t* mutexattr) 540{ 541 return 0; 542} 543 544/*****************************************************************************/ 545 546int dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t* mutexattr, int type) 547{ 548 return 0; 549} 550 551/*****************************************************************************/ 552 553int dng_pthread_mutex_lock(dng_pthread_mutex_t *mutex) 554{ 555 ValidateMutex(mutex); 556 (*mutex)->Lock(); 557 return 0; 558} 559 560/*****************************************************************************/ 561 562int dng_pthread_mutex_unlock(dng_pthread_mutex_t *mutex) 563{ 564 ValidateMutex(mutex); 565 (*mutex)->Unlock(); 566 return 0; 567} 568 569/*****************************************************************************/ 570 571static 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 653int 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 662int 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 683int 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 715int 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 744int 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 768int 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 782int 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 791int 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 800void *dng_pthread_getspecific(dng_pthread_key_t key) 801{ 802 return ::TlsGetValue((DWORD)key); 803} 804 805/*****************************************************************************/ 806 807namespace { 808 struct rw_waiter { 809 struct rw_waiter *prev; 810 struct rw_waiter *next; 811 HANDLE semaphore; 812 bool is_writer; 813 }; 814} 815 816struct 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 861int 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 876int 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 902int 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 949int 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 968int 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 989int 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 1029int 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 1079void dng_pthread_disassociate() 1080{ 1081 FreeThreadSemaphore(); 1082} 1083 1084void dng_pthread_terminate() 1085 { 1086 finalize_thread_TLS(); 1087 } 1088 1089/*****************************************************************************/ 1090 1091} // extern "C" 1092 1093/*****************************************************************************/ 1094 1095#endif 1096 1097/*****************************************************************************/ 1098 1099int 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