• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
dng_pthread_mutex_impldng_pthread_mutex_impl73 	dng_pthread_mutex_impl()  { ::InitializeCriticalSection(&lock); }
~dng_pthread_mutex_impldng_pthread_mutex_impl74 	~dng_pthread_mutex_impl() { ::DeleteCriticalSection(&lock); }
Lockdng_pthread_mutex_impl75 	void Lock()				   { ::EnterCriticalSection(&lock); }
Unlockdng_pthread_mutex_impl76 	void Unlock()			   { ::LeaveCriticalSection(&lock); }
77 private:
78 	dng_pthread_mutex_impl &operator=(const dng_pthread_mutex_impl &);
dng_pthread_mutex_impldng_pthread_mutex_impl79 	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 
dng_pthread_cond_impldng_pthread_cond_impl93 	dng_pthread_cond_impl() : head_waiter(NULL), tail_waiter(NULL), broadcast_generation(0) { }
~dng_pthread_cond_impldng_pthread_cond_impl94 	~dng_pthread_cond_impl() { } ;
95 
96 // Non copyable
97 private:
98 	dng_pthread_cond_impl &operator=(const dng_pthread_cond_impl &);
dng_pthread_cond_impldng_pthread_cond_impl99 	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 
ScopedLock__anon065eb9540211::ScopedLock112 		ScopedLock(dng_pthread_mutex_impl *arg) : mutex(arg)
113 		{
114 			mutex->Lock();
115 		}
ScopedLock__anon065eb9540211::ScopedLock116 		ScopedLock(dng_pthread_mutex_impl &arg) : mutex(&arg)
117 		{
118 			mutex->Lock();
119 		}
~ScopedLock__anon065eb9540211::ScopedLock120 		~ScopedLock()
121 		{
122 			mutex->Unlock();
123 		}
124 	private:
125 		ScopedLock &operator=(const ScopedLock &);
ScopedLock__anon065eb9540211::ScopedLock126 		ScopedLock(const ScopedLock &) { }
127 	};
128 
129 	dng_pthread_mutex_impl validationLock;
130 
ValidateMutex(dng_pthread_mutex_t * mutex)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 
ValidateCond(dng_pthread_cond_t * cond)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 
init_thread_TLS()157 	void init_thread_TLS()
158 	{
159 		thread_wait_sema_TLS_index = ::TlsAlloc();
160 		thread_wait_sema_inited = true;
161 	}
162 
finalize_thread_TLS()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 
GetThreadSemaphore()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 
FreeThreadSemaphore()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
trampoline(void * arg_arg)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 
dng_pthread_attr_init(pthread_attr_t * attr)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 
dng_pthread_attr_destroy(pthread_attr_t * attr)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 
dng_pthread_attr_setstacksize(dng_pthread_attr_t * attr,size_t stacksize)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 
dng_pthread_attr_getstacksize(const dng_pthread_attr_t * attr,size_t * stacksize)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 
dng_pthread_create(dng_pthread_t * thread,const pthread_attr_t * attrs,void * (* func)(void *),void * arg)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 
dng_pthread_detach(dng_pthread_t thread)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 
dng_pthread_join(dng_pthread_t thread,void ** result)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 
dng_pthread_self()449 dng_pthread_t dng_pthread_self()
450 {
451 	return (dng_pthread_t)::GetCurrentThreadId();
452 }
453 
454 /*****************************************************************************/
455 
dng_pthread_exit(void * result)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 
dng_pthread_mutex_init(dng_pthread_mutex_t * mutex,void *)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 
dng_pthread_mutex_destroy(dng_pthread_mutex_t * mutex)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 
dng_pthread_cond_init(dng_pthread_cond_t * cond,void *)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 
dng_pthread_cond_destroy(dng_pthread_cond_t * cond)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 
dng_pthread_mutexattr_init(dng_pthread_mutexattr_t * mutexattr)539 int dng_pthread_mutexattr_init(dng_pthread_mutexattr_t* mutexattr)
540 {
541 	return 0;
542 }
543 
544 /*****************************************************************************/
545 
dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t * mutexattr,int type)546 int dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t* mutexattr, int type)
547 {
548 	return 0;
549 }
550 
551 /*****************************************************************************/
552 
dng_pthread_mutex_lock(dng_pthread_mutex_t * mutex)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 
dng_pthread_mutex_unlock(dng_pthread_mutex_t * mutex)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 
cond_wait_internal(dng_pthread_cond_t * cond,dng_pthread_mutex_t * mutex,int timeout_milliseconds)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 
dng_pthread_cond_wait(dng_pthread_cond_t * cond,dng_pthread_mutex_t * mutex)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 
dng_pthread_cond_timedwait(dng_pthread_cond_t * cond,dng_pthread_mutex_t * mutex,struct dng_timespec * latest_time)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 
dng_pthread_cond_signal(dng_pthread_cond_t * cond)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 
dng_pthread_cond_broadcast(dng_pthread_cond_t * cond)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 
dng_pthread_once(dng_pthread_once_t * once,void (* init_func)())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 
dng_pthread_key_create(dng_pthread_key_t * key,void (* destructor)(void *))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 
dng_pthread_key_delete(dng_pthread_key_t key)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 
dng_pthread_setspecific(dng_pthread_key_t key,const void * value)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 
dng_pthread_getspecific(dng_pthread_key_t key)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 
dng_pthread_rwlock_impldng_pthread_rwlock_impl830 	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 
~dng_pthread_rwlock_impldng_pthread_rwlock_impl842 	~dng_pthread_rwlock_impl ()
843 	{
844 	}
845 
WakeHeadWaiterdng_pthread_rwlock_impl846 	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 
dng_pthread_rwlock_init(dng_pthread_rwlock_t * rwlock,const pthread_rwlockattr_t * attrs)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 
dng_pthread_rwlock_destroy(dng_pthread_rwlock_t * rwlock)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 
dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t * rwlock)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 
dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t * rwlock)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 
dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t * rwlock)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 
dng_pthread_rwlock_unlock(dng_pthread_rwlock_t * rwlock)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 
dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t * rwlock)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 
dng_pthread_disassociate()1079 void dng_pthread_disassociate()
1080 {
1081 	FreeThreadSemaphore();
1082 }
1083 
dng_pthread_terminate()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 
dng_pthread_now(struct timespec * now)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