38#include "blocxx/BLOCXX_config.h"
49#if defined(BLOCXX_WIN32)
59#ifdef BLOCXX_HAVE_SYS_TIME_H
65#ifdef BLOCXX_HAVE_UNISTD_H
72#ifdef BLOCXX_USE_PTHREAD
116#if defined(BLOCXX_HAVE_SCHED_YIELD)
118#elif defined(BLOCXX_WIN32)
126#if defined(BLOCXX_USE_PTHREAD)
128struct LocalThreadParm
135threadStarter(
void* arg)
139 pthread_setcancel(CANCEL_ON);
140 pthread_setasynccancel(CANCEL_OFF);
142 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
143 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
148 int rv = sigfillset(&signalSet);
150 rv = sigdelset(&signalSet, SIGUSR1);
152 rv = pthread_sigmask(SIG_SETMASK, &signalSet, 0);
155 LocalThreadParm* parg =
static_cast<LocalThreadParm*
>(arg);
157 void* funcParm = parg->m_funcParm;
159 Int32 rval = (*func)(funcParm);
160 void* prval =
reinterpret_cast<void*
>(
static_cast<ptrdiff_t
>(rval));
167struct default_stack_size
169#if !defined(BLOCXX_NCR)
174 needsSetting =
false;
179#ifdef _POSIX_THREAD_ATTR_STACKSIZE
180 pthread_attr_t stack_size_attr;
181 if (pthread_attr_init(&stack_size_attr) != 0)
185 if (pthread_attr_getstacksize(&stack_size_attr, &val) != 0)
195#ifdef PTHREAD_STACK_MIN
196 if (PTHREAD_STACK_MIN > val)
198 val = PTHREAD_STACK_MIN;
211 needsSetting =
false;
216#ifdef _POSIX_THREAD_ATTR_STACKSIZE
217 pthread_attr_t stack_size_attr;
218 if (pthread_attr_create(&stack_size_attr) != 0)
223 val = pthread_attr_getstacksize(stack_size_attr);
224 if (
static_cast<signed>(val) == -1)
232#if defined(PTHREAD_STACK_MIN) && defined(_SC_THREAD_STACK_MIN)
233 if (PTHREAD_STACK_MIN > val)
235 val = PTHREAD_STACK_MIN;
245 static bool needsSetting;
248size_t default_stack_size::val = 0;
249bool default_stack_size::needsSetting(
false);
250default_stack_size g_theDefaultStackSize;
252pthread_once_t once_control = PTHREAD_ONCE_INIT;
264SIGUSR1Handler(
int sig)
271static void doOneTimeThreadInitialization()
274 pthread_keycreate(&theKey, NULL);
276 pthread_key_create(&theKey, NULL);
279 struct sigaction temp;
280 memset(&temp,
'\0',
sizeof(temp));
281 sigaction(SIGUSR1, 0, &temp);
282 temp.sa_handler = SIGUSR1Handler;
283 sigemptyset(&temp.sa_mask);
285 sigaction(SIGUSR1, &temp, NULL);
292#if !defined(BLOCXX_NCR)
296 void* funcParm, UInt32 threadFlags)
300 pthread_attr_init(&attr);
303 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
306#if !defined(BLOCXX_VALGRIND_SUPPORT)
308 if (default_stack_size::needsSetting)
310 pthread_attr_setstacksize(&attr, default_stack_size::val);
314 LocalThreadParm* parg =
new LocalThreadParm;
316 parg->m_funcParm = funcParm;
317 cc = pthread_create(&handle, &attr, threadStarter, parg);
318 pthread_attr_destroy(&attr);
326 void* funcParm, UInt32 threadFlags)
330 pthread_attr_create(&attr);
332#if !defined(BLOCXX_VALGRIND_SUPPORT)
334 if (default_stack_size::needsSetting)
336 pthread_attr_setstacksize(&attr, default_stack_size::val);
340 LocalThreadParm* parg =
new LocalThreadParm;
342 parg->m_funcParm = funcParm;
343 if (pthread_create(&handle, attr, threadStarter, parg) != 0)
350 pthread_detach(&handle);
353 pthread_attr_delete(&attr);
362 void* prval =
reinterpret_cast<void*
>(
static_cast<ptrdiff_t
>(rval));
367#if defined(BLOCXX_SIZEOF_PTHREAD_T)
368#if BLOCXX_SIZEOF_PTHREAD_T == 2
369#define BLOCXX_THREAD_CONVERTER UInt16
370#elif BLOCXX_SIZEOF_PTHREAD_T == 4
371#define BLOCXX_THREAD_CONVERTER UInt32
372#elif BLOCXX_SIZEOF_PTHREAD_T == 8
373#define BLOCXX_THREAD_CONVERTER UInt64
376#define BLOCXX_THREAD_CONVERTER UInt16
378#error Unexpected size for pthread_t
382#error No pthread_t size was found!
388 return UInt64(BLOCXX_THREAD_CONVERTER(cma_thread_get_unique(&thr)));
390 return UInt64(BLOCXX_THREAD_CONVERTER(thr));
393#undef BLOCXX_THREAD_CONVERTER
407 int cc = pthread_detach(&handle);
409 int cc = pthread_detach(handle);
426 if ((errno = pthread_join(handle, &prval)) == 0)
428 rval =
static_cast<Int32
>(
reinterpret_cast<ptrdiff_t
>(prval));
441 pthread_once(&once_control, &doOneTimeThreadInitialization);
442 Thread* theThread = NULL;
444 pthread_addr_t addr_ptr = NULL;
445 int ret = pthread_getspecific(theKey, &addr_ptr);
448 theThread =
reinterpret_cast<Thread*
>(addr_ptr);
451 theThread =
reinterpret_cast<Thread*
>(pthread_getspecific(theKey));
457 if (
AtomicGet(theThread->m_cancelRequested) == 1)
464 throw ThreadCancelledException();
471 pthread_once(&once_control, &doOneTimeThreadInitialization);
473 if ((rc = pthread_setspecific(theKey, pTheThread)) != 0)
475 BLOCXX_THROW(ThreadException, Format(
"pthread_setspecific failed. error = %1(%2)", rc, strerror(rc)).c_str());
482 if ((rc = pthread_kill(threadID, signo)) != 0)
484 BLOCXX_THROW(ThreadException, Format(
"pthread_kill failed. error = %1(%2)", rc, strerror(rc)).c_str());
488void cancel(Thread_t threadID)
491 if ((rc = pthread_cancel(threadID)) != 0)
493 BLOCXX_THROW(ThreadException, Format(
"pthread_cancel failed. error = %1(%2)", rc, strerror(rc)).c_str());
498#if defined(BLOCXX_WIN32)
508typedef Map<DWORD, WThreadInfo> Win32ThreadMap;
509Win32ThreadMap g_threads;
512struct LocalThreadParm
520unsigned __stdcall threadStarter(
void* arg)
522 LocalThreadParm* parg =
reinterpret_cast<LocalThreadParm*
>(arg);
524 void* funcParm = parg->m_funcParm;
526 Int32 rval = (*func)(funcParm);
527 ::_endthreadex(
static_cast<unsigned>(rval));
534addThreadToMap(DWORD threadId, HANDLE threadHandle)
536 MutexLock ml(g_threadsGuard);
538 wi.handle = threadHandle;
540 g_threads[threadId] = wi;
545getThreadHandle(DWORD threadId)
547 MutexLock ml(g_threadsGuard);
549 Win32ThreadMap::iterator it = g_threads.find(threadId);
550 if (it != g_threads.end())
552 chdl = it->second.handle;
559setThreadPointer(DWORD threadId, Thread* pTheThread)
561 MutexLock ml(g_threadsGuard);
562 Win32ThreadMap::iterator it = g_threads.find(threadId);
563 if (it != g_threads.end())
565 it->second.pTheThread = pTheThread;
571removeThreadFromMap(DWORD threadId)
573 MutexLock ml(g_threadsGuard);
575 Win32ThreadMap::iterator it = g_threads.find(threadId);
576 if (it != g_threads.end())
578 chdl = it->second.handle;
586getThreadObject(DWORD threadId)
588 Thread* pTheThread = 0;
589 MutexLock ml(g_threadsGuard);
590 Win32ThreadMap::iterator it = g_threads.find(threadId);
591 if (it != g_threads.end())
593 pTheThread = it->second.pTheThread;
604 void* funcParm, UInt32 threadFlags)
610 LocalThreadParm* parg =
new LocalThreadParm;
612 parg->m_funcParm = funcParm;
613 hThread =
reinterpret_cast<HANDLE
>(::_beginthreadex(NULL, 0, threadStarter,
614 parg, 0, &threadId));
617 addThreadToMap(threadId, hThread);
633 ::_endthreadex(
static_cast<unsigned>(rval));
641 BLOCXX_ASSERTMSG(
sizeof(
unsigned long) >=
sizeof(Thread_t),
" Thread_t truncated!");
642 return static_cast<UInt64
>(thr);
650 HANDLE thdl = removeThreadFromMap(threadId);
671 HANDLE thdl = getThreadHandle(threadId);
674 if (::WaitForSingleObject(thdl, INFINITE) != WAIT_FAILED)
676 if (::GetExitCodeThread(thdl, &rval) != 0)
678 rvalArg =
static_cast<Int32
>(rval);
691 Thread* pTheThread = getThreadObject(threadId);
694 if (
AtomicGet(pTheThread->m_cancelRequested) == 1)
701 throw ThreadCancelledException();
708 Thread* pThread =
static_cast<Thread*
>(pThreadArg);
709 DWORD threadId = pThread->getId();
710 setThreadPointer(threadId, pThread);
717void cancel(Thread_t threadId)
719 HANDLE thdl = getThreadHandle(threadId);
722 ::TerminateThread(thdl, -1);
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(),...
#define BLOCXX_ASSERTMSG(CON, MSG)
BLOCXX_ASSERTMSG works the same as BLOCXX_ASSERT, but with a second string parameter that will be add...
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
#define BLOCXX_THREAD_FLG_JOINABLE
The Condition class represents a synchronization device that allows threads to suspend execution and ...
bool timedWait(NonRecursiveMutexLock &lock, const Timeout &timeout)
Atomically unlock a given mutex and wait for a given amount of time for this Condition object to get ...
Note that descriptions of what exceptions may be thrown assumes that object is used correctly,...
Note that descriptions of what exceptions may be thrown assumes that object is used correctly,...
Descriptions of exceptions thrown assume that the object is used correctly, i.e., method precondition...
A timeout can be absolute, which means that it will happen at the specified DateTime.
static Timeout relative(float seconds)
A TimeoutTimer is used by an algorithm to determine when a timeout has expired.
bool expired() const
Indicates whether the last loop time has exceeded the timeout.
void loop()
Meant to be called by timeout functions which loop, but don't want to reset the interval.
Timeout asAbsoluteTimeout() const
Converts the timer to an absolute timeout.
BLOCXX_COMMON_API void testCancel()
Test if this thread has been cancelled.
BLOCXX_COMMON_API void destroyThread(Thread_t &handle)
Destroy any resources associated with a thread that was created with the createThread method.
BLOCXX_COMMON_API int joinThread(Thread_t &handle, Int32 &rval)
Join a thread that has been previously set to joinable.
BLOCXX_COMMON_API UInt64 thread_t_ToUInt64(Thread_t thr)
Convert a Thread_t to an UInt64.
BLOCXX_COMMON_API int createThread(Thread_t &handle, ThreadFunction func, void *funcParm, UInt32 threadFlags)
Starts a thread running the given function.
BLOCXX_COMMON_API int setThreadDetached(Thread_t &handle)
Set a thread that was previously in the joinable state to a detached state.
BLOCXX_COMMON_API void cancel(Thread_t threadID)
void yield()
Voluntarily yield to the processor giving the next thread in the chain the opportunity to run.
void sleep(UInt32 milliSeconds)
Suspend execution of the current thread until the given number of milliSeconds have elapsed.
BLOCXX_COMMON_API void exitThread(Thread_t &handle, Int32 rval)
Exit thread method.
BLOCXX_COMMON_API void saveThreadInTLS(void *pTheThread)
BLOCXX_COMMON_API void sendSignalToThread(Thread_t threadID, int signo)
Int32(* ThreadFunction)(void *)
int AtomicGet(Atomic_t const &v)