1 /* Threads.h -- multithreading library 2 2024-03-28 : Igor Pavlov : Public domain */ 3 4 #ifndef ZIP7_INC_THREADS_H 5 #define ZIP7_INC_THREADS_H 6 7 #ifdef _WIN32 8 #include "7zWindows.h" 9 10 #else 11 12 #include "Compiler.h" 13 14 // #define Z7_AFFINITY_DISABLE 15 #if defined(__linux__) 16 #if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) 17 #ifndef Z7_AFFINITY_DISABLE 18 #define Z7_AFFINITY_SUPPORTED 19 // #pragma message(" ==== Z7_AFFINITY_SUPPORTED") 20 #if !defined(_GNU_SOURCE) 21 // #pragma message(" ==== _GNU_SOURCE set") 22 // we need _GNU_SOURCE for cpu_set_t, if we compile for MUSL 23 Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER 24 #define _GNU_SOURCE 25 Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER 26 #endif 27 #endif 28 #endif 29 #endif 30 31 #include <pthread.h> 32 33 #endif 34 35 #include "7zTypes.h" 36 37 EXTERN_C_BEGIN 38 39 #ifdef _WIN32 40 41 WRes HandlePtr_Close(HANDLE *h); 42 WRes Handle_WaitObject(HANDLE h); 43 44 typedef HANDLE CThread; 45 46 #define Thread_CONSTRUCT(p) { *(p) = NULL; } 47 #define Thread_WasCreated(p) (*(p) != NULL) 48 #define Thread_Close(p) HandlePtr_Close(p) 49 // #define Thread_Wait(p) Handle_WaitObject(*(p)) 50 51 #ifdef UNDER_CE 52 // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() 53 // if (USE_THREADS_CreateThread is not definned), we use CreateThread() 54 #define USE_THREADS_CreateThread 55 #endif 56 57 typedef 58 #ifdef USE_THREADS_CreateThread 59 DWORD 60 #else 61 unsigned 62 #endif 63 THREAD_FUNC_RET_TYPE; 64 65 #define THREAD_FUNC_RET_ZERO 0 66 67 typedef DWORD_PTR CAffinityMask; 68 typedef DWORD_PTR CCpuSet; 69 70 #define CpuSet_Zero(p) *(p) = (0) 71 #define CpuSet_Set(p, cpu) *(p) |= ((DWORD_PTR)1 << (cpu)) 72 73 #else // _WIN32 74 75 typedef struct 76 { 77 pthread_t _tid; 78 int _created; 79 } CThread; 80 81 #define Thread_CONSTRUCT(p) { (p)->_tid = 0; (p)->_created = 0; } 82 #define Thread_WasCreated(p) ((p)->_created != 0) 83 WRes Thread_Close(CThread *p); 84 // #define Thread_Wait Thread_Wait_Close 85 86 typedef void * THREAD_FUNC_RET_TYPE; 87 #define THREAD_FUNC_RET_ZERO NULL 88 89 90 typedef UInt64 CAffinityMask; 91 92 #ifdef Z7_AFFINITY_SUPPORTED 93 94 typedef cpu_set_t CCpuSet; 95 #define CpuSet_Zero(p) CPU_ZERO(p) 96 #define CpuSet_Set(p, cpu) CPU_SET(cpu, p) 97 #define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p) 98 99 #else 100 101 typedef UInt64 CCpuSet; 102 #define CpuSet_Zero(p) *(p) = (0) 103 #define CpuSet_Set(p, cpu) *(p) |= ((UInt64)1 << (cpu)) 104 #define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0) 105 106 #endif 107 108 109 #endif // _WIN32 110 111 112 #define THREAD_FUNC_CALL_TYPE Z7_STDCALL 113 114 #if defined(_WIN32) && defined(__GNUC__) 115 /* GCC compiler for x86 32-bit uses the rule: 116 the stack is 16-byte aligned before CALL instruction for function calling. 117 But only root function main() contains instructions that 118 set 16-byte alignment for stack pointer. And another functions 119 just keep alignment, if it was set in some parent function. 120 121 The problem: 122 if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), 123 the root function of thread doesn't set 16-byte alignment. 124 And stack frames in all child functions also will be unaligned in that case. 125 126 Here we set (force_align_arg_pointer) attribute for root function of new thread. 127 Do we need (force_align_arg_pointer) also for another systems? */ 128 129 #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) 130 // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions 131 #else 132 #define THREAD_FUNC_ATTRIB_ALIGN_ARG 133 #endif 134 135 #define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE 136 137 typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); 138 WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); 139 WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); 140 WRes Thread_Wait_Close(CThread *p); 141 142 #ifdef _WIN32 143 #define Thread_Create_With_CpuSet(p, func, param, cs) \ 144 Thread_Create_With_Affinity(p, func, param, *cs) 145 #else 146 WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); 147 #endif 148 149 150 #ifdef _WIN32 151 152 typedef HANDLE CEvent; 153 typedef CEvent CAutoResetEvent; 154 typedef CEvent CManualResetEvent; 155 #define Event_Construct(p) *(p) = NULL 156 #define Event_IsCreated(p) (*(p) != NULL) 157 #define Event_Close(p) HandlePtr_Close(p) 158 #define Event_Wait(p) Handle_WaitObject(*(p)) 159 WRes Event_Set(CEvent *p); 160 WRes Event_Reset(CEvent *p); 161 WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); 162 WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); 163 WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); 164 WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); 165 166 typedef HANDLE CSemaphore; 167 #define Semaphore_Construct(p) *(p) = NULL 168 #define Semaphore_IsCreated(p) (*(p) != NULL) 169 #define Semaphore_Close(p) HandlePtr_Close(p) 170 #define Semaphore_Wait(p) Handle_WaitObject(*(p)) 171 WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); 172 WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); 173 WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); 174 WRes Semaphore_Release1(CSemaphore *p); 175 176 typedef CRITICAL_SECTION CCriticalSection; 177 WRes CriticalSection_Init(CCriticalSection *p); 178 #define CriticalSection_Delete(p) DeleteCriticalSection(p) 179 #define CriticalSection_Enter(p) EnterCriticalSection(p) 180 #define CriticalSection_Leave(p) LeaveCriticalSection(p) 181 182 183 #else // _WIN32 184 185 typedef struct 186 { 187 int _created; 188 int _manual_reset; 189 int _state; 190 pthread_mutex_t _mutex; 191 pthread_cond_t _cond; 192 } CEvent; 193 194 typedef CEvent CAutoResetEvent; 195 typedef CEvent CManualResetEvent; 196 197 #define Event_Construct(p) (p)->_created = 0 198 #define Event_IsCreated(p) ((p)->_created) 199 200 WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); 201 WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); 202 WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); 203 WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); 204 205 WRes Event_Set(CEvent *p); 206 WRes Event_Reset(CEvent *p); 207 WRes Event_Wait(CEvent *p); 208 WRes Event_Close(CEvent *p); 209 210 211 typedef struct 212 { 213 int _created; 214 UInt32 _count; 215 UInt32 _maxCount; 216 pthread_mutex_t _mutex; 217 pthread_cond_t _cond; 218 } CSemaphore; 219 220 #define Semaphore_Construct(p) (p)->_created = 0 221 #define Semaphore_IsCreated(p) ((p)->_created) 222 223 WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); 224 WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); 225 WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); 226 #define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) 227 WRes Semaphore_Wait(CSemaphore *p); 228 WRes Semaphore_Close(CSemaphore *p); 229 230 231 typedef struct 232 { 233 pthread_mutex_t _mutex; 234 } CCriticalSection; 235 236 WRes CriticalSection_Init(CCriticalSection *p); 237 void CriticalSection_Delete(CCriticalSection *cs); 238 void CriticalSection_Enter(CCriticalSection *cs); 239 void CriticalSection_Leave(CCriticalSection *cs); 240 241 LONG InterlockedIncrement(LONG volatile *addend); 242 LONG InterlockedDecrement(LONG volatile *addend); 243 244 #endif // _WIN32 245 246 WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p); 247 248 EXTERN_C_END 249 250 #endif 251