ythread.c
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * $Id: ythread.c 26964 2017-03-29 08:57:59Z seb $
4  *
5  * OS-independent thread and synchronization library
6  *
7  * - - - - - - - - - License information: - - - - - - - - -
8  *
9  * Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland.
10  *
11  * Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual
12  * non-exclusive license to use, modify, copy and integrate this
13  * file into your software for the sole purpose of interfacing
14  * with Yoctopuce products.
15  *
16  * You may reproduce and distribute copies of this file in
17  * source or object form, as long as the sole purpose of this
18  * code is to interface with Yoctopuce products. You must retain
19  * this notice in the distributed source file.
20  *
21  * You should refer to Yoctopuce General Terms and Conditions
22  * for additional information regarding your rights and
23  * obligations.
24  *
25  * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
26  * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
27  * WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS
28  * FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO
29  * EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
30  * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
31  * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR
32  * SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT
33  * LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR
34  * CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE
35  * BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF
36  * WARRANTY, OR OTHERWISE.
37  *
38  *********************************************************************/
39 
40 #include "ythread.h"
41 #define __FILE_ID__ "ythread"
42 
43 
44 #ifdef WINDOWS_API
45 
46 static DWORD yTlsBucket = TLS_OUT_OF_INDEXES;
47 static DWORD yNextThreadIdx = 1;
48 
49 void yCreateEvent(yEvent *event)
50 {
51  *event = CreateEvent(0, 0, 0, 0);
52 }
53 
54 void yCreateManualEvent(yEvent *event, int initialState)
55 {
56  *event = CreateEvent(0, TRUE, initialState != 0, 0);
57 }
58 
59 
60 void ySetEvent(yEvent *ev)
61 {
62  SetEvent(*ev);
63 }
64 
65 void yResetEvent(yEvent *ev)
66 {
67  ResetEvent(*ev);
68 }
69 
70 
71 
72 int yWaitForEvent(yEvent *ev, int time)
73 {
74  DWORD usec;
75  DWORD res;
76  if (time < 0) {
77  usec = INFINITE;
78  } else {
79  usec = time;
80  }
81  res = WaitForSingleObject(*ev, usec);
82  return res == WAIT_OBJECT_0;
83 }
84 
85 void yCloseEvent(yEvent *ev)
86 {
87  CloseHandle(*ev);
88 }
89 
90 
91 static int yCreateDetachedThreadEx(osThread *th_hdl, void* (*fun)(void *), void *arg)
92 {
93  *th_hdl = CreateThread(
94  NULL, // default security attibutes
95  0, // use default stack size
96  (LPTHREAD_START_ROUTINE)fun, // thread function name
97  arg, // argument to thread function
98  0, // use default creation flags
99  NULL);
100  if (*th_hdl == NULL) {
101  return -1;
102  }
103  return 0;
104 }
105 
106 
107 static void yReleaseDetachedThreadEx(osThread *th_hdl)
108 {
109  CloseHandle(*th_hdl);
110 }
111 
112 
113 static int yWaitEndThread(osThread *th)
114 {
115  DWORD result = WaitForSingleObject(*th, INFINITE);
116  return result == WAIT_OBJECT_0 ? 0 : -1;
117 }
118 
119 static void yKillThread(osThread *th)
120 {
121  TerminateThread(*th, 0);
122 }
123 
124 
125 int yThreadIndex(void)
126 {
127  u8* tls_ptr;
128 
129  if (yTlsBucket == TLS_OUT_OF_INDEXES) {
130  // Only happens the very first time, from main thread
131  yTlsBucket = TlsAlloc();
132  }
133  tls_ptr = TlsGetValue(yTlsBucket);
134  if (tls_ptr == 0) {
135  // tiny risk of race condition, but thread idx is only
136  // used for debug log purposes and is not sensitive
137  DWORD res = yNextThreadIdx++;
138  TlsSetValue(yTlsBucket, ((u8*)NULL) + res);
139  return res;
140  } else {
141  return (int)(tls_ptr - ((u8*)NULL));
142  }
143 }
144 
145 #else
146 #include <sys/time.h>
147 #include <pthread.h>
148 #include <errno.h>
149 
150 static pthread_once_t yInitKeyOnce = PTHREAD_ONCE_INIT;
151 static pthread_key_t yTsdKey;
152 static unsigned yNextThreadIdx = 1;
153 
154 static void initTsdKey()
155 {
156  pthread_key_create(&yTsdKey, NULL);
157 }
158 
160 {
161  pthread_cond_init(&ev->cond, NULL);
162  pthread_mutex_init(&ev->mtx, NULL);
163  ev->verif = 0;
164  ev->autoreset = 1;
165 }
166 
167 void yCreateManualEvent(yEvent *ev, int initialState)
168 {
169  pthread_cond_init(&ev->cond, NULL);
170  pthread_mutex_init(&ev->mtx, NULL);
171  ev->verif = initialState > 0;
172  ev->autoreset = 0;
173 }
174 
175 void ySetEvent(yEvent *ev)
176 {
177  pthread_mutex_lock(&ev->mtx);
178  ev->verif = 1;
179  // set verif to 1 because pthread condition seems
180  // to allow conditional wait to exit event if nobody
181  // has set the alarm (see google or linux books of seb)
182  pthread_cond_signal(&ev->cond);
183  pthread_mutex_unlock(&ev->mtx);
184 
185 }
186 
188 {
189  pthread_mutex_lock(&ev->mtx);
190  ev->verif = 0;
191  pthread_mutex_unlock(&ev->mtx);
192 
193 }
194 
195 
196 int yWaitForEvent(yEvent *ev, int time)
197 {
198  int retval;
199  pthread_mutex_lock(&ev->mtx);
200  if (!ev->verif) {
201  if (time >= 0) {
202  struct timeval now;
203  struct timespec later;
204  gettimeofday(&now, NULL);
205  later.tv_sec = now.tv_sec + time / 1000;
206  later.tv_nsec = now.tv_usec * 1000 + (time % 1000) * 1000000;
207  if (later.tv_nsec >= 1000000000) {
208  later.tv_sec++;
209  later.tv_nsec -= 1000000000;
210  }
211  pthread_cond_timedwait(&ev->cond, &ev->mtx, &later);
212  } else {
213  pthread_cond_wait(&ev->cond, &ev->mtx);
214  }
215  }
216  retval = ev->verif;
217  if (ev->autoreset)
218  ev->verif = 0;
219  pthread_mutex_unlock(&ev->mtx);
220  return retval;
221 
222 }
224 {
225  pthread_cond_destroy(&ev->cond);
226  pthread_mutex_destroy(&ev->mtx);
227 }
228 
229 static int yCreateDetachedThreadEx(osThread *th, void* (*fun)(void *), void *arg)
230 {
231  pthread_attr_t attr;
232  int result;
233 
234  pthread_attr_init(&attr);
235  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
236 
237  if (pthread_create(th, &attr, fun, arg) != 0) {
238  result = -1;
239  } else {
240  result = 0;
241  }
242  pthread_attr_destroy(&attr);
243 
244  return result;
245 }
246 
247 static void yReleaseDetachedThreadEx(osThread *th_hdl)
248 {
249 }
250 
251 
252 
253 static int yWaitEndThread(osThread *th)
254 {
255  return pthread_join(*th, NULL);
256 }
257 
258 
259 static void yKillThread(osThread *th)
260 {
261  pthread_cancel(*th);
262 }
263 
264 int yThreadIndex(void)
265 {
266  int res;
267 
268  pthread_once(&yInitKeyOnce, initTsdKey);
269  res = (int)((u8 *)pthread_getspecific(yTsdKey) - (u8 *)NULL);
270  if (!res) {
271  // tiny risk of race condition, but thread idx is only
272  // used for debug log purposes and is not sensitive
273  res = yNextThreadIdx++;
274  pthread_setspecific(yTsdKey, (void*)((u8 *)NULL + res));
275  }
276  return res;
277 }
278 
279 #endif
280 
281 
282 int yCreateDetachedThread(void* (*fun)(void *), void *arg)
283 {
284  osThread th_hdl;
285  if (yCreateDetachedThreadEx(&th_hdl, fun, arg) < 0) {
286  return -1;
287  }
288  yReleaseDetachedThreadEx(&th_hdl);
289  return 0;
290 }
291 
292 
293 int yThreadCreate(yThread *yth, void* (*fun)(void *), void *arg)
294 {
295  if (yth->st == YTHREAD_RUNNING)
296  return 0; // allready started nothing to do
297  if (yth->st == YTHREAD_NOT_STARTED) {
298  yth->ctx = arg;
299  yCreateEvent(&yth->ev);
300  if (yCreateDetachedThreadEx(&yth->th, fun, yth) < 0) {
301  yCloseEvent(&yth->ev);
302  return-1;
303  }
304  yWaitForEvent(&yth->ev, -1);
305  yCloseEvent(&yth->ev);
306  return 1;
307  }
308  return -1;
309 }
310 
312 {
313  if (yth->st == YTHREAD_RUNNING || yth->st == YTHREAD_MUST_STOP)
314  return 1;
315  return 0;
316 }
317 
319 {
320  //send ok to parent thread
321  yth->st = YTHREAD_RUNNING;
322  ySetEvent(&yth->ev);
323 }
324 
325 
327 {
328  yth->st = YTHREAD_STOPED;
329 }
330 
332 {
333  if (yth->st == YTHREAD_RUNNING) {
334  yth->st = YTHREAD_MUST_STOP;
335  }
336 }
337 
339 {
340  return yth->st != YTHREAD_RUNNING;
341 }
342 
344 {
345  if (yThreadIsRunning(yth)) {
346 #ifdef WINDOWS_API
347  //means thread still running lets give it some time
348  if (!yWaitForEvent(&yth->th, 1000)) {
349  yKillThread(&yth->th);
350  }
351 #else
352  yKillThread(&yth->th);
353 #endif
354  } else {
355  yWaitEndThread(&yth->th);
357  }
358 }
359 
360 
361 #ifdef DEBUG_CRITICAL_SECTION
362 
363 //#include "yproto.h"
364 /* printf example */
365 #include <stdio.h>
366 #include <stdlib.h>
367 #include <string.h>
368 
369 #define MAX_DB_CS 128
370 
371 
372 
373 
374 static u32 nbycs = 0;
375 
376 #ifdef __arm__
377 #define CS_BREAK {while(1);}
378 #else
379 #if defined(WINDOWS_API) && (_MSC_VER)
380 #define CS_BREAK { _asm {int 3}}
381 #else
382 #define CS_BREAK {__asm__("int3");}
383 #endif
384 #endif
385 
386 #define CS_ASSERT(x) if(!(x)){printf("ASSERT FAILED:%s:%d (%s:%d)\n",__FILE__ , __LINE__,fileid,lineno);dump_YCS(csptr);CS_BREAK}
387 #define CS_TRACK_NO 24
388 
389 CRITICAL_SECTION CS_CS;
390 
391 void yInitDebugCS()
392 {
393  InitializeCriticalSection(&CS_CS);
394 }
395 
396 void yFreeDebugCS()
397 {
398  DeleteCriticalSection(&CS_CS);
399 }
400 
401 
402 
403 static const char* YCS_STATE_STR[] = {
404  "UNALLOCATED",
405  "ALLOCATED",
406  "DELETED"
407 };
408 
409 static const char* YCS_ACTION_STR[] = {
410  "NONE ",
411  "INIT ",
412  "LOCK ",
413  "LOCKTRY",
414  "RELEASE",
415  "DELETE "
416 };
417 
418 static void dump_YCS(yCRITICAL_SECTION *csptr)
419 {
420  int i;
421  yCRITICAL_SECTION_ST *ycs = *csptr;
422  const char* state_str;
423  if (csptr == NULL) {
424  printf("NULL csptr");
425  return;
426  }
427  if (ycs->state < sizeof(YCS_STATE_STR)) {
428  state_str= YCS_STATE_STR[ycs->state];
429  } else {
430  state_str = "INVALID";
431  }
432  printf("%p:%02x: state=%s lock=%d\n", ycs, ycs->no, state_str, ycs->lock);
433  for (i = 0; i < YCS_NB_TRACE; i++) {
434  u32 action = ycs->last_actions[i].action;
435  const char* action_str = "INVALID";
436  const char* file_str = ycs->last_actions[i].fileid;
437  if (action < sizeof(YCS_ACTION_STR)) {
438  action_str = YCS_ACTION_STR[action];
439  }
440  if (file_str == NULL) {
441  file_str = "NULL";
442  }
443  printf(" - %s on %s:%d (th=%d)\n", action_str,
444  file_str, ycs->last_actions[i].lineno, ycs->last_actions[i].thread);
445  }
446 }
447 
448 
449 static void pushCSAction(int threadid, const char* fileid, int lineno, yCRITICAL_SECTION_ST *csptr, YCS_ACTION action)
450 {
451  memmove(&csptr->last_actions[1], &csptr->last_actions[0], sizeof(YCS_LOC)*(YCS_NB_TRACE - 1));
452  csptr->last_actions[0].thread = threadid;
453  csptr->last_actions[0].fileid = fileid;
454  csptr->last_actions[0].lineno = lineno;
455  csptr->last_actions[0].action = action;
456 }
457 
458 
459 void yDbgInitializeCriticalSection(const char* fileid, int lineno, yCRITICAL_SECTION *csptr)
460 {
461  int res;
462  int threadid = yThreadIndex();
463  *csptr = malloc(sizeof(yCRITICAL_SECTION_ST));
464  memset(*csptr, 0, sizeof(yCRITICAL_SECTION_ST));
465  EnterCriticalSection(&CS_CS);
466  (*csptr)->no = nbycs++;
467  LeaveCriticalSection(&CS_CS);
468  if ((*csptr)->no == CS_TRACK_NO || CS_TRACK_NO < 0) {
469  printf("NEW CS on %s:%d:%p (%d)\n", fileid, lineno, (*csptr), (*csptr)->no);
470  }
471 
472  (*csptr)->state = YCS_ALLOCATED;
473  pushCSAction(threadid, fileid, lineno, (*csptr), YCS_INIT);
474 #if MICROCHIP_API
475  (*csptr)->cs = 0;
476  res = 0;
477 #elif defined(WINDOWS_API)
478  res = 0;
479  InitializeCriticalSection(&((*csptr)->cs));
480 #else
481  res = pthread_mutex_init(&((*csptr)->cs), NULL);
482 #endif
483  EnterCriticalSection(&((*csptr)->cs));
484  LeaveCriticalSection(&((*csptr)->cs));
485 #if 0
486  CS_ASSERT(res == 0);
487  res = pthread_mutex_lock(&((*csptr)->cs));
488  CS_ASSERT(res == 0);
489  res = pthread_mutex_unlock(&((*csptr)->cs));
490 #endif
491  CS_ASSERT(res == 0);
492  }
493 
494 
495 void yDbgEnterCriticalSection(const char* fileid, int lineno, yCRITICAL_SECTION *csptr)
496 {
497  int res;
498  int threadid = yThreadIndex();
499 
500  CS_ASSERT((*csptr)->no < nbycs);
501  CS_ASSERT((*csptr)->state == YCS_ALLOCATED);
502 
503  if ((*csptr)->no == CS_TRACK_NO || CS_TRACK_NO < 0) {
504  printf("enter CS on %s:%d:%p (%d)\n", fileid, lineno, (*csptr), (*csptr)->no);
505 }
506 
507 #if MICROCHIP_API
508  (*csptr)->cs = 1;
509 #elif defined(WINDOWS_API)
510  res = 0;
511  EnterCriticalSection(&((*csptr)->cs));
512 #else
513  res = pthread_mutex_lock(&((*csptr)->cs));
514 #endif
515  CS_ASSERT(res == 0);
516  CS_ASSERT((*csptr)->lock == 0);
517  (*csptr)->lock++;
518  pushCSAction(threadid, fileid, lineno, (*csptr), YCS_LOCK);
519 }
520 
521 
522 int yDbgTryEnterCriticalSection(const char* fileid, int lineno, yCRITICAL_SECTION *csptr)
523 {
524  int res;
525  int threadid = yThreadIndex();
526 
527  CS_ASSERT((*csptr)->no < nbycs);
528  CS_ASSERT((*csptr)->state == YCS_ALLOCATED);
529 
530  if ((*csptr)->no == CS_TRACK_NO || CS_TRACK_NO < 0) {
531  printf("enter CS on %s:%d:%p (%d)\n", fileid, lineno, (*csptr), (*csptr)->no);
532  }
533 
534 
535 #if MICROCHIP_API
536  if ((*csptr)->cs)
537  return 0;
538  (*csptr)->cs = 1;
539 #elif defined(WINDOWS_API)
540  res = TryEnterCriticalSection(&((*csptr)->cs));
541  if (res == 0)
542  return 0;
543  CS_ASSERT(res == 1);
544 #else
545  res = pthread_mutex_trylock(&((*csptr)->cs));
546  if (res == EBUSY)
547  return 0;
548  CS_ASSERT(res == 0);
549 #endif
550  CS_ASSERT((*csptr)->lock == 0);
551  (*csptr)->lock++;
552  pushCSAction(threadid, fileid, lineno, (*csptr), YCS_LOCKTRY);
553  return 1;
554  }
555 
556 
557 void yDbgLeaveCriticalSection(const char* fileid, int lineno, yCRITICAL_SECTION *csptr)
558 {
559  int res;
560  int threadid = yThreadIndex();
561 
562 
563  CS_ASSERT((*csptr)->no < nbycs);
564  CS_ASSERT((*csptr)->state == YCS_ALLOCATED);
565  CS_ASSERT((*csptr)->lock == 1);
566  if ((*csptr)->no == CS_TRACK_NO || CS_TRACK_NO < 0) {
567  printf("leave CS on %s:%d:%p (%d)\n", fileid, lineno, (*csptr), (*csptr)->no);
568  }
569 
570  (*csptr)->lock--;
571  pushCSAction(threadid, fileid, lineno, (*csptr), YCS_RELEASE);
572 
573 #if MICROCHIP_API
574  (*csptr)->cs = 0;
575  res = 0;
576 #elif defined(WINDOWS_API)
577  res = 0;
578  LeaveCriticalSection(&((*csptr)->cs));
579 #else
580  res = pthread_mutex_unlock(&((*csptr)->cs));
581 #endif
582  CS_ASSERT(res == 0);
583 }
584 
585 void yDbgDeleteCriticalSection(const char* fileid, int lineno, yCRITICAL_SECTION *csptr)
586 {
587  int res;
588  int threadid = yThreadIndex();
589 
590 
591  CS_ASSERT((*csptr)->no < nbycs);
592  CS_ASSERT((*csptr)->state == YCS_ALLOCATED);
593  CS_ASSERT((*csptr)->lock == 0);
594 
595  if ((*csptr)->no == CS_TRACK_NO || CS_TRACK_NO < 0) {
596  printf("delete CS on %s:%d:%p (%p)\n", fileid, lineno, (*csptr), &((*csptr)->cs));
597  }
598 
599 #if MICROCHIP_API
600  (*csptr)->cs = 0xCA;
601  res = 0;
602 #elif defined(WINDOWS_API)
603  res = 0;
604  DeleteCriticalSection(&((*csptr)->cs));
605 #else
606  res = pthread_mutex_destroy(&((*csptr)->cs));
607 #endif
608  CS_ASSERT(res == 0);
609  (*csptr)->state = YCS_DELETED;
610  pushCSAction(threadid, fileid, lineno, (*csptr), YCS_DELETE);
611 }
612 
613 #elif !defined(MICROCHIP_API)
614 
615 #include <stdio.h>
616 #include <stdlib.h>
617 #include <string.h>
618 
619 
620 typedef struct {
621 #if defined(WINDOWS_API)
622  CRITICAL_SECTION cs;
623 #else
624  pthread_mutex_t cs;
625 #endif
627 
628 
630 {
631  yCRITICAL_SECTION_ST *ycsptr;
632  ycsptr = (yCRITICAL_SECTION_ST*)malloc(sizeof(yCRITICAL_SECTION_ST));
633  memset(ycsptr, 0, sizeof(yCRITICAL_SECTION_ST));
634 #if defined(WINDOWS_API)
635  InitializeCriticalSection(&(ycsptr->cs));
636 #else
637  {
638  pthread_mutexattr_t attr;
639  pthread_mutexattr_init(&attr);
640  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
641  pthread_mutex_init(&(ycsptr->cs), &attr);
642  }
643 #endif
644  *cs = ycsptr;
645 }
646 
648 {
649  yCRITICAL_SECTION_ST *ycsptr = (yCRITICAL_SECTION_ST*)(*cs);
650 #if defined(WINDOWS_API)
651  EnterCriticalSection(&(ycsptr->cs));
652 #else
653  pthread_mutex_lock(&(ycsptr->cs));
654 #endif
655 }
656 
658 {
659  yCRITICAL_SECTION_ST *ycsptr = (yCRITICAL_SECTION_ST*)(*cs);
660 #if defined(WINDOWS_API)
661  return TryEnterCriticalSection(&(ycsptr->cs));
662 #else
663  {
664  int res = pthread_mutex_trylock(&(ycsptr->cs));
665  if (res == EBUSY)
666  return 0;
667  return 1;
668  }
669 #endif
670 }
671 
673 {
674  yCRITICAL_SECTION_ST *ycsptr = (yCRITICAL_SECTION_ST*)(*cs);
675 #if defined(WINDOWS_API)
676  LeaveCriticalSection(&(ycsptr->cs));
677 #else
678  pthread_mutex_unlock(&(ycsptr->cs));
679 #endif
680 }
681 
683 {
684  yCRITICAL_SECTION_ST *ycsptr = (yCRITICAL_SECTION_ST*)(*cs);
685 #if defined(WINDOWS_API)
686  DeleteCriticalSection(&(ycsptr->cs));
687 #else
688  pthread_mutex_destroy(&(ycsptr->cs));
689 #endif
690  free(*cs);
691  *cs = NULL;
692 }
693 
694 #endif
695 
696 
YTHREAD_STATE st
Definition: ythread.h:98
pthread_mutex_t mtx
Definition: ythread.h:63
void yThreadKill(yThread *yth)
Definition: ythread.c:343
int yWaitForEvent(yEvent *ev, int time)
Definition: ythread.c:196
void * yCRITICAL_SECTION
Definition: ydef.h:366
void yCreateEvent(yEvent *ev)
Definition: ythread.c:159
int autoreset
Definition: ythread.h:65
static pthread_key_t yTsdKey
Definition: ythread.c:151
static unsigned yNextThreadIdx
Definition: ythread.c:152
void yDeleteCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:682
int yThreadCreate(yThread *yth, void *(*fun)(void *), void *arg)
Definition: ythread.c:293
static pthread_once_t yInitKeyOnce
Definition: ythread.c:150
static int yWaitEndThread(osThread *th)
Definition: ythread.c:253
int yTryEnterCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:657
static void initTsdKey()
Definition: ythread.c:154
static void yKillThread(osThread *th)
Definition: ythread.c:259
osThread th
Definition: ythread.h:99
int yCreateDetachedThread(void *(*fun)(void *), void *arg)
Definition: ythread.c:282
void yThreadRequestEnd(yThread *yth)
Definition: ythread.c:331
void * ctx
Definition: ythread.h:96
void yResetEvent(yEvent *ev)
Definition: ythread.c:187
pthread_mutex_t cs
Definition: ythread.c:624
void yLeaveCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:672
void yInitializeCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:629
pthread_t osThread
Definition: ythread.h:84
Definition: ythread.h:61
void ySetEvent(yEvent *ev)
Definition: ythread.c:175
int yThreadIndex(void)
Definition: ythread.c:264
void yEnterCriticalSection(yCRITICAL_SECTION *cs)
Definition: ythread.c:647
void yCreateManualEvent(yEvent *ev, int initialState)
Definition: ythread.c:167
static int yCreateDetachedThreadEx(osThread *th, void *(*fun)(void *), void *arg)
Definition: ythread.c:229
static void yReleaseDetachedThreadEx(osThread *th_hdl)
Definition: ythread.c:247
yEvent ev
Definition: ythread.h:97
void yThreadSignalEnd(yThread *yth)
Definition: ythread.c:326
int verif
Definition: ythread.h:64
void yCloseEvent(yEvent *ev)
Definition: ythread.c:223
int yThreadMustEnd(yThread *yth)
Definition: ythread.c:338
pthread_cond_t cond
Definition: ythread.h:62
int yThreadIsRunning(yThread *yth)
Definition: ythread.c:311
void yThreadSignalStart(yThread *yth)
Definition: ythread.c:318


yoctopuce_altimeter
Author(s): Anja Sheppard
autogenerated on Mon Jun 10 2019 15:49:13