Home | History | Annotate | Download | only in source
      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