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