This is Unofficial EPICS BASE Doxygen Site
osdThread.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * Copyright (c) 2013 ITER Organization.
7 * EPICS BASE is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 /* Author: Marty Kraimer Date: 18JAN2000 */
12 
13 /* This is a posix implementation of epicsThread */
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <pthread.h>
22 #include <signal.h>
23 #include <sched.h>
24 #include <unistd.h>
25 
26 #if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
27 #include <sys/mman.h>
28 #endif
29 
30 #include "epicsStdio.h"
31 #include "ellLib.h"
32 #include "epicsEvent.h"
33 #include "epicsMutex.h"
34 #include "epicsString.h"
35 #include "epicsThread.h"
36 #include "cantProceed.h"
37 #include "errlog.h"
38 #include "epicsAssert.h"
39 #include "epicsExit.h"
40 #include "epicsAtomic.h"
41 
42 LIBCOM_API void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
43 LIBCOM_API void osdThreadHooksRun(epicsThreadId id);
44 LIBCOM_API void osdThreadHooksRunMain(epicsThreadId id);
45 
46 static int mutexLock(pthread_mutex_t *id)
47 {
48  int status;
49 
50  while(1) {
51  status = pthread_mutex_lock(id);
52  if(status!=EINTR) return status;
53  fprintf(stderr,"pthread_mutex_lock returned EINTR. Violates SUSv3\n");
54  }
55 }
56 
57 #if defined DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
58 #undef _POSIX_THREAD_PRIORITY_SCHEDULING
59 #endif
60 
61 typedef struct commonAttr{
62  pthread_attr_t attr;
63  struct sched_param schedParam;
67  int usePolicy;
68 } commonAttr;
69 
70 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
71 typedef struct {
72  int min_pri, max_pri;
73  int policy;
74  int ok;
75 } priAvailable;
76 #endif
77 
78 static pthread_key_t getpthreadInfo;
79 static pthread_mutex_t onceLock;
80 static pthread_mutex_t listLock;
81 static ELLLIST pthreadList = ELLLIST_INIT;
82 static commonAttr *pcommonAttr = 0;
83 static int epicsThreadOnceCalled = 0;
84 
85 static epicsThreadOSD *createImplicit(void);
86 
87 #define checkStatus(status,message) \
88 if((status)) {\
89  errlogPrintf("%s error %s\n",(message),strerror((status))); \
90 }
91 
92 #define checkStatusQuit(status,message,method) \
93 if(status) { \
94  errlogPrintf("%s error %s\n",(message),strerror((status))); \
95  cantProceed((method)); \
96 }
97 
98 /* The following are for use by once, which is only invoked from epicsThreadInit*/
99 /* Until epicsThreadInit completes errlogInit will not work */
100 /* It must also be used by init_threadInfo otherwise errlogInit could get */
101 /* called recursively */
102 #define checkStatusOnce(status,message) \
103 if((status)) {\
104  fprintf(stderr,"%s error %s\n",(message),strerror((status))); }
105 
106 #define checkStatusOnceQuit(status,message,method) \
107 if(status) { \
108  fprintf(stderr,"%s error %s",(message),strerror((status))); \
109  fprintf(stderr," %s\n",method); \
110  fprintf(stderr,"epicsThreadInit cant proceed. Program exiting\n"); \
111  exit(-1);\
112 }
113 
114 
115 LIBCOM_API int epicsThreadGetPosixPriority(epicsThreadId pthreadInfo)
116 {
117 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
118  double maxPriority,minPriority,slope,oss;
119 
120  if(pcommonAttr->maxPriority==pcommonAttr->minPriority)
121  return(pcommonAttr->maxPriority);
122  maxPriority = (double)pcommonAttr->maxPriority;
123  minPriority = (double)pcommonAttr->minPriority;
124  slope = (maxPriority - minPriority)/100.0;
125  oss = (double)pthreadInfo->osiPriority * slope + minPriority;
126  return((int)oss);
127 #else
128  return 0;
129 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
130 }
131 
132 static void setSchedulingPolicy(epicsThreadOSD *pthreadInfo,int policy)
133 {
134 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
135  int status;
136 
137  if(!pcommonAttr->usePolicy) return;
138 
139  status = pthread_attr_getschedparam(
140  &pthreadInfo->attr,&pthreadInfo->schedParam);
141  checkStatusOnce(status,"pthread_attr_getschedparam");
142  pthreadInfo->schedParam.sched_priority = epicsThreadGetPosixPriority(pthreadInfo);
143  pthreadInfo->schedPolicy = policy;
144  status = pthread_attr_setschedpolicy(
145  &pthreadInfo->attr,policy);
146  checkStatusOnce(status,"pthread_attr_setschedpolicy");
147  status = pthread_attr_setschedparam(
148  &pthreadInfo->attr,&pthreadInfo->schedParam);
149  checkStatusOnce(status,"pthread_attr_setschedparam");
150  status = pthread_attr_setinheritsched(
151  &pthreadInfo->attr,PTHREAD_EXPLICIT_SCHED);
152  checkStatusOnce(status,"pthread_attr_setinheritsched");
153 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
154 }
155 
156 static epicsThreadOSD * create_threadInfo(const char *name)
157 {
158  epicsThreadOSD *pthreadInfo;
159 
160  /* sizeof(epicsThreadOSD) includes one byte for the '\0' */
161  pthreadInfo = calloc(1,sizeof(*pthreadInfo) + strlen(name));
162  if(!pthreadInfo)
163  return NULL;
165  if(!pthreadInfo->suspendEvent){
166  free(pthreadInfo);
167  return NULL;
168  }
169  strcpy(pthreadInfo->name, name);
170  epicsAtomicIncrIntT(&pthreadInfo->refcnt); /* initial ref for the thread itself */
171  return pthreadInfo;
172 }
173 
174 static epicsThreadOSD * init_threadInfo(const char *name,
175  unsigned int priority, unsigned int stackSize,
176  EPICSTHREADFUNC funptr,void *parm,
177  unsigned joinable)
178 {
179  epicsThreadOSD *pthreadInfo;
180  int status;
181 
182  pthreadInfo = create_threadInfo(name);
183  if(!pthreadInfo)
184  return NULL;
185  pthreadInfo->createFunc = funptr;
186  pthreadInfo->createArg = parm;
187  pthreadInfo->joinable = !!joinable; /* ensure 0 or 1 for later atomic compare+swap */
188  status = pthread_attr_init(&pthreadInfo->attr);
189  checkStatusOnce(status,"pthread_attr_init");
190  if(status) return 0;
191  if(!joinable){
192  status = pthread_attr_setdetachstate(
193  &pthreadInfo->attr, PTHREAD_CREATE_DETACHED);
194  checkStatusOnce(status,"pthread_attr_setdetachstate");
195  }
196 #if defined (_POSIX_THREAD_ATTR_STACKSIZE)
197 #if ! defined (OSITHREAD_USE_DEFAULT_STACK)
198  status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize);
199  checkStatusOnce(status,"pthread_attr_setstacksize");
200 #endif /*OSITHREAD_USE_DEFAULT_STACK*/
201 #endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
202  status = pthread_attr_setscope(&pthreadInfo->attr,PTHREAD_SCOPE_PROCESS);
203  if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
204  pthreadInfo->osiPriority = priority;
205  return(pthreadInfo);
206 }
207 
208 static void free_threadInfo(epicsThreadOSD *pthreadInfo)
209 {
210  int status;
211 
212  if(epicsAtomicDecrIntT(&pthreadInfo->refcnt) > 0) return;
213 
214  status = mutexLock(&listLock);
215  checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo");
216  if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node);
217  status = pthread_mutex_unlock(&listLock);
218  checkStatusQuit(status,"pthread_mutex_unlock","free_threadInfo");
219  epicsEventDestroy(pthreadInfo->suspendEvent);
220  status = pthread_attr_destroy(&pthreadInfo->attr);
221  checkStatusQuit(status,"pthread_attr_destroy","free_threadInfo");
222  free(pthreadInfo);
223 }
224 
225 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
226 /*
227  * The actually available range priority range (at least under linux)
228  * may be restricted by resource limitations (but that is ignored
229  * by sched_get_priority_max()). See bug #835138 which is fixed by
230  * this code.
231  */
232 
233 static int try_pri(int pri, int policy)
234 {
235 struct sched_param schedp;
236 
237  schedp.sched_priority = pri;
238  return pthread_setschedparam(pthread_self(), policy, &schedp);
239 }
240 
241 static void*
242 find_pri_range(void *arg)
243 {
244 priAvailable *prm = arg;
245 int min = sched_get_priority_min(prm->policy);
246 int max = sched_get_priority_max(prm->policy);
247 int low, try;
248 
249  if ( -1 == min || -1 == max ) {
250  /* something is very wrong; maintain old behavior
251  * (warning message if sched_get_priority_xxx() fails
252  * and use default policy's sched_priority [even if
253  * that is likely to cause epicsThreadCreate to fail
254  * because that priority is not suitable for SCHED_FIFO]).
255  */
256  prm->min_pri = prm->max_pri = -1;
257  return 0;
258  }
259 
260 
261  if ( try_pri(min, prm->policy) ) {
262  /* cannot create thread at minimum priority;
263  * probably no permission to use SCHED_FIFO
264  * at all. However, we still must return
265  * a priority range accepted by the SCHED_FIFO
266  * policy. Otherwise, epicsThreadCreate() cannot
267  * detect the unsufficient permission (EPERM)
268  * and fall back to a non-RT thread (because
269  * pthread_attr_setschedparam would fail with
270  * EINVAL due to the bad priority).
271  */
272  prm->min_pri = prm->max_pri = min;
273  return 0;
274  }
275 
276 
277  /* Binary search through available priorities.
278  * The actually available range may be restricted
279  * by resource limitations (but that is ignored
280  * by sched_get_priority_max() [linux]).
281  */
282  low = min;
283 
284  while ( low < max ) {
285  try = (max+low)/2;
286  if ( try_pri(try, prm->policy) ) {
287  max = try;
288  } else {
289  low = try + 1;
290  }
291  }
292 
293  prm->min_pri = min;
294  prm->max_pri = try_pri(max, prm->policy) ? max-1 : max;
295  prm->ok = 1;
296 
297  return 0;
298 }
299 
300 static void findPriorityRange(commonAttr *a_p)
301 {
302 priAvailable arg;
303 pthread_t id;
304 void *dummy;
305 int status;
306 
307  arg.policy = a_p->schedPolicy;
308  arg.ok = 0;
309 
310  status = pthread_create(&id, 0, find_pri_range, &arg);
311  checkStatusQuit(status, "pthread_create","epicsThreadInit");
312 
313  status = pthread_join(id, &dummy);
314  checkStatusQuit(status, "pthread_join","epicsThreadInit");
315 
316  a_p->minPriority = arg.min_pri;
317  a_p->maxPriority = arg.max_pri;
318  a_p->usePolicy = arg.ok;
319 }
320 #endif
321 
322 
323 static void once(void)
324 {
325  epicsThreadOSD *pthreadInfo;
326  int status;
327 
328  pthread_key_create(&getpthreadInfo,0);
329  status = pthread_mutex_init(&onceLock,0);
330  checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
331  status = pthread_mutex_init(&listLock,0);
332  checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
333  pcommonAttr = calloc(1,sizeof(commonAttr));
334  if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit");
335  status = pthread_attr_init(&pcommonAttr->attr);
336  checkStatusOnceQuit(status,"pthread_attr_init","epicsThreadInit");
337  status = pthread_attr_setdetachstate(
338  &pcommonAttr->attr, PTHREAD_CREATE_DETACHED);
339  checkStatusOnce(status,"pthread_attr_setdetachstate");
340  status = pthread_attr_setscope(&pcommonAttr->attr,PTHREAD_SCOPE_PROCESS);
341  if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
342 
343 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
344  status = pthread_attr_setschedpolicy(
345  &pcommonAttr->attr,SCHED_FIFO);
346  checkStatusOnce(status,"pthread_attr_setschedpolicy");
347  status = pthread_attr_getschedpolicy(
348  &pcommonAttr->attr,&pcommonAttr->schedPolicy);
349  checkStatusOnce(status,"pthread_attr_getschedpolicy");
350  status = pthread_attr_getschedparam(
351  &pcommonAttr->attr,&pcommonAttr->schedParam);
352  checkStatusOnce(status,"pthread_attr_getschedparam");
353 
354  findPriorityRange(pcommonAttr);
355 
356  if(pcommonAttr->maxPriority == -1) {
357  pcommonAttr->maxPriority = pcommonAttr->schedParam.sched_priority;
358  fprintf(stderr,"sched_get_priority_max failed set to %d\n",
359  pcommonAttr->maxPriority);
360  }
361  if(pcommonAttr->minPriority == -1) {
362  pcommonAttr->minPriority = pcommonAttr->schedParam.sched_priority;
363  fprintf(stderr,"sched_get_priority_min failed set to %d\n",
364  pcommonAttr->maxPriority);
365  }
366 
367  if (errVerbose) {
368  fprintf(stderr, "LRT: min priority: %d max priority %d\n",
369  pcommonAttr->minPriority, pcommonAttr->maxPriority);
370  }
371 
372 #else
373  if(errVerbose) fprintf(stderr,"task priorities are not implemented\n");
374 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
375 
376  pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0,0);
377  assert(pthreadInfo!=NULL);
378  status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
379  checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit");
380  status = mutexLock(&listLock);
381  checkStatusQuit(status,"pthread_mutex_lock","epicsThreadInit");
382  ellAdd(&pthreadList,&pthreadInfo->node);
383  pthreadInfo->isOnThreadList = 1;
384  status = pthread_mutex_unlock(&listLock);
385  checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");
386  status = atexit(epicsExitCallAtExits);
387  checkStatusOnce(status,"atexit");
388  osdThreadHooksRunMain(pthreadInfo);
389  epicsThreadOnceCalled = 1;
390 }
391 
392 static void * start_routine(void *arg)
393 {
394  epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg;
395  int status;
396  sigset_t blockAllSig;
397 
398  sigfillset(&blockAllSig);
399  pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);
400  status = pthread_setspecific(getpthreadInfo,arg);
401  checkStatusQuit(status,"pthread_setspecific","start_routine");
402  status = mutexLock(&listLock);
403  checkStatusQuit(status,"pthread_mutex_lock","start_routine");
404  ellAdd(&pthreadList,&pthreadInfo->node);
405  pthreadInfo->isOnThreadList = 1;
406  status = pthread_mutex_unlock(&listLock);
407  checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
408  osdThreadHooksRun(pthreadInfo);
409 
410  (*pthreadInfo->createFunc)(pthreadInfo->createArg);
411 
413  free_threadInfo(pthreadInfo);
414  return(0);
415 }
416 
417 static void epicsThreadInit(void)
418 {
419  static pthread_once_t once_control = PTHREAD_ONCE_INIT;
420  int status = pthread_once(&once_control,once);
421  checkStatusQuit(status,"pthread_once","epicsThreadInit");
422 }
423 
424 LIBCOM_API
426 {
427 #if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0
428  if (pcommonAttr->maxPriority > pcommonAttr->minPriority) {
429  int status = mlockall(MCL_CURRENT | MCL_FUTURE);
430 
431  if (status) {
432  const int err = errno;
433  switch(err) {
434 #ifdef __linux__
435  case ENOMEM:
436  fprintf(stderr, "epicsThreadRealtimeLock "
437  "Warning: unable to lock memory. RLIMIT_MEMLOCK is too small or missing CAP_IPC_LOCK\n");
438  break;
439  case EPERM:
440  fprintf(stderr, "epicsThreadRealtimeLock "
441  "Warning: unable to lock memory. missing CAP_IPC_LOCK\n");
442  break;
443 #endif
444  default:
445  fprintf(stderr, "epicsThreadRealtimeLock "
446  "Warning: Unable to lock the virtual address space.\n"
447  "VM page faults may harm real-time performance. errno=%d\n",
448  err);
449  }
450  }
451  }
452 #endif
453 }
454 
455 #if defined (OSITHREAD_USE_DEFAULT_STACK)
456 #define STACK_SIZE(f) (0)
457 #elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0
458  #define STACK_SIZE(f) (f * 0x10000 * sizeof(void *))
459  static const unsigned stackSizeTable[epicsThreadStackBig+1] = {
460  STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4)
461  };
462 #else
463 #define STACK_SIZE(f) (0)
464 #endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
465 
466 LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
467 {
468 #if defined (OSITHREAD_USE_DEFAULT_STACK)
469  return 0;
470 #elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0
471  if (stackSizeClass<epicsThreadStackSmall) {
472  errlogPrintf("epicsThreadGetStackSize illegal argument (too small)");
473  return stackSizeTable[epicsThreadStackBig];
474  }
475 
476  if (stackSizeClass>epicsThreadStackBig) {
477  errlogPrintf("epicsThreadGetStackSize illegal argument (too large)");
478  return stackSizeTable[epicsThreadStackBig];
479  }
480 
481  return stackSizeTable[stackSizeClass];
482 #else
483  return 0;
484 #endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
485 }
486 
487 LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
488 {
489  static struct epicsThreadOSD threadOnceComplete;
490  #define EPICS_THREAD_ONCE_DONE &threadOnceComplete
491  int status;
492 
493  epicsThreadInit();
494  status = mutexLock(&onceLock);
495  if(status) {
496  fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
497  strerror(status));
498  exit(-1);
499  }
500 
501  if (*id != EPICS_THREAD_ONCE_DONE) {
502  if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
503  *id = epicsThreadGetIdSelf(); /* mark active */
504  status = pthread_mutex_unlock(&onceLock);
505  checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
506  func(arg);
507  status = mutexLock(&onceLock);
508  checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
509  *id = EPICS_THREAD_ONCE_DONE; /* mark done */
510  } else if (*id == epicsThreadGetIdSelf()) {
511  status = pthread_mutex_unlock(&onceLock);
512  checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
513  cantProceed("Recursive epicsThreadOnce() initialization\n");
514  } else
515  while (*id != EPICS_THREAD_ONCE_DONE) {
516  /* Another thread is in the above func(arg) call. */
517  status = pthread_mutex_unlock(&onceLock);
518  checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
520  status = mutexLock(&onceLock);
521  checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
522  }
523  }
524  status = pthread_mutex_unlock(&onceLock);
525  checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
526 }
527 
529 epicsThreadCreateOpt(const char * name,
530  EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts )
531 {
532  unsigned int stackSize;
533  epicsThreadOSD *pthreadInfo;
534  int status;
535  sigset_t blockAllSig, oldSig;
536 
537  epicsThreadInit();
538  assert(pcommonAttr);
539 
540  if (!opts) {
541  static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT;
542  opts = &opts_default;
543  }
544  stackSize = opts->stackSize;
545  if (stackSize <= epicsThreadStackBig)
546  stackSize = epicsThreadGetStackSize(stackSize);
547 
548  sigfillset(&blockAllSig);
549  pthread_sigmask(SIG_SETMASK, &blockAllSig, &oldSig);
550 
551  pthreadInfo = init_threadInfo(name, opts->priority, stackSize, funptr,
552  parm, opts->joinable);
553  if (pthreadInfo==0)
554  return 0;
555 
556  pthreadInfo->isEpicsThread = 1;
557  setSchedulingPolicy(pthreadInfo, SCHED_FIFO);
558  pthreadInfo->isRealTimeScheduled = 1;
559 
560  if (pthreadInfo->joinable) {
561  /* extra ref for epicsThreadMustJoin() */
562  epicsAtomicIncrIntT(&pthreadInfo->refcnt);
563  }
564 
565  status = pthread_create(&pthreadInfo->tid, &pthreadInfo->attr,
566  start_routine, pthreadInfo);
567  if (status==EPERM) {
568  /* Try again without SCHED_FIFO*/
569  free_threadInfo(pthreadInfo);
570 
571  pthreadInfo = init_threadInfo(name, opts->priority, stackSize,
572  funptr, parm, opts->joinable);
573  if (pthreadInfo==0)
574  return 0;
575 
576  pthreadInfo->isEpicsThread = 1;
577  status = pthread_create(&pthreadInfo->tid, &pthreadInfo->attr,
578  start_routine, pthreadInfo);
579  }
580  checkStatusOnce(status, "pthread_create");
581  if (status) {
582  if (pthreadInfo->joinable) {
583  /* release extra ref which would have been for epicsThreadMustJoin() */
584  epicsAtomicDecrIntT(&pthreadInfo->refcnt);
585  }
586 
587  free_threadInfo(pthreadInfo);
588  return 0;
589  }
590 
591  status = pthread_sigmask(SIG_SETMASK, &oldSig, NULL);
592  checkStatusOnce(status, "pthread_sigmask");
593  return pthreadInfo;
594 }
595 
596 /*
597  * Create dummy context for threads not created by epicsThreadCreate().
598  */
599 static epicsThreadOSD *createImplicit(void)
600 {
601  epicsThreadOSD *pthreadInfo;
602  char name[64];
603  pthread_t tid;
604  int status;
605 
606  tid = pthread_self();
607  sprintf(name, "non-EPICS_%ld", (long)tid);
608  pthreadInfo = create_threadInfo(name);
609  assert(pthreadInfo);
610  pthreadInfo->tid = tid;
611  pthreadInfo->osiPriority = 0;
612 
613 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
614  if(pthread_getschedparam(tid,&pthreadInfo->schedPolicy,&pthreadInfo->schedParam) == 0) {
615  if ( pcommonAttr->usePolicy && pthreadInfo->schedPolicy == pcommonAttr->schedPolicy ) {
616  pthreadInfo->osiPriority =
617  (pthreadInfo->schedParam.sched_priority - pcommonAttr->minPriority) * 100.0 /
618  (pcommonAttr->maxPriority - pcommonAttr->minPriority + 1);
619  }
620  }
621 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
622 
623  status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
624  checkStatus(status,"pthread_setspecific createImplicit");
625  if(status){
626  free_threadInfo(pthreadInfo);
627  return NULL;
628  }
629  return pthreadInfo;
630 }
631 
633 {
634  void *ret = NULL;
635  int status;
636 
637  if(!id) {
638  return;
639  } else if(epicsAtomicCmpAndSwapIntT(&id->joinable, 1, 0)!=1) {
640  if(epicsThreadGetIdSelf()==id) {
641  errlogPrintf("Warning: %s thread self-join of unjoinable\n", id->name);
642 
643  } else {
644  /* try to error nicely, however in all likelyhood de-ref of
645  * 'id' has already caused SIGSEGV as we are racing thread exit,
646  * which free's 'id'.
647  */
648  cantProceed("Error: %s thread not joinable.\n", id->name);
649  }
650  return;
651  }
652 
653  status = pthread_join(id->tid, &ret);
654  if(status == EDEADLK) {
655  /* Thread can't join itself (directly or indirectly)
656  * so we detach instead.
657  */
658  status = pthread_detach(id->tid);
659  checkStatusOnce(status, "pthread_detach");
660  } else checkStatusOnce(status, "pthread_join");
661  free_threadInfo(id);
662 }
663 
664 LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
665 {
666  epicsThreadOSD *pthreadInfo;
667 
668  epicsThreadInit();
669  pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
670  if(pthreadInfo==NULL)
671  pthreadInfo = createImplicit();
672  pthreadInfo->isSuspended = 1;
673  epicsEventWait(pthreadInfo->suspendEvent);
674 }
675 
676 LIBCOM_API void epicsStdCall epicsThreadResume(epicsThreadOSD *pthreadInfo)
677 {
678  assert(epicsThreadOnceCalled);
679  pthreadInfo->isSuspended = 0;
680  epicsEventSignal(pthreadInfo->suspendEvent);
681 }
682 
683 LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
684 {
685  epicsThreadOSD *pthreadInfo;
686 
687  epicsThreadInit();
688  pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
689  if(pthreadInfo==NULL)
690  pthreadInfo = createImplicit();
691  if(pthreadInfo->createFunc) {
692  errlogPrintf("called from non-main thread\n");
693  cantProceed("epicsThreadExitMain");
694  }
695  else {
696  free_threadInfo(pthreadInfo);
697  pthread_exit(0);
698  }
699 }
700 
701 LIBCOM_API unsigned int epicsStdCall epicsThreadGetPriority(epicsThreadId pthreadInfo)
702 {
703  assert(epicsThreadOnceCalled);
704  return(pthreadInfo->osiPriority);
705 }
706 
707 LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
708 {
709  epicsThreadInit();
711 }
712 
713 LIBCOM_API void epicsStdCall epicsThreadSetPriority(epicsThreadId pthreadInfo,unsigned int priority)
714 {
715 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
716  int status;
717 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
718 
719  assert(epicsThreadOnceCalled);
720  assert(pthreadInfo);
721  if(!pthreadInfo->isEpicsThread) {
722  fprintf(stderr,"epicsThreadSetPriority called by non epics thread\n");
723  return;
724  }
725  pthreadInfo->osiPriority = priority;
726  if(!pthreadInfo->isRealTimeScheduled) return;
727 
728 #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
729  if(!pcommonAttr->usePolicy) return;
730  pthreadInfo->schedParam.sched_priority = epicsThreadGetPosixPriority(pthreadInfo);
731  status = pthread_attr_setschedparam(
732  &pthreadInfo->attr,&pthreadInfo->schedParam);
733  if(errVerbose) checkStatus(status,"pthread_attr_setschedparam");
734  status = pthread_setschedparam(
735  pthreadInfo->tid, pthreadInfo->schedPolicy, &pthreadInfo->schedParam);
736  if(errVerbose) checkStatus(status,"pthread_setschedparam");
737 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
738 }
739 
741  unsigned int priority, unsigned *pPriorityJustBelow)
742 {
743  unsigned newPriority = priority - 1;
744 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
745  int diff;
746  diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
747  if(diff<0) diff = -diff;
748  if(diff>1 && diff <100) newPriority -= 100/(diff+1);
749 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
750  if (newPriority <= 99) {
751  *pPriorityJustBelow = newPriority;
753  }
755 }
756 
758  unsigned int priority, unsigned *pPriorityJustAbove)
759 {
760  unsigned newPriority = priority + 1;
761 
762 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
763  int diff;
764  diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
765  if(diff<0) diff = -diff;
766  if(diff>1 && diff <100) newPriority += 100/(diff+1);
767 #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
768 
769  if (newPriority <= 99) {
770  *pPriorityJustAbove = newPriority;
772  }
774 }
775 
776 LIBCOM_API int epicsStdCall epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
777 {
778  assert(epicsThreadOnceCalled);
779  assert(p1);
780  assert(p2);
781  return(pthread_equal(p1->tid,p2->tid));
782 }
783 
784 LIBCOM_API int epicsStdCall epicsThreadIsSuspended(epicsThreadId pthreadInfo) {
785  assert(epicsThreadOnceCalled);
786  assert(pthreadInfo);
787  return(pthreadInfo->isSuspended ? 1 : 0);
788 }
789 
790 LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
791 {
792  struct timespec delayTime;
793  struct timespec remainingTime;
794  double nanoseconds;
795 
796  if (seconds > 0) {
797  delayTime.tv_sec = seconds;
798  nanoseconds = (seconds - delayTime.tv_sec) *1e9;
799  delayTime.tv_nsec = nanoseconds;
800  }
801  else {
802  delayTime.tv_sec = 0;
803  delayTime.tv_nsec = 0;
804  }
805  while (nanosleep(&delayTime, &remainingTime) == -1 &&
806  errno == EINTR)
807  delayTime = remainingTime;
808 }
809 
810 LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void) {
811  epicsThreadOSD *pthreadInfo;
812 
813  epicsThreadInit();
814  pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
815  if(pthreadInfo==NULL)
816  pthreadInfo = createImplicit();
817  assert ( pthreadInfo );
818  return(pthreadInfo);
819 }
820 
821 LIBCOM_API pthread_t epicsThreadGetPosixThreadId ( epicsThreadId threadId )
822 {
823  return threadId->tid;
824 }
825 
826 LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetId(const char *name) {
827  epicsThreadOSD *pthreadInfo;
828  int status;
829 
830  assert(epicsThreadOnceCalled);
831  status = mutexLock(&listLock);
832  checkStatus(status,"pthread_mutex_lock epicsThreadGetId");
833  if(status)
834  return NULL;
835  pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
836  while(pthreadInfo) {
837  if(strcmp(name,pthreadInfo->name) == 0) break;
838  pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
839  }
840  status = pthread_mutex_unlock(&listLock);
841  checkStatus(status,"pthread_mutex_unlock epicsThreadGetId");
842 
843  return(pthreadInfo);
844 }
845 
846 LIBCOM_API const char epicsStdCall *epicsThreadGetNameSelf()
847 {
848  epicsThreadOSD *pthreadInfo;
849 
850  epicsThreadInit();
851  pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
852  if(pthreadInfo==NULL)
853  pthreadInfo = createImplicit();
854  return(pthreadInfo->name);
855 }
856 
857 LIBCOM_API void epicsStdCall epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
858 {
859  assert(epicsThreadOnceCalled);
860  strncpy(name, pthreadInfo->name, size-1);
861  name[size-1] = '\0';
862 }
863 
865 {
866  epicsThreadOSD *pthreadInfo;
867  int status;
868 
869  epicsThreadInit();
870  status = mutexLock(&listLock);
871  checkStatus(status, "pthread_mutex_lock epicsThreadMap");
872  if (status)
873  return;
874  pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
875  while (pthreadInfo) {
876  func(pthreadInfo);
877  pthreadInfo = (epicsThreadOSD *)ellNext(&pthreadInfo->node);
878  }
879  status = pthread_mutex_unlock(&listLock);
880  checkStatus(status, "pthread_mutex_unlock epicsThreadMap");
881 }
882 
883 LIBCOM_API void epicsStdCall epicsThreadShowAll(unsigned int level)
884 {
885  epicsThreadOSD *pthreadInfo;
886  int status;
887 
888  epicsThreadInit();
889  epicsThreadShow(0,level);
890  status = mutexLock(&listLock);
891  checkStatus(status,"pthread_mutex_lock epicsThreadShowAll");
892  if(status)
893  return;
894  pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
895  while(pthreadInfo) {
896  epicsThreadShowInfo(pthreadInfo,level);
897  pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
898  }
899  status = pthread_mutex_unlock(&listLock);
900  checkStatus(status,"pthread_mutex_unlock epicsThreadShowAll");
901 }
902 
903 LIBCOM_API void epicsStdCall epicsThreadShow(epicsThreadId showThread, unsigned int level)
904 {
905  epicsThreadOSD *pthreadInfo;
906  int status;
907  int found = 0;
908 
909  epicsThreadInit();
910  if(!showThread) {
911  epicsThreadShowInfo(0,level);
912  return;
913  }
914  status = mutexLock(&listLock);
915  checkStatus(status,"pthread_mutex_lock epicsThreadShowAll");
916  if(status)
917  return;
918  pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
919  while(pthreadInfo) {
920  if (((epicsThreadId)pthreadInfo == showThread)
921  || ((epicsThreadId)pthreadInfo->tid == showThread)) {
922  found = 1;
923  epicsThreadShowInfo(pthreadInfo,level);
924  }
925  pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
926  }
927  status = pthread_mutex_unlock(&listLock);
928  checkStatus(status,"pthread_mutex_unlock epicsThreadShowAll");
929  if(status) return;
930  if (!found)
931  printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);
932 }
933 
934 LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
935 {
936  pthread_key_t *key;
937  int status;
938 
939  epicsThreadInit();
940  key = calloc(1,sizeof(pthread_key_t));
941  if(!key)
942  return NULL;
943  status = pthread_key_create(key,0);
944  checkStatus(status,"pthread_key_create epicsThreadPrivateCreate");
945  if(status)
946  return NULL;
947  return((epicsThreadPrivateId)key);
948 }
949 
950 LIBCOM_API void epicsStdCall epicsThreadPrivateDelete(epicsThreadPrivateId id)
951 {
952  pthread_key_t *key = (pthread_key_t *)id;
953  int status;
954 
955  assert(epicsThreadOnceCalled);
956  status = pthread_key_delete(*key);
957  checkStatusQuit(status,"pthread_key_delete","epicsThreadPrivateDelete");
958  free((void *)key);
959 }
960 
961 LIBCOM_API void epicsStdCall epicsThreadPrivateSet (epicsThreadPrivateId id, void *value)
962 {
963  pthread_key_t *key = (pthread_key_t *)id;
964  int status;
965 
966  assert(epicsThreadOnceCalled);
967  if(errVerbose && !value)
968  errlogPrintf("epicsThreadPrivateSet: setting value of 0\n");
969  status = pthread_setspecific(*key,value);
970  checkStatusQuit(status,"pthread_setspecific","epicsThreadPrivateSet");
971 }
972 
973 LIBCOM_API void epicsStdCall *epicsThreadPrivateGet(epicsThreadPrivateId id)
974 {
975  pthread_key_t *key = (pthread_key_t *)id;
976 
977  assert(epicsThreadOnceCalled);
978  return pthread_getspecific(*key);
979 }
980 
981 LIBCOM_API double epicsStdCall epicsThreadSleepQuantum ()
982 {
983  double hz;
984  hz = sysconf ( _SC_CLK_TCK );
985  if(hz<=0)
986  return 0.0;
987  return 1.0 / hz;
988 }
989 
990 LIBCOM_API int epicsThreadGetCPUs(void)
991 {
992  long ret;
993 #ifdef _SC_NPROCESSORS_ONLN
994  ret = sysconf(_SC_NPROCESSORS_ONLN);
995  if (ret > 0)
996  return ret;
997 #endif
998 #ifdef _SC_NPROCESSORS_CONF
999  ret = sysconf(_SC_NPROCESSORS_CONF);
1000  if (ret > 0)
1001  return ret;
1002 #endif
1003  return 1;
1004 }
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass stackSizeClass)
Definition: osdThread.c:466
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadHighestPriorityLevelBelow(unsigned int priority, unsigned *pPriorityJustBelow)
Definition: osdThread.c:740
LIBCOM_API int epicsThreadGetCPUs(void)
Definition: osdThread.c:990
LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
Definition: osdThread.c:934
pthread_t tid
Definition: osdThread.h:26
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
Definition: link.h:174
#define max(x, y)
Definition: flexdef.h:81
void * createArg
Definition: osdThread.h:32
LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
Definition: osdThread.c:683
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
epicsThreadBooleanStatus
Definition: epicsThread.h:93
unsigned int osiPriority
Definition: osdThread.h:38
epicsEventId suspendEvent
Definition: osdThread.h:33
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
int schedPolicy
Definition: osdThread.c:66
LIBCOM_API void epicsExitCallAtThreadExits(void)
Internal routine that runs the registered thread exit routines.
Definition: epicsExit.c:121
struct sched_param schedParam
Definition: osdThread.h:29
pthread_attr_t attr
Definition: osdThread.c:62
#define min(x, y)
Definition: flexdef.h:78
ELLNODE node
Definition: osdThread.h:24
LIBCOM_API void epicsThreadRealtimeLock(void)
Definition: osdThread.c:425
int maxPriority
Definition: osdThread.c:64
LIBCOM_API double epicsStdCall epicsThreadSleepQuantum()
Query a value approximating the OS timer/scheduler resolution.
Definition: osdThread.c:981
void(* EPICS_THREAD_HOOK_ROUTINE)(epicsThreadId id)
Definition: epicsThread.h:302
#define printf
Definition: epicsStdio.h:41
#define epicsEventWait(ID)
Definition: osdEvent.h:19
struct epicsThreadOSD * epicsThreadId
Definition: epicsThread.h:106
#define NULL
Definition: catime.c:38
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT(int *pTarget, int oldVal, int newVal)
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadLowestPriorityLevelAbove(unsigned int priority, unsigned *pPriorityJustAbove)
Definition: osdThread.c:757
#define ELLLIST_INIT
Value of an empty list.
Definition: ellLib.h:63
unsigned int joinable
Definition: epicsThread.h:158
time_t tv_sec
Definition: osdTime.h:22
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId id, void *value)
Definition: osdThread.c:961
int isRealTimeScheduled
Definition: osdThread.h:36
LIBCOM_API void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
Definition: osdThread.c:487
int usePolicy
Definition: osdThread.c:67
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
int isEpicsThread
Definition: osdThread.h:35
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
struct commonAttr commonAttr
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
LIBCOM_API int epicsThreadGetPosixPriority(epicsThreadId pthreadInfo)
Definition: osdThread.c:115
long tv_nsec
Definition: osdTime.h:23
epicsThreadStackSizeClass
Definition: epicsThread.h:89
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
int errVerbose
Definition: errlog.c:41
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall * epicsThreadPrivateGet(epicsThreadPrivateId id)
Definition: osdThread.c:973
epicsThreadId epicsThreadCreateOpt(const char *name, EPICSTHREADFUNC funptr, void *parm, const epicsThreadOpts *opts)
Allocate and start a new OS thread.
Definition: osdThread.c:529
unsigned int stackSize
Definition: epicsThread.h:154
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
Definition: osdThread.c:707
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetId(const char *name)
Definition: osdThread.c:826
#define checkStatus(status, message)
Definition: osdThread.c:87
Extended replacement for the Posix exit and atexit routines.
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Definition: osdThread.c:664
LIBCOM_API void epicsEventDestroy(epicsEventId id)
Destroy an epicsEvent and any resources it holds.
Definition: osdEvent.c:70
LIBCOM_API void epicsStdCall epicsThreadShow(epicsThreadId showThread, unsigned int level)
Definition: osdThread.c:903
LIBCOM_API int epicsStdCall epicsThreadIsSuspended(epicsThreadId pthreadInfo)
Definition: osdThread.c:784
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
int minPriority
Definition: osdThread.c:65
struct sched_param schedParam
Definition: osdThread.c:63
LIBCOM_API void epicsStdCall epicsThreadResume(epicsThreadOSD *pthreadInfo)
Definition: osdThread.c:676
APIs for the epicsEvent binary semaphore.
epics::pvData::PVStructurePtr dummy
Definition: pvAccess.cpp:72
LIBCOM_API void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func)
Definition: osdThread.c:864
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT(int *pTarget)
LIBCOM_API void osdThreadHooksRunMain(epicsThreadId id)
pthread_attr_t attr
Definition: osdThread.h:28
char name[1]
Definition: osdThread.h:40
EPICSTHREADFUNC createFunc
Definition: osdThread.h:31
int isOnThreadList
Definition: osdThread.h:37
unsigned int priority
Definition: epicsThread.h:150
LIBCOM_API void epicsStdCall epicsThreadShowAll(unsigned int level)
Definition: osdThread.c:883
#define checkStatusOnce(status, message)
Definition: osdThread.c:102
#define EPICS_THREAD_OPTS_INIT
Definition: epicsThread.h:167
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT(int *pTarget)
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
LIBCOM_API void epicsExitCallAtExits(void)
Internal routine that runs the registered exit routines.
Definition: epicsExit.c:102
LIBCOM_API pthread_t epicsThreadGetPosixThreadId(epicsThreadId threadId)
Definition: osdThread.c:821
Defined by POSIX Real Time.
Definition: osdTime.h:21
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPriority(epicsThreadId pthreadInfo)
Definition: osdThread.c:701
void epicsThreadMustJoin(epicsThreadId id)
Definition: osdThread.c:632
Routines for code that can&#39;t continue or return after an error.
#define stderr
Definition: epicsStdio.h:32
LIBCOM_API void osdThreadHooksRun(epicsThreadId id)
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810
#define checkStatusQuit(status, message, method)
Definition: osdThread.c:92
LIBCOM_API void epicsStdCall epicsThreadSetPriority(epicsThreadId pthreadInfo, unsigned int priority)
Definition: osdThread.c:713
List header type.
Definition: ellLib.h:56
#define checkStatusOnceQuit(status, message, method)
Definition: osdThread.c:106
C++ and C descriptions for a thread.
LIBCOM_API void epicsStdCall epicsThreadPrivateDelete(epicsThreadPrivateId id)
Definition: osdThread.c:950
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
LIBCOM_API epicsEventId epicsEventCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code, or return NULL.
Definition: osdEvent.c:47
void(* EPICSTHREADFUNC)(void *parm)
Definition: epicsThread.h:66
#define EPICS_THREAD_ONCE_DONE
#define STACK_SIZE(f)
Definition: osdThread.c:463
LIBCOM_API const char epicsStdCall * epicsThreadGetNameSelf()
Definition: osdThread.c:846
LIBCOM_API int epicsStdCall epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
Definition: osdThread.c:776
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
LIBCOM_API void epicsStdCall epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
Definition: osdThread.c:857