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