1370b324cSopenharmony_ci/* Threads.c -- multithreading library
2370b324cSopenharmony_ci2023-03-04 : Igor Pavlov : Public domain */
3370b324cSopenharmony_ci
4370b324cSopenharmony_ci#include "Precomp.h"
5370b324cSopenharmony_ci
6370b324cSopenharmony_ci#ifdef _WIN32
7370b324cSopenharmony_ci
8370b324cSopenharmony_ci#ifndef USE_THREADS_CreateThread
9370b324cSopenharmony_ci#include <process.h>
10370b324cSopenharmony_ci#endif
11370b324cSopenharmony_ci
12370b324cSopenharmony_ci#include "Threads.h"
13370b324cSopenharmony_ci
14370b324cSopenharmony_cistatic WRes GetError(void)
15370b324cSopenharmony_ci{
16370b324cSopenharmony_ci  const DWORD res = GetLastError();
17370b324cSopenharmony_ci  return res ? (WRes)res : 1;
18370b324cSopenharmony_ci}
19370b324cSopenharmony_ci
20370b324cSopenharmony_cistatic WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
21370b324cSopenharmony_cistatic WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
22370b324cSopenharmony_ci
23370b324cSopenharmony_ciWRes HandlePtr_Close(HANDLE *p)
24370b324cSopenharmony_ci{
25370b324cSopenharmony_ci  if (*p != NULL)
26370b324cSopenharmony_ci  {
27370b324cSopenharmony_ci    if (!CloseHandle(*p))
28370b324cSopenharmony_ci      return GetError();
29370b324cSopenharmony_ci    *p = NULL;
30370b324cSopenharmony_ci  }
31370b324cSopenharmony_ci  return 0;
32370b324cSopenharmony_ci}
33370b324cSopenharmony_ci
34370b324cSopenharmony_ciWRes Handle_WaitObject(HANDLE h)
35370b324cSopenharmony_ci{
36370b324cSopenharmony_ci  DWORD dw = WaitForSingleObject(h, INFINITE);
37370b324cSopenharmony_ci  /*
38370b324cSopenharmony_ci    (dw) result:
39370b324cSopenharmony_ci    WAIT_OBJECT_0  // 0
40370b324cSopenharmony_ci    WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space
41370b324cSopenharmony_ci    WAIT_TIMEOUT   // 0x00000102 : is     compatible with Win32 Error space
42370b324cSopenharmony_ci    WAIT_FAILED    // 0xFFFFFFFF
43370b324cSopenharmony_ci  */
44370b324cSopenharmony_ci  if (dw == WAIT_FAILED)
45370b324cSopenharmony_ci  {
46370b324cSopenharmony_ci    dw = GetLastError();
47370b324cSopenharmony_ci    if (dw == 0)
48370b324cSopenharmony_ci      return WAIT_FAILED;
49370b324cSopenharmony_ci  }
50370b324cSopenharmony_ci  return (WRes)dw;
51370b324cSopenharmony_ci}
52370b324cSopenharmony_ci
53370b324cSopenharmony_ci#define Thread_Wait(p) Handle_WaitObject(*(p))
54370b324cSopenharmony_ci
55370b324cSopenharmony_ciWRes Thread_Wait_Close(CThread *p)
56370b324cSopenharmony_ci{
57370b324cSopenharmony_ci  WRes res = Thread_Wait(p);
58370b324cSopenharmony_ci  WRes res2 = Thread_Close(p);
59370b324cSopenharmony_ci  return (res != 0 ? res : res2);
60370b324cSopenharmony_ci}
61370b324cSopenharmony_ci
62370b324cSopenharmony_ciWRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
63370b324cSopenharmony_ci{
64370b324cSopenharmony_ci  /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
65370b324cSopenharmony_ci
66370b324cSopenharmony_ci  #ifdef USE_THREADS_CreateThread
67370b324cSopenharmony_ci
68370b324cSopenharmony_ci  DWORD threadId;
69370b324cSopenharmony_ci  *p = CreateThread(NULL, 0, func, param, 0, &threadId);
70370b324cSopenharmony_ci
71370b324cSopenharmony_ci  #else
72370b324cSopenharmony_ci
73370b324cSopenharmony_ci  unsigned threadId;
74370b324cSopenharmony_ci  *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
75370b324cSopenharmony_ci
76370b324cSopenharmony_ci  #endif
77370b324cSopenharmony_ci
78370b324cSopenharmony_ci  /* maybe we must use errno here, but probably GetLastError() is also OK. */
79370b324cSopenharmony_ci  return HandleToWRes(*p);
80370b324cSopenharmony_ci}
81370b324cSopenharmony_ci
82370b324cSopenharmony_ci
83370b324cSopenharmony_ciWRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
84370b324cSopenharmony_ci{
85370b324cSopenharmony_ci  #ifdef USE_THREADS_CreateThread
86370b324cSopenharmony_ci
87370b324cSopenharmony_ci  UNUSED_VAR(affinity)
88370b324cSopenharmony_ci  return Thread_Create(p, func, param);
89370b324cSopenharmony_ci
90370b324cSopenharmony_ci  #else
91370b324cSopenharmony_ci
92370b324cSopenharmony_ci  /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
93370b324cSopenharmony_ci  HANDLE h;
94370b324cSopenharmony_ci  WRes wres;
95370b324cSopenharmony_ci  unsigned threadId;
96370b324cSopenharmony_ci  h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
97370b324cSopenharmony_ci  *p = h;
98370b324cSopenharmony_ci  wres = HandleToWRes(h);
99370b324cSopenharmony_ci  if (h)
100370b324cSopenharmony_ci  {
101370b324cSopenharmony_ci    {
102370b324cSopenharmony_ci      // DWORD_PTR prevMask =
103370b324cSopenharmony_ci      SetThreadAffinityMask(h, (DWORD_PTR)affinity);
104370b324cSopenharmony_ci      /*
105370b324cSopenharmony_ci      if (prevMask == 0)
106370b324cSopenharmony_ci      {
107370b324cSopenharmony_ci        // affinity change is non-critical error, so we can ignore it
108370b324cSopenharmony_ci        // wres = GetError();
109370b324cSopenharmony_ci      }
110370b324cSopenharmony_ci      */
111370b324cSopenharmony_ci    }
112370b324cSopenharmony_ci    {
113370b324cSopenharmony_ci      DWORD prevSuspendCount = ResumeThread(h);
114370b324cSopenharmony_ci      /* ResumeThread() returns:
115370b324cSopenharmony_ci         0 : was_not_suspended
116370b324cSopenharmony_ci         1 : was_resumed
117370b324cSopenharmony_ci        -1 : error
118370b324cSopenharmony_ci      */
119370b324cSopenharmony_ci      if (prevSuspendCount == (DWORD)-1)
120370b324cSopenharmony_ci        wres = GetError();
121370b324cSopenharmony_ci    }
122370b324cSopenharmony_ci  }
123370b324cSopenharmony_ci
124370b324cSopenharmony_ci  /* maybe we must use errno here, but probably GetLastError() is also OK. */
125370b324cSopenharmony_ci  return wres;
126370b324cSopenharmony_ci
127370b324cSopenharmony_ci  #endif
128370b324cSopenharmony_ci}
129370b324cSopenharmony_ci
130370b324cSopenharmony_ci
131370b324cSopenharmony_cistatic WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
132370b324cSopenharmony_ci{
133370b324cSopenharmony_ci  *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
134370b324cSopenharmony_ci  return HandleToWRes(*p);
135370b324cSopenharmony_ci}
136370b324cSopenharmony_ci
137370b324cSopenharmony_ciWRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
138370b324cSopenharmony_ciWRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
139370b324cSopenharmony_ci
140370b324cSopenharmony_ciWRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
141370b324cSopenharmony_ciWRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
142370b324cSopenharmony_ciWRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
143370b324cSopenharmony_ciWRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
144370b324cSopenharmony_ci
145370b324cSopenharmony_ci
146370b324cSopenharmony_ciWRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
147370b324cSopenharmony_ci{
148370b324cSopenharmony_ci  // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore()
149370b324cSopenharmony_ci  *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
150370b324cSopenharmony_ci  return HandleToWRes(*p);
151370b324cSopenharmony_ci}
152370b324cSopenharmony_ci
153370b324cSopenharmony_ciWRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
154370b324cSopenharmony_ci{
155370b324cSopenharmony_ci  // if (Semaphore_IsCreated(p))
156370b324cSopenharmony_ci  {
157370b324cSopenharmony_ci    WRes wres = Semaphore_Close(p);
158370b324cSopenharmony_ci    if (wres != 0)
159370b324cSopenharmony_ci      return wres;
160370b324cSopenharmony_ci  }
161370b324cSopenharmony_ci  return Semaphore_Create(p, initCount, maxCount);
162370b324cSopenharmony_ci}
163370b324cSopenharmony_ci
164370b324cSopenharmony_cistatic WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
165370b324cSopenharmony_ci  { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
166370b324cSopenharmony_ciWRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
167370b324cSopenharmony_ci  { return Semaphore_Release(p, (LONG)num, NULL); }
168370b324cSopenharmony_ciWRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
169370b324cSopenharmony_ci
170370b324cSopenharmony_ciWRes CriticalSection_Init(CCriticalSection *p)
171370b324cSopenharmony_ci{
172370b324cSopenharmony_ci  /* InitializeCriticalSection() can raise exception:
173370b324cSopenharmony_ci     Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception
174370b324cSopenharmony_ci     Windows Vista+   : no exceptions */
175370b324cSopenharmony_ci  #ifdef _MSC_VER
176370b324cSopenharmony_ci  #ifdef __clang__
177370b324cSopenharmony_ci    #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
178370b324cSopenharmony_ci  #endif
179370b324cSopenharmony_ci  __try
180370b324cSopenharmony_ci  #endif
181370b324cSopenharmony_ci  {
182370b324cSopenharmony_ci    InitializeCriticalSection(p);
183370b324cSopenharmony_ci    /* InitializeCriticalSectionAndSpinCount(p, 0); */
184370b324cSopenharmony_ci  }
185370b324cSopenharmony_ci  #ifdef _MSC_VER
186370b324cSopenharmony_ci  __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; }
187370b324cSopenharmony_ci  #endif
188370b324cSopenharmony_ci  return 0;
189370b324cSopenharmony_ci}
190370b324cSopenharmony_ci
191370b324cSopenharmony_ci
192370b324cSopenharmony_ci
193370b324cSopenharmony_ci
194370b324cSopenharmony_ci#else // _WIN32
195370b324cSopenharmony_ci
196370b324cSopenharmony_ci// ---------- POSIX ----------
197370b324cSopenharmony_ci
198370b324cSopenharmony_ci#ifndef __APPLE__
199370b324cSopenharmony_ci#ifndef Z7_AFFINITY_DISABLE
200370b324cSopenharmony_ci// _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET
201370b324cSopenharmony_ci// clang < 3.6       : unknown warning group '-Wreserved-id-macro'
202370b324cSopenharmony_ci// clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier"
203370b324cSopenharmony_ci// clang >= 13       : do not give warning
204370b324cSopenharmony_ci#if !defined(_GNU_SOURCE)
205370b324cSopenharmony_ci  #if defined(__clang__) && (__clang_major__ >= 4) && (__clang_major__ <= 12)
206370b324cSopenharmony_ci    #pragma GCC diagnostic ignored "-Wreserved-id-macro"
207370b324cSopenharmony_ci  #endif
208370b324cSopenharmony_ci#define _GNU_SOURCE
209370b324cSopenharmony_ci#endif // !defined(_GNU_SOURCE)
210370b324cSopenharmony_ci#endif // Z7_AFFINITY_DISABLE
211370b324cSopenharmony_ci#endif // __APPLE__
212370b324cSopenharmony_ci
213370b324cSopenharmony_ci#include "Threads.h"
214370b324cSopenharmony_ci
215370b324cSopenharmony_ci#include <errno.h>
216370b324cSopenharmony_ci#include <stdlib.h>
217370b324cSopenharmony_ci#include <string.h>
218370b324cSopenharmony_ci#ifdef Z7_AFFINITY_SUPPORTED
219370b324cSopenharmony_ci// #include <sched.h>
220370b324cSopenharmony_ci#endif
221370b324cSopenharmony_ci
222370b324cSopenharmony_ci
223370b324cSopenharmony_ci// #include <stdio.h>
224370b324cSopenharmony_ci// #define PRF(p) p
225370b324cSopenharmony_ci#define PRF(p)
226370b324cSopenharmony_ci#define Print(s) PRF(printf("\n%s\n", s);)
227370b324cSopenharmony_ci
228370b324cSopenharmony_ciWRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet)
229370b324cSopenharmony_ci{
230370b324cSopenharmony_ci  // new thread in Posix probably inherits affinity from parrent thread
231370b324cSopenharmony_ci  Print("Thread_Create_With_CpuSet")
232370b324cSopenharmony_ci
233370b324cSopenharmony_ci  pthread_attr_t attr;
234370b324cSopenharmony_ci  int ret;
235370b324cSopenharmony_ci  // int ret2;
236370b324cSopenharmony_ci
237370b324cSopenharmony_ci  p->_created = 0;
238370b324cSopenharmony_ci
239370b324cSopenharmony_ci  RINOK(pthread_attr_init(&attr))
240370b324cSopenharmony_ci
241370b324cSopenharmony_ci  ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
242370b324cSopenharmony_ci
243370b324cSopenharmony_ci  if (!ret)
244370b324cSopenharmony_ci  {
245370b324cSopenharmony_ci    if (cpuSet)
246370b324cSopenharmony_ci    {
247370b324cSopenharmony_ci      #ifdef Z7_AFFINITY_SUPPORTED
248370b324cSopenharmony_ci
249370b324cSopenharmony_ci      /*
250370b324cSopenharmony_ci      printf("\n affinity :");
251370b324cSopenharmony_ci      unsigned i;
252370b324cSopenharmony_ci      for (i = 0; i < sizeof(*cpuSet) && i < 8; i++)
253370b324cSopenharmony_ci      {
254370b324cSopenharmony_ci        Byte b = *((const Byte *)cpuSet + i);
255370b324cSopenharmony_ci        char temp[32];
256370b324cSopenharmony_ci        #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
257370b324cSopenharmony_ci        temp[0] = GET_HEX_CHAR((b & 0xF));
258370b324cSopenharmony_ci        temp[1] = GET_HEX_CHAR((b >> 4));
259370b324cSopenharmony_ci        // temp[0] = GET_HEX_CHAR((b >> 4));  // big-endian
260370b324cSopenharmony_ci        // temp[1] = GET_HEX_CHAR((b & 0xF));  // big-endian
261370b324cSopenharmony_ci        temp[2] = 0;
262370b324cSopenharmony_ci        printf("%s", temp);
263370b324cSopenharmony_ci      }
264370b324cSopenharmony_ci      printf("\n");
265370b324cSopenharmony_ci      */
266370b324cSopenharmony_ci
267370b324cSopenharmony_ci      // ret2 =
268370b324cSopenharmony_ci      pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet);
269370b324cSopenharmony_ci      // if (ret2) ret = ret2;
270370b324cSopenharmony_ci      #endif
271370b324cSopenharmony_ci    }
272370b324cSopenharmony_ci
273370b324cSopenharmony_ci    ret = pthread_create(&p->_tid, &attr, func, param);
274370b324cSopenharmony_ci
275370b324cSopenharmony_ci    if (!ret)
276370b324cSopenharmony_ci    {
277370b324cSopenharmony_ci      p->_created = 1;
278370b324cSopenharmony_ci      /*
279370b324cSopenharmony_ci      if (cpuSet)
280370b324cSopenharmony_ci      {
281370b324cSopenharmony_ci        // ret2 =
282370b324cSopenharmony_ci        pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet);
283370b324cSopenharmony_ci        // if (ret2) ret = ret2;
284370b324cSopenharmony_ci      }
285370b324cSopenharmony_ci      */
286370b324cSopenharmony_ci    }
287370b324cSopenharmony_ci  }
288370b324cSopenharmony_ci  // ret2 =
289370b324cSopenharmony_ci  pthread_attr_destroy(&attr);
290370b324cSopenharmony_ci  // if (ret2 != 0) ret = ret2;
291370b324cSopenharmony_ci  return ret;
292370b324cSopenharmony_ci}
293370b324cSopenharmony_ci
294370b324cSopenharmony_ci
295370b324cSopenharmony_ciWRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
296370b324cSopenharmony_ci{
297370b324cSopenharmony_ci  return Thread_Create_With_CpuSet(p, func, param, NULL);
298370b324cSopenharmony_ci}
299370b324cSopenharmony_ci
300370b324cSopenharmony_ci
301370b324cSopenharmony_ciWRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
302370b324cSopenharmony_ci{
303370b324cSopenharmony_ci  Print("Thread_Create_WithAffinity")
304370b324cSopenharmony_ci  CCpuSet cs;
305370b324cSopenharmony_ci  unsigned i;
306370b324cSopenharmony_ci  CpuSet_Zero(&cs);
307370b324cSopenharmony_ci  for (i = 0; i < sizeof(affinity) * 8; i++)
308370b324cSopenharmony_ci  {
309370b324cSopenharmony_ci    if (affinity == 0)
310370b324cSopenharmony_ci      break;
311370b324cSopenharmony_ci    if (affinity & 1)
312370b324cSopenharmony_ci    {
313370b324cSopenharmony_ci      CpuSet_Set(&cs, i);
314370b324cSopenharmony_ci    }
315370b324cSopenharmony_ci    affinity >>= 1;
316370b324cSopenharmony_ci  }
317370b324cSopenharmony_ci  return Thread_Create_With_CpuSet(p, func, param, &cs);
318370b324cSopenharmony_ci}
319370b324cSopenharmony_ci
320370b324cSopenharmony_ci
321370b324cSopenharmony_ciWRes Thread_Close(CThread *p)
322370b324cSopenharmony_ci{
323370b324cSopenharmony_ci  // Print("Thread_Close")
324370b324cSopenharmony_ci  int ret;
325370b324cSopenharmony_ci  if (!p->_created)
326370b324cSopenharmony_ci    return 0;
327370b324cSopenharmony_ci
328370b324cSopenharmony_ci  ret = pthread_detach(p->_tid);
329370b324cSopenharmony_ci  p->_tid = 0;
330370b324cSopenharmony_ci  p->_created = 0;
331370b324cSopenharmony_ci  return ret;
332370b324cSopenharmony_ci}
333370b324cSopenharmony_ci
334370b324cSopenharmony_ci
335370b324cSopenharmony_ciWRes Thread_Wait_Close(CThread *p)
336370b324cSopenharmony_ci{
337370b324cSopenharmony_ci  // Print("Thread_Wait_Close")
338370b324cSopenharmony_ci  void *thread_return;
339370b324cSopenharmony_ci  int ret;
340370b324cSopenharmony_ci  if (!p->_created)
341370b324cSopenharmony_ci    return EINVAL;
342370b324cSopenharmony_ci
343370b324cSopenharmony_ci  ret = pthread_join(p->_tid, &thread_return);
344370b324cSopenharmony_ci  // probably we can't use that (_tid) after pthread_join(), so we close thread here
345370b324cSopenharmony_ci  p->_created = 0;
346370b324cSopenharmony_ci  p->_tid = 0;
347370b324cSopenharmony_ci  return ret;
348370b324cSopenharmony_ci}
349370b324cSopenharmony_ci
350370b324cSopenharmony_ci
351370b324cSopenharmony_ci
352370b324cSopenharmony_cistatic WRes Event_Create(CEvent *p, int manualReset, int signaled)
353370b324cSopenharmony_ci{
354370b324cSopenharmony_ci  RINOK(pthread_mutex_init(&p->_mutex, NULL))
355370b324cSopenharmony_ci  RINOK(pthread_cond_init(&p->_cond, NULL))
356370b324cSopenharmony_ci  p->_manual_reset = manualReset;
357370b324cSopenharmony_ci  p->_state = (signaled ? True : False);
358370b324cSopenharmony_ci  p->_created = 1;
359370b324cSopenharmony_ci  return 0;
360370b324cSopenharmony_ci}
361370b324cSopenharmony_ci
362370b324cSopenharmony_ciWRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
363370b324cSopenharmony_ci  { return Event_Create(p, True, signaled); }
364370b324cSopenharmony_ciWRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
365370b324cSopenharmony_ci  { return ManualResetEvent_Create(p, 0); }
366370b324cSopenharmony_ciWRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
367370b324cSopenharmony_ci  { return Event_Create(p, False, signaled); }
368370b324cSopenharmony_ciWRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
369370b324cSopenharmony_ci  { return AutoResetEvent_Create(p, 0); }
370370b324cSopenharmony_ci
371370b324cSopenharmony_ci
372370b324cSopenharmony_ciWRes Event_Set(CEvent *p)
373370b324cSopenharmony_ci{
374370b324cSopenharmony_ci  RINOK(pthread_mutex_lock(&p->_mutex))
375370b324cSopenharmony_ci  p->_state = True;
376370b324cSopenharmony_ci  int res1 = pthread_cond_broadcast(&p->_cond);
377370b324cSopenharmony_ci  int res2 = pthread_mutex_unlock(&p->_mutex);
378370b324cSopenharmony_ci  return (res2 ? res2 : res1);
379370b324cSopenharmony_ci}
380370b324cSopenharmony_ci
381370b324cSopenharmony_ciWRes Event_Reset(CEvent *p)
382370b324cSopenharmony_ci{
383370b324cSopenharmony_ci  RINOK(pthread_mutex_lock(&p->_mutex))
384370b324cSopenharmony_ci  p->_state = False;
385370b324cSopenharmony_ci  return pthread_mutex_unlock(&p->_mutex);
386370b324cSopenharmony_ci}
387370b324cSopenharmony_ci
388370b324cSopenharmony_ciWRes Event_Wait(CEvent *p)
389370b324cSopenharmony_ci{
390370b324cSopenharmony_ci  RINOK(pthread_mutex_lock(&p->_mutex))
391370b324cSopenharmony_ci  while (p->_state == False)
392370b324cSopenharmony_ci  {
393370b324cSopenharmony_ci    // ETIMEDOUT
394370b324cSopenharmony_ci    // ret =
395370b324cSopenharmony_ci    pthread_cond_wait(&p->_cond, &p->_mutex);
396370b324cSopenharmony_ci    // if (ret != 0) break;
397370b324cSopenharmony_ci  }
398370b324cSopenharmony_ci  if (p->_manual_reset == False)
399370b324cSopenharmony_ci  {
400370b324cSopenharmony_ci    p->_state = False;
401370b324cSopenharmony_ci  }
402370b324cSopenharmony_ci  return pthread_mutex_unlock(&p->_mutex);
403370b324cSopenharmony_ci}
404370b324cSopenharmony_ci
405370b324cSopenharmony_ciWRes Event_Close(CEvent *p)
406370b324cSopenharmony_ci{
407370b324cSopenharmony_ci  if (!p->_created)
408370b324cSopenharmony_ci    return 0;
409370b324cSopenharmony_ci  p->_created = 0;
410370b324cSopenharmony_ci  {
411370b324cSopenharmony_ci    int res1 = pthread_mutex_destroy(&p->_mutex);
412370b324cSopenharmony_ci    int res2 = pthread_cond_destroy(&p->_cond);
413370b324cSopenharmony_ci    return (res1 ? res1 : res2);
414370b324cSopenharmony_ci  }
415370b324cSopenharmony_ci}
416370b324cSopenharmony_ci
417370b324cSopenharmony_ci
418370b324cSopenharmony_ciWRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
419370b324cSopenharmony_ci{
420370b324cSopenharmony_ci  if (initCount > maxCount || maxCount < 1)
421370b324cSopenharmony_ci    return EINVAL;
422370b324cSopenharmony_ci  RINOK(pthread_mutex_init(&p->_mutex, NULL))
423370b324cSopenharmony_ci  RINOK(pthread_cond_init(&p->_cond, NULL))
424370b324cSopenharmony_ci  p->_count = initCount;
425370b324cSopenharmony_ci  p->_maxCount = maxCount;
426370b324cSopenharmony_ci  p->_created = 1;
427370b324cSopenharmony_ci  return 0;
428370b324cSopenharmony_ci}
429370b324cSopenharmony_ci
430370b324cSopenharmony_ci
431370b324cSopenharmony_ciWRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
432370b324cSopenharmony_ci{
433370b324cSopenharmony_ci  if (Semaphore_IsCreated(p))
434370b324cSopenharmony_ci  {
435370b324cSopenharmony_ci    /*
436370b324cSopenharmony_ci    WRes wres = Semaphore_Close(p);
437370b324cSopenharmony_ci    if (wres != 0)
438370b324cSopenharmony_ci      return wres;
439370b324cSopenharmony_ci    */
440370b324cSopenharmony_ci    if (initCount > maxCount || maxCount < 1)
441370b324cSopenharmony_ci      return EINVAL;
442370b324cSopenharmony_ci    // return EINVAL; // for debug
443370b324cSopenharmony_ci    p->_count = initCount;
444370b324cSopenharmony_ci    p->_maxCount = maxCount;
445370b324cSopenharmony_ci    return 0;
446370b324cSopenharmony_ci  }
447370b324cSopenharmony_ci  return Semaphore_Create(p, initCount, maxCount);
448370b324cSopenharmony_ci}
449370b324cSopenharmony_ci
450370b324cSopenharmony_ci
451370b324cSopenharmony_ciWRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
452370b324cSopenharmony_ci{
453370b324cSopenharmony_ci  UInt32 newCount;
454370b324cSopenharmony_ci  int ret;
455370b324cSopenharmony_ci
456370b324cSopenharmony_ci  if (releaseCount < 1)
457370b324cSopenharmony_ci    return EINVAL;
458370b324cSopenharmony_ci
459370b324cSopenharmony_ci  RINOK(pthread_mutex_lock(&p->_mutex))
460370b324cSopenharmony_ci
461370b324cSopenharmony_ci  newCount = p->_count + releaseCount;
462370b324cSopenharmony_ci  if (newCount > p->_maxCount)
463370b324cSopenharmony_ci    ret = ERROR_TOO_MANY_POSTS; // EINVAL;
464370b324cSopenharmony_ci  else
465370b324cSopenharmony_ci  {
466370b324cSopenharmony_ci    p->_count = newCount;
467370b324cSopenharmony_ci    ret = pthread_cond_broadcast(&p->_cond);
468370b324cSopenharmony_ci  }
469370b324cSopenharmony_ci  RINOK(pthread_mutex_unlock(&p->_mutex))
470370b324cSopenharmony_ci  return ret;
471370b324cSopenharmony_ci}
472370b324cSopenharmony_ci
473370b324cSopenharmony_ciWRes Semaphore_Wait(CSemaphore *p)
474370b324cSopenharmony_ci{
475370b324cSopenharmony_ci  RINOK(pthread_mutex_lock(&p->_mutex))
476370b324cSopenharmony_ci  while (p->_count < 1)
477370b324cSopenharmony_ci  {
478370b324cSopenharmony_ci    pthread_cond_wait(&p->_cond, &p->_mutex);
479370b324cSopenharmony_ci  }
480370b324cSopenharmony_ci  p->_count--;
481370b324cSopenharmony_ci  return pthread_mutex_unlock(&p->_mutex);
482370b324cSopenharmony_ci}
483370b324cSopenharmony_ci
484370b324cSopenharmony_ciWRes Semaphore_Close(CSemaphore *p)
485370b324cSopenharmony_ci{
486370b324cSopenharmony_ci  if (!p->_created)
487370b324cSopenharmony_ci    return 0;
488370b324cSopenharmony_ci  p->_created = 0;
489370b324cSopenharmony_ci  {
490370b324cSopenharmony_ci    int res1 = pthread_mutex_destroy(&p->_mutex);
491370b324cSopenharmony_ci    int res2 = pthread_cond_destroy(&p->_cond);
492370b324cSopenharmony_ci    return (res1 ? res1 : res2);
493370b324cSopenharmony_ci  }
494370b324cSopenharmony_ci}
495370b324cSopenharmony_ci
496370b324cSopenharmony_ci
497370b324cSopenharmony_ci
498370b324cSopenharmony_ciWRes CriticalSection_Init(CCriticalSection *p)
499370b324cSopenharmony_ci{
500370b324cSopenharmony_ci  // Print("CriticalSection_Init")
501370b324cSopenharmony_ci  if (!p)
502370b324cSopenharmony_ci    return EINTR;
503370b324cSopenharmony_ci  return pthread_mutex_init(&p->_mutex, NULL);
504370b324cSopenharmony_ci}
505370b324cSopenharmony_ci
506370b324cSopenharmony_civoid CriticalSection_Enter(CCriticalSection *p)
507370b324cSopenharmony_ci{
508370b324cSopenharmony_ci  // Print("CriticalSection_Enter")
509370b324cSopenharmony_ci  if (p)
510370b324cSopenharmony_ci  {
511370b324cSopenharmony_ci    // int ret =
512370b324cSopenharmony_ci    pthread_mutex_lock(&p->_mutex);
513370b324cSopenharmony_ci  }
514370b324cSopenharmony_ci}
515370b324cSopenharmony_ci
516370b324cSopenharmony_civoid CriticalSection_Leave(CCriticalSection *p)
517370b324cSopenharmony_ci{
518370b324cSopenharmony_ci  // Print("CriticalSection_Leave")
519370b324cSopenharmony_ci  if (p)
520370b324cSopenharmony_ci  {
521370b324cSopenharmony_ci    // int ret =
522370b324cSopenharmony_ci    pthread_mutex_unlock(&p->_mutex);
523370b324cSopenharmony_ci  }
524370b324cSopenharmony_ci}
525370b324cSopenharmony_ci
526370b324cSopenharmony_civoid CriticalSection_Delete(CCriticalSection *p)
527370b324cSopenharmony_ci{
528370b324cSopenharmony_ci  // Print("CriticalSection_Delete")
529370b324cSopenharmony_ci  if (p)
530370b324cSopenharmony_ci  {
531370b324cSopenharmony_ci    // int ret =
532370b324cSopenharmony_ci    pthread_mutex_destroy(&p->_mutex);
533370b324cSopenharmony_ci  }
534370b324cSopenharmony_ci}
535370b324cSopenharmony_ci
536370b324cSopenharmony_ciLONG InterlockedIncrement(LONG volatile *addend)
537370b324cSopenharmony_ci{
538370b324cSopenharmony_ci  // Print("InterlockedIncrement")
539370b324cSopenharmony_ci  #ifdef USE_HACK_UNSAFE_ATOMIC
540370b324cSopenharmony_ci    LONG val = *addend + 1;
541370b324cSopenharmony_ci    *addend = val;
542370b324cSopenharmony_ci    return val;
543370b324cSopenharmony_ci  #else
544370b324cSopenharmony_ci
545370b324cSopenharmony_ci  #if defined(__clang__) && (__clang_major__ >= 8)
546370b324cSopenharmony_ci    #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst"
547370b324cSopenharmony_ci  #endif
548370b324cSopenharmony_ci    return __sync_add_and_fetch(addend, 1);
549370b324cSopenharmony_ci  #endif
550370b324cSopenharmony_ci}
551370b324cSopenharmony_ci
552370b324cSopenharmony_ci#endif // _WIN32
553370b324cSopenharmony_ci
554370b324cSopenharmony_ciWRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p)
555370b324cSopenharmony_ci{
556370b324cSopenharmony_ci  if (Event_IsCreated(p))
557370b324cSopenharmony_ci    return Event_Reset(p);
558370b324cSopenharmony_ci  return AutoResetEvent_CreateNotSignaled(p);
559370b324cSopenharmony_ci}
560370b324cSopenharmony_ci
561370b324cSopenharmony_ci#undef PRF
562370b324cSopenharmony_ci#undef Print
563