xref: /aosp_15_r20/external/lzma/C/Threads.c (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 /* Threads.c -- multithreading library
2 2024-03-28 : Igor Pavlov : Public domain */
3 
4 #include "Precomp.h"
5 
6 #ifdef _WIN32
7 
8 #ifndef USE_THREADS_CreateThread
9 #include <process.h>
10 #endif
11 
12 #include "Threads.h"
13 
GetError(void)14 static WRes GetError(void)
15 {
16   const DWORD res = GetLastError();
17   return res ? (WRes)res : 1;
18 }
19 
HandleToWRes(HANDLE h)20 static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
BOOLToWRes(BOOL v)21 static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
22 
HandlePtr_Close(HANDLE * p)23 WRes HandlePtr_Close(HANDLE *p)
24 {
25   if (*p != NULL)
26   {
27     if (!CloseHandle(*p))
28       return GetError();
29     *p = NULL;
30   }
31   return 0;
32 }
33 
Handle_WaitObject(HANDLE h)34 WRes Handle_WaitObject(HANDLE h)
35 {
36   DWORD dw = WaitForSingleObject(h, INFINITE);
37   /*
38     (dw) result:
39     WAIT_OBJECT_0  // 0
40     WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space
41     WAIT_TIMEOUT   // 0x00000102 : is     compatible with Win32 Error space
42     WAIT_FAILED    // 0xFFFFFFFF
43   */
44   if (dw == WAIT_FAILED)
45   {
46     dw = GetLastError();
47     if (dw == 0)
48       return WAIT_FAILED;
49   }
50   return (WRes)dw;
51 }
52 
53 #define Thread_Wait(p) Handle_WaitObject(*(p))
54 
Thread_Wait_Close(CThread * p)55 WRes Thread_Wait_Close(CThread *p)
56 {
57   WRes res = Thread_Wait(p);
58   WRes res2 = Thread_Close(p);
59   return (res != 0 ? res : res2);
60 }
61 
Thread_Create(CThread * p,THREAD_FUNC_TYPE func,LPVOID param)62 WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
63 {
64   /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
65 
66   #ifdef USE_THREADS_CreateThread
67 
68   DWORD threadId;
69   *p = CreateThread(NULL, 0, func, param, 0, &threadId);
70 
71   #else
72 
73   unsigned threadId;
74   *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
75 
76   #endif
77 
78   /* maybe we must use errno here, but probably GetLastError() is also OK. */
79   return HandleToWRes(*p);
80 }
81 
82 
Thread_Create_With_Affinity(CThread * p,THREAD_FUNC_TYPE func,LPVOID param,CAffinityMask affinity)83 WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
84 {
85   #ifdef USE_THREADS_CreateThread
86 
87   UNUSED_VAR(affinity)
88   return Thread_Create(p, func, param);
89 
90   #else
91 
92   /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
93   HANDLE h;
94   WRes wres;
95   unsigned threadId;
96   h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
97   *p = h;
98   wres = HandleToWRes(h);
99   if (h)
100   {
101     {
102       // DWORD_PTR prevMask =
103       SetThreadAffinityMask(h, (DWORD_PTR)affinity);
104       /*
105       if (prevMask == 0)
106       {
107         // affinity change is non-critical error, so we can ignore it
108         // wres = GetError();
109       }
110       */
111     }
112     {
113       DWORD prevSuspendCount = ResumeThread(h);
114       /* ResumeThread() returns:
115          0 : was_not_suspended
116          1 : was_resumed
117         -1 : error
118       */
119       if (prevSuspendCount == (DWORD)-1)
120         wres = GetError();
121     }
122   }
123 
124   /* maybe we must use errno here, but probably GetLastError() is also OK. */
125   return wres;
126 
127   #endif
128 }
129 
130 
Event_Create(CEvent * p,BOOL manualReset,int signaled)131 static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
132 {
133   *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
134   return HandleToWRes(*p);
135 }
136 
Event_Set(CEvent * p)137 WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
Event_Reset(CEvent * p)138 WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
139 
ManualResetEvent_Create(CManualResetEvent * p,int signaled)140 WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
AutoResetEvent_Create(CAutoResetEvent * p,int signaled)141 WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
ManualResetEvent_CreateNotSignaled(CManualResetEvent * p)142 WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
AutoResetEvent_CreateNotSignaled(CAutoResetEvent * p)143 WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
144 
145 
Semaphore_Create(CSemaphore * p,UInt32 initCount,UInt32 maxCount)146 WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
147 {
148   // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore()
149   *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
150   return HandleToWRes(*p);
151 }
152 
Semaphore_OptCreateInit(CSemaphore * p,UInt32 initCount,UInt32 maxCount)153 WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
154 {
155   // if (Semaphore_IsCreated(p))
156   {
157     WRes wres = Semaphore_Close(p);
158     if (wres != 0)
159       return wres;
160   }
161   return Semaphore_Create(p, initCount, maxCount);
162 }
163 
Semaphore_Release(CSemaphore * p,LONG releaseCount,LONG * previousCount)164 static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
165   { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
Semaphore_ReleaseN(CSemaphore * p,UInt32 num)166 WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
167   { return Semaphore_Release(p, (LONG)num, NULL); }
Semaphore_Release1(CSemaphore * p)168 WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
169 
CriticalSection_Init(CCriticalSection * p)170 WRes CriticalSection_Init(CCriticalSection *p)
171 {
172   /* InitializeCriticalSection() can raise exception:
173      Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception
174      Windows Vista+   : no exceptions */
175   #ifdef _MSC_VER
176   #ifdef __clang__
177     #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
178   #endif
179   __try
180   #endif
181   {
182     InitializeCriticalSection(p);
183     /* InitializeCriticalSectionAndSpinCount(p, 0); */
184   }
185   #ifdef _MSC_VER
186   __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; }
187   #endif
188   return 0;
189 }
190 
191 
192 
193 
194 #else // _WIN32
195 
196 // ---------- POSIX ----------
197 
198 #if defined(__linux__) && !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__)
199 #ifndef Z7_AFFINITY_DISABLE
200 // _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET
201 // clang < 3.6       : unknown warning group '-Wreserved-id-macro'
202 // clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier"
203 // clang >= 13       : do not give warning
204 #if !defined(_GNU_SOURCE)
205 Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
206 // #define _GNU_SOURCE
207 Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
208 #endif // !defined(_GNU_SOURCE)
209 #endif // Z7_AFFINITY_DISABLE
210 #endif // __linux__
211 
212 #include "Threads.h"
213 
214 #include <errno.h>
215 #include <stdlib.h>
216 #include <string.h>
217 #ifdef Z7_AFFINITY_SUPPORTED
218 // #include <sched.h>
219 #endif
220 
221 
222 // #include <stdio.h>
223 // #define PRF(p) p
224 #define PRF(p)
225 #define Print(s) PRF(printf("\n%s\n", s);)
226 
Thread_Create_With_CpuSet(CThread * p,THREAD_FUNC_TYPE func,LPVOID param,const CCpuSet * cpuSet)227 WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet)
228 {
229   // new thread in Posix probably inherits affinity from parrent thread
230   Print("Thread_Create_With_CpuSet")
231 
232   pthread_attr_t attr;
233   int ret;
234   // int ret2;
235 
236   p->_created = 0;
237 
238   RINOK(pthread_attr_init(&attr))
239 
240   ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
241 
242   if (!ret)
243   {
244     if (cpuSet)
245     {
246       // pthread_attr_setaffinity_np() is not supported for MUSL compile.
247       // so we check for __GLIBC__ here
248 #if defined(Z7_AFFINITY_SUPPORTED) && defined( __GLIBC__)
249       /*
250       printf("\n affinity :");
251       unsigned i;
252       for (i = 0; i < sizeof(*cpuSet) && i < 8; i++)
253       {
254         Byte b = *((const Byte *)cpuSet + i);
255         char temp[32];
256         #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
257         temp[0] = GET_HEX_CHAR((b & 0xF));
258         temp[1] = GET_HEX_CHAR((b >> 4));
259         // temp[0] = GET_HEX_CHAR((b >> 4));  // big-endian
260         // temp[1] = GET_HEX_CHAR((b & 0xF));  // big-endian
261         temp[2] = 0;
262         printf("%s", temp);
263       }
264       printf("\n");
265       */
266 
267       // ret2 =
268       pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet);
269       // if (ret2) ret = ret2;
270 #endif
271     }
272 
273     ret = pthread_create(&p->_tid, &attr, func, param);
274 
275     if (!ret)
276     {
277       p->_created = 1;
278       /*
279       if (cpuSet)
280       {
281         // ret2 =
282         pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet);
283         // if (ret2) ret = ret2;
284       }
285       */
286     }
287   }
288   // ret2 =
289   pthread_attr_destroy(&attr);
290   // if (ret2 != 0) ret = ret2;
291   return ret;
292 }
293 
294 
Thread_Create(CThread * p,THREAD_FUNC_TYPE func,LPVOID param)295 WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
296 {
297   return Thread_Create_With_CpuSet(p, func, param, NULL);
298 }
299 
300 
Thread_Create_With_Affinity(CThread * p,THREAD_FUNC_TYPE func,LPVOID param,CAffinityMask affinity)301 WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
302 {
303   Print("Thread_Create_WithAffinity")
304   CCpuSet cs;
305   unsigned i;
306   CpuSet_Zero(&cs);
307   for (i = 0; i < sizeof(affinity) * 8; i++)
308   {
309     if (affinity == 0)
310       break;
311     if (affinity & 1)
312     {
313       CpuSet_Set(&cs, i);
314     }
315     affinity >>= 1;
316   }
317   return Thread_Create_With_CpuSet(p, func, param, &cs);
318 }
319 
320 
Thread_Close(CThread * p)321 WRes Thread_Close(CThread *p)
322 {
323   // Print("Thread_Close")
324   int ret;
325   if (!p->_created)
326     return 0;
327 
328   ret = pthread_detach(p->_tid);
329   p->_tid = 0;
330   p->_created = 0;
331   return ret;
332 }
333 
334 
Thread_Wait_Close(CThread * p)335 WRes Thread_Wait_Close(CThread *p)
336 {
337   // Print("Thread_Wait_Close")
338   void *thread_return;
339   int ret;
340   if (!p->_created)
341     return EINVAL;
342 
343   ret = pthread_join(p->_tid, &thread_return);
344   // probably we can't use that (_tid) after pthread_join(), so we close thread here
345   p->_created = 0;
346   p->_tid = 0;
347   return ret;
348 }
349 
350 
351 
Event_Create(CEvent * p,int manualReset,int signaled)352 static WRes Event_Create(CEvent *p, int manualReset, int signaled)
353 {
354   RINOK(pthread_mutex_init(&p->_mutex, NULL))
355   RINOK(pthread_cond_init(&p->_cond, NULL))
356   p->_manual_reset = manualReset;
357   p->_state = (signaled ? True : False);
358   p->_created = 1;
359   return 0;
360 }
361 
ManualResetEvent_Create(CManualResetEvent * p,int signaled)362 WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
363   { return Event_Create(p, True, signaled); }
ManualResetEvent_CreateNotSignaled(CManualResetEvent * p)364 WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
365   { return ManualResetEvent_Create(p, 0); }
AutoResetEvent_Create(CAutoResetEvent * p,int signaled)366 WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
367   { return Event_Create(p, False, signaled); }
AutoResetEvent_CreateNotSignaled(CAutoResetEvent * p)368 WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
369   { return AutoResetEvent_Create(p, 0); }
370 
371 
372 #if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13)
373 // freebsd:
374 #pragma GCC diagnostic ignored "-Wthread-safety-analysis"
375 #endif
376 
Event_Set(CEvent * p)377 WRes Event_Set(CEvent *p)
378 {
379   RINOK(pthread_mutex_lock(&p->_mutex))
380   p->_state = True;
381   {
382     const int res1 = pthread_cond_broadcast(&p->_cond);
383     const int res2 = pthread_mutex_unlock(&p->_mutex);
384     return (res2 ? res2 : res1);
385   }
386 }
387 
Event_Reset(CEvent * p)388 WRes Event_Reset(CEvent *p)
389 {
390   RINOK(pthread_mutex_lock(&p->_mutex))
391   p->_state = False;
392   return pthread_mutex_unlock(&p->_mutex);
393 }
394 
Event_Wait(CEvent * p)395 WRes Event_Wait(CEvent *p)
396 {
397   RINOK(pthread_mutex_lock(&p->_mutex))
398   while (p->_state == False)
399   {
400     // ETIMEDOUT
401     // ret =
402     pthread_cond_wait(&p->_cond, &p->_mutex);
403     // if (ret != 0) break;
404   }
405   if (p->_manual_reset == False)
406   {
407     p->_state = False;
408   }
409   return pthread_mutex_unlock(&p->_mutex);
410 }
411 
Event_Close(CEvent * p)412 WRes Event_Close(CEvent *p)
413 {
414   if (!p->_created)
415     return 0;
416   p->_created = 0;
417   {
418     const int res1 = pthread_mutex_destroy(&p->_mutex);
419     const int res2 = pthread_cond_destroy(&p->_cond);
420     return (res1 ? res1 : res2);
421   }
422 }
423 
424 
Semaphore_Create(CSemaphore * p,UInt32 initCount,UInt32 maxCount)425 WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
426 {
427   if (initCount > maxCount || maxCount < 1)
428     return EINVAL;
429   RINOK(pthread_mutex_init(&p->_mutex, NULL))
430   RINOK(pthread_cond_init(&p->_cond, NULL))
431   p->_count = initCount;
432   p->_maxCount = maxCount;
433   p->_created = 1;
434   return 0;
435 }
436 
437 
Semaphore_OptCreateInit(CSemaphore * p,UInt32 initCount,UInt32 maxCount)438 WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
439 {
440   if (Semaphore_IsCreated(p))
441   {
442     /*
443     WRes wres = Semaphore_Close(p);
444     if (wres != 0)
445       return wres;
446     */
447     if (initCount > maxCount || maxCount < 1)
448       return EINVAL;
449     // return EINVAL; // for debug
450     p->_count = initCount;
451     p->_maxCount = maxCount;
452     return 0;
453   }
454   return Semaphore_Create(p, initCount, maxCount);
455 }
456 
457 
Semaphore_ReleaseN(CSemaphore * p,UInt32 releaseCount)458 WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
459 {
460   UInt32 newCount;
461   int ret;
462 
463   if (releaseCount < 1)
464     return EINVAL;
465 
466   RINOK(pthread_mutex_lock(&p->_mutex))
467 
468   newCount = p->_count + releaseCount;
469   if (newCount > p->_maxCount)
470     ret = ERROR_TOO_MANY_POSTS; // EINVAL;
471   else
472   {
473     p->_count = newCount;
474     ret = pthread_cond_broadcast(&p->_cond);
475   }
476   RINOK(pthread_mutex_unlock(&p->_mutex))
477   return ret;
478 }
479 
Semaphore_Wait(CSemaphore * p)480 WRes Semaphore_Wait(CSemaphore *p)
481 {
482   RINOK(pthread_mutex_lock(&p->_mutex))
483   while (p->_count < 1)
484   {
485     pthread_cond_wait(&p->_cond, &p->_mutex);
486   }
487   p->_count--;
488   return pthread_mutex_unlock(&p->_mutex);
489 }
490 
Semaphore_Close(CSemaphore * p)491 WRes Semaphore_Close(CSemaphore *p)
492 {
493   if (!p->_created)
494     return 0;
495   p->_created = 0;
496   {
497     const int res1 = pthread_mutex_destroy(&p->_mutex);
498     const int res2 = pthread_cond_destroy(&p->_cond);
499     return (res1 ? res1 : res2);
500   }
501 }
502 
503 
504 
CriticalSection_Init(CCriticalSection * p)505 WRes CriticalSection_Init(CCriticalSection *p)
506 {
507   // Print("CriticalSection_Init")
508   if (!p)
509     return EINTR;
510   return pthread_mutex_init(&p->_mutex, NULL);
511 }
512 
CriticalSection_Enter(CCriticalSection * p)513 void CriticalSection_Enter(CCriticalSection *p)
514 {
515   // Print("CriticalSection_Enter")
516   if (p)
517   {
518     // int ret =
519     pthread_mutex_lock(&p->_mutex);
520   }
521 }
522 
CriticalSection_Leave(CCriticalSection * p)523 void CriticalSection_Leave(CCriticalSection *p)
524 {
525   // Print("CriticalSection_Leave")
526   if (p)
527   {
528     // int ret =
529     pthread_mutex_unlock(&p->_mutex);
530   }
531 }
532 
CriticalSection_Delete(CCriticalSection * p)533 void CriticalSection_Delete(CCriticalSection *p)
534 {
535   // Print("CriticalSection_Delete")
536   if (p)
537   {
538     // int ret =
539     pthread_mutex_destroy(&p->_mutex);
540   }
541 }
542 
InterlockedIncrement(LONG volatile * addend)543 LONG InterlockedIncrement(LONG volatile *addend)
544 {
545   // Print("InterlockedIncrement")
546   #ifdef USE_HACK_UNSAFE_ATOMIC
547     LONG val = *addend + 1;
548     *addend = val;
549     return val;
550   #else
551 
552   #if defined(__clang__) && (__clang_major__ >= 8)
553     #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst"
554   #endif
555     return __sync_add_and_fetch(addend, 1);
556   #endif
557 }
558 
InterlockedDecrement(LONG volatile * addend)559 LONG InterlockedDecrement(LONG volatile *addend)
560 {
561   // Print("InterlockedDecrement")
562   #ifdef USE_HACK_UNSAFE_ATOMIC
563     LONG val = *addend - 1;
564     *addend = val;
565     return val;
566   #else
567     return __sync_sub_and_fetch(addend, 1);
568   #endif
569 }
570 
571 #endif // _WIN32
572 
AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent * p)573 WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p)
574 {
575   if (Event_IsCreated(p))
576     return Event_Reset(p);
577   return AutoResetEvent_CreateNotSignaled(p);
578 }
579 
580 #undef PRF
581 #undef Print
582