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