2 Copyright (C) 2013 Waves Audio Ltd.
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.
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.
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.
19 #include "Threads/WCThreadSafe.h"
21 #if XPLATFORMTHREADS_WINDOWS
22 #define _WIN32_WINNT 0x0500 // need at least Windows2000 (for TryEnterCriticalSection() and SignalObjectAndWait()
23 #include "IncludeWindows.h"
25 #endif // XPLATFORMTHREADS_WINDOWS
28 #if defined(__MACOS__)
29 #include <CoreServices/CoreServices.h>
33 #if XPLATFORMTHREADS_POSIX
34 #include </usr/include/unistd.h> // avoid the framework version and use the /usr/include version
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;
47 #endif //XPLATFORMTHREADS_POSIX
49 #include "Akupara/threading/atomic_ops.hpp"
51 static const unsigned int knMicrosecondsPerSecond = 1000*1000;
52 static const unsigned int knNanosecondsPerMicrosecond = 1000;
53 static const unsigned int knNanosecondsPerSecond = knMicrosecondsPerSecond*knNanosecondsPerMicrosecond;
58 //--------------------------------------------------------------------------------
59 static inline bool EnsureThreadingInitialized()
65 //--------------------------------------------------------------------------------
70 //--------------------------------------------------------------------------------
71 static uint32_t CalculateTicksPerMicrosecond();
72 static uint32_t CalculateTicksPerMicrosecond()
74 uint32_t nTicksPerMicrosecond=0;
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;
84 //--------------------- begin measurement code
85 // poll to align to a tick of gettimeofday
86 ::gettimeofday(&tvtmp,0);
88 ::gettimeofday(&tvstart,0);
89 __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tstart)); // RDTSC
90 } while (tvtmp.tv_usec!=tvstart.tv_usec);
92 ::usleep(sktd_TSC_MeasurementPeriod);
94 ::gettimeofday(&tvtmp,0);
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
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);
105 return nTicksPerMicrosecond;
108 #if defined(__MACOS__) //&& !defined(__MACH__)
111 bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface) // sIP and sInterface are both char[16]
113 FILE *fProcess , *pSubcall;
114 char sLine[256]="", *pToken, sCommand[150];
118 fProcess = popen("ifconfig -l inet", "r");
121 memset(sInterface, '\0', 16);
122 iret = BSDfread(sLine, sizeof(char), sizeof(sLine), fProcess);
123 pToken = strtok(sLine, " ");
126 sprintf(sCommand, "ifconfig %s | grep \"inet %s \"", pToken, sIP);
128 pSubcall = popen(sCommand, "r");
131 char sSubline[100]="";
132 if (BSDfread(sSubline, sizeof(char), sizeof(sSubline), pSubcall))
135 strcpy(sInterface, pToken);
142 pToken = strtok(NULL, " ");
154 EnsureThreadingInitialized();
155 static const uint32_t nTicksPerMicrosecond = CalculateTicksPerMicrosecond();
157 if (nTicksPerMicrosecond)
160 ::QueryPerformanceCounter(&TSC);
161 return timestamp(uint32_t(TSC.QuadPart/nTicksPerMicrosecond));
163 else return timestamp(0);
164 #elif defined(__MACOS__)
165 if (nTicksPerMicrosecond) {} // prevent 'unused' warnings
167 ::Microseconds(&usecs);
168 return timestamp(usecs.lo);
169 #elif defined(__linux__) && defined(__i386__) && defined(__gnu_linux__)
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
176 #error Dont know how to get microseconds timer !
177 #endif // defined(_WIN32)
181 void sleep_milliseconds(unsigned int nMillisecs)
183 EnsureThreadingInitialized();
184 #if XPLATFORMTHREADS_WINDOWS
186 #elif XPLATFORMTHREADS_POSIX
187 ::usleep(nMillisecs*1000);
189 #error Not implemented for your OS
194 #if XPLATFORMTHREADS_WINDOWS
195 inline DWORD win32_milliseconds(timediff td) { return (td+499)/1000; }
198 void sleep(timediff _td)
202 EnsureThreadingInitialized();
203 #if XPLATFORMTHREADS_WINDOWS
204 ::Sleep(win32_milliseconds(_td)); // This is the best we can do in windows
205 #elif XPLATFORMTHREADS_POSIX
208 #error Not implemented for your OS
214 #if XPLATFORMTHREADS_WINDOWS
215 void yield() { ::Sleep(0); }
216 #elif XPLATFORMTHREADS_POSIX
217 void yield() { ::sched_yield(); }
223 class ThreadMutexInited::OSDependentMutex : public noncopyableobject
225 #if defined (XPLATFORMTHREADS_WINDOWS)
227 CRITICAL_SECTION m_critsec;
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; }
236 #elif defined (XPLATFORMTHREADS_POSIX)
238 pthread_mutex_t m_ptmutex;
240 inline OSDependentMutex()
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);
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; }
256 ThreadMutexInited::ThreadMutexInited() :
259 void ThreadMutexInited::init()
263 m_osdmutex = new OSDependentMutex;
267 void ThreadMutexInited::uninit()
276 ThreadMutexInited::~ThreadMutexInited()
281 void ThreadMutexInited::obtain()
285 m_osdmutex->obtain();
289 void ThreadMutexInited::release()
293 m_osdmutex->release();
297 bool ThreadMutexInited::tryobtain()
302 retVal = m_osdmutex->tryobtain();
307 class ThreadConditionSignal::OSDependentObject : public noncopyableobject
309 #if defined (XPLATFORMTHREADS_POSIX)
312 pthread_cond_t m_ptcond;
313 pthread_mutex_t m_ptmutex;
315 inline OSDependentObject()
317 EnsureThreadingInitialized();
318 ::pthread_mutex_init(&m_ptmutex,0);
319 ::pthread_cond_init(&m_ptcond, 0);
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)
327 timespec tspecDeadline;
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;
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); }
342 #elif XPLATFORMTHREADS_WINDOWS
344 unsigned int m_nWaiterCount;
345 CRITICAL_SECTION m_csectWaiterCount;
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
353 // - - - - - - - - - - - - - - - - - - - - - - - -
354 bool await_signal_win32(DWORD dwTimeout)
356 ::EnterCriticalSection(&m_csectWaiterCount);
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;
362 ::EnterCriticalSection(&m_csectWaiterCount);
363 bool bLastWaiter = --m_nWaiterCount==0 && m_bBroadcastSignalled;
364 ::LeaveCriticalSection(&m_csectWaiterCount);
366 // re-acquire the mutex
368 ::SignalObjectAndWait(m_hndEventAllWaitersReleased, m_hndMutex, INFINITE, FALSE);
370 ::WaitForSingleObject(m_hndMutex, INFINITE);
371 return bWaitSucceeded;
377 inline bool await_signal(timediff td) { return await_signal_win32((win32_milliseconds(td))); }
378 inline void await_signal() { await_signal_win32(INFINITE); }
380 OSDependentObject() : m_nWaiterCount(0), m_bBroadcastSignalled(false)
382 EnsureThreadingInitialized();
383 ::InitializeCriticalSection(&m_csectWaiterCount);
384 m_hndEventAllWaitersReleased = ::CreateEvent(
387 FALSE, // initial state non-sognalled
389 m_hndSemaphoreSignaller = ::CreateSemaphore(
391 0, // initial count (and will stay this way)
392 0x100000, // maximum count (should be as large as the maximum number of waiting threads)
394 m_hndMutex = ::CreateMutex(
396 FALSE, // not owned initially
398 //if (m_hndEventAllWaitersReleased==INVALID_HANDLE_VALUE || m_hndSemaphoreSignaller==INVALID_HANDLE_VALUE)
399 // throw something();
404 ::CloseHandle(m_hndMutex);
405 ::CloseHandle(m_hndSemaphoreSignaller);
406 ::CloseHandle(m_hndEventAllWaitersReleased);
407 ::DeleteCriticalSection(&m_csectWaiterCount);
410 inline void signal_unicast()
412 ::EnterCriticalSection(&m_csectWaiterCount);
413 unsigned int nWaiters = m_nWaiterCount;
414 ::LeaveCriticalSection(&m_csectWaiterCount);
416 ::ReleaseSemaphore(m_hndSemaphoreSignaller, 1, 0); // release 1 semaphore credit to release one waiting thread
419 void signal_broadcast()
421 ::EnterCriticalSection(&m_csectWaiterCount);
422 unsigned int nWaiters = m_nWaiterCount;
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;
434 ::LeaveCriticalSection(&m_csectWaiterCount);
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 //------------------------------------------------
444 void ThreadConditionSignal::obtain_mutex()
446 m_osdepobj.obtain_mutex();
448 bool ThreadConditionSignal::tryobtain_mutex() { return m_osdepobj.tryobtain_mutex(); }
449 void ThreadConditionSignal::release_mutex()
451 m_osdepobj.release_mutex();
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(); }
459 ThreadConditionSignal::ThreadConditionSignal() : m_osdepobj(*new OSDependentObject) {}
460 ThreadConditionSignal::~ThreadConditionSignal() { delete &m_osdepobj; }
469 #if XPLATFORMTHREADS_POSIX
472 inline int max_FIFO_schedparam()
474 static const int max_priority = ::sched_get_priority_max(SCHED_FIFO);
477 inline int schedparam_by_percentage(unsigned short percentage)
479 return (max_FIFO_schedparam()*10*percentage+500)/1000;
481 class POSIXThreadPriority
486 POSIXThreadPriority(ThreadPriority pri)
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;
499 } // namespace anonymous
500 #endif // XPLATFORMTHREADS_POSIX
502 #if XPLATFORMTHREADS_WINDOWS
505 inline int WinThreadPriority(ThreadPriority pri)
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;
517 #endif // XPLATFORMTHREADS_WINDOWS
521 void SetMyThreadPriority(ThreadPriority pri)
523 #if XPLATFORMTHREADS_WINDOWS
524 ::SetThreadPriority(::GetCurrentThread(), WinThreadPriority(pri));
525 #endif // XPLATFORMTHREADS_WINDOWS
526 #if XPLATFORMTHREADS_POSIX
527 const POSIXThreadPriority posixpri(pri);
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_
534 pthread_setschedparam(pthread_self(), posixpri.m_SchedPolicy, &sparam);
536 #endif // XPLATFORMTHREADS_POSIX
540 struct ThreadWrapperData
542 ThreadFunction *func;
543 ThreadFunctionArgument arg;
546 #if XPLATFORMTHREADS_WINDOWS
547 static unsigned int __stdcall ThreadWrapper(void * arg)
549 register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
550 ThreadFunction *func=twd->func;
551 ThreadFunctionArgument farg=twd->arg;
553 return DWORD(func(farg));
555 #elif XPLATFORMTHREADS_POSIX
556 static void * ThreadWrapper(void *arg)
558 register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
559 ThreadFunction *func=twd->func;
560 ThreadFunctionArgument farg=twd->arg;
562 return reinterpret_cast<void*>(func(farg));
564 typedef void*(ThreadWrapperFunction)(void*);
566 static ThreadWrapperFunction *ThunkedThreadWrapper = ThreadWrapper;
574 class ThreadHandle::OSDependent
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); }
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));
596 inline void ThreadHandle::OSDependent::StartThread(ThreadWrapperData *ptwdata, ThreadHandle &th, ThreadPriority pri)
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
605 0 // where to store thread ID
611 if (pri!=ThreadPriority::Normal)
612 ::SetThreadPriority(to_oshandle(h), WinThreadPriority(pri));
616 #elif XPLATFORMTHREADS_POSIX
617 pthread_attr_t my_thread_attr, *pmy_thread_attr = 0;
618 sched_param my_schedparam;
620 if (pri!=ThreadPriority::Normal)
622 pmy_thread_attr = &my_thread_attr;
624 const POSIXThreadPriority posixpriority(pri);
626 result = pthread_attr_init (pmy_thread_attr);
627 result = pthread_attr_setschedpolicy(pmy_thread_attr, posixpriority.m_SchedPolicy);
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);
635 int anyerr = pthread_create(
636 &pt, // variable for thread handle
637 pmy_thread_attr, // default attributes
638 ThunkedThreadWrapper,
645 th.m_oshandle = OSDependent::from_oshandle(pt);
649 inline bool ThreadHandle::OSDependent::KillThread(ThreadHandle h)
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;
658 bool ThreadHandle::OSDependent::JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
660 #if XPLATFORMTHREADS_WINDOWS
661 const bool kbReturnedOk = (WAIT_OBJECT_0 == ::WaitForSingleObject(OSDependent::to_oshandle(h.m_oshandle), INFINITE));
662 if (kbReturnedOk && pretval)
665 ::GetExitCodeThread(to_oshandle(h.m_oshandle), &dwExitCode);
666 *pretval = (ThreadFunctionReturnType)(dwExitCode);
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);
676 *pretval = ptrExitCode;
682 #if XPLATFORMTHREADS_WINDOWS
683 inline void ThreadHandle::OSDependent::Close(ThreadHandle h)
685 ::CloseHandle(OSDependent::to_oshandle(h.m_oshandle));
687 #endif // XPLATFORMTHREADS_WINDOWS
688 #if XPLATFORMTHREADS_POSIX
689 inline void ThreadHandle::OSDependent::Close(ThreadHandle) {}
690 #endif // XPLATFORMTHREADS_POSIX
692 //**********************************************************************************************
694 class WCThreadRef::OSDependent
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); }
707 //**********************************************************************************************
708 inline void WCThreadRef::OSDependent::GetCurrentThreadRef(WCThreadRef& tid)
710 #if XPLATFORMTHREADS_WINDOWS
711 DWORD thread_id = ::GetCurrentThreadId();
712 tid.m_osThreadRef = OSDependent::from_os(thread_id);
714 #elif XPLATFORMTHREADS_POSIX
715 pthread_t thread_id = ::pthread_self();
716 tid.m_osThreadRef = OSDependent::from_os(thread_id);
721 //**********************************************************************************************
723 ThreadHandle StartThread(ThreadFunction func, ThreadFunctionArgument arg, ThreadPriority thpri)
725 EnsureThreadingInitialized();
726 ThreadWrapperData *ptwdata = new ThreadWrapperData;
727 ptwdata->func = func;
729 ThreadHandle thToReturn;
730 ThreadHandle::OSDependent::StartThread(ptwdata, thToReturn, thpri);
734 bool KillThread(ThreadHandle h)
736 EnsureThreadingInitialized();
737 return ThreadHandle::OSDependent::KillThread(h);
740 bool JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
742 EnsureThreadingInitialized();
743 return ThreadHandle::OSDependent::JoinThread(h, pretval);
746 void Close(ThreadHandle h)
748 EnsureThreadingInitialized();
749 return ThreadHandle::OSDependent::Close(h);
752 //*******************************************************************************************
754 WCThreadRef GetCurrentThreadRef()
756 EnsureThreadingInitialized(); // Is it necessary?
757 WCThreadRef tRefToReturn;
758 WCThreadRef::OSDependent::GetCurrentThreadRef(tRefToReturn);
762 //*******************************************************************************************
764 bool IsThreadExists(const WCThreadRef& threadRef)
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
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
777 return true; // the thread exists
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
783 return false; // the thread does not exists
785 return true; // the thread exists
790 //*******************************************************************************************
792 bool operator==(const WCThreadRef& first, const WCThreadRef& second)
794 return (first.m_osThreadRef == second.m_osThreadRef);
797 bool operator!=(const WCThreadRef& first, const WCThreadRef& second)
799 return (first.m_osThreadRef != second.m_osThreadRef);
802 bool operator<(const WCThreadRef& first, const WCThreadRef& second)
804 return (first.m_osThreadRef < second.m_osThreadRef);
807 bool operator>(const WCThreadRef& first, const WCThreadRef& second)
809 return (first.m_osThreadRef > second.m_osThreadRef);
812 bool WCAtomicLock::obtain(const uint32_t in_num_trys)
816 uint32_t timeOut = in_num_trys;
819 retVal = Akupara::threading::atomic::compare_and_store<int32_t>(&m_the_lock, int32_t(0), int32_t(1));
830 sleep_milliseconds(1000);
837 void WCAtomicLock::release()
842 } // namespace wvThread
843 } // namespace wvNS {