/* * THREADING.H */ #ifndef __threading_h__ #define __threading_h__ 1 /* Platform detection */ #ifdef _WIN32_WCE #define PLATFORM_POCKETPC #elif (defined _WIN32) #define PLATFORM_WIN32 #elif (defined __linux__) #define PLATFORM_LINUX #elif (defined __APPLE__) && (defined __MACH__) #define PLATFORM_OSX #elif (defined __NetBSD__) || (defined __FreeBSD__) || (defined BSD) #define PLATFORM_BSD #elif (defined __QNX__) #define PLATFORM_QNX #elif (defined __CYGWIN__) #define PLATFORM_CYGWIN #else #error "Unknown platform!" #endif typedef int bool_t; #ifndef FALSE # define FALSE 0 # define TRUE 1 #endif typedef unsigned int uint_t; #if defined(PLATFORM_WIN32) && defined(__GNUC__) /* MinGW with MSVCR80.DLL */ /* Do this BEFORE including time.h so that it is declaring _mktime32() * as it would have declared mktime(). */ # define mktime _mktime32 #endif #include /* Note: ERROR is a defined entity on Win32 */ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; #define THREADAPI_WINDOWS 1 #define THREADAPI_PTHREAD 2 #if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) #define THREADAPI THREADAPI_WINDOWS #else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) #define THREADAPI THREADAPI_PTHREAD #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) /*---=== Locks & Signals ===--- */ #if THREADAPI == THREADAPI_WINDOWS #define WIN32_LEAN_AND_MEAN // 'SignalObjectAndWait' needs this (targets Windows 2000 and above) #define _WIN32_WINNT 0x0400 #include #include // MSDN: http://msdn2.microsoft.com/en-us/library/ms684254.aspx // // CRITICAL_SECTION can be used for simple code protection. Mutexes are // needed for use with the SIGNAL system. // #define MUTEX_T HANDLE void MUTEX_INIT( MUTEX_T *ref ); #define MUTEX_RECURSIVE_INIT(ref) MUTEX_INIT(ref) /* always recursive in Win32 */ void MUTEX_FREE( MUTEX_T *ref ); void MUTEX_LOCK( MUTEX_T *ref ); void MUTEX_UNLOCK( MUTEX_T *ref ); typedef unsigned int THREAD_RETURN_T; #define SIGNAL_T HANDLE #define YIELD() Sleep(0) #define THREAD_CALLCONV __stdcall #else // THREADAPI == THREADAPI_PTHREAD // PThread (Linux, OS X, ...) // #include #ifdef PLATFORM_LINUX # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP #else /* OS X, ... */ # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE #endif #define MUTEX_T pthread_mutex_t #define MUTEX_INIT(ref) pthread_mutex_init(ref,NULL) #define MUTEX_RECURSIVE_INIT(ref) \ { pthread_mutexattr_t a; pthread_mutexattr_init( &a ); \ pthread_mutexattr_settype( &a, _MUTEX_RECURSIVE ); \ pthread_mutex_init(ref,&a); pthread_mutexattr_destroy( &a ); \ } #define MUTEX_FREE(ref) pthread_mutex_destroy(ref) #define MUTEX_LOCK(ref) pthread_mutex_lock(ref) #define MUTEX_UNLOCK(ref) pthread_mutex_unlock(ref) typedef void * THREAD_RETURN_T; typedef pthread_cond_t SIGNAL_T; void SIGNAL_ONE( SIGNAL_T *ref ); // Yield is non-portable: // // OS X 10.4.8/9 has pthread_yield_np() // Linux 2.4 has pthread_yield() if _GNU_SOURCE is #defined // FreeBSD 6.2 has pthread_yield() // ... // #ifdef PLATFORM_OSX #define YIELD() pthread_yield_np() #else #define YIELD() pthread_yield() #endif #define THREAD_CALLCONV #endif //THREADAPI == THREADAPI_PTHREAD void SIGNAL_INIT( SIGNAL_T *ref ); void SIGNAL_FREE( SIGNAL_T *ref ); void SIGNAL_ALL( SIGNAL_T *ref ); /* * 'time_d': <0.0 for no timeout * 0.0 for instant check * >0.0 absolute timeout in secs + ms */ typedef double time_d; time_d now_secs(void); time_d SIGNAL_TIMEOUT_PREPARE( double rel_secs ); bool_t SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout ); /*---=== Threading ===--- */ #if THREADAPI == THREADAPI_WINDOWS typedef HANDLE THREAD_T; # define THREAD_ISNULL( _h) (_h == 0) // void THREAD_CREATE( THREAD_T *ref, THREAD_RETURN_T (__stdcall *func)( void * ), void *data, int prio /* -3..+3 */ ); # define THREAD_PRIO_MIN (-3) # define THREAD_PRIO_MAX (+3) #else // THREADAPI == THREADAPI_PTHREAD /* Platforms that have a timed 'pthread_join()' can get away with a simpler * implementation. Others will use a condition variable. */ # ifdef USE_PTHREAD_TIMEDJOIN # ifdef PLATFORM_OSX # error "No 'pthread_timedjoin()' on this system" # else /* Linux, ... */ # define PTHREAD_TIMEDJOIN pthread_timedjoin_np # endif # endif typedef pthread_t THREAD_T; # define THREAD_ISNULL( _h) 0 // pthread_t may be a structure: never 'null' by itself void THREAD_CREATE( THREAD_T *ref, THREAD_RETURN_T (*func)( void * ), void *data, int prio /* -2..+2 */ ); # if defined(PLATFORM_LINUX) volatile bool_t sudo; # ifdef LINUX_SCHED_RR # define THREAD_PRIO_MIN (sudo ? -2 : 0) # else # define THREAD_PRIO_MIN (0) # endif # define THREAD_PRIO_MAX (sudo ? +2 : 0) # else # define THREAD_PRIO_MIN (-2) # define THREAD_PRIO_MAX (+2) # endif #endif // THREADAPI == THREADAPI_WINDOWS /* * Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout. * Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach. */ #define THREADWAIT_TIMEOUT 1 #define THREADWAIT_CONDVAR 2 #if THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN) #define THREADWAIT_METHOD THREADWAIT_TIMEOUT #else // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN) #define THREADWAIT_METHOD THREADWAIT_CONDVAR #endif // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN) #if THREADWAIT_METHOD == THREADWAIT_TIMEOUT bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs); #define THREAD_WAIT( a, b, c, d, e) THREAD_WAIT_IMPL( a, b) #else // THREADWAIT_METHOD == THREADWAIT_CONDVAR bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref); #define THREAD_WAIT THREAD_WAIT_IMPL #endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR void THREAD_KILL( THREAD_T *ref ); #endif // __threading_h__