CAEN Utility  2.0.2
Utilities for CAEN projects
CAENThread.c
Go to the documentation of this file.
1 /******************************************************************************
2 *
3 * CAEN SpA - Software Division
4 * Via Vetraia, 11 - 55049 - Viareggio ITALY
5 * +39 0594 388 398 - www.caen.it
6 *
7 *******************************************************************************
8 *
9 * Copyright (C) 2019-2022 CAEN SpA
10 *
11 * This file is part of the CAEN Utility.
12 *
13 * The CAEN Utility is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 3 of the License, or (at your option) any later version.
17 *
18 * The CAEN Utility is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with the CAEN Utility; if not, see
25 * https://www.gnu.org/licenses/.
26 *
27 * SPDX-License-Identifier: LGPL-3.0-or-later
28 *
29 ***************************************************************************/
37 #include <CAENThread.h>
38 
39 #ifdef _WIN32
40 #include <process.h>
41 #else
42 #include <unistd.h>
43 #include <pthread.h>
44 #include <sched.h>
45 #include <errno.h>
46 #include <time.h> // for CLOCK_REALTIME
47 #endif
48 
49 #include <CAENUtility.h>
50 #include <CAENMultiplatform.h>
51 #include <CAENLogger.h>
52 
53 INIT_C_LOGGER("CAENThreadLog.txt", "CAENThread.c");
54 
55 /*
56  * Windows implementation is mostly copied from https://github.com/microsoft/STL/blob/main/stl/src/cthread.cpp,
57  * that is used as backend for std::thread in the Windows C++ standard library. Even if undocumented, it has
58  * the same API of C11 threads.
59  *
60  * Linux implementation is inspired from the glibc, based on pthread. C11 threads are almost identical to
61  * pthread, with minor differences like the signature of the function pointer passed to thrd_create, returning
62  * int instead of void*.
63  *
64  * As extension, we add boolean field to c_thread_t to mark the validity of the object, be used for internal
65  * checks.
66  */
67 
68 int32_t c_thread_setaffinity(c_thread_t thr, uint64_t mask) {
69  int32_t ret = CAENThread_RetCode_Success;
70 #ifdef _WIN32
71 #if 0 // HACK removed because it gave problems in Windows 10...
72  const DWORD_PTR r = SetThreadAffinityMask(thr.handle, (DWORD_PTR)mask);
73  if (r == 0)
75 #else
76  c_unused_parameter(thr);
77  c_unused_parameter(mask);
78 #endif
79 #else
80  cpu_set_t cpuset;
81  CPU_ZERO(&cpuset);
82  for (size_t i = 0; mask != 0; ++i, mask >>= 1)
83  if (mask & 0x1)
84  CPU_SET(i, &cpuset);
85  int r = pthread_setaffinity_np(thr.handle, sizeof(cpu_set_t), &cpuset);
86  switch (r) {
87  case 0:
88  break;
89  case EFAULT:
90  case EINVAL:
91  case ESRCH:
92  default:
94  break;
95  }
96 #endif
97  return ret;
98 }
99 
101  c_thread_t result;
102  result.valid = TRUE;
103 #ifdef _WIN32
104  result.handle = NULL;
105  result.id = GetCurrentThreadId();
106 #else
107  result.handle = pthread_self();
108 #endif
109  return result;
110 }
111 
112 void c_thread_yield(void) {
113 #ifdef _WIN32
114  /*
115  * Can be implemented with:
116  * - Sleep(0)
117  * - SwitchToThread()
118  * We use the second solution, as it is used by Microsoft on _Thrd_yield() on xthreads.h.
119  * See https://stackoverflow.com/a/1383966/3287591 for detils.
120  */
121  SwitchToThread();
122 #else
123  sched_yield();
124 #endif
125 }
126 
128  int32_t ret = CAENThread_RetCode_Success;
129 #ifdef _WIN32
130  if (!CloseHandle(thr.handle))
132 #else
133  int r = pthread_detach(thr.handle);
134  switch (r) {
135  case 0:
136  break;
137  case EINVAL:
138  case ESRCH:
139  default:
141  break;
142  }
143 #endif
144  return ret;
145 }
146 
147 void c_thread_exit(int res) {
148 #ifdef _WIN32
149  _endthreadex((unsigned int)res);
150 #else
151  pthread_exit((void*)(intptr_t)res);
152 #endif
153 }
154 
156  if (!lhs.valid && !rhs.valid)
157  return true; // FALSE validity is enough to declare invalid c_thread_t equality
158 #ifdef _WIN32
159  return lhs.id == rhs.id;
160 #else
161  return pthread_equal(lhs.handle, rhs.handle);
162 #endif
163 }
164 
165 #ifndef _WIN32
166 // creates a timespec representing time NOW+ms from epoch
167 static struct timespec _getTimeSpecFromNow(uint32_t ms) {
168  struct timespec ts;
169  uint32_t sec = (ms / 1000);
170  uint32_t nsec = (ms - sec * 1000) * 1000000;
171  clock_gettime(CLOCK_REALTIME, &ts);
172  ts.tv_sec += sec;
173  ts.tv_nsec += nsec;
174  //tv_nsec can be now higher than 1e9
175  ts.tv_sec += ts.tv_nsec / 1000000000;
176  ts.tv_nsec = ts.tv_nsec % 1000000000;
177  return ts;
178 }
179 #endif
180 
182  if (c_unlikely(s == NULL))
184  int32_t ret = CAENThread_RetCode_Success;
185 #ifndef _WIN32
186  if (sem_init(s, 0, 0) != 0)
188 #else
189  const HANDLE sem = CreateSemaphoreA(NULL, 0, 1, NULL);
190  if (sem == NULL)
192  else
193  *s = sem;
194 #endif
195  return ret;
196 }
197 
199  if (c_unlikely(s == NULL))
201  int32_t ret = CAENThread_RetCode_Success;
202 #ifndef _WIN32
203  if (sem_init(s, 0, 0) != 0)
205 #else
206  const HANDLE semaphore = CreateSemaphoreA(NULL, 0, MAXLONG, NULL);
207  if (semaphore == NULL)
209  else
210  *s = semaphore;
211 #endif
212  return ret;
213 }
214 
216  if (c_unlikely(s == NULL))
218  int32_t ret = CAENThread_RetCode_Success;
219 #ifndef _WIN32
220  if (sem_destroy(s) != 0)
222 #else
223  if (!CloseHandle(*s))
225 #endif
226  return ret;
227 }
228 
229 int32_t c_semaphore_wait(c_semaphore_t *s, int32_t ms) {
230  if (c_unlikely(s == NULL))
232  int32_t ret = CAENThread_RetCode_Success;
233 #ifndef _WIN32
234  int r;
235  switch (ms) {
236  case 0:
237  r = (sem_timedwait(s, &(struct timespec){ 0 }) == 0) ? 0 : errno;
238  break;
239  case INFINITE:
240  r = (sem_wait(s) == 0) ? 0 : errno;
241  break;
242  default: {
243  const struct timespec ts = _getTimeSpecFromNow(ms);
244  r = (sem_timedwait(s, &ts) == 0) ? 0 : errno;
245  break;
246  }
247  }
248  switch (r) {
249  case 0:
250  break;
251  case ETIMEDOUT:
253  break;
254  default:
256  break;
257  }
258 #else
259  const DWORD r = WaitForSingleObjectEx(*s, (DWORD)ms, FALSE);
260  switch (r) {
261  case WAIT_OBJECT_0:
262  break;
263  case WAIT_TIMEOUT:
265  break;
266  default:
268  break;
269  }
270 #endif
271  return ret;
272 }
273 
275  if (c_unlikely(s == NULL))
277  int32_t ret = CAENThread_RetCode_Success;
278 #ifndef _WIN32
279  if (sem_post(s) != 0)
281 #else
282  if (!ReleaseSemaphore(*s, 1, NULL))
284 #endif
285  return ret;
286 }
287 
288 int32_t c_mutex_init(c_mutex_t *m) {
289  if (c_unlikely(m == NULL))
291  int32_t ret = CAENThread_RetCode_Success;
292 #ifndef _WIN32
293  const int r = pthread_mutex_init(m, NULL);
294  switch (r) {
295  case 0:
296  break;
297  case ENOMEM:
299  break;
300  case EAGAIN:
301  case EPERM:
302  default:
304  break;
305  }
306 #else
307  const HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
308  if (mutex == NULL)
310  else
311  *m = mutex;
312 #endif
313  return ret;
314 }
315 
317  if (c_unlikely(m == NULL))
319  int32_t ret = CAENThread_RetCode_Success;
320 #ifndef _WIN32
321  const int r = pthread_mutex_lock(m);
322  switch (r) {
323  case 0:
324  break;
325  case EAGAIN:
326  case EINVAL:
327  case EDEADLK:
328  default:
330  break;
331  }
332 #else
333  const DWORD r = WaitForSingleObjectEx(*m, INFINITE, FALSE);
334  if (r != WAIT_OBJECT_0)
336 #endif
337  return ret;
338 }
339 
341  if (c_unlikely(m == NULL))
343  int32_t ret = CAENThread_RetCode_Success;
344 #ifndef _WIN32
345  const int r = pthread_mutex_trylock(m);
346  switch (r) {
347  case 0:
348  break;
349  case EBUSY:
351  break;
352  case EAGAIN:
353  case EINVAL:
354  default:
356  break;
357  }
358 #else
359  const DWORD ms_wait = 0;
360  const DWORD r = WaitForSingleObjectEx(*m, ms_wait, FALSE);
361  if (r != WAIT_OBJECT_0)
363 #endif
364  return ret;
365 }
366 
368  if (c_unlikely(m == NULL))
370  int32_t ret = CAENThread_RetCode_Success;
371 #ifndef _WIN32
372  const int r = pthread_mutex_unlock(m);
373  switch (r) {
374  case 0:
375  break;
376  case EPERM:
377  case EAGAIN:
378  case EINVAL:
379  default:
381  break;
382  }
383 #else
384  if (!ReleaseMutex(*m))
386 #endif
387  return ret;
388 }
389 
391  if (c_unlikely(m == NULL))
393  int32_t ret = CAENThread_RetCode_Success;
394 #ifndef _WIN32
395  const int r = pthread_mutex_destroy(m);
396  switch (r) {
397  case 0:
398  break;
399  case EBUSY:
401  break;
402  case EINVAL:
403  default:
405  break;
406  }
407 #else
408  if (!CloseHandle(*m))
410 #endif
411  return ret;
412 }
413 
415 #ifdef _WIN32
416  InitializeConditionVariable(&(cond->_cond));
417  InitializeCriticalSection(&(cond->_critical_section));
418 #else
419  if (pthread_cond_init(&(cond->_cond), NULL) != 0)
423 #endif
425 }
426 
428 #ifdef _WIN32
429  DeleteCriticalSection(&(cond->_critical_section));
430 #else
431  if (pthread_cond_destroy(&(cond->_cond)) != 0)
435 #endif
437 }
438 
440 #ifdef _WIN32
441  EnterCriticalSection(&(cond->_critical_section));
443 #else
444  return c_mutex_lock(&(cond->_mutex));
445 #endif
446 }
447 
449 #ifdef _WIN32
450  LeaveCriticalSection(&(cond->_critical_section));
452 #else
453  return c_mutex_unlock(&(cond->_mutex));
454 #endif
455 }
456 
457 int32_t c_condition_wait(c_condition_t *cond, int32_t ms) {
458  int32_t ret = CAENThread_RetCode_Success;
459 #ifdef _WIN32
460  if (!SleepConditionVariableCS(&(cond->_cond), &(cond->_critical_section), (DWORD)ms)) {
461  switch (GetLastError()) {
462  case ERROR_TIMEOUT:
464  break;
465  default:
467  break;
468  }
469  }
470 #else
471  int r;
472  switch (ms) {
473  case 0:
474  r = (pthread_cond_timedwait(&(cond->_cond), &(cond->_mutex), &(struct timespec){ 0 }) == 0) ? 0 : errno;
475  break;
476  case INFINITE:
477  r = (pthread_cond_wait(&(cond->_cond), &(cond->_mutex)) == 0) ? 0 : errno;
478  break;
479  default: {
480  const struct timespec ts = _getTimeSpecFromNow(ms);
481  r = (pthread_cond_timedwait(&(cond->_cond), &(cond->_mutex), &ts) == 0) ? 0 : errno;
482  break;
483  }
484  }
485  switch (r) {
486  case 0:
487  break;
488  case ETIMEDOUT:
490  break;
491  case EINVAL:
492  case EPERM:
493  default:
495  break;
496  }
497 #endif
498  return ret;
499 }
500 
502  int32_t ret = CAENThread_RetCode_Success;
503 #ifdef _WIN32
504  WakeConditionVariable(&(cond->_cond));
505 #else
506  const int r = pthread_cond_signal(&(cond->_cond));
507  switch (r) {
508  case 0:
509  break;
510  case EINVAL:
511  default:
513  break;
514  }
515 #endif
516  return ret;
517 }
518 
520  int32_t ret = CAENThread_RetCode_Success;
521 #ifdef _WIN32
522  WakeAllConditionVariable(&(cond->_cond));
523 #else
524  const int r = pthread_cond_broadcast(&(cond->_cond));
525  switch (r) {
526  case 0:
527  break;
528  case EINVAL:
529  default:
531  break;
532  }
533 #endif
534  return ret;
535 }
536 
537 int32_t c_thread_sleep(const struct timespec* duration, struct timespec* remaining) {
538  int32_t ret = CAENThread_RetCode_Success;
539 #ifdef _WIN32
540  struct timespec start;
541  if (timespec_get(&start, TIME_UTC) == 0)
543  const DWORD ms = (DWORD)(duration->tv_sec * 1000 + duration->tv_nsec / 1000000 + (((duration->tv_nsec % 1000000) == 0) ? 0 : 1));
544  const DWORD r = SleepEx(ms, TRUE);
545  if (r != 0) {
546  if (remaining != NULL) {
547  if (timespec_get(remaining, TIME_UTC) == 0)
549  remaining->tv_sec -= start.tv_sec;
550  remaining->tv_nsec -= start.tv_nsec;
551  if (remaining->tv_nsec < 0) {
552  remaining->tv_nsec += 1000000000;
553  remaining->tv_sec -= 1;
554  }
555  }
556  ret = (r == WAIT_IO_COMPLETION) ? -1 : -2;
557  }
558 #else
559  const int r = nanosleep(duration, remaining);
560  if (r != 0)
561  ret = (errno == EINTR) ? -1 : -2;
562 #endif
563  return ret;
564 }
565 
566 int32_t c_sleep(uint32_t ms) {
567  int32_t ret = CAENThread_RetCode_Success;
568 #ifdef _WIN32
569  // SleepEx() never fails if bAlertable is FALSE
570  SleepEx((DWORD)ms, FALSE);
571 #else // Linux
572  // usleep() return 0 in case of success. errno could be read for error details.
573  const int r = usleep(ms * 1000);
574  if (r != 0) {
575  switch (errno) {
576  case EINTR:
577  case EINVAL:
578  default:
580  }
581  }
582 #endif
583  return ret;
584 }
585 
588  void *arg;
589 };
590 
591 // wrappers to make c_tstart_t the same on Windows and Linux
592 #ifdef _WIN32
593 static unsigned __stdcall _tstart_wrapper_function(void* _arg) {
594 #else
595 static void* _tstart_wrapper_function(void* _arg) {
596 #endif
597  struct tstart_wrapper_t* wrapper = _arg;
598  c_tstart_t f = wrapper->f;
599  void* arg = wrapper->arg;
600  c_free(wrapper);
601  int r = f(arg);
602 #ifdef _WIN32
603  return (unsigned)r;
604 #else
605  return (void*)(intptr_t)r;
606 #endif
607 }
608 
610  c_thread_t res;
611 #ifdef _WIN32 // Windows
612  res.handle = NULL;
613  res.id = 0;
614 #else
615  res.handle = 0;
616  res.valid = FALSE;
617 #endif
618  return res;
619 }
620 
621 int32_t c_thread_create(c_thread_t *thr, c_tstart_t t, void *arg) {
622  int32_t ret = CAENThread_RetCode_Success;
623  struct tstart_wrapper_t *wrapper = c_malloc(sizeof(*wrapper)); // freed by the thread
624  if (wrapper == NULL) {
626  }
627  wrapper->f = t;
628  wrapper->arg = arg;
629 #ifdef _WIN32 // Windows
630  thr->handle = (HANDLE)_beginthreadex(NULL, 0, _tstart_wrapper_function, wrapper, 0, &thr->id);
631  if (thr->handle == NULL) {
633  }
634 #else // Linux
635  const int r = pthread_create(&(thr->handle), NULL, _tstart_wrapper_function, (void*)wrapper);
636  switch (r) {
637  case 0:
638  break;
639  case EAGAIN:
640  case EINVAL:
641  case EPERM:
642  default:
644  break;
645  }
646 #endif
647  if (ret == CAENThread_RetCode_Success)
648  thr->valid = TRUE;
649  else
650  *thr = c_thread_invalid();
651  return ret;
652 }
653 
654 int32_t c_thread_join(c_thread_t thr, int *res) {
655  return c_thread_timedjoin(thr, res, INFINITE);
656 }
657 
658 int32_t c_thread_timedjoin(c_thread_t thr, int *res, int32_t ms) {
659  int32_t ret = CAENThread_RetCode_Success;
660 #ifndef _WIN32
661  int r;
662  void *lres;
663  switch (ms) {
664  case INFINITE:
665  r = pthread_join(thr.handle, &lres);
666  break;
667  default: {
668  struct timespec ts = _getTimeSpecFromNow(ms);
669  r = pthread_timedjoin_np(thr.handle, &lres, &ts);
670  break;
671  }
672  }
673  switch (r) {
674  case 0:
675  break;
676  case ETIMEDOUT: // pthread_timedjoin_np only
678  break;
679  case EBUSY: // pthread_timedjoin_np only
681  break;
682  case EINVAL:
683  case ESRCH:
684  case EDEADLK:
685  default:
687  break;
688  }
689  if (res != NULL) {
690  *res = (int)(intptr_t)lres;
691  }
692 #else
693  const DWORD r = WaitForSingleObjectEx(thr.handle, (DWORD)ms, FALSE);
694  switch (r) {
695  case WAIT_OBJECT_0:
697  break;
698  case WAIT_TIMEOUT:
700  break;
701  default:
703  break;
704  }
705  if (res != NULL) {
706  DWORD lres;
707  if (!GetExitCodeThread(thr.handle, &lres)) {
709  } else {
710  *res = (int)lres;
711  }
712  }
713  if (!CloseHandle(thr.handle))
715 #endif
716  return ret;
717 }
718 
719 int32_t c_ticket_init(c_ticket_t *ticket) {
720  ticket->_queue_tail = 0;
721  ticket->_queue_head = 0;
722  return c_condition_init(&ticket->_condition);
723 }
724 
725 int32_t c_ticket_delete(c_ticket_t *ticket) {
726  return c_condition_destroy(&ticket->_condition);
727 }
728 
729 static uint64_t _getnewticketnumber(c_ticket_t* ticket) {
730  uint64_t res = ticket->_queue_tail++;
731  // check if 'queue_tail' overflowed. In case, reset everything keeping tail/head difference
732  if (c_unlikely(ticket->_queue_tail < res)) {
733  uint64_t diff = res - ticket->_queue_head; // NOTE: queue_me is always greater than head
734  res = diff;
735  ticket->_queue_tail = res + 1;
736  ticket->_queue_head = 0;
737  }
738  return res;
739 }
740 
741 int32_t c_ticket_lock(c_ticket_t *ticket) {
742 
743  int32_t ret = c_condition_lock(&ticket->_condition);
744  if (ret != CAENThread_RetCode_Success)
745  return ret;
746 
747  // lock only if this thread is not already holding the lock
749 
750  uint64_t queue_me = _getnewticketnumber(ticket);
751 
752  while (ret == CAENThread_RetCode_Success && queue_me != ticket->_queue_head) {
753  ret = c_condition_wait(&ticket->_condition, 1000);
754  if (ret == CAENThread_RetCode_Timedout) {
755  logMsg(c_logger_Severity_WARNING, "Ticket number %" PRIu64 " has timed out. Going on anyway.", queue_me);
757  }
758  }
759  // now the mutex is locked. Get the thread ID holding it.
761  }
762  else {
763  // ERROR? DEBUG ASSERTION? IGNORE?
764  logMsg(c_logger_Severity_WARNING, "A thread is trying to lock a ticket it already holds. Ignoring lock.");
765  }
766 
767  // while() needed to remove C26165 on MSVC:
768  // - on Windows c_condition_unlock cannot fail
769  // - on Linux c_condition_unlock cannot fail if lock succeeded just before
771 
772  return ret;
773 }
774 
775 int32_t c_ticket_unlock(c_ticket_t *ticket) {
776 
777  int32_t ret = c_condition_lock(&ticket->_condition);
778  if (ret != CAENThread_RetCode_Success)
779  return ret;
780 
781  // unlock only if this thread is holding the lock
783  ticket->_queue_head++;
785  ret = c_condition_broadcast(&ticket->_condition);
786  }
787  else {
788  // ERROR? DEBUG ASSERTION? IGNORE?
789  logMsg(c_logger_Severity_WARNING, "A thread is trying to unlock a ticket it doesn't hold. Ignoring unlock.");
790  }
791 
792  // while() needed to remove C26165 on MSVC:
793  // - on Windows c_condition_unlock cannot fail
794  // - on Linux c_condition_unlock cannot fail if lock succeeded just before
796 
797  return ret;
798 }
int32_t c_ticket_lock(c_ticket_t *ticket)
Definition: CAENThread.c:741
int32_t c_mutex_lock(c_mutex_t *m)
Definition: CAENThread.c:316
c_conditionvariable_t _cond
A condition variable.
int32_t c_semaphore_destroy(c_semaphore_t *s)
Definition: CAENThread.c:215
int32_t c_condition_unlock(c_condition_t *cond)
Definition: CAENThread.c:448
#define INFINITE
int32_t c_semaphore_post(c_semaphore_t *s)
Definition: CAENThread.c:274
void c_free(void *ptr)
int32_t c_mutex_init(c_mutex_t *m)
Definition: CAENThread.c:288
pthread_t handle
int32_t c_semaphore_wait(c_semaphore_t *s, int32_t ms)
Definition: CAENThread.c:229
#define c_unused_parameter(P)
Platform independent macro to remove unreferenced parameter warning.
Definition: CAENUtility.h:117
int32_t c_condition_broadcast(c_condition_t *cond)
Definition: CAENThread.c:519
Main header and generic tools.
int32_t c_mutex_destroy(c_mutex_t *m)
Definition: CAENThread.c:390
int32_t c_semaphore_init(c_semaphore_t *s)
Definition: CAENThread.c:181
Ticket type.
int32_t c_ticket_init(c_ticket_t *ticket)
Definition: CAENThread.c:719
uint64_t _queue_head
int32_t c_thread_create(c_thread_t *thr, c_tstart_t t, void *arg)
Definition: CAENThread.c:621
int32_t c_sleep(uint32_t ms)
Definition: CAENThread.c:566
int32_t c_ticket_unlock(c_ticket_t *ticket)
Definition: CAENThread.c:775
c_thread_t _holding_thread_id
int32_t c_condition_lock(c_condition_t *cond)
Definition: CAENThread.c:439
c_condition_t _condition
c_thread_t c_thread_current(void)
Definition: CAENThread.c:100
int32_t c_thread_detach(c_thread_t thr)
Definition: CAENThread.c:127
#define c_unlikely(x)
Definition: CAENUtility.h:293
c_thread_t c_thread_invalid()
Definition: CAENThread.c:609
pthread_mutex_t _mutex
On Linux a pthread_cond_t is use with a pthread_mutex_t.
void c_thread_exit(int res)
Definition: CAENThread.c:147
#define TRUE
#define FALSE
Functions to handle threads, inspired to C11 threads.h.
void * c_malloc(size_t size)
c_tstart_t f
Definition: CAENThread.c:587
Generic wrappers to platform-dependent functions.
int32_t c_thread_join(c_thread_t thr, int *res)
Definition: CAENThread.c:654
int32_t c_ticket_delete(c_ticket_t *ticket)
Definition: CAENThread.c:725
int32_t c_mutex_trylock(c_mutex_t *m)
Definition: CAENThread.c:340
#define INIT_C_LOGGER(fname, mname)
Definition: CAENLogger.h:139
void c_thread_yield(void)
Definition: CAENThread.c:112
static uint64_t _getnewticketnumber(c_ticket_t *ticket)
Definition: CAENThread.c:729
sem_t c_semaphore_t
Semaphore type.
int32_t c_condition_destroy(c_condition_t *cond)
Definition: CAENThread.c:427
Logger implemented in C.
#define logMsg(s,...)
Definition: CAENLogger.h:157
int32_t c_condition_wait(c_condition_t *cond, int32_t ms)
Definition: CAENThread.c:457
int32_t c_condition_init(c_condition_t *cond)
Definition: CAENThread.c:414
pthread_mutex_t c_mutex_t
Mutex type.
#define c_use_decl_annotations
Definition: CAENUtility.h:278
int32_t c_semaphore_multi_init(c_semaphore_t *s)
Definition: CAENThread.c:198
int(* c_tstart_t)(void *)
Thread function type, as defined in C11.
uint64_t _queue_tail
int32_t c_thread_setaffinity(c_thread_t thr, uint64_t mask)
Definition: CAENThread.c:68
int32_t c_thread_sleep(const struct timespec *duration, struct timespec *remaining)
Definition: CAENThread.c:537
int32_t c_mutex_unlock(c_mutex_t *m)
Definition: CAENThread.c:367
static struct timespec _getTimeSpecFromNow(uint32_t ms)
Definition: CAENThread.c:167
bool c_thread_equal(c_thread_t lhs, c_thread_t rhs)
Definition: CAENThread.c:155
int32_t c_condition_signal_one(c_condition_t *cond)
Definition: CAENThread.c:501
static void * _tstart_wrapper_function(void *_arg)
Definition: CAENThread.c:595
int32_t c_thread_timedjoin(c_thread_t thr, int *res, int32_t ms)
Definition: CAENThread.c:658
Needed because a condition variable on Linux is associated with a mutex, while on Windows it is assoc...