new audio engine backend for native CoreAudio audio I/O, and PortMIDI for MIDI.
[ardour.git] / libs / backends / wavesaudio / wavesapi / threads / WCThreadSafe.cpp
1 /*
2     Copyright (C) 2013 Waves Audio Ltd.
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19 #include "Threads/WCThreadSafe.h"
20     
21 #if XPLATFORMTHREADS_WINDOWS
22     #define _WIN32_WINNT 0x0500   // need at least Windows2000 (for TryEnterCriticalSection() and SignalObjectAndWait()
23     #include "IncludeWindows.h"
24     #include <process.h>
25 #endif // XPLATFORMTHREADS_WINDOWS
26
27
28 #if defined(__MACOS__)
29     #include <CoreServices/CoreServices.h>
30     #include <stdio.h>
31 #endif // __MACOS__
32
33 #if XPLATFORMTHREADS_POSIX
34     #include </usr/include/unistd.h>   // avoid the framework version and use the /usr/include version
35     #include <pthread.h>
36     #include <sched.h>
37     #include <sys/time.h>
38     #include <errno.h>
39     #include <signal.h>
40 // We do this externs because <stdio.h> comes from MSL
41 extern "C" FILE *popen(const char *command, const char *type);
42 extern "C" int pclose(FILE *stream);
43 static int (*BSDfread)( void *, size_t, size_t, FILE * ) = 0;
44
45 #include <string.h>
46
47 #endif //XPLATFORMTHREADS_POSIX
48
49 #include "Akupara/threading/atomic_ops.hpp"
50 namespace wvNS {
51 static const unsigned int knMicrosecondsPerSecond = 1000*1000;
52 static const unsigned int knNanosecondsPerMicrosecond = 1000;
53 static const unsigned int knNanosecondsPerSecond = knMicrosecondsPerSecond*knNanosecondsPerMicrosecond;
54
55 namespace wvThread
56 {
57
58     //--------------------------------------------------------------------------------
59     static inline bool EnsureThreadingInitialized()
60     {
61         bool bRetval = true;
62
63         return bRetval;
64     }
65     //--------------------------------------------------------------------------------
66
67
68
69
70     //--------------------------------------------------------------------------------
71     static uint32_t CalculateTicksPerMicrosecond();
72     static uint32_t CalculateTicksPerMicrosecond()
73     {
74         uint32_t nTicksPerMicrosecond=0;
75 #if defined(_WIN32)
76         LARGE_INTEGER TSC;
77         ::QueryPerformanceFrequency(&TSC);
78         nTicksPerMicrosecond = uint32_t (TSC.QuadPart / knMicrosecondsPerSecond);
79 #elif defined(__linux__) && defined(__i386__)
80         static const timediff sktd_TSC_MeasurementPeriod = 40*1000; // delay for CalculateTicksPerMicrosecond() to measure the TSC frequency
81         uint64_t Tstart, Tend;
82         timeval tvtmp, tvstart, tvend;
83
84         //--------------------- begin measurement code
85         // poll to align to a tick of gettimeofday
86         ::gettimeofday(&tvtmp,0);
87         do { 
88             ::gettimeofday(&tvstart,0);
89             __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tstart));  // RDTSC
90         } while (tvtmp.tv_usec!=tvstart.tv_usec);
91         // delay some
92         ::usleep(sktd_TSC_MeasurementPeriod);
93         //
94         ::gettimeofday(&tvtmp,0);
95         do { 
96             ::gettimeofday(&tvend,0);
97             __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tend));    // RDTSC
98         } while (tvtmp.tv_usec!=tvend.tv_usec);
99         //--------------------- end measurement code
100
101         suseconds_t elapsed_usec = (tvend.tv_sec-tvstart.tv_sec)*knMicrosecondsPerSecond + (tvend.tv_usec-tvstart.tv_usec);
102         uint64_t elapsed_ticks = Tend-Tstart;
103         nTicksPerMicrosecond = uint32_t (elapsed_ticks/elapsed_usec);
104 #endif
105         return nTicksPerMicrosecond;
106     }
107     
108 #if defined(__MACOS__) //&& !defined(__MACH__)
109
110     
111     bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface) // sIP and sInterface are both char[16]
112     {
113         FILE *fProcess , *pSubcall;
114         char sLine[256]="", *pToken, sCommand[150];
115         bool res = false;
116         int iret;
117
118         fProcess = popen("ifconfig -l inet", "r");
119         if (fProcess)
120         {
121             memset(sInterface, '\0', 16);
122             iret = BSDfread(sLine, sizeof(char), sizeof(sLine), fProcess);
123             pToken = strtok(sLine, " ");
124             while (pToken)
125             {
126                 sprintf(sCommand, "ifconfig %s | grep \"inet %s \"", pToken, sIP);
127                 
128                 pSubcall = popen(sCommand, "r");
129                 if (pSubcall)
130                 {
131                     char sSubline[100]="";
132                     if (BSDfread(sSubline, sizeof(char), sizeof(sSubline), pSubcall))
133                     {
134                         // found
135                         strcpy(sInterface, pToken);
136                         res = true;
137                         pclose(pSubcall);
138                         break;
139                     }
140                 }
141                 pclose(pSubcall);
142                 pToken = strtok(NULL, " ");    
143             }
144             
145         }
146         pclose(fProcess);
147         
148         return res;
149     }
150 #endif // MACOS
151
152     timestamp now(void)
153     {
154         EnsureThreadingInitialized();
155         static const uint32_t nTicksPerMicrosecond = CalculateTicksPerMicrosecond();
156 #if defined(_WIN32)
157         if (nTicksPerMicrosecond)
158         {
159             LARGE_INTEGER TSC;
160             ::QueryPerformanceCounter(&TSC);
161             return timestamp(uint32_t(TSC.QuadPart/nTicksPerMicrosecond));
162         }
163         else return timestamp(0);
164 #elif defined(__MACOS__)
165         if (nTicksPerMicrosecond) {} // prevent 'unused' warnings
166         UnsignedWide usecs;
167         ::Microseconds(&usecs);
168         return timestamp(usecs.lo);
169 #elif defined(__linux__) && defined(__i386__) && defined(__gnu_linux__)
170         uint64_t TSC;
171         __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (TSC));  // RDTSC
172         return timestamp(TSC/nTicksPerMicrosecond);
173 #elif defined(__linux__) && defined(__PPC__) && defined(__gnu_linux__)
174     #warning need to implement maybe
175 #else
176     #error Dont know how to get microseconds timer !
177 #endif // defined(_WIN32)
178     }
179
180
181     void sleep_milliseconds(unsigned int nMillisecs)
182     {
183         EnsureThreadingInitialized();
184 #if XPLATFORMTHREADS_WINDOWS
185         ::Sleep(nMillisecs);
186 #elif XPLATFORMTHREADS_POSIX
187         ::usleep(nMillisecs*1000);
188 #else
189     #error Not implemented for your OS
190 #endif
191     }
192
193
194 #if XPLATFORMTHREADS_WINDOWS
195     inline DWORD win32_milliseconds(timediff td) { return (td+499)/1000; }
196 #endif
197
198     void sleep(timediff _td)
199     {
200         if (_td>0)
201         {
202             EnsureThreadingInitialized();
203 #if XPLATFORMTHREADS_WINDOWS
204             ::Sleep(win32_milliseconds(_td));    // This is the best we can do in windows
205 #elif XPLATFORMTHREADS_POSIX
206             ::usleep(_td);
207 #else
208     #error Not implemented for your OS
209 #endif
210         }
211     }
212
213
214 #if XPLATFORMTHREADS_WINDOWS
215     void yield()   {  ::Sleep(0);   }
216 #elif XPLATFORMTHREADS_POSIX
217     void yield()   {  ::sched_yield();  }
218 #endif
219  
220
221
222
223     class  ThreadMutexInited::OSDependentMutex : public noncopyableobject
224     {
225 #if defined (XPLATFORMTHREADS_WINDOWS)
226     protected:
227         CRITICAL_SECTION m_critsec;
228     public:
229
230         inline OSDependentMutex()  { EnsureThreadingInitialized(); ::InitializeCriticalSection(&m_critsec); }
231         inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::DeleteCriticalSection    (&m_critsec); }
232         inline void obtain()       { EnsureThreadingInitialized(); ::EnterCriticalSection     (&m_critsec); }
233         inline void release()      { EnsureThreadingInitialized(); ::LeaveCriticalSection     (&m_critsec); }
234         inline bool tryobtain()    { EnsureThreadingInitialized(); return TryEnterCriticalSection(&m_critsec)!=FALSE; }
235         
236 #elif defined (XPLATFORMTHREADS_POSIX)
237     protected:
238         pthread_mutex_t  m_ptmutex;
239     public:
240         inline OSDependentMutex()  
241         { 
242             EnsureThreadingInitialized(); 
243             pthread_mutexattr_t attr;
244             pthread_mutexattr_init(&attr);
245             pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
246             ::pthread_mutex_init (&m_ptmutex, &attr);
247         }
248         inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::pthread_mutex_destroy(&m_ptmutex); }
249         inline void obtain()       { EnsureThreadingInitialized(); ::pthread_mutex_lock       (&m_ptmutex); }
250         inline void release()      { EnsureThreadingInitialized(); ::pthread_mutex_unlock     (&m_ptmutex); }
251         inline bool tryobtain()    { EnsureThreadingInitialized(); return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
252
253 #endif
254     };
255
256     ThreadMutexInited::ThreadMutexInited() :
257                         m_osdmutex(0) {}
258     
259     void ThreadMutexInited::init()
260     {
261         if (! is_init())
262         {
263             m_osdmutex = new OSDependentMutex;
264         }
265     }
266     
267     void ThreadMutexInited::uninit()
268     {
269         if (is_init())
270         {
271             delete m_osdmutex;
272             m_osdmutex = 0;
273         }
274     }
275     
276     ThreadMutexInited::~ThreadMutexInited()
277     {
278         uninit();
279     }    
280     
281     void ThreadMutexInited::obtain()
282     {
283         if (is_init())
284         {
285             m_osdmutex->obtain(); 
286         }
287     }    
288
289     void ThreadMutexInited::release()
290     {
291         if (is_init())
292         {
293             m_osdmutex->release(); 
294         }
295     }    
296     
297     bool ThreadMutexInited::tryobtain()
298     {
299         bool retVal = true;
300         if (is_init())
301         {
302             retVal = m_osdmutex->tryobtain(); 
303         }
304         return retVal;
305     }    
306     
307     class ThreadConditionSignal::OSDependentObject : public noncopyableobject
308     {
309 #if defined (XPLATFORMTHREADS_POSIX)
310
311     protected:
312         pthread_cond_t  m_ptcond;
313         pthread_mutex_t m_ptmutex;
314     public:
315         inline OSDependentObject()      
316         {
317             EnsureThreadingInitialized(); 
318             ::pthread_mutex_init(&m_ptmutex,0);
319             ::pthread_cond_init(&m_ptcond, 0); 
320         }
321         inline ~OSDependentObject()     { ::pthread_cond_destroy(&m_ptcond), ::pthread_mutex_destroy(&m_ptmutex); }
322         inline void signal_unicast()    { ::pthread_cond_signal(&m_ptcond);    }
323         inline void signal_broadcast()  { ::pthread_cond_broadcast(&m_ptcond); }
324         inline void await_signal()      { ::pthread_cond_wait(&m_ptcond, &m_ptmutex); }
325         inline bool await_signal(timediff td) 
326         {
327             timespec tspecDeadline;
328             timeval  tvNow;
329             ::gettimeofday(&tvNow,0);
330             tspecDeadline.tv_nsec = (tvNow.tv_usec + td%knMicrosecondsPerSecond)*knNanosecondsPerMicrosecond;
331             tspecDeadline.tv_sec  = tvNow.tv_sec  + td/knMicrosecondsPerSecond;
332             if (!(tspecDeadline.tv_nsec < suseconds_t(knNanosecondsPerSecond)))
333                 ++tspecDeadline.tv_sec, tspecDeadline.tv_nsec-=knNanosecondsPerSecond;
334             return ::pthread_cond_timedwait(&m_ptcond, &m_ptmutex, &tspecDeadline) != ETIMEDOUT;
335         }
336
337         void obtain_mutex()    { ::pthread_mutex_lock(&m_ptmutex); }
338         bool tryobtain_mutex() { return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
339         void release_mutex()   { ::pthread_mutex_unlock(&m_ptmutex); }
340
341
342 #elif XPLATFORMTHREADS_WINDOWS
343     protected:
344         unsigned int     m_nWaiterCount;
345         CRITICAL_SECTION m_csectWaiterCount;
346
347         HANDLE m_hndSemaphoreSignaller;        // We keep this semaphore always at 0 count (non-signalled). We use it to release a controlled number of threads.
348         HANDLE m_hndEventAllWaitersReleased;   // auto-reset
349         HANDLE m_hndMutex;                     // the mutex associated with the condition
350         bool   m_bBroadcastSignalled;          // means that the last waiter must signal m_hndEventAllWaitersReleased when done waiting
351
352     protected:
353         // - - - - - - - - - - - - - - - - - - - - - - - -
354         bool await_signal_win32(DWORD dwTimeout)
355         {
356             ::EnterCriticalSection(&m_csectWaiterCount);
357             ++m_nWaiterCount;
358             ::LeaveCriticalSection(&m_csectWaiterCount);
359             // This is the actual wait for the signal
360             bool bWaitSucceeded = ::SignalObjectAndWait(m_hndMutex, m_hndSemaphoreSignaller, dwTimeout, FALSE) == WAIT_OBJECT_0;
361             //
362             ::EnterCriticalSection(&m_csectWaiterCount);
363             bool bLastWaiter = --m_nWaiterCount==0 && m_bBroadcastSignalled;
364             ::LeaveCriticalSection(&m_csectWaiterCount);
365
366             // re-acquire the mutex
367             if (bLastWaiter)
368                 ::SignalObjectAndWait(m_hndEventAllWaitersReleased, m_hndMutex, INFINITE, FALSE);
369             else
370                 ::WaitForSingleObject(m_hndMutex, INFINITE);
371             return bWaitSucceeded;
372         }
373
374
375     public:
376
377         inline bool await_signal(timediff td)  { return await_signal_win32((win32_milliseconds(td))); }
378         inline void await_signal()             { await_signal_win32(INFINITE); }
379
380         OSDependentObject() : m_nWaiterCount(0), m_bBroadcastSignalled(false)
381         {
382             EnsureThreadingInitialized();
383             ::InitializeCriticalSection(&m_csectWaiterCount);
384             m_hndEventAllWaitersReleased = ::CreateEvent(
385                     0,      // security
386                     FALSE,  // auto-reset
387                     FALSE,  // initial state non-sognalled
388                     0);     // name
389             m_hndSemaphoreSignaller = ::CreateSemaphore(
390                     0,         // security
391                     0,         // initial count (and will stay this way)
392                     0x100000,  // maximum count (should be as large as the maximum number of waiting threads)
393                     0);        // name
394             m_hndMutex = ::CreateMutex(
395                     0,         // security
396                     FALSE,     // not owned initially
397                     0);        // name
398             //if (m_hndEventAllWaitersReleased==INVALID_HANDLE_VALUE || m_hndSemaphoreSignaller==INVALID_HANDLE_VALUE)
399             //    throw something();
400         }
401
402         ~OSDependentObject()
403         {
404             ::CloseHandle(m_hndMutex);
405             ::CloseHandle(m_hndSemaphoreSignaller);
406             ::CloseHandle(m_hndEventAllWaitersReleased);
407             ::DeleteCriticalSection(&m_csectWaiterCount);
408         }
409
410         inline void signal_unicast()
411         {
412             ::EnterCriticalSection(&m_csectWaiterCount);
413             unsigned int nWaiters = m_nWaiterCount;
414             ::LeaveCriticalSection(&m_csectWaiterCount);
415             if (nWaiters)
416                 ::ReleaseSemaphore(m_hndSemaphoreSignaller, 1, 0);  // release 1 semaphore credit to release one waiting thread
417         }
418
419         void signal_broadcast()
420         {
421             ::EnterCriticalSection(&m_csectWaiterCount);
422             unsigned int nWaiters = m_nWaiterCount;
423             if (nWaiters)
424             {
425                 m_bBroadcastSignalled = true;
426                 ::ReleaseSemaphore(m_hndSemaphoreSignaller, nWaiters, 0);  // release as many credits as there are waiting threads
427                 ::LeaveCriticalSection(&m_csectWaiterCount);
428                 ::WaitForSingleObject(m_hndEventAllWaitersReleased, INFINITE);
429                 // at this point all threads are waiting on m_hndMutex, which would be released outside this function call
430                 m_bBroadcastSignalled = false;
431             }
432             else
433                 // no one is waiting
434                 ::LeaveCriticalSection(&m_csectWaiterCount);
435         }
436         //------------------------------------------------
437         inline void obtain_mutex()    { ::WaitForSingleObject(m_hndMutex, INFINITE); }
438         inline bool tryobtain_mutex() { return ::WaitForSingleObject(m_hndMutex,0) == WAIT_OBJECT_0; }
439         inline void release_mutex()   { ::ReleaseMutex(m_hndMutex); }
440         //------------------------------------------------
441 #endif // OS switch
442     };
443
444     void ThreadConditionSignal::obtain_mutex()    
445     { 
446         m_osdepobj.obtain_mutex();    
447     }
448     bool ThreadConditionSignal::tryobtain_mutex() { return m_osdepobj.tryobtain_mutex(); }
449     void ThreadConditionSignal::release_mutex()   
450     { 
451         m_osdepobj.release_mutex();   
452     }
453
454     void ThreadConditionSignal::await_condition()                   { m_osdepobj.await_signal();  }
455     bool ThreadConditionSignal::await_condition(timediff tdTimeout) { return m_osdepobj.await_signal(tdTimeout);  }
456     void ThreadConditionSignal::signal_condition_single()           { m_osdepobj.signal_unicast();    }
457     void ThreadConditionSignal::signal_condition_broadcast()        { m_osdepobj.signal_broadcast();  }
458
459     ThreadConditionSignal::ThreadConditionSignal() : m_osdepobj(*new OSDependentObject) {}
460     ThreadConditionSignal::~ThreadConditionSignal() { delete &m_osdepobj; }
461
462
463
464
465
466
467
468
469 #if XPLATFORMTHREADS_POSIX
470     namespace // anon
471     {
472         inline int max_FIFO_schedparam()
473         {
474             static const int max_priority = ::sched_get_priority_max(SCHED_FIFO);
475             return max_priority;
476         }
477         inline int schedparam_by_percentage(unsigned short percentage)
478         {
479             return (max_FIFO_schedparam()*10*percentage+500)/1000;
480         }
481         class POSIXThreadPriority
482         {
483         public:
484             int m_SchedPolicy;
485             int m_SchedPriority;
486             POSIXThreadPriority(ThreadPriority pri)
487             {
488                 switch (pri)
489                 {
490                 case ThreadPriority::TimeCritical: m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(80); break;
491                 case ThreadPriority::AboveNormal:  m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(20); break;
492                 case ThreadPriority::BelowNormal:  // fall through to normal; nothing is below normal in POSIX
493                 case ThreadPriority::Normal: // fall through to default
494                 default: m_SchedPolicy=SCHED_OTHER, m_SchedPriority=0; break;
495                 }
496             }
497         };
498
499     } // namespace anonymous
500 #endif // XPLATFORMTHREADS_POSIX
501
502 #if XPLATFORMTHREADS_WINDOWS
503     namespace // anon
504     {
505         inline int WinThreadPriority(ThreadPriority pri)
506         {
507             switch (pri)
508             {
509             case ThreadPriority::BelowNormal:  return THREAD_PRIORITY_BELOW_NORMAL;
510             case ThreadPriority::AboveNormal:  return THREAD_PRIORITY_ABOVE_NORMAL;
511             case ThreadPriority::TimeCritical: return THREAD_PRIORITY_TIME_CRITICAL;
512             case ThreadPriority::Normal: // fall through to default
513             default: return THREAD_PRIORITY_NORMAL;
514             }
515         }
516     } // namespace anon
517 #endif // XPLATFORMTHREADS_WINDOWS
518
519
520
521     void SetMyThreadPriority(ThreadPriority pri)
522     {
523 #if XPLATFORMTHREADS_WINDOWS
524         ::SetThreadPriority(::GetCurrentThread(), WinThreadPriority(pri));
525 #endif // XPLATFORMTHREADS_WINDOWS
526 #if XPLATFORMTHREADS_POSIX
527         const POSIXThreadPriority posixpri(pri);
528         sched_param sparam;
529         ::memset(&sparam, 0, sizeof(sparam));
530         sparam.sched_priority = posixpri.m_SchedPriority;
531 #if defined(__linux__)
532         ::sched_setscheduler(0, posixpri.m_SchedPolicy, &sparam);  // linux uses this function instead of pthread_
533 #else
534         pthread_setschedparam(pthread_self(), posixpri.m_SchedPolicy, &sparam);
535 #endif
536 #endif // XPLATFORMTHREADS_POSIX
537     }
538
539
540     struct ThreadWrapperData
541     {
542         ThreadFunction *func;
543         ThreadFunctionArgument arg;
544     };
545
546 #if XPLATFORMTHREADS_WINDOWS
547     static unsigned int __stdcall ThreadWrapper(void * arg)
548     {
549         register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
550         ThreadFunction        *func=twd->func;
551         ThreadFunctionArgument farg=twd->arg;
552         delete twd;
553         return DWORD(func(farg));
554     }
555 #elif XPLATFORMTHREADS_POSIX
556     static void * ThreadWrapper(void *arg)
557     {
558         register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
559         ThreadFunction        *func=twd->func;
560         ThreadFunctionArgument farg=twd->arg;
561         delete twd;
562         return reinterpret_cast<void*>(func(farg));
563     }
564     typedef void*(ThreadWrapperFunction)(void*);
565
566     static ThreadWrapperFunction *ThunkedThreadWrapper = ThreadWrapper;
567
568 #endif // OS switch
569
570
571
572
573
574     class ThreadHandle::OSDependent
575     {
576     public:
577         static void StartThread(ThreadWrapperData *, ThreadHandle &, ThreadPriority);
578         static bool KillThread(ThreadHandle);
579         static bool JoinThread(ThreadHandle, ThreadFunctionReturnType*);
580         static void Close(ThreadHandle);
581 #if XPLATFORMTHREADS_WINDOWS
582         static inline uintptr_t from_oshandle(HANDLE h) { return reinterpret_cast<uintptr_t>(h); }
583         static inline HANDLE to_oshandle(uintptr_t h) { return reinterpret_cast<HANDLE>(h); }
584 #elif XPLATFORMTHREADS_POSIX
585         static inline uintptr_t from_oshandle(pthread_t pt) { return uintptr_t(pt); }
586         static inline pthread_t to_oshandle(uintptr_t h) { return pthread_t(h); }
587 #endif // OS switch
588     };
589
590 #if XPLATFORMTHREADS_WINDOWS
591     const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(INVALID_HANDLE_VALUE));
592 #elif XPLATFORMTHREADS_POSIX
593     const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(0));
594 #endif // OS switch
595
596     inline void ThreadHandle::OSDependent::StartThread(ThreadWrapperData *ptwdata, ThreadHandle &th, ThreadPriority pri)
597     {
598 #if XPLATFORMTHREADS_WINDOWS
599         uintptr_t h = ::_beginthreadex(
600                 0,                 // no security attributes, not inheritable
601                 0,                 // default stack size
602                 ThreadWrapper,     // function to call
603                 (void*)(ptwdata),   // argument for function
604                 0,                 // creation flags
605                 0                  // where to store thread ID
606             );
607
608         if (h) 
609         {
610             th.m_oshandle = h;
611             if (pri!=ThreadPriority::Normal)
612                 ::SetThreadPriority(to_oshandle(h), WinThreadPriority(pri));
613         }
614         else
615             th=Invalid;
616 #elif XPLATFORMTHREADS_POSIX
617         pthread_attr_t my_thread_attr, *pmy_thread_attr = 0;
618         sched_param my_schedparam;
619
620         if (pri!=ThreadPriority::Normal)
621         {
622             pmy_thread_attr = &my_thread_attr;
623
624             const POSIXThreadPriority posixpriority(pri);
625             int result;
626             result = pthread_attr_init          (pmy_thread_attr);
627             result = pthread_attr_setschedpolicy(pmy_thread_attr, posixpriority.m_SchedPolicy);
628
629             memset(&my_schedparam, 0, sizeof(my_schedparam));
630             my_schedparam.sched_priority = posixpriority.m_SchedPriority;
631             result = pthread_attr_setschedparam(pmy_thread_attr, &my_schedparam);
632         }
633
634         pthread_t pt;
635         int anyerr = pthread_create(
636                 &pt,   // variable for thread handle
637                 pmy_thread_attr,     // default attributes
638                 ThunkedThreadWrapper,
639                 ptwdata
640             );
641             
642         if (anyerr) 
643             th=Invalid;
644         else
645             th.m_oshandle = OSDependent::from_oshandle(pt);
646 #endif
647     }
648
649     inline bool ThreadHandle::OSDependent::KillThread(ThreadHandle h)
650     {
651 #if XPLATFORMTHREADS_WINDOWS
652         return ::TerminateThread(to_oshandle(h.m_oshandle), (DWORD)-1) != 0;
653 #elif XPLATFORMTHREADS_POSIX
654         return pthread_cancel(to_oshandle(h.m_oshandle)) == 0;
655 #endif
656     }
657
658     bool ThreadHandle::OSDependent::JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
659     {
660 #if XPLATFORMTHREADS_WINDOWS
661         const bool kbReturnedOk = (WAIT_OBJECT_0 == ::WaitForSingleObject(OSDependent::to_oshandle(h.m_oshandle), INFINITE));
662         if (kbReturnedOk && pretval)
663         {
664             DWORD dwExitCode;
665             ::GetExitCodeThread(to_oshandle(h.m_oshandle), &dwExitCode);
666             *pretval = (ThreadFunctionReturnType)(dwExitCode);
667         }
668         return kbReturnedOk;
669 #endif
670 #if XPLATFORMTHREADS_POSIX
671         ThreadFunctionReturnType ptrExitCode = 0;
672         int join_return_code = pthread_join(to_oshandle(h.m_oshandle), (void**)ptrExitCode);
673         const bool kbReturnedOk = (0 == join_return_code);
674         if (0 != pretval)
675         {
676             *pretval = ptrExitCode;
677         }
678         return kbReturnedOk;
679 #endif
680     }
681
682 #if XPLATFORMTHREADS_WINDOWS
683     inline void ThreadHandle::OSDependent::Close(ThreadHandle h)
684     {
685         ::CloseHandle(OSDependent::to_oshandle(h.m_oshandle));
686     }
687 #endif // XPLATFORMTHREADS_WINDOWS
688 #if XPLATFORMTHREADS_POSIX
689     inline void ThreadHandle::OSDependent::Close(ThreadHandle) {}
690 #endif // XPLATFORMTHREADS_POSIX
691
692     //**********************************************************************************************
693
694     class WCThreadRef::OSDependent
695     {
696     public:
697         static void GetCurrentThreadRef(WCThreadRef& tid); 
698 #if XPLATFORMTHREADS_WINDOWS
699         static inline uintptr_t from_os(DWORD thread_id) { return (uintptr_t)(thread_id); }
700         static inline DWORD to_os(uintptr_t thread_id)   { return (DWORD)(thread_id); }
701 #elif XPLATFORMTHREADS_POSIX
702     static inline uintptr_t from_os(pthread_t thread_id) { return (uintptr_t)(thread_id); }
703     static inline pthread_t to_os(uintptr_t thread_id)   { return pthread_t(thread_id); }
704 #endif // OS switch
705     };
706
707     //**********************************************************************************************
708     inline void WCThreadRef::OSDependent::GetCurrentThreadRef(WCThreadRef& tid)
709     {
710 #if XPLATFORMTHREADS_WINDOWS
711         DWORD thread_id = ::GetCurrentThreadId();
712         tid.m_osThreadRef = OSDependent::from_os(thread_id);
713
714 #elif XPLATFORMTHREADS_POSIX
715         pthread_t thread_id = ::pthread_self();
716         tid.m_osThreadRef = OSDependent::from_os(thread_id);
717
718 #endif // OS switch
719     }
720
721     //**********************************************************************************************
722
723     ThreadHandle StartThread(ThreadFunction func, ThreadFunctionArgument arg, ThreadPriority thpri)
724     {
725         EnsureThreadingInitialized();
726         ThreadWrapperData *ptwdata = new ThreadWrapperData;
727         ptwdata->func = func;
728         ptwdata->arg  = arg;
729         ThreadHandle thToReturn;
730         ThreadHandle::OSDependent::StartThread(ptwdata, thToReturn, thpri);
731         return thToReturn;
732     }
733
734     bool KillThread(ThreadHandle h)
735     {
736         EnsureThreadingInitialized();
737         return ThreadHandle::OSDependent::KillThread(h);
738     }
739
740     bool JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
741     {
742         EnsureThreadingInitialized();
743         return ThreadHandle::OSDependent::JoinThread(h, pretval);
744     }
745
746     void Close(ThreadHandle h)
747     {
748         EnsureThreadingInitialized();
749         return ThreadHandle::OSDependent::Close(h);
750     }
751
752     //*******************************************************************************************
753
754     WCThreadRef GetCurrentThreadRef()
755     {
756         EnsureThreadingInitialized(); // Is it necessary?  
757         WCThreadRef tRefToReturn;
758         WCThreadRef::OSDependent::GetCurrentThreadRef(tRefToReturn);
759         return tRefToReturn;
760     }
761
762     //*******************************************************************************************
763
764     bool IsThreadExists(const WCThreadRef& threadRef)
765     {
766 #if XPLATFORMTHREADS_WINDOWS
767         DWORD dwThreadId = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
768         HANDLE handle = ::OpenThread(SYNCHRONIZE, // dwDesiredAccess - use of the thread handle in any of the wait functions
769                                      FALSE,          // bInheritHandle  - processes do not inherit this handle
770                                      dwThreadId);
771
772         // Now we have the handle, check if the associated thread exists:
773         DWORD retVal = WaitForSingleObject(handle, 0);
774         if (retVal == WAIT_FAILED)
775             return false;    // the thread does not exists
776         else
777             return true;    // the thread exists
778
779 #elif XPLATFORMTHREADS_POSIX
780         pthread_t pthreadRef = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
781         int retVal = pthread_kill(pthreadRef, 0);    // send a signal to the thread, but do nothing
782         if (retVal == ESRCH)
783             return false;    // the thread does not exists
784         else
785             return true;    // the thread exists
786
787 #endif // OS switch
788     }
789
790     //*******************************************************************************************
791
792     bool operator==(const WCThreadRef& first, const WCThreadRef& second)
793     {
794         return (first.m_osThreadRef == second.m_osThreadRef);
795     }
796
797     bool operator!=(const WCThreadRef& first, const WCThreadRef& second)
798     {
799         return (first.m_osThreadRef != second.m_osThreadRef);
800     }
801
802     bool operator<(const WCThreadRef& first, const WCThreadRef& second)
803     {
804         return (first.m_osThreadRef < second.m_osThreadRef);
805     }
806
807     bool operator>(const WCThreadRef& first, const WCThreadRef& second)
808     {
809         return (first.m_osThreadRef > second.m_osThreadRef);
810     }
811
812     bool WCAtomicLock::obtain(const uint32_t in_num_trys)
813     {
814         bool retVal = false;
815         
816         uint32_t timeOut = in_num_trys;
817         while (true)
818         {
819             retVal = Akupara::threading::atomic::compare_and_store<int32_t>(&m_the_lock, int32_t(0), int32_t(1));
820             if (retVal)
821             {
822                 break;
823             }
824             else
825             {
826                 if (--timeOut == 0)
827                 {
828                     break;
829                 }
830                 sleep_milliseconds(1000);
831             }
832         }
833         
834         return retVal;
835     }
836
837     void WCAtomicLock::release()
838     {
839         m_the_lock = 0;
840     }
841
842 } //    namespace wvThread
843 } // namespace wvNS {
844