Threads.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. /* Threads.c -- multithreading library
  2. : Igor Pavlov : Public domain */
  3. #include "Precomp.h"
  4. #ifdef _WIN32
  5. #ifndef USE_THREADS_CreateThread
  6. #include <process.h>
  7. #endif
  8. #include "Threads.h"
  9. static WRes GetError(void)
  10. {
  11. const DWORD res = GetLastError();
  12. return res ? (WRes)res : 1;
  13. }
  14. static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
  15. static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
  16. WRes HandlePtr_Close(HANDLE *p)
  17. {
  18. if (*p != NULL)
  19. {
  20. if (!CloseHandle(*p))
  21. return GetError();
  22. *p = NULL;
  23. }
  24. return 0;
  25. }
  26. WRes Handle_WaitObject(HANDLE h)
  27. {
  28. DWORD dw = WaitForSingleObject(h, INFINITE);
  29. /*
  30. (dw) result:
  31. WAIT_OBJECT_0 // 0
  32. WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space
  33. WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space
  34. WAIT_FAILED // 0xFFFFFFFF
  35. */
  36. if (dw == WAIT_FAILED)
  37. {
  38. dw = GetLastError();
  39. if (dw == 0)
  40. return WAIT_FAILED;
  41. }
  42. return (WRes)dw;
  43. }
  44. #define Thread_Wait(p) Handle_WaitObject(*(p))
  45. WRes Thread_Wait_Close(CThread *p)
  46. {
  47. WRes res = Thread_Wait(p);
  48. WRes res2 = Thread_Close(p);
  49. return (res != 0 ? res : res2);
  50. }
  51. typedef struct MY_PROCESSOR_NUMBER {
  52. WORD Group;
  53. BYTE Number;
  54. BYTE Reserved;
  55. } MY_PROCESSOR_NUMBER, *MY_PPROCESSOR_NUMBER;
  56. typedef struct MY_GROUP_AFFINITY {
  57. #if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 100000)
  58. // KAFFINITY is not defined in old mingw
  59. ULONG_PTR
  60. #else
  61. KAFFINITY
  62. #endif
  63. Mask;
  64. WORD Group;
  65. WORD Reserved[3];
  66. } MY_GROUP_AFFINITY, *MY_PGROUP_AFFINITY;
  67. typedef BOOL (WINAPI *Func_SetThreadGroupAffinity)(
  68. HANDLE hThread,
  69. CONST MY_GROUP_AFFINITY *GroupAffinity,
  70. MY_PGROUP_AFFINITY PreviousGroupAffinity);
  71. typedef BOOL (WINAPI *Func_GetThreadGroupAffinity)(
  72. HANDLE hThread,
  73. MY_PGROUP_AFFINITY GroupAffinity);
  74. typedef BOOL (WINAPI *Func_GetProcessGroupAffinity)(
  75. HANDLE hProcess,
  76. PUSHORT GroupCount,
  77. PUSHORT GroupArray);
  78. Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
  79. #if 0
  80. #include <stdio.h>
  81. #define PRF(x) x
  82. /*
  83. --
  84. before call of SetThreadGroupAffinity()
  85. GetProcessGroupAffinity return one group.
  86. after call of SetThreadGroupAffinity():
  87. GetProcessGroupAffinity return more than group,
  88. if SetThreadGroupAffinity() was to another group.
  89. --
  90. GetProcessAffinityMask MS DOCs:
  91. {
  92. If the calling process contains threads in multiple groups,
  93. the function returns zero for both affinity masks.
  94. }
  95. but tests in win10 with 2 groups (less than 64 cores total):
  96. GetProcessAffinityMask() still returns non-zero affinity masks
  97. even after SetThreadGroupAffinity() calls.
  98. */
  99. static void PrintProcess_Info()
  100. {
  101. {
  102. const
  103. Func_GetProcessGroupAffinity fn_GetProcessGroupAffinity =
  104. (Func_GetProcessGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
  105. "GetProcessGroupAffinity");
  106. if (fn_GetProcessGroupAffinity)
  107. {
  108. unsigned i;
  109. USHORT GroupCounts[64];
  110. USHORT GroupCount = Z7_ARRAY_SIZE(GroupCounts);
  111. BOOL boolRes = fn_GetProcessGroupAffinity(GetCurrentProcess(),
  112. &GroupCount, GroupCounts);
  113. printf("\n====== GetProcessGroupAffinity : "
  114. "boolRes=%u GroupCounts = %u :",
  115. boolRes, (unsigned)GroupCount);
  116. for (i = 0; i < GroupCount; i++)
  117. printf(" %u", GroupCounts[i]);
  118. printf("\n");
  119. }
  120. }
  121. {
  122. DWORD_PTR processAffinityMask, systemAffinityMask;
  123. if (GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask))
  124. {
  125. PRF(printf("\n====== GetProcessAffinityMask : "
  126. ": processAffinityMask=%x, systemAffinityMask=%x\n",
  127. (UInt32)processAffinityMask, (UInt32)systemAffinityMask);)
  128. }
  129. else
  130. printf("\n==GetProcessAffinityMask FAIL");
  131. }
  132. }
  133. #else
  134. #ifndef USE_THREADS_CreateThread
  135. // #define PRF(x)
  136. #endif
  137. #endif
  138. WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
  139. {
  140. /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
  141. #ifdef USE_THREADS_CreateThread
  142. DWORD threadId;
  143. *p = CreateThread(NULL, 0, func, param, 0, &threadId);
  144. #else
  145. unsigned threadId;
  146. *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
  147. #if 0 // 1 : for debug
  148. {
  149. DWORD_PTR prevMask;
  150. DWORD_PTR affinity = 1 << 0;
  151. prevMask = SetThreadAffinityMask(*p, (DWORD_PTR)affinity);
  152. prevMask = prevMask;
  153. }
  154. #endif
  155. #if 0 // 1 : for debug
  156. {
  157. /* win10: new thread will be created in same group that is assigned to parent thread
  158. but affinity mask will contain all allowed threads of that group,
  159. even if affinity mask of parent group is not full
  160. win11: what group it will be created, if we have set
  161. affinity of parent thread with ThreadGroupAffinity?
  162. */
  163. const
  164. Func_GetThreadGroupAffinity fn =
  165. (Func_GetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
  166. "GetThreadGroupAffinity");
  167. if (fn)
  168. {
  169. // BOOL wres2;
  170. MY_GROUP_AFFINITY groupAffinity;
  171. memset(&groupAffinity, 0, sizeof(groupAffinity));
  172. /* wres2 = */ fn(*p, &groupAffinity);
  173. PRF(printf("\n==Thread_Create cur = %6u GetThreadGroupAffinity(): "
  174. "wres2_BOOL = %u, group=%u mask=%x\n",
  175. GetCurrentThreadId(),
  176. wres2,
  177. groupAffinity.Group,
  178. (UInt32)groupAffinity.Mask);)
  179. }
  180. }
  181. #endif
  182. #endif
  183. /* maybe we must use errno here, but probably GetLastError() is also OK. */
  184. return HandleToWRes(*p);
  185. }
  186. WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
  187. {
  188. #ifdef USE_THREADS_CreateThread
  189. UNUSED_VAR(affinity)
  190. return Thread_Create(p, func, param);
  191. #else
  192. /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
  193. HANDLE h;
  194. WRes wres;
  195. unsigned threadId;
  196. h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
  197. *p = h;
  198. wres = HandleToWRes(h);
  199. if (h)
  200. {
  201. {
  202. // DWORD_PTR prevMask =
  203. SetThreadAffinityMask(h, (DWORD_PTR)affinity);
  204. /*
  205. if (prevMask == 0)
  206. {
  207. // affinity change is non-critical error, so we can ignore it
  208. // wres = GetError();
  209. }
  210. */
  211. }
  212. {
  213. const DWORD prevSuspendCount = ResumeThread(h);
  214. /* ResumeThread() returns:
  215. 0 : was_not_suspended
  216. 1 : was_resumed
  217. -1 : error
  218. */
  219. if (prevSuspendCount == (DWORD)-1)
  220. wres = GetError();
  221. }
  222. }
  223. /* maybe we must use errno here, but probably GetLastError() is also OK. */
  224. return wres;
  225. #endif
  226. }
  227. WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinityMask)
  228. {
  229. #ifdef USE_THREADS_CreateThread
  230. UNUSED_VAR(group)
  231. UNUSED_VAR(affinityMask)
  232. return Thread_Create(p, func, param);
  233. #else
  234. /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
  235. HANDLE h;
  236. WRes wres;
  237. unsigned threadId;
  238. h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
  239. *p = h;
  240. wres = HandleToWRes(h);
  241. if (h)
  242. {
  243. // PrintProcess_Info();
  244. {
  245. const
  246. Func_SetThreadGroupAffinity fn =
  247. (Func_SetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
  248. "SetThreadGroupAffinity");
  249. if (fn)
  250. {
  251. // WRes wres2;
  252. MY_GROUP_AFFINITY groupAffinity, prev_groupAffinity;
  253. memset(&groupAffinity, 0, sizeof(groupAffinity));
  254. // groupAffinity.Mask must use only bits that supported by current group
  255. // (groupAffinity.Mask = 0) means all allowed bits
  256. groupAffinity.Mask = affinityMask;
  257. groupAffinity.Group = (WORD)group;
  258. // wres2 =
  259. fn(h, &groupAffinity, &prev_groupAffinity);
  260. /*
  261. if (groupAffinity.Group == prev_groupAffinity.Group)
  262. wres2 = wres2;
  263. else
  264. wres2 = wres2;
  265. if (wres2 == 0)
  266. {
  267. wres2 = GetError();
  268. PRF(printf("\n==SetThreadGroupAffinity error: %u\n", wres2);)
  269. }
  270. else
  271. {
  272. PRF(printf("\n==Thread_Create_With_Group::SetThreadGroupAffinity()"
  273. " threadId = %6u"
  274. " group=%u mask=%x\n",
  275. threadId,
  276. prev_groupAffinity.Group,
  277. (UInt32)prev_groupAffinity.Mask);)
  278. }
  279. */
  280. }
  281. }
  282. {
  283. const DWORD prevSuspendCount = ResumeThread(h);
  284. /* ResumeThread() returns:
  285. 0 : was_not_suspended
  286. 1 : was_resumed
  287. -1 : error
  288. */
  289. if (prevSuspendCount == (DWORD)-1)
  290. wres = GetError();
  291. }
  292. }
  293. /* maybe we must use errno here, but probably GetLastError() is also OK. */
  294. return wres;
  295. #endif
  296. }
  297. static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
  298. {
  299. *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
  300. return HandleToWRes(*p);
  301. }
  302. WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
  303. WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
  304. WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
  305. WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
  306. WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
  307. WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
  308. WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
  309. {
  310. // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore()
  311. *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
  312. return HandleToWRes(*p);
  313. }
  314. WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
  315. {
  316. // if (Semaphore_IsCreated(p))
  317. {
  318. WRes wres = Semaphore_Close(p);
  319. if (wres != 0)
  320. return wres;
  321. }
  322. return Semaphore_Create(p, initCount, maxCount);
  323. }
  324. static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
  325. { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
  326. WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
  327. { return Semaphore_Release(p, (LONG)num, NULL); }
  328. WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
  329. WRes CriticalSection_Init(CCriticalSection *p)
  330. {
  331. /* InitializeCriticalSection() can raise exception:
  332. Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception
  333. Windows Vista+ : no exceptions */
  334. #ifdef _MSC_VER
  335. #ifdef __clang__
  336. #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
  337. #endif
  338. __try
  339. #endif
  340. {
  341. InitializeCriticalSection(p);
  342. /* InitializeCriticalSectionAndSpinCount(p, 0); */
  343. }
  344. #ifdef _MSC_VER
  345. __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; }
  346. #endif
  347. return 0;
  348. }
  349. #else // _WIN32
  350. // ---------- POSIX ----------
  351. #if defined(__linux__) && !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__)
  352. #ifndef Z7_AFFINITY_DISABLE
  353. // _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET
  354. // clang < 3.6 : unknown warning group '-Wreserved-id-macro'
  355. // clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier"
  356. // clang >= 13 : do not give warning
  357. #if !defined(_GNU_SOURCE)
  358. Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
  359. // #define _GNU_SOURCE
  360. Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
  361. #endif // !defined(_GNU_SOURCE)
  362. #endif // Z7_AFFINITY_DISABLE
  363. #endif // __linux__
  364. #include "Threads.h"
  365. #include <errno.h>
  366. #include <stdlib.h>
  367. #include <string.h>
  368. #ifdef Z7_AFFINITY_SUPPORTED
  369. // #include <sched.h>
  370. #endif
  371. // #include <stdio.h>
  372. // #define PRF(p) p
  373. #define PRF(p)
  374. #define Print(s) PRF(printf("\n%s\n", s);)
  375. WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet)
  376. {
  377. // new thread in Posix probably inherits affinity from parrent thread
  378. Print("Thread_Create_With_CpuSet")
  379. pthread_attr_t attr;
  380. int ret;
  381. // int ret2;
  382. p->_created = 0;
  383. RINOK(pthread_attr_init(&attr))
  384. ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  385. if (!ret)
  386. {
  387. if (cpuSet)
  388. {
  389. // pthread_attr_setaffinity_np() is not supported for MUSL compile.
  390. // so we check for __GLIBC__ here
  391. #if defined(Z7_AFFINITY_SUPPORTED) && defined( __GLIBC__)
  392. /*
  393. printf("\n affinity :");
  394. unsigned i;
  395. for (i = 0; i < sizeof(*cpuSet) && i < 8; i++)
  396. {
  397. Byte b = *((const Byte *)cpuSet + i);
  398. char temp[32];
  399. #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
  400. temp[0] = GET_HEX_CHAR((b & 0xF));
  401. temp[1] = GET_HEX_CHAR((b >> 4));
  402. // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian
  403. // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian
  404. temp[2] = 0;
  405. printf("%s", temp);
  406. }
  407. printf("\n");
  408. */
  409. // ret2 =
  410. pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet);
  411. // if (ret2) ret = ret2;
  412. #endif
  413. }
  414. ret = pthread_create(&p->_tid, &attr, func, param);
  415. if (!ret)
  416. {
  417. p->_created = 1;
  418. /*
  419. if (cpuSet)
  420. {
  421. // ret2 =
  422. pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet);
  423. // if (ret2) ret = ret2;
  424. }
  425. */
  426. }
  427. }
  428. // ret2 =
  429. pthread_attr_destroy(&attr);
  430. // if (ret2 != 0) ret = ret2;
  431. return ret;
  432. }
  433. WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
  434. {
  435. return Thread_Create_With_CpuSet(p, func, param, NULL);
  436. }
  437. /*
  438. WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinity)
  439. {
  440. UNUSED_VAR(group)
  441. return Thread_Create_With_Affinity(p, func, param, affinity);
  442. }
  443. */
  444. WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
  445. {
  446. Print("Thread_Create_WithAffinity")
  447. CCpuSet cs;
  448. unsigned i;
  449. CpuSet_Zero(&cs);
  450. for (i = 0; i < sizeof(affinity) * 8; i++)
  451. {
  452. if (affinity == 0)
  453. break;
  454. if (affinity & 1)
  455. {
  456. CpuSet_Set(&cs, i);
  457. }
  458. affinity >>= 1;
  459. }
  460. return Thread_Create_With_CpuSet(p, func, param, &cs);
  461. }
  462. WRes Thread_Close(CThread *p)
  463. {
  464. // Print("Thread_Close")
  465. int ret;
  466. if (!p->_created)
  467. return 0;
  468. ret = pthread_detach(p->_tid);
  469. p->_tid = 0;
  470. p->_created = 0;
  471. return ret;
  472. }
  473. WRes Thread_Wait_Close(CThread *p)
  474. {
  475. // Print("Thread_Wait_Close")
  476. void *thread_return;
  477. int ret;
  478. if (!p->_created)
  479. return EINVAL;
  480. ret = pthread_join(p->_tid, &thread_return);
  481. // probably we can't use that (_tid) after pthread_join(), so we close thread here
  482. p->_created = 0;
  483. p->_tid = 0;
  484. return ret;
  485. }
  486. static WRes Event_Create(CEvent *p, int manualReset, int signaled)
  487. {
  488. RINOK(pthread_mutex_init(&p->_mutex, NULL))
  489. RINOK(pthread_cond_init(&p->_cond, NULL))
  490. p->_manual_reset = manualReset;
  491. p->_state = (signaled ? True : False);
  492. p->_created = 1;
  493. return 0;
  494. }
  495. WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
  496. { return Event_Create(p, True, signaled); }
  497. WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
  498. { return ManualResetEvent_Create(p, 0); }
  499. WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
  500. { return Event_Create(p, False, signaled); }
  501. WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
  502. { return AutoResetEvent_Create(p, 0); }
  503. #if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13)
  504. // freebsd:
  505. #pragma GCC diagnostic ignored "-Wthread-safety-analysis"
  506. #endif
  507. WRes Event_Set(CEvent *p)
  508. {
  509. RINOK(pthread_mutex_lock(&p->_mutex))
  510. p->_state = True;
  511. {
  512. const int res1 = pthread_cond_broadcast(&p->_cond);
  513. const int res2 = pthread_mutex_unlock(&p->_mutex);
  514. return (res2 ? res2 : res1);
  515. }
  516. }
  517. WRes Event_Reset(CEvent *p)
  518. {
  519. RINOK(pthread_mutex_lock(&p->_mutex))
  520. p->_state = False;
  521. return pthread_mutex_unlock(&p->_mutex);
  522. }
  523. WRes Event_Wait(CEvent *p)
  524. {
  525. RINOK(pthread_mutex_lock(&p->_mutex))
  526. while (p->_state == False)
  527. {
  528. // ETIMEDOUT
  529. // ret =
  530. pthread_cond_wait(&p->_cond, &p->_mutex);
  531. // if (ret != 0) break;
  532. }
  533. if (p->_manual_reset == False)
  534. {
  535. p->_state = False;
  536. }
  537. return pthread_mutex_unlock(&p->_mutex);
  538. }
  539. WRes Event_Close(CEvent *p)
  540. {
  541. if (!p->_created)
  542. return 0;
  543. p->_created = 0;
  544. {
  545. const int res1 = pthread_mutex_destroy(&p->_mutex);
  546. const int res2 = pthread_cond_destroy(&p->_cond);
  547. return (res1 ? res1 : res2);
  548. }
  549. }
  550. WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
  551. {
  552. if (initCount > maxCount || maxCount < 1)
  553. return EINVAL;
  554. RINOK(pthread_mutex_init(&p->_mutex, NULL))
  555. RINOK(pthread_cond_init(&p->_cond, NULL))
  556. p->_count = initCount;
  557. p->_maxCount = maxCount;
  558. p->_created = 1;
  559. return 0;
  560. }
  561. WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
  562. {
  563. if (Semaphore_IsCreated(p))
  564. {
  565. /*
  566. WRes wres = Semaphore_Close(p);
  567. if (wres != 0)
  568. return wres;
  569. */
  570. if (initCount > maxCount || maxCount < 1)
  571. return EINVAL;
  572. // return EINVAL; // for debug
  573. p->_count = initCount;
  574. p->_maxCount = maxCount;
  575. return 0;
  576. }
  577. return Semaphore_Create(p, initCount, maxCount);
  578. }
  579. WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
  580. {
  581. UInt32 newCount;
  582. int ret;
  583. if (releaseCount < 1)
  584. return EINVAL;
  585. RINOK(pthread_mutex_lock(&p->_mutex))
  586. newCount = p->_count + releaseCount;
  587. if (newCount > p->_maxCount)
  588. ret = ERROR_TOO_MANY_POSTS; // EINVAL;
  589. else
  590. {
  591. p->_count = newCount;
  592. ret = pthread_cond_broadcast(&p->_cond);
  593. }
  594. RINOK(pthread_mutex_unlock(&p->_mutex))
  595. return ret;
  596. }
  597. WRes Semaphore_Wait(CSemaphore *p)
  598. {
  599. RINOK(pthread_mutex_lock(&p->_mutex))
  600. while (p->_count < 1)
  601. {
  602. pthread_cond_wait(&p->_cond, &p->_mutex);
  603. }
  604. p->_count--;
  605. return pthread_mutex_unlock(&p->_mutex);
  606. }
  607. WRes Semaphore_Close(CSemaphore *p)
  608. {
  609. if (!p->_created)
  610. return 0;
  611. p->_created = 0;
  612. {
  613. const int res1 = pthread_mutex_destroy(&p->_mutex);
  614. const int res2 = pthread_cond_destroy(&p->_cond);
  615. return (res1 ? res1 : res2);
  616. }
  617. }
  618. WRes CriticalSection_Init(CCriticalSection *p)
  619. {
  620. // Print("CriticalSection_Init")
  621. if (!p)
  622. return EINTR;
  623. return pthread_mutex_init(&p->_mutex, NULL);
  624. }
  625. void CriticalSection_Enter(CCriticalSection *p)
  626. {
  627. // Print("CriticalSection_Enter")
  628. if (p)
  629. {
  630. // int ret =
  631. pthread_mutex_lock(&p->_mutex);
  632. }
  633. }
  634. void CriticalSection_Leave(CCriticalSection *p)
  635. {
  636. // Print("CriticalSection_Leave")
  637. if (p)
  638. {
  639. // int ret =
  640. pthread_mutex_unlock(&p->_mutex);
  641. }
  642. }
  643. void CriticalSection_Delete(CCriticalSection *p)
  644. {
  645. // Print("CriticalSection_Delete")
  646. if (p)
  647. {
  648. // int ret =
  649. pthread_mutex_destroy(&p->_mutex);
  650. }
  651. }
  652. LONG InterlockedIncrement(LONG volatile *addend)
  653. {
  654. // Print("InterlockedIncrement")
  655. #ifdef USE_HACK_UNSAFE_ATOMIC
  656. LONG val = *addend + 1;
  657. *addend = val;
  658. return val;
  659. #else
  660. #if defined(__clang__) && (__clang_major__ >= 8)
  661. #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst"
  662. #endif
  663. return __sync_add_and_fetch(addend, 1);
  664. #endif
  665. }
  666. LONG InterlockedDecrement(LONG volatile *addend)
  667. {
  668. // Print("InterlockedDecrement")
  669. #ifdef USE_HACK_UNSAFE_ATOMIC
  670. LONG val = *addend - 1;
  671. *addend = val;
  672. return val;
  673. #else
  674. return __sync_sub_and_fetch(addend, 1);
  675. #endif
  676. }
  677. #endif // _WIN32
  678. WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p)
  679. {
  680. if (Event_IsCreated(p))
  681. return Event_Reset(p);
  682. return AutoResetEvent_CreateNotSignaled(p);
  683. }
  684. void ThreadNextGroup_Init(CThreadNextGroup *p, UInt32 numGroups, UInt32 startGroup)
  685. {
  686. // printf("\n====== ThreadNextGroup_Init numGroups = %x: startGroup=%x\n", numGroups, startGroup);
  687. if (numGroups == 0)
  688. numGroups = 1;
  689. p->NumGroups = numGroups;
  690. p->NextGroup = startGroup % numGroups;
  691. }
  692. UInt32 ThreadNextGroup_GetNext(CThreadNextGroup *p)
  693. {
  694. const UInt32 next = p->NextGroup;
  695. p->NextGroup = (next + 1) % p->NumGroups;
  696. return next;
  697. }
  698. #undef PRF
  699. #undef Print