38 #include "blocxx/BLOCXX_config.h" 49 #if defined(BLOCXX_WIN32) 59 #ifdef BLOCXX_HAVE_SYS_TIME_H 63 #include <sys/types.h> 65 #ifdef BLOCXX_HAVE_UNISTD_H 72 #ifdef BLOCXX_USE_PTHREAD 84 namespace ThreadImpl {
116 #if defined(BLOCXX_HAVE_SCHED_YIELD) 118 #elif defined(BLOCXX_WIN32) 126 #if defined(BLOCXX_USE_PTHREAD) 128 struct LocalThreadParm
135 threadStarter(
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));
167 struct 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;
203 #endif //#ifdef _POSIX_THREAD_ATTR_STACKSIZE 206 #else //#if !defined(BLOCXX_NCR) 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;
240 #endif //#ifdef _POSIX_THREAD_ATTR_STACKSIZE 242 #endif //#if !defined(BLOCXX_NCR) 245 static bool needsSetting;
248 size_t default_stack_size::val = 0;
249 bool default_stack_size::needsSetting(
false);
250 default_stack_size g_theDefaultStackSize;
252 pthread_once_t once_control = PTHREAD_ONCE_INIT;
253 pthread_key_t theKey;
264 SIGUSR1Handler(
int sig)
271 static 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) // valgrind doesn't like us to set the stack size 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);
322 #else //#if !defined(BLOCXX_NCR) 326 void* funcParm, UInt32 threadFlags)
330 pthread_attr_create(&attr);
332 #if !defined(BLOCXX_VALGRIND_SUPPORT) // valgrind doesn't like us to set the stack size 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);
356 #endif //#if !defined(BLOCXX_NCR) 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 375 #ifdef BLOCXX_NCR //BLOCXX_SIZEOF_PTHREAD_T=0 for this OS 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);
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));
471 pthread_once(&once_control, &doOneTimeThreadInitialization);
473 if ((rc = pthread_setspecific(theKey, pTheThread)) != 0)
482 if ((rc = pthread_kill(threadID, signo)) != 0)
488 void cancel(Thread_t threadID)
491 if ((rc = pthread_cancel(threadID)) != 0)
496 #endif // #ifdef BLOCXX_USE_PTHREAD 498 #if defined(BLOCXX_WIN32) 509 Win32ThreadMap g_threads;
510 Mutex g_threadsGuard;
512 struct LocalThreadParm
520 unsigned __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));
534 addThreadToMap(DWORD threadId, HANDLE threadHandle)
538 wi.handle = threadHandle;
540 g_threads[threadId] = wi;
545 getThreadHandle(DWORD threadId)
549 Win32ThreadMap::iterator it = g_threads.find(threadId);
550 if (it != g_threads.end())
552 chdl = it->second.handle;
559 setThreadPointer(DWORD threadId,
Thread* pTheThread)
562 Win32ThreadMap::iterator it = g_threads.find(threadId);
563 if (it != g_threads.end())
565 it->second.pTheThread = pTheThread;
571 removeThreadFromMap(DWORD threadId)
575 Win32ThreadMap::iterator it = g_threads.find(threadId);
576 if (it != g_threads.end())
578 chdl = it->second.handle;
586 getThreadObject(DWORD threadId)
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);
667 joinThread(Thread_t& threadId, Int32& rvalArg)
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);
709 DWORD threadId = pThread->
getId();
710 setThreadPointer(threadId, pThread);
717 void cancel(Thread_t threadId)
719 HANDLE thdl = getThreadHandle(threadId);
722 ::TerminateThread(thdl, -1);
726 #endif // #ifdef BLOCXX_WIN32 Int32(* ThreadFunction)(void *)
BLOCXX_COMMON_API void exitThread(Thread_t &handle, Int32 rval)
Exit thread method.
Timeout asAbsoluteTimeout() const
Converts the timer to an absolute timeout.
Thread_t getId()
Get this Thread object's id.
A TimeoutTimer is used by an algorithm to determine when a timeout has expired.
int AtomicGet(Atomic_t const &v)
void loop()
Meant to be called by timeout functions which loop, but don't want to reset the interval.
#define BLOCXX_ASSERTMSG(CON, MSG)
BLOCXX_ASSERTMSG works the same as BLOCXX_ASSERT, but with a second string parameter that will be add...
Descriptions of exceptions thrown assume that the object is used correctly, i.e., method precondition...
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(), it throws an AssertionException.
BLOCXX_COMMON_API UInt64 thread_t_ToUInt64(Thread_t thr)
Convert a Thread_t to an UInt64.
bool expired() const
Indicates whether the last loop time has exceeded the timeout.
Atomic_t m_cancelRequested
BLOCXX_COMMON_API void testCancel()
Test if this thread has been cancelled.
static Timeout relative(float seconds)
A timeout can be absolute, which means that it will happen at the specified DateTime.
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 ...
BLOCXX_COMMON_API void cancel(Thread_t threadID)
void sleep(UInt32 milliSeconds)
Suspend execution of the current thread until the given number of milliSeconds have elapsed...
#define BLOCXX_THREAD_FLG_JOINABLE
BLOCXX_COMMON_API int setThreadDetached(Thread_t &handle)
Set a thread that was previously in the joinable state to a detached state.
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
BLOCXX_COMMON_API int joinThread(Thread_t &handle, Int32 &rval)
Join a thread that has been previously set to joinable.
BLOCXX_COMMON_API void saveThreadInTLS(void *pTheThread)
BLOCXX_COMMON_API void sendSignalToThread(Thread_t threadID, int signo)
Note that descriptions of what exceptions may be thrown assumes that object is used correctly...
BLOCXX_COMMON_API int createThread(Thread_t &handle, ThreadFunction func, void *funcParm, UInt32 threadFlags)
Starts a thread running the given function.
Note that descriptions of what exceptions may be thrown assumes that object is used correctly...
BLOCXX_COMMON_API void destroyThread(Thread_t &handle)
Destroy any resources associated with a thread that was created with the createThread method...
In the event a thread has been cancelled, a ThreadCancelledException will be thrown.
void yield()
Voluntarily yield to the processor giving the next thread in the chain the opportunity to run...
The Condition class represents a synchronization device that allows threads to suspend execution and ...