xref: /third_party/lzma/C/Threads.c (revision 370b324c)
1/* Threads.c -- multithreading library
22023-03-04 : 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
14static WRes GetError(void)
15{
16  const DWORD res = GetLastError();
17  return res ? (WRes)res : 1;
18}
19
20static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
21static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
22
23WRes 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
34WRes 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
55WRes 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
62WRes 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
83WRes 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
131static 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
137WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
138WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
139
140WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
141WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
142WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
143WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
144
145
146WRes 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
153WRes 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
164static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
165  { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
166WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
167  { return Semaphore_Release(p, (LONG)num, NULL); }
168WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
169
170WRes 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#ifndef __APPLE__
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  #if defined(__clang__) && (__clang_major__ >= 4) && (__clang_major__ <= 12)
206    #pragma GCC diagnostic ignored "-Wreserved-id-macro"
207  #endif
208#define _GNU_SOURCE
209#endif // !defined(_GNU_SOURCE)
210#endif // Z7_AFFINITY_DISABLE
211#endif // __APPLE__
212
213#include "Threads.h"
214
215#include <errno.h>
216#include <stdlib.h>
217#include <string.h>
218#ifdef Z7_AFFINITY_SUPPORTED
219// #include <sched.h>
220#endif
221
222
223// #include <stdio.h>
224// #define PRF(p) p
225#define PRF(p)
226#define Print(s) PRF(printf("\n%s\n", s);)
227
228WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet)
229{
230  // new thread in Posix probably inherits affinity from parrent thread
231  Print("Thread_Create_With_CpuSet")
232
233  pthread_attr_t attr;
234  int ret;
235  // int ret2;
236
237  p->_created = 0;
238
239  RINOK(pthread_attr_init(&attr))
240
241  ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
242
243  if (!ret)
244  {
245    if (cpuSet)
246    {
247      #ifdef Z7_AFFINITY_SUPPORTED
248
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
295WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
296{
297  return Thread_Create_With_CpuSet(p, func, param, NULL);
298}
299
300
301WRes 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
321WRes 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
335WRes 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
352static 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
362WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
363  { return Event_Create(p, True, signaled); }
364WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
365  { return ManualResetEvent_Create(p, 0); }
366WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
367  { return Event_Create(p, False, signaled); }
368WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
369  { return AutoResetEvent_Create(p, 0); }
370
371
372WRes Event_Set(CEvent *p)
373{
374  RINOK(pthread_mutex_lock(&p->_mutex))
375  p->_state = True;
376  int res1 = pthread_cond_broadcast(&p->_cond);
377  int res2 = pthread_mutex_unlock(&p->_mutex);
378  return (res2 ? res2 : res1);
379}
380
381WRes Event_Reset(CEvent *p)
382{
383  RINOK(pthread_mutex_lock(&p->_mutex))
384  p->_state = False;
385  return pthread_mutex_unlock(&p->_mutex);
386}
387
388WRes Event_Wait(CEvent *p)
389{
390  RINOK(pthread_mutex_lock(&p->_mutex))
391  while (p->_state == False)
392  {
393    // ETIMEDOUT
394    // ret =
395    pthread_cond_wait(&p->_cond, &p->_mutex);
396    // if (ret != 0) break;
397  }
398  if (p->_manual_reset == False)
399  {
400    p->_state = False;
401  }
402  return pthread_mutex_unlock(&p->_mutex);
403}
404
405WRes Event_Close(CEvent *p)
406{
407  if (!p->_created)
408    return 0;
409  p->_created = 0;
410  {
411    int res1 = pthread_mutex_destroy(&p->_mutex);
412    int res2 = pthread_cond_destroy(&p->_cond);
413    return (res1 ? res1 : res2);
414  }
415}
416
417
418WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
419{
420  if (initCount > maxCount || maxCount < 1)
421    return EINVAL;
422  RINOK(pthread_mutex_init(&p->_mutex, NULL))
423  RINOK(pthread_cond_init(&p->_cond, NULL))
424  p->_count = initCount;
425  p->_maxCount = maxCount;
426  p->_created = 1;
427  return 0;
428}
429
430
431WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
432{
433  if (Semaphore_IsCreated(p))
434  {
435    /*
436    WRes wres = Semaphore_Close(p);
437    if (wres != 0)
438      return wres;
439    */
440    if (initCount > maxCount || maxCount < 1)
441      return EINVAL;
442    // return EINVAL; // for debug
443    p->_count = initCount;
444    p->_maxCount = maxCount;
445    return 0;
446  }
447  return Semaphore_Create(p, initCount, maxCount);
448}
449
450
451WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
452{
453  UInt32 newCount;
454  int ret;
455
456  if (releaseCount < 1)
457    return EINVAL;
458
459  RINOK(pthread_mutex_lock(&p->_mutex))
460
461  newCount = p->_count + releaseCount;
462  if (newCount > p->_maxCount)
463    ret = ERROR_TOO_MANY_POSTS; // EINVAL;
464  else
465  {
466    p->_count = newCount;
467    ret = pthread_cond_broadcast(&p->_cond);
468  }
469  RINOK(pthread_mutex_unlock(&p->_mutex))
470  return ret;
471}
472
473WRes Semaphore_Wait(CSemaphore *p)
474{
475  RINOK(pthread_mutex_lock(&p->_mutex))
476  while (p->_count < 1)
477  {
478    pthread_cond_wait(&p->_cond, &p->_mutex);
479  }
480  p->_count--;
481  return pthread_mutex_unlock(&p->_mutex);
482}
483
484WRes Semaphore_Close(CSemaphore *p)
485{
486  if (!p->_created)
487    return 0;
488  p->_created = 0;
489  {
490    int res1 = pthread_mutex_destroy(&p->_mutex);
491    int res2 = pthread_cond_destroy(&p->_cond);
492    return (res1 ? res1 : res2);
493  }
494}
495
496
497
498WRes CriticalSection_Init(CCriticalSection *p)
499{
500  // Print("CriticalSection_Init")
501  if (!p)
502    return EINTR;
503  return pthread_mutex_init(&p->_mutex, NULL);
504}
505
506void CriticalSection_Enter(CCriticalSection *p)
507{
508  // Print("CriticalSection_Enter")
509  if (p)
510  {
511    // int ret =
512    pthread_mutex_lock(&p->_mutex);
513  }
514}
515
516void CriticalSection_Leave(CCriticalSection *p)
517{
518  // Print("CriticalSection_Leave")
519  if (p)
520  {
521    // int ret =
522    pthread_mutex_unlock(&p->_mutex);
523  }
524}
525
526void CriticalSection_Delete(CCriticalSection *p)
527{
528  // Print("CriticalSection_Delete")
529  if (p)
530  {
531    // int ret =
532    pthread_mutex_destroy(&p->_mutex);
533  }
534}
535
536LONG InterlockedIncrement(LONG volatile *addend)
537{
538  // Print("InterlockedIncrement")
539  #ifdef USE_HACK_UNSAFE_ATOMIC
540    LONG val = *addend + 1;
541    *addend = val;
542    return val;
543  #else
544
545  #if defined(__clang__) && (__clang_major__ >= 8)
546    #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst"
547  #endif
548    return __sync_add_and_fetch(addend, 1);
549  #endif
550}
551
552#endif // _WIN32
553
554WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p)
555{
556  if (Event_IsCreated(p))
557    return Event_Reset(p);
558  return AutoResetEvent_CreateNotSignaled(p);
559}
560
561#undef PRF
562#undef Print
563