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