/* Threads.h -- multithreading library 2021-12-21 : Igor Pavlov : Public domain */ #ifndef __7Z_THREADS_H #define __7Z_THREADS_H #ifdef _WIN32 #include #else #if defined(__linux__) #if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) #ifndef _7ZIP_AFFINITY_DISABLE #define _7ZIP_AFFINITY_SUPPORTED // #pragma message(" ==== _7ZIP_AFFINITY_SUPPORTED") // #define _GNU_SOURCE #endif #endif #endif #include #endif #include "7zTypes.h" EXTERN_C_BEGIN #ifdef _WIN32 WRes HandlePtr_Close(HANDLE *h); WRes Handle_WaitObject(HANDLE h); typedef HANDLE CThread; #define Thread_Construct(p) { *(p) = NULL; } #define Thread_WasCreated(p) (*(p) != NULL) #define Thread_Close(p) HandlePtr_Close(p) // #define Thread_Wait(p) Handle_WaitObject(*(p)) #ifdef UNDER_CE // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() // if (USE_THREADS_CreateThread is not definned), we use CreateThread() #define USE_THREADS_CreateThread #endif typedef #ifdef USE_THREADS_CreateThread DWORD #else unsigned #endif THREAD_FUNC_RET_TYPE; typedef DWORD_PTR CAffinityMask; typedef DWORD_PTR CCpuSet; #define CpuSet_Zero(p) { *(p) = 0; } #define CpuSet_Set(p, cpu) { *(p) |= ((DWORD_PTR)1 << (cpu)); } #else // _WIN32 typedef struct _CThread { pthread_t _tid; int _created; } CThread; #define Thread_Construct(p) { (p)->_tid = 0; (p)->_created = 0; } #define Thread_WasCreated(p) ((p)->_created != 0) WRes Thread_Close(CThread *p); // #define Thread_Wait Thread_Wait_Close typedef void * THREAD_FUNC_RET_TYPE; typedef UInt64 CAffinityMask; #ifdef _7ZIP_AFFINITY_SUPPORTED typedef cpu_set_t CCpuSet; #define CpuSet_Zero(p) CPU_ZERO(p) #define CpuSet_Set(p, cpu) CPU_SET(cpu, p) #define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p) #else typedef UInt64 CCpuSet; #define CpuSet_Zero(p) { *(p) = 0; } #define CpuSet_Set(p, cpu) { *(p) |= ((UInt64)1 << (cpu)); } #define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0) #endif #endif // _WIN32 #define THREAD_FUNC_CALL_TYPE MY_STD_CALL #if defined(_WIN32) && defined(__GNUC__) /* GCC compiler for x86 32-bit uses the rule: the stack is 16-byte aligned before CALL instruction for function calling. But only root function main() contains instructions that set 16-byte alignment for stack pointer. And another functions just keep alignment, if it was set in some parent function. The problem: if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), the root function of thread doesn't set 16-byte alignment. And stack frames in all child functions also will be unaligned in that case. Here we set (force_align_arg_pointer) attribute for root function of new thread. Do we need (force_align_arg_pointer) also for another systems? */ #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions #else #define THREAD_FUNC_ATTRIB_ALIGN_ARG #endif #define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); WRes Thread_Wait_Close(CThread *p); #ifdef _WIN32 #define Thread_Create_With_CpuSet(p, func, param, cs) \ Thread_Create_With_Affinity(p, func, param, *cs) #else WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); #endif #ifdef _WIN32 typedef HANDLE CEvent; typedef CEvent CAutoResetEvent; typedef CEvent CManualResetEvent; #define Event_Construct(p) *(p) = NULL #define Event_IsCreated(p) (*(p) != NULL) #define Event_Close(p) HandlePtr_Close(p) #define Event_Wait(p) Handle_WaitObject(*(p)) WRes Event_Set(CEvent *p); WRes Event_Reset(CEvent *p); WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); typedef HANDLE CSemaphore; #define Semaphore_Construct(p) *(p) = NULL #define Semaphore_IsCreated(p) (*(p) != NULL) #define Semaphore_Close(p) HandlePtr_Close(p) #define Semaphore_Wait(p) Handle_WaitObject(*(p)) WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); WRes Semaphore_Release1(CSemaphore *p); typedef CRITICAL_SECTION CCriticalSection; WRes CriticalSection_Init(CCriticalSection *p); #define CriticalSection_Delete(p) DeleteCriticalSection(p) #define CriticalSection_Enter(p) EnterCriticalSection(p) #define CriticalSection_Leave(p) LeaveCriticalSection(p) #else // _WIN32 typedef struct _CEvent { int _created; int _manual_reset; int _state; pthread_mutex_t _mutex; pthread_cond_t _cond; } CEvent; typedef CEvent CAutoResetEvent; typedef CEvent CManualResetEvent; #define Event_Construct(p) (p)->_created = 0 #define Event_IsCreated(p) ((p)->_created) WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); WRes Event_Set(CEvent *p); WRes Event_Reset(CEvent *p); WRes Event_Wait(CEvent *p); WRes Event_Close(CEvent *p); typedef struct _CSemaphore { int _created; UInt32 _count; UInt32 _maxCount; pthread_mutex_t _mutex; pthread_cond_t _cond; } CSemaphore; #define Semaphore_Construct(p) (p)->_created = 0 #define Semaphore_IsCreated(p) ((p)->_created) WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); #define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) WRes Semaphore_Wait(CSemaphore *p); WRes Semaphore_Close(CSemaphore *p); typedef struct _CCriticalSection { pthread_mutex_t _mutex; } CCriticalSection; WRes CriticalSection_Init(CCriticalSection *p); void CriticalSection_Delete(CCriticalSection *cs); void CriticalSection_Enter(CCriticalSection *cs); void CriticalSection_Leave(CCriticalSection *cs); LONG InterlockedIncrement(LONG volatile *addend); #endif // _WIN32 EXTERN_C_END #endif