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