This is Unofficial EPICS BASE Doxygen Site
osdThread.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Saskatchewan
3 * EPICS BASE is distributed subject to a Software License Agreement found
4 * in file LICENSE that is included with this distribution.
5 \*************************************************************************/
6 /*
7  * RTEMS osdThread.c
8  * Author: W. Eric Norum
9  */
10 
11 /*
12  * We want to print out some task information which is
13  * normally hidden from application programs.
14  */
15 #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
16 
17 #include <stddef.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <stddef.h>
21 #include <stdio.h>
22 #include <assert.h>
23 #include <syslog.h>
24 #include <limits.h>
25 #include <pthread.h>
26 
27 #include <rtems.h>
28 #include <rtems/error.h>
29 
30 #include "epicsStdio.h"
31 #include "errlog.h"
32 #include "epicsMutex.h"
33 #include "epicsString.h"
34 #include "epicsThread.h"
35 #include "cantProceed.h"
36 #include "osiUnistd.h"
37 #include "osdInterrupt.h"
38 #include "epicsExit.h"
39 #include "epicsAtomic.h"
40 
41 LIBCOM_API void osdThreadHooksRun(epicsThreadId id);
42 LIBCOM_API void osdThreadHooksRunMain(epicsThreadId id);
43 
44 /*
45  * Per-task variables
46  */
47 struct taskVar {
48  struct taskVar *forw;
49  struct taskVar *back;
50  char *name;
51  rtems_id id;
52  rtems_id join_barrier; /* only valid if joinable */
53  int refcnt;
54  int joinable;
56  void *parm;
57  unsigned int threadVariableCapacity;
59 };
60 static struct epicsMutexOSD *taskVarMutex;
61 static struct taskVar *taskVarHead;
62 #define RTEMS_NOTEPAD_TASKVAR 11
63 
64 /*
65  * Support for `once-only' execution
66  */
67 static volatile int initialized = 0; /* strictly speaking 'volatile' is not enough here, but it shouldn't hurt */
68 static struct epicsMutexOSD *onceMutex;
69 
70 static
71 void epicsMutexOsdMustLock(struct epicsMutexOSD * L)
72 {
74  cantProceed("epicsThreadOnce() mutex error");
75  }
76 }
77 
78 /*
79  * Just map osi 0 to 99 into RTEMS 199 to 100
80  * For RTEMS lower number means higher priority
81  * RTEMS = 100 + (99 - osi)
82  * = 199 - osi
83  * osi = 199 - RTEMS
84  */
85 int epicsThreadGetOsiPriorityValue(int ossPriority)
86 {
87  if (ossPriority < 100) {
89  }
90  else if (ossPriority > 199) {
92  }
93  else {
94  return (199u - (unsigned int)ossPriority);
95  }
96 }
97 
98 int epicsThreadGetOssPriorityValue(unsigned int osiPriority)
99 {
100  if (osiPriority > 99) {
101  return 100;
102  }
103  else {
104  return (199 - (signed int)osiPriority);
105  }
106 }
107 
108 /*
109  * epicsThreadLowestPriorityLevelAbove ()
110  */
112  (unsigned int priority, unsigned *pPriorityJustAbove)
113 {
114  unsigned newPriority = priority + 1;
115 
116  newPriority = priority + 1;
117  if (newPriority <= 99) {
118  *pPriorityJustAbove = newPriority;
120  }
122 }
123 
124 /*
125  * epicsThreadHighestPriorityLevelBelow ()
126  */
128  (unsigned int priority, unsigned *pPriorityJustBelow)
129 {
130  unsigned newPriority = priority - 1;
131 
132  if (newPriority <= 99) {
133  *pPriorityJustBelow = newPriority;
135  }
137 }
138 
139 unsigned int
141 {
142  unsigned int stackSize = 11000;
143  switch(size) {
144  case epicsThreadStackSmall: stackSize = 5000; break;
145  case epicsThreadStackMedium: stackSize = 8000; break;
146  case epicsThreadStackBig: break;
147  default:
148  errlogPrintf("epicsThreadGetStackSize illegal argument");
149  break;
150  }
151  if (stackSize < RTEMS_MINIMUM_STACK_SIZE)
152  stackSize = RTEMS_MINIMUM_STACK_SIZE;
153  return stackSize;
154 }
155 
156 /*
157  * Ensure integrity of task variable list
158  */
159 static void
160 taskVarLock (void)
161 {
162  epicsMutexOsdMustLock (taskVarMutex);
163 }
164 
165 static void
166 taskVarUnlock (void)
167 {
168  epicsMutexOsdUnlock (taskVarMutex);
169 }
170 
171 static
172 void taskUnref(struct taskVar *v)
173 {
174  int ref = epicsAtomicDecrIntT(&v->refcnt);
175  assert(ref>=0);
176  if(ref>0) return;
177 
178 
179  if (v->joinable) {
180  rtems_barrier_delete(v->join_barrier);
181  }
182  free (v->threadVariables);
183  free (v->name);
184  free (v);
185 }
186 
187 /*
188  * EPICS threads destroy themselves by returning from the thread entry function.
189  * This simple wrapper provides the same semantics on RTEMS.
190  */
191 static rtems_task
192 threadWrapper (rtems_task_argument arg)
193 {
194  struct taskVar *v = (struct taskVar *)arg;
195 
197  (*v->funptr)(v->parm);
199  taskVarLock ();
200  if (v->back)
201  v->back->forw = v->forw;
202  else
203  taskVarHead = v->forw;
204  if (v->forw)
205  v->forw->back = v->back;
206  taskVarUnlock ();
207  if(v->joinable) {
208  rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT);
209  if(sc!=RTEMS_SUCCESSFUL)
210  cantProceed("oops %s\n", rtems_status_text(sc));
211  }
212  taskUnref(v);
213  rtems_task_delete (RTEMS_SELF);
214 }
215 
216 /*
217  * The task wrapper takes care of cleanup
218  */
220 {
221 }
222 
223 static rtems_status_code
224 setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr,
225  void *parm, int joinable)
226 {
227  struct taskVar *v;
228  uint32_t note;
229  rtems_status_code sc = RTEMS_SUCCESSFUL;
230 
231  v = mallocMustSucceed (sizeof *v, "epicsThreadCreate_vars");
232  v->name = epicsStrDup(name);
233  v->id = tid;
234  v->funptr = funptr;
235  v->parm = parm;
236  v->joinable = joinable;
237  v->refcnt = joinable ? 2 : 1;
238  v->threadVariableCapacity = 0;
239  v->threadVariables = NULL;
240  if (joinable) {
241  char c[3];
242  strncpy(c, v->name, 3);
243  sc = rtems_barrier_create(rtems_build_name('~', c[0], c[1], c[2]),
244  RTEMS_BARRIER_AUTOMATIC_RELEASE | RTEMS_LOCAL,
245  2, &v->join_barrier);
246  if (sc != RTEMS_SUCCESSFUL) {
247  free(v);
248  return sc;
249  }
250  }
251  note = (uint32_t)v;
252  rtems_task_set_note (tid, RTEMS_NOTEPAD_TASKVAR, note);
253  taskVarLock ();
254  v->forw = taskVarHead;
255  v->back = NULL;
256  if (v->forw)
257  v->forw->back = v;
258  taskVarHead = v;
259  taskVarUnlock ();
260  if (funptr) {
261  sc = rtems_task_start (tid, threadWrapper, (rtems_task_argument)v);
262  }
263  if (sc != RTEMS_SUCCESSFUL) {
264  if (joinable) {
265  rtems_barrier_delete(v->join_barrier);
266  }
267  free(v);
268  }
269  return sc;
270 }
271 
272 /*
273  * OS-dependent initialization
274  * No need to worry about making this thread-safe since
275  * it must be called before epicsThreadCreate creates
276  * any new threads.
277  */
278 static void
279 epicsThreadInit (void)
280 {
281  if (!initialized) {
282  rtems_id tid;
283  rtems_task_priority old;
284 
285  rtems_task_set_priority (RTEMS_SELF, epicsThreadGetOssPriorityValue(99), &old);
286  onceMutex = epicsMutexOsdCreate();
287  taskVarMutex = epicsMutexOsdCreate();
288  if (!onceMutex || !taskVarMutex)
289  cantProceed("epicsThreadInit() can't create global mutexes\n");
290  rtems_task_ident (RTEMS_SELF, 0, &tid);
291  if(setThreadInfo (tid, "_main_", NULL, NULL, 0) != RTEMS_SUCCESSFUL)
292  cantProceed("epicsThreadInit() unable to setup _main_");
294  initialized = 1;
295  epicsThreadCreate ("ImsgDaemon", 99,
298  }
299 }
300 
302 {}
303 
304 /*
305  * Create and start a new thread
306  */
309  const char * name,
310  EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts )
311 {
312  unsigned int stackSize;
313  rtems_id tid;
314  rtems_status_code sc;
315  char c[4];
316 
317  if (!initialized)
318  epicsThreadInit();
319 
320  if (!opts) {
321  static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT;
322  opts = &opts_default;
323  }
324  stackSize = opts->stackSize;
325  if (stackSize <= epicsThreadStackBig)
326  stackSize = epicsThreadGetStackSize(stackSize);
327 
328  if (stackSize < RTEMS_MINIMUM_STACK_SIZE) {
329  errlogPrintf ("Warning: epicsThreadCreate %s illegal stackSize %d\n",
330  name, stackSize);
331  stackSize = RTEMS_MINIMUM_STACK_SIZE;
332  }
333  strncpy (c, name, sizeof c);
334  sc = rtems_task_create (rtems_build_name (c[0], c[1], c[2], c[3]),
336  stackSize,
337  RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
338  RTEMS_FLOATING_POINT|RTEMS_LOCAL,
339  &tid);
340  if (sc != RTEMS_SUCCESSFUL) {
341  errlogPrintf ("epicsThreadCreate create failure for %s: %s\n",
342  name, rtems_status_text(sc));
343  return 0;
344  }
345  sc = setThreadInfo (tid, name, funptr, parm, opts->joinable);
346  if (sc != RTEMS_SUCCESSFUL) {
347  errlogPrintf ("epicsThreadCreate create failure during setup for %s: %s\n",
348  name, rtems_status_text(sc));
349  rtems_task_delete(tid);
350  return 0;
351  }
352  return (epicsThreadId)tid;
353 }
354 
356 threadMustCreate (const char *name,
357  unsigned int priority, unsigned int stackSize,
358  EPICSTHREADFUNC funptr,void *parm)
359 {
360  epicsThreadId tid = epicsThreadCreate(name, priority, stackSize, funptr, parm);
361 
362  if (tid == NULL)
363  cantProceed(0);
364  return tid;
365 }
366 
368 {
369  rtems_id target_tid = (rtems_id)id, self_tid;
370  struct taskVar *v = 0;
371 
372  rtems_task_ident (RTEMS_SELF, 0, &self_tid);
373 
374  {
375  uint32_t note;
376  rtems_task_get_note (target_tid, RTEMS_NOTEPAD_TASKVAR, &note);
377  v = (void *)note;
378  }
379  /* 'v' may be NULL if 'id' represents a non-EPICS thread other than _main_. */
380 
381  if(!v || !v->joinable) {
382  if(epicsThreadGetIdSelf()==id) {
383  errlogPrintf("Warning: %s thread self-join of unjoinable\n", v ? v->name : "non-EPICS thread");
384 
385  } else {
386  /* try to error nicely, however in all likelyhood de-ref of
387  * 'id' has already caused SIGSEGV as we are racing thread exit,
388  * which free's 'id'.
389  */
390  cantProceed("Error: %s thread not joinable.\n", v->name);
391  }
392  return;
393 
394  } else if(target_tid!=self_tid) {
395  /* wait for target to complete */
396  rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT);
397  if(sc!=RTEMS_SUCCESSFUL)
398  cantProceed("oopsj %s\n", rtems_status_text(sc));
399 
400  if(sc != RTEMS_SUCCESSFUL) {
401  errlogPrintf("epicsThreadMustJoin('%s') -> %s\n", v->name, rtems_status_text(sc));
402  }
403  }
404 
405  v->joinable = 0;
406  taskUnref(v);
407  /* target task may be deleted.
408  * self task is not deleted, even for self join.
409  */
410 }
411 
412 void
414 {
415  rtems_status_code sc;
416 
417  sc = rtems_task_suspend (RTEMS_SELF);
418  if (sc != RTEMS_SUCCESSFUL)
419  errlogPrintf("epicsThreadSuspendSelf failed: %s\n",
420  rtems_status_text(sc));
421 }
422 
424 {
425  rtems_id tid = (rtems_id)id;
426  rtems_status_code sc;
427 
428  sc = rtems_task_resume (tid);
429  if (sc != RTEMS_SUCCESSFUL)
430  errlogPrintf("epicsThreadResume failed: %s\n",
431  rtems_status_text (sc));
432 }
433 
435 {
436  rtems_id tid = (rtems_id)id;
437  rtems_status_code sc;
438  rtems_task_priority pri;
439 
440  sc = rtems_task_set_priority (tid, RTEMS_CURRENT_PRIORITY, &pri);
441  if (sc != RTEMS_SUCCESSFUL)
442  errlogPrintf("epicsThreadGetPriority failed: %s\n",
443  rtems_status_text(sc));
444  return epicsThreadGetOsiPriorityValue(pri);
445 }
446 
447 unsigned int epicsThreadGetPrioritySelf(void)
448 {
449  return epicsThreadGetPriority((epicsThreadId)RTEMS_SELF);
450 }
451 
452 void
453 epicsThreadSetPriority (epicsThreadId id,unsigned int osip)
454 {
455  rtems_id tid = (rtems_id)id;
456  rtems_status_code sc;
457  rtems_task_priority pri = epicsThreadGetOssPriorityValue(osip);
458 
459  sc = rtems_task_set_priority (tid, pri, &pri);
460  if (sc != RTEMS_SUCCESSFUL)
461  errlogPrintf("epicsThreadSetPriority failed: %s\n",
462  rtems_status_text(sc));
463 }
464 
465 int
467 {
468  return (id1 == id2);
469 }
470 
471 int
473 {
474  rtems_id tid = (rtems_id)id;
475  rtems_status_code sc;
476 
477  switch (sc = rtems_task_is_suspended (tid)) {
478  case RTEMS_SUCCESSFUL:
479  return 0;
480 
481  case RTEMS_ALREADY_SUSPENDED:
482  return 1;
483 
484  default:
485  return 1;
486  }
487 }
488 
489 void
490 epicsThreadSleep (double seconds)
491 {
492  rtems_status_code sc;
493  rtems_interval delay;
494  extern double rtemsTicksPerSecond_double;
495 
496  if (seconds > 0.0) {
497  seconds *= rtemsTicksPerSecond_double;
498  seconds += 0.99999999; /* 8 9s here is optimal */
499  delay = (seconds >= INT_MAX) ? INT_MAX : (int) seconds;
500  }
501  else { /* seconds <= 0 or NAN */
502  delay = 0;
503  }
504  sc = rtems_task_wake_after (delay);
505  if(sc != RTEMS_SUCCESSFUL)
506  errlogPrintf("epicsThreadSleep: %s\n", rtems_status_text(sc));
507 }
508 
511 {
512  rtems_id tid;
513 
514  rtems_task_ident (RTEMS_SELF, 0, &tid);
515  return (epicsThreadId)tid;
516 }
517 
518 const char *epicsThreadGetNameSelf(void)
519 {
520  uint32_t note;
521  struct taskVar *v;
522 
523  rtems_task_get_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, &note);
524  v = (void *)note;
525  return v->name;
526 }
527 
528 void epicsThreadGetName (epicsThreadId id, char *name, size_t size)
529 {
530  rtems_id tid = (rtems_id)id;
531  struct taskVar *v;
532  int haveName = 0;
533 
534  taskVarLock ();
535  for (v=taskVarHead ; v != NULL ; v=v->forw) {
536  if (v->id == tid) {
537  strncpy(name, v->name, size);
538  haveName = 1;
539  break;
540  }
541  }
542  taskVarUnlock ();
543  if (!haveName) {
544 #if (__RTEMS_MAJOR__>4 || \
545  (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>8) || \
546  (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==8 && __RTEMS_REVISION__>=99))
547  if (_Objects_Get_name_as_string((rtems_id)id, size, name) != NULL)
548  haveName = 1;
549 #else
550  /*
551  * Try to get the RTEMS task name
552  */
553  Thread_Control *thr;
554  Objects_Locations l;
555  if ((thr=_Thread_Get(tid, &l)) != NULL) {
556  if (OBJECTS_LOCAL == l) {
557  int length;
558  Objects_Information *oi = _Objects_Get_information(tid);
559  if (oi->name_length >= size)
560  length = size - 1;
561  else
562  length = oi->name_length;
563  if (oi->is_string)
564  strncpy(name, thr->Object.name, length);
565  else
566  _Objects_Copy_name_raw( &thr->Object.name, name, length);
567  name[length] = '\0';
568  haveName = 1;
569  }
570  _Thread_Enable_dispatch();
571  }
572 #endif
573  }
574  if (!haveName)
575  snprintf(name, size, "0x%lx", (long)tid);
576  name[size-1] = '\0';
577 }
578 
579 epicsThreadId epicsThreadGetId (const char *name)
580 {
581  struct taskVar *v;
582  rtems_id tid = 0;
583 
584  /*
585  * Linear search is good enough since this routine
586  * is invoked only by command-line calls.
587  */
588  taskVarLock ();
589  for (v = taskVarHead ; v != NULL ; v = v->forw) {
590  if (strcmp (name, v->name) == 0) {
591  tid = v->id;
592  break;
593  }
594  }
595  taskVarUnlock ();
596  return (epicsThreadId)tid;
597 }
598 
599 /*
600  * Ensure func() is run only once.
601  */
602 void epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
603 {
604  #define EPICS_THREAD_ONCE_DONE (epicsThreadId) 1
605 
606  if (!initialized) epicsThreadInit();
607  epicsMutexOsdMustLock(onceMutex);
608  if (*id != EPICS_THREAD_ONCE_DONE) {
609  if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
610  *id = epicsThreadGetIdSelf(); /* mark active */
611  epicsMutexOsdUnlock(onceMutex);
612  func(arg);
613  epicsMutexOsdMustLock(onceMutex);
614  *id = EPICS_THREAD_ONCE_DONE; /* mark done */
615  } else if (*id == epicsThreadGetIdSelf()) {
616  epicsMutexOsdUnlock(onceMutex);
617  cantProceed("Recursive epicsThreadOnce() initialization\n");
618  } else
619  while (*id != EPICS_THREAD_ONCE_DONE) {
620  /* Another thread is in the above func(arg) call. */
621  epicsMutexOsdUnlock(onceMutex);
623  epicsMutexOsdMustLock(onceMutex);
624  }
625  }
626  epicsMutexOsdUnlock(onceMutex);
627 }
628 
629 /*
630  * Thread private storage implementation based on the vxWorks
631  * implementation by Andrew Johnson APS/ASD.
632  */
634 {
635  unsigned int taskVarIndex;
636  static volatile unsigned int threadVariableCount = 0;
637 
638  if (!initialized) epicsThreadInit ();
639  taskVarLock ();
640  taskVarIndex = ++threadVariableCount;
641  taskVarUnlock ();
642  return (epicsThreadPrivateId)taskVarIndex;
643 }
644 
646 {
647  /* empty */
648 }
649 
651 {
652  unsigned int varIndex = (unsigned int)id;
653  uint32_t note;
654  struct taskVar *v;
655  int i;
656 
657  rtems_task_get_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, &note);
658  v = (struct taskVar *)note;
659  if (varIndex >= v->threadVariableCapacity) {
660  v->threadVariables = realloc (v->threadVariables,
661  (varIndex + 1) * sizeof(void *));
662  if (v->threadVariables == NULL)
663  cantProceed("epicsThreadPrivateSet realloc failed\n");
664  for (i = v->threadVariableCapacity ; i < varIndex ; i++)
665  v->threadVariables[i] = NULL;
666  v->threadVariableCapacity = varIndex + 1;
667  }
668  v->threadVariables[varIndex] = pvt;
669 }
670 
672 {
673  unsigned int varIndex = (unsigned int)id;
674  uint32_t note;
675  struct taskVar *v;
676 
677  rtems_task_get_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, &note);
678  v = (struct taskVar *)note;
679  if (varIndex >= v->threadVariableCapacity)
680  return NULL;
681  return v->threadVariables[varIndex];
682 }
683 
684 /*
685  * Show task info
686  */
687 struct bitmap {
688  char *msg;
689  unsigned long mask;
690  unsigned long state;
691 };
692 
693 static void
694 showBitmap (char *cbuf, unsigned long bits, const struct bitmap *bp)
695 {
696  for ( ; bp->msg != NULL ; bp++) {
697  if ((bp->mask & bits) == bp->state) {
698  strcpy (cbuf, bp->msg);
699  cbuf += strlen (bp->msg);
700  }
701  }
702 }
703 
704 static void
705 showInternalTaskInfo (rtems_id tid)
706 {
707 #ifdef __RTEMS_VIOLATE_KERNEL_VISIBILITY__
708  int epicsPri;
709  Thread_Control *the_thread;
710  Objects_Locations location;
711  static Thread_Control thread;
712  static char bitbuf[120];
713  static const struct bitmap taskState[] = {
714  { "RUN", STATES_ALL_SET, STATES_READY },
715  { "DORM", STATES_DORMANT, STATES_DORMANT },
716  { "SUSP", STATES_SUSPENDED, STATES_SUSPENDED },
717  { "TRANS", STATES_TRANSIENT, STATES_TRANSIENT },
718  { "Delay", STATES_DELAYING, STATES_DELAYING },
719  { "Wtime", STATES_WAITING_FOR_TIME, STATES_WAITING_FOR_TIME },
720  { "Wbuf", STATES_WAITING_FOR_BUFFER, STATES_WAITING_FOR_BUFFER },
721  { "Wseg", STATES_WAITING_FOR_SEGMENT, STATES_WAITING_FOR_SEGMENT },
722  { "Wmsg" , STATES_WAITING_FOR_MESSAGE, STATES_WAITING_FOR_MESSAGE },
723  { "Wevnt", STATES_WAITING_FOR_EVENT, STATES_WAITING_FOR_EVENT },
724  { "Wsem", STATES_WAITING_FOR_SEMAPHORE,STATES_WAITING_FOR_SEMAPHORE },
725  { "Wmtx", STATES_WAITING_FOR_MUTEX, STATES_WAITING_FOR_MUTEX },
726  { "Wjoin", STATES_WAITING_FOR_JOIN_AT_EXIT,STATES_WAITING_FOR_JOIN_AT_EXIT },
727  { "Wrpc", STATES_WAITING_FOR_RPC_REPLY,STATES_WAITING_FOR_RPC_REPLY },
728  { "Wrate", STATES_WAITING_FOR_PERIOD, STATES_WAITING_FOR_PERIOD },
729  { "Wsig", STATES_WAITING_FOR_SIGNAL, STATES_WAITING_FOR_SIGNAL },
730  { NULL, 0, 0 },
731  };
732 
733  the_thread = _Thread_Get (tid, &location);
734  if (location != OBJECTS_LOCAL) {
735  fprintf(epicsGetStdout(),"%-30s", " *** RTEMS task gone! ***");
736  return;
737  }
738  thread = *the_thread;
739  _Thread_Enable_dispatch();
740 
741  /* This looks a bit weird, but it has to support RTEMS versions both before
742  * and after 4.10.2 when threads changed how their priorities are stored.
743  */
744  int policy;
745  struct sched_param sp;
746  rtems_task_priority real_priority, current_priority;
747  rtems_status_code sc = pthread_getschedparam(tid, &policy, &sp);
748  if (sc == RTEMS_SUCCESSFUL) {
749  real_priority = sp.sched_priority;
750  sc = rtems_task_set_priority(tid, RTEMS_CURRENT_PRIORITY, &current_priority);
751  }
752  if (sc != RTEMS_SUCCESSFUL) {
753  fprintf(epicsGetStdout(),"%-30s", " *** RTEMS task gone! ***");
754  return;
755  }
756 
757  /*
758  * Show both real and current priorities if they differ.
759  * Note that the epicsThreadGetOsiPriorityValue routine is not used here.
760  * If a thread has a priority outside the normal EPICS range then
761  * that priority should be displayed, not the value truncated to
762  * the EPICS range.
763  */
764  epicsPri = 199-real_priority;
765  if (epicsPri < 0)
766  fprintf(epicsGetStdout()," <0");
767  else if (epicsPri > 99)
768  fprintf(epicsGetStdout()," >99");
769  else
770  fprintf(epicsGetStdout()," %4d", epicsPri);
771  if (current_priority == real_priority)
772  fprintf(epicsGetStdout(),"%4d ", (int)current_priority);
773  else
774  fprintf(epicsGetStdout(),"%4d/%-3d", (int)real_priority, (int)current_priority);
775  showBitmap (bitbuf, thread.current_state, taskState);
776  fprintf(epicsGetStdout(),"%8.8s", bitbuf);
777  if (thread.current_state & (STATES_WAITING_FOR_SEMAPHORE |
778  STATES_WAITING_FOR_MUTEX |
779  STATES_WAITING_FOR_MESSAGE))
780  fprintf(epicsGetStdout()," %8.8x", (int)thread.Wait.id);
781  else
782  fprintf(epicsGetStdout()," %8.8s", "");
783 #endif
784 }
785 
786 static void
787 epicsThreadShowInfo (struct taskVar *v, unsigned int level)
788 {
789  if (!v) {
790  fprintf(epicsGetStdout()," PRIORITY\n");
791  fprintf(epicsGetStdout()," ID EPICS RTEMS STATE WAIT NAME\n");
792  fprintf(epicsGetStdout(),"+--------+-----------+--------+--------+---------------------+\n");
793  } else {
794  fprintf(epicsGetStdout(),"%9.8x", (int)v->id);
795  showInternalTaskInfo (v->id);
796  fprintf(epicsGetStdout()," %s\n", v->name);
797  }
798 }
799 
800 void epicsThreadShow (epicsThreadId id, unsigned int level)
801 {
802  struct taskVar *v;
803 
804  if (!id) {
805  epicsThreadShowInfo (NULL, level);
806  return;
807  }
808  taskVarLock ();
809  for (v = taskVarHead ; v != NULL ; v = v->forw) {
810  if ((rtems_id)id == v->id) {
811  epicsThreadShowInfo (v, level);
812  taskVarUnlock ();
813  return;
814  }
815  }
816  taskVarUnlock ();
817  fprintf(epicsGetStdout(),"*** Thread %x does not exist.\n", (unsigned int)id);
818 }
819 
821 {
822  struct taskVar *v;
823 
824  taskVarLock ();
825  /*
826  * Map tasks in the order of creation (backwards through list)
827  */
828  for (v = taskVarHead ; v != NULL && v->forw != NULL ; v = v->forw)
829  continue;
830  while (v) {
831  func ((epicsThreadId)v->id);
832  v = v->back;
833  }
834  taskVarUnlock ();
835 }
836 
837 void epicsThreadShowAll (unsigned int level)
838 {
839  struct taskVar *v;
840 
841  epicsThreadShowInfo (NULL, level);
842  taskVarLock ();
843  /*
844  * Show tasks in the order of creation (backwards through list)
845  */
846  for (v = taskVarHead ; v != NULL && v->forw != NULL ; v = v->forw)
847  continue;
848  while (v) {
849  epicsThreadShowInfo (v, level);
850  v = v->back;
851  }
852  taskVarUnlock ();
853 }
854 
855 double epicsThreadSleepQuantum ( void )
856 {
857  extern double rtemsTicksPerSecond_double;
858 
859  return 1.0 / rtemsTicksPerSecond_double;
860 }
861 
862 LIBCOM_API int epicsThreadGetCPUs(void)
863 {
864 #if defined(RTEMS_SMP)
865  return rtems_smp_get_number_of_processors();
866 #else
867  return 1;
868 #endif
869 }
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
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
epicsThreadId threadMustCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: osdThread.c:356
LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
Definition: osdThread.c:683
int epicsThreadGetOsiPriorityValue(int ossPriority)
Definition: osdThread.c:85
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
epicsThreadBooleanStatus
Definition: epicsThread.h:93
#define RTEMS_NOTEPAD_TASKVAR
Definition: osdThread.c:62
LIBCOM_API void epicsExitCallAtThreadExits(void)
Internal routine that runs the registered thread exit routines.
Definition: epicsExit.c:121
int i
Definition: scan.c:967
unsigned long mask
Definition: osdThread.c:689
struct taskVar * forw
Definition: osdThread.c:48
void InterruptContextMessageDaemon(void *unused)
Definition: osdInterrupt.c:64
LIBCOM_API void epicsThreadRealtimeLock(void)
Definition: osdThread.c:425
rtems_id join_barrier
Definition: osdThread.c:52
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
rtems_id id
Definition: osdThread.c:51
#define NULL
Definition: catime.c:38
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadLowestPriorityLevelAbove(unsigned int priority, unsigned *pPriorityJustAbove)
Definition: osdThread.c:757
unsigned int joinable
Definition: epicsThread.h:158
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId id, void *value)
Definition: osdThread.c:961
LIBCOM_API void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level)
EPICSTHREADFUNC funptr
Definition: osdThread.c:55
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
Definition: osdThread.c:487
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
double rtemsTicksPerSecond_double
Definition: osdTime.cpp:143
FILE *epicsStdCall epicsGetStdout(void)
Definition: epicsStdio.c:47
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
epicsThreadStackSizeClass
Definition: epicsThread.h:89
int epicsThreadGetOssPriorityValue(unsigned int osiPriority)
Definition: osdThread.c:98
#define epicsThreadPriorityMax
Definition: epicsThread.h:71
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
int joinable
Definition: osdThread.c:54
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
Definition: osdThread.c:707
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetId(const char *name)
Definition: osdThread.c:826
Extended replacement for the Posix exit and atexit routines.
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Definition: osdThread.c:664
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
LIBCOM_API void epicsStdCall epicsThreadResume(epicsThreadOSD *pthreadInfo)
Definition: osdThread.c:676
char * epicsStrDup(const char *s)
Definition: epicsString.c:233
void ** threadVariables
Definition: osdThread.c:58
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)
LIBCOM_API void * mallocMustSucceed(size_t size, const char *msg)
A malloc() that never returns NULL.
Definition: cantProceed.c:38
int snprintf(char *str, size_t size, const char *format,...)
unsigned int priority
Definition: epicsThread.h:150
LIBCOM_API void epicsStdCall epicsThreadShowAll(unsigned int level)
Definition: osdThread.c:883
#define EPICS_THREAD_OPTS_INIT
Definition: epicsThread.h:167
#define EPICS_THREAD_ONCE_DONE
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
#define epicsMutexOsdUnlock(ID)
Definition: osdMutex.h:22
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPriority(epicsThreadId pthreadInfo)
Definition: osdThread.c:701
void epicsThreadMustJoin(epicsThreadId id)
Definition: osdThread.c:632
#define epicsMutexOsdLock(ID)
Definition: osdMutex.h:24
Routines for code that can&#39;t continue or return after an error.
LIBCOM_API void osdThreadHooksRun(epicsThreadId id)
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810
struct taskVar * back
Definition: osdThread.c:49
LIBCOM_API void epicsStdCall epicsThreadSetPriority(epicsThreadId pthreadInfo, unsigned int priority)
Definition: osdThread.c:713
unsigned int threadVariableCapacity
Definition: osdThread.c:57
C++ and C descriptions for a thread.
LIBCOM_API void epicsStdCall epicsThreadPrivateDelete(epicsThreadPrivateId id)
Definition: osdThread.c:950
#define epicsThreadPriorityMin
Definition: epicsThread.h:72
void(* EPICSTHREADFUNC)(void *parm)
Definition: epicsThread.h:66
char * name
Definition: osdThread.c:50
int refcnt
Definition: osdThread.c:53
char * msg
Definition: osdThread.c:688
void * parm
Definition: osdThread.c:56
LIBCOM_API const char epicsStdCall * epicsThreadGetNameSelf()
Definition: osdThread.c:846
LIBCOM_API int epicsStdCall epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
Definition: osdThread.c:776
unsigned long state
Definition: osdThread.c:690
LIBCOM_API void epicsStdCall epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
Definition: osdThread.c:857