This is Unofficial EPICS BASE Doxygen Site
epicsGeneralTime.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2008 Diamond Light Source Ltd
5 * Copyright (c) 2004 Oak Ridge National Laboratory
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /* Original Authors: David H. Thompson & Sheng Peng (ORNL) */
11 
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #include "epicsTypes.h"
16 #include "epicsEvent.h"
17 #include "epicsMutex.h"
18 #include "epicsMessageQueue.h"
19 #include "epicsString.h"
20 #include "epicsStdioRedirect.h"
21 #include "epicsThread.h"
22 #include "epicsTime.h"
23 #include "epicsTimer.h"
24 #include "epicsInterrupt.h"
25 #include "osiSock.h"
26 #include "ellLib.h"
27 #include "errlog.h"
28 #include "cantProceed.h"
29 #include "envDefs.h"
30 #include "generalTimeSup.h"
31 #include "epicsGeneralTime.h"
32 
33 /* Change 'undef' to 'define' to turn on debug statements: */
34 #undef DEBUG_GENERAL_TIME
35 
36 #ifdef DEBUG_GENERAL_TIME
37  int generalTimeDebug = 10;
38 # define IFDEBUG(n) \
39  if (generalTimeDebug >= n) /* block or statement */
40 #else
41 # define IFDEBUG(n) \
42  if(0) /* Compiler will elide the block or statement */
43 #endif
44 
45 /* Declarations */
46 
47 typedef struct {
49  char *name;
50  int priority;
51  union {
54  } get;
55  union {
56  TIMECURRENTFUN Time;
57  TIMEEVENTFUN Event;
58  } getInt;
59 } gtProvider;
60 
61 static struct {
66 
72 
74 } gtPvt;
75 
77 
78 static const char * const tsfmt = "%Y-%m-%d %H:%M:%S.%09f";
79 
80 /* defined in osiClockTime.c or osdTime.cpp */
81 int osdTimeGetCurrent ( epicsTimeStamp *pDest );
82 /* cleared if/when gtPvt.timeProviders contains more than the default osdTimeGetCurrent() */
83 static int useOsdGetCurrent = 1;
84 
85 /* Implementation */
86 
87 static void generalTime_InitOnce(void *dummy)
88 {
89  ellInit(&gtPvt.timeProviders);
90  gtPvt.timeListLock = epicsMutexMustCreate();
91 
92  ellInit(&gtPvt.eventProviders);
93  gtPvt.eventListLock = epicsMutexMustCreate();
94 
95  IFDEBUG(1)
96  printf("General Time Initialized\n");
97 }
98 
99 void generalTime_Init(void)
100 {
101  epicsThreadOnce(&onceId, generalTime_InitOnce, NULL);
102 }
103 
104 
105 int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int *pPrio, int ignore)
106 {
107  gtProvider *ptp;
109 
110  if(useOsdGetCurrent)
111  return osdTimeGetCurrent(pDest);
112 
114 
115  IFDEBUG(2)
116  printf("generalTimeGetExceptPriority(ignore=%d)\n", ignore);
117 
118  epicsMutexMustLock(gtPvt.timeListLock);
119  for (ptp = (gtProvider *)ellFirst(&gtPvt.timeProviders);
120  ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
121  if ((ignore > 0 && ptp->priority == ignore) ||
122  (ignore < 0 && ptp->priority != -ignore))
123  continue;
124 
125  status = ptp->get.Time(pDest);
126  if (status == epicsTimeOK) {
127  /* No ratchet, time from this routine may go backwards */
128  if (pPrio)
129  *pPrio = ptp->priority;
130  break;
131  }
132  else IFDEBUG(2)
133  printf("gTGExP provider '%s' returned error\n", ptp->name);
134  }
135  epicsMutexUnlock(gtPvt.timeListLock);
136 
137  IFDEBUG(2) {
138  if (ptp && status == epicsTimeOK) {
139  char buff[40];
140 
141  epicsTimeToStrftime(buff, sizeof(buff), tsfmt, pDest);
142  printf("gTGExP returning %s from provider '%s'\n",
143  buff, ptp->name);
144  }
145  else
146  printf("gTGExP returning error\n");
147  }
148 
149  return status;
150 }
151 
152 int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
153 {
154  gtProvider *ptp;
156  epicsTimeStamp ts;
157 
158  if(useOsdGetCurrent)
159  return osdTimeGetCurrent(pDest);
160 
162 
163  IFDEBUG(20)
164  printf("epicsTimeGetCurrent()\n");
165 
166  epicsMutexMustLock(gtPvt.timeListLock);
167  for (ptp = (gtProvider *)ellFirst(&gtPvt.timeProviders);
168  ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
169 
170  status = ptp->get.Time(&ts);
171  if (status == epicsTimeOK) {
172  /* check time is monotonic */
173  if (epicsTimeGreaterThanEqual(&ts, &gtPvt.lastProvidedTime)) {
174  *pDest = ts;
175  gtPvt.lastProvidedTime = ts;
176  gtPvt.lastTimeProvider = ptp;
177  } else {
178  int key;
179 
180  *pDest = gtPvt.lastProvidedTime;
181  key = epicsInterruptLock();
182  gtPvt.ErrorCounts++;
184 
185  IFDEBUG(10) {
186  char last[40], buff[40];
187 
188  epicsTimeToStrftime(last, sizeof(last), tsfmt,
189  &gtPvt.lastProvidedTime);
190  epicsTimeToStrftime(buff, sizeof(buff), tsfmt, &ts);
191  printf("eTGC provider '%s' returned older time\n"
192  " %s, using %s instead\n", ptp->name, buff, last);
193  }
194  }
195  break;
196  }
197  }
198  if (status)
199  gtPvt.lastTimeProvider = NULL;
200  epicsMutexUnlock(gtPvt.timeListLock);
201 
202  IFDEBUG(20) {
203  if (ptp && status == epicsTimeOK) {
204  char buff[40];
205 
206  epicsTimeToStrftime(buff, sizeof(buff), tsfmt, &ts);
207  printf("eTGC returning %s from provider '%s'\n",
208  buff, ptp->name);
209  }
210  else
211  printf("eTGC returning error\n");
212  }
213 
214  return status;
215 }
216 
218 {
220  pDest->nsec = now%1000000000ul;
221  pDest->secPastEpoch = now/1000000000ul;
222  return 0;
223 }
224 
226 {
227  gtProvider *ptp = gtPvt.lastTimeProvider;
228 
229  if (ptp == NULL ||
230  ptp->getInt.Time == NULL) {
231  IFDEBUG(20)
232  epicsInterruptContextMessage("eTGCInt: No support\n");
233  return S_time_noProvider;
234  }
235 
236  return ptp->getInt.Time(pDest);
237 }
238 
239 
240 static int generalTimeGetEventPriority(epicsTimeStamp *pDest, int eventNumber,
241  int *pPrio)
242 {
243  gtProvider *ptp;
245  epicsTimeStamp ts;
247 
249 
250  IFDEBUG(2)
251  printf("generalTimeGetEventPriority(eventNum=%d)\n", eventNumber);
252 
253  if (eventNumber < epicsTimeEventBestTime)
254  return S_time_badEvent;
255 
256  epicsMutexMustLock(gtPvt.eventListLock);
257  for (ptp = (gtProvider *)ellFirst(&gtPvt.eventProviders);
258  ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
259 
260  status = ptp->get.Event(&ts, eventNumber);
261  if (status == epicsTimeOK) {
262  gtPvt.lastEventProvider = ptp;
263  if (pPrio)
264  *pPrio = ptp->priority;
265 
266  if (eventNumber >= NUM_TIME_EVENTS) {
267  *pDest = ts;
268  } else if (eventNumber == epicsTimeEventBestTime) {
270  &gtPvt.lastProvidedBestTime)) {
271  *pDest = ts;
272  gtPvt.lastProvidedBestTime = ts;
273  } else {
274  int key;
275 
276  *pDest = gtPvt.lastProvidedBestTime;
277  key = epicsInterruptLock();
278  gtPvt.ErrorCounts++;
280 
281  IFDEBUG(10) {
282  char last[40], buff[40];
283 
284  epicsTimeToStrftime(last, sizeof(last), tsfmt,
285  &gtPvt.lastProvidedBestTime);
286  epicsTimeToStrftime(buff, sizeof(buff), tsfmt, &ts);
287  printf("gTGEvP provider '%s' returned older time\n"
288  " %s, using %s instead\n",
289  ptp->name, buff, last);
290  }
291  }
292  } else {
294  &gtPvt.eventTime[eventNumber])) {
295  *pDest = ts;
296  gtPvt.eventTime[eventNumber] = ts;
297  } else {
298  int key;
299 
300  *pDest = gtPvt.eventTime[eventNumber];
301  key = epicsInterruptLock();
302  gtPvt.ErrorCounts++;
304 
305  IFDEBUG(10) {
306  char last[40], buff[40];
307 
308  epicsTimeToStrftime(last, sizeof(last), tsfmt,
309  &gtPvt.lastProvidedBestTime);
310  epicsTimeToStrftime(buff, sizeof(buff), tsfmt, &ts);
311  printf("gTGEvP provider '%s' returned older time\n"
312  " %s, using %s instead\n",
313  ptp->name, buff, last);
314  }
315  }
316  }
317  break;
318  }
319  else IFDEBUG(2)
320  printf("gTGEvP provider '%s' returned error\n", ptp->name);
321  }
322  if (status)
323  gtPvt.lastEventProvider = NULL;
324  epicsMutexUnlock(gtPvt.eventListLock);
325 
326  IFDEBUG(10) {
327  if (ptp && status == epicsTimeOK) {
328  char buff[40];
329 
330  epicsTimeToStrftime(buff, sizeof(buff), tsfmt, &ts);
331  printf("gTGEvP returning %s from provider '%s'\n",
332  buff, ptp->name);
333  }
334  else
335  printf("gTGEvP returning error\n");
336  }
337 
338  return status;
339 }
340 
341 int epicsStdCall epicsTimeGetEvent(epicsTimeStamp *pDest, int eventNumber)
342 {
343  if (eventNumber == epicsTimeEventCurrentTime) {
344  return epicsTimeGetCurrent(pDest);
345  } else {
346  return generalTimeGetEventPriority(pDest, eventNumber, NULL);
347  }
348 }
349 
350 int epicsTimeGetEventInt(epicsTimeStamp *pDest, int eventNumber)
351 {
352  if (eventNumber == epicsTimeEventCurrentTime) {
353  return epicsTimeGetCurrentInt(pDest);
354  } else {
355  gtProvider *ptp = gtPvt.lastEventProvider;
356 
357  if (ptp == NULL ||
358  ptp->getInt.Event == NULL) {
359  IFDEBUG(20)
360  epicsInterruptContextMessage("eTGEvInt: No support\n");
361  return S_time_noProvider;
362  }
363 
364  return ptp->getInt.Event(pDest, eventNumber);
365  }
366 }
367 
368 
369 /* Provider Registration */
370 
371 static void insertProvider(gtProvider *ptp, ELLLIST *plist, epicsMutexId lock)
372 {
373  gtProvider *ptpref;
374 
375  epicsMutexMustLock(lock);
376 
377  for (ptpref = (gtProvider *)ellFirst(plist);
378  ptpref; ptpref = (gtProvider *)ellNext(&ptpref->node)) {
379  if (ptpref->priority > ptp->priority)
380  break;
381  }
382 
383  if (ptpref) {
384  /* Found a provider below the new one */
385  ptpref = (gtProvider *)ellPrevious(&ptpref->node);
386  ellInsert(plist, &ptpref->node, &ptp->node);
387  } else {
388  ellAdd(plist, &ptp->node);
389  }
390 
391  /* Check to see if we have more than just the OS default time source */
392  if(plist==&gtPvt.timeProviders && (ellCount(plist)!=1 || ptp->get.Time!=&osdTimeGetCurrent)) {
393  useOsdGetCurrent = 0;
394  }
395 
396  epicsMutexUnlock(lock);
397 }
398 
399 static gtProvider * findProvider(ELLLIST *plist, epicsMutexId lock,
400  const char *name, int priority)
401 {
402  gtProvider *ptp;
403 
404  epicsMutexMustLock(lock);
405 
406  for (ptp = (gtProvider *)ellFirst(plist);
407  ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
408  if (ptp->priority == priority &&
409  !strcmp(ptp->name, name))
410  break;
411  }
412 
413  epicsMutexUnlock(lock);
414  return ptp;
415 }
416 
417 int generalTimeRegisterEventProvider(const char *name, int priority,
418  TIMEEVENTFUN getEvent)
419 {
420  gtProvider *ptp;
421 
423 
424  if (name == NULL || getEvent == NULL)
425  return S_time_badArgs;
426 
427  ptp = (gtProvider *)malloc(sizeof(gtProvider));
428  if (ptp == NULL)
429  return S_time_noMemory;
430 
431  ptp->name = epicsStrDup(name);
432  ptp->priority = priority;
433  ptp->get.Event = getEvent;
434  ptp->getInt.Event = NULL;
435 
436  insertProvider(ptp, &gtPvt.eventProviders, gtPvt.eventListLock);
437 
438  IFDEBUG(1)
439  printf("Registered event provider '%s' at %d\n", name, priority);
440 
441  return epicsTimeOK;
442 }
443 
444 int generalTimeAddIntEventProvider(const char *name, int priority,
445  TIMEEVENTFUN getEvent)
446 {
447  gtProvider *ptp = findProvider(&gtPvt.eventProviders, gtPvt.eventListLock,
448  name, priority);
449  if (ptp == NULL)
450  return S_time_noProvider;
451 
452  ptp->getInt.Event = getEvent;
453 
454  IFDEBUG(1)
455  printf("Event provider '%s' is interrupt-callable\n", name);
456 
457  return epicsTimeOK;
458 }
459 
460 int generalTimeRegisterCurrentProvider(const char *name, int priority,
461  TIMECURRENTFUN getTime)
462 {
463  gtProvider *ptp;
464 
466 
467  if (name == NULL || getTime == NULL)
468  return S_time_badArgs;
469 
470  ptp = (gtProvider *)malloc(sizeof(gtProvider));
471  if (ptp == NULL)
472  return S_time_noMemory;
473 
474  ptp->name = epicsStrDup(name);
475  ptp->priority = priority;
476  ptp->get.Time = getTime;
477  ptp->getInt.Time = NULL;
478 
479  insertProvider(ptp, &gtPvt.timeProviders, gtPvt.timeListLock);
480 
481  IFDEBUG(1)
482  printf("Registered time provider '%s' at %d\n", name, priority);
483 
484  return epicsTimeOK;
485 }
486 
487 int generalTimeAddIntCurrentProvider(const char *name, int priority,
488  TIMECURRENTFUN getTime)
489 {
490  gtProvider *ptp = findProvider(&gtPvt.timeProviders, gtPvt.timeListLock,
491  name, priority);
492  if (ptp == NULL)
493  return S_time_noProvider;
494 
495  ptp->getInt.Time = getTime;
496 
497  IFDEBUG(1)
498  printf("Time provider '%s' is interrupt-callable\n", name);
499 
500  return epicsTimeOK;
501 }
502 
503 /*
504  * Provide an optional "last resort" provider for Event Time.
505  *
506  * This is deliberately optional, as it represents site policy.
507  * It is intended to be installed as an EventTime provider at the lowest
508  * priority, to return the current time for an event if there is no
509  * better time provider for event times.
510  *
511  * Typically, this will only be used during startup, or a time-provider
512  * resynchronisation, where events are being generated by the event system
513  * but the time provided by the system is not yet valid.
514  */
515 static int lastResortGetEvent(epicsTimeStamp *timeStamp, int eventNumber)
516 {
517  return epicsTimeGetCurrent(timeStamp);
518 }
519 
521 {
522  return generalTimeEventTpRegister("Last Resort Event",
523  LAST_RESORT_PRIORITY, lastResortGetEvent);
524 }
525 
526 
527 /* Status Report */
528 
529 long generalTimeReport(int level)
530 {
531  int items;
532 
533  if (onceId == EPICS_THREAD_ONCE_INIT) {
534  printf("General time framework not yet initialized.\n");
535  return epicsTimeOK;
536  }
537 
538  printf("Backwards time errors prevented %u times.\n\n",
540 
541  /* Use an output buffer to avoid holding mutexes during printing */
542 
543  printf("Current Time Providers:\n");
544  epicsMutexMustLock(gtPvt.timeListLock);
545  if ((items = ellCount(&gtPvt.timeProviders))) {
546  gtProvider *ptp;
547  char *message; /* Temporary output buffer */
548  char *pout;
549 
550  message = calloc(items, 80 * 2); /* Each provider needs 2 lines */
551  if (!message) {
552  epicsMutexUnlock(gtPvt.timeListLock);
553  printf("Out of memory\n");
554  return S_time_noMemory;
555  }
556 
557  pout = message;
558 
559  for (ptp = (gtProvider *)ellFirst(&gtPvt.timeProviders);
560  ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
561  pout += sprintf(pout, " \"%s\", priority = %d\n",
562  ptp->name, ptp->priority);
563  if (level) {
564  epicsTimeStamp tempTS;
565  if (ptp->get.Time(&tempTS) == epicsTimeOK) {
566  char tempTSText[40];
567  epicsTimeToStrftime(tempTSText, sizeof(tempTSText),
568  "%Y-%m-%d %H:%M:%S.%06f", &tempTS);
569  pout += sprintf(pout, "\tCurrent Time is %s.\n",
570  tempTSText);
571  } else {
572  pout += sprintf(pout, "\tCurrent Time not available\n");
573  }
574  }
575  }
576  epicsMutexUnlock(gtPvt.timeListLock);
577  puts(message);
578  free(message);
579  } else {
580  epicsMutexUnlock(gtPvt.timeListLock);
581  printf("\tNo Providers registered.\n");
582  }
583 
584  printf("Event Time Providers:\n");
585  epicsMutexMustLock(gtPvt.eventListLock);
586  if ((items = ellCount(&gtPvt.eventProviders)))
587  {
588  gtProvider *ptp;
589  char *message; /* Temporary output buffer */
590  char *pout;
591 
592  message = calloc(items, 80); /* Each provider needs 1 line, */
593  if (!message) {
594  epicsMutexUnlock(gtPvt.eventListLock);
595  printf("Out of memory\n");
596  return S_time_noMemory;
597  }
598 
599  pout = message;
600 
601  for (ptp = (gtProvider *)ellFirst(&gtPvt.eventProviders);
602  ptp; ptp = (gtProvider *)ellNext(&ptp->node)) {
603  pout += sprintf(pout, " \"%s\", priority = %d\n",
604  ptp->name, ptp->priority);
605  }
606  epicsMutexUnlock(gtPvt.eventListLock);
607  puts(message);
608  free(message);
609  }
610  else
611  {
612  epicsMutexUnlock(gtPvt.eventListLock);
613  printf("\tNo Providers registered.\n");
614  }
615 
616  return epicsTimeOK;
617 }
618 
619 /*
620  * Access to internal status values.
621  */
622 
624 {
625  int key = epicsInterruptLock();
626  gtPvt.ErrorCounts = 0;
628 }
629 
631 {
632  int key = epicsInterruptLock();
633  int errors = gtPvt.ErrorCounts;
635  return errors;
636 }
637 
639 {
640  if (gtPvt.lastTimeProvider)
641  return gtPvt.lastTimeProvider->name;
642  return NULL;
643 }
644 
646 {
647  if (gtPvt.lastEventProvider)
648  return gtPvt.lastEventProvider->name;
649  return NULL;
650 }
651 
653 {
654  gtProvider *ptp;
655 
656  epicsMutexMustLock(gtPvt.timeListLock);
657  ptp = (gtProvider *)ellFirst(&gtPvt.timeProviders);
658  epicsMutexUnlock(gtPvt.timeListLock);
659  return ptp ? ptp->name : NULL;
660 }
The generalTime framework provides a mechanism for several time providers to be present within the sy...
const char * generalTimeCurrentProviderName(void)
Return the nume of the provider that last returned a valid current time, or NULL if none...
int generalTimeRegisterCurrentProvider(const char *name, int priority, TIMECURRENTFUN getTime)
LIBCOM_API void epicsInterruptUnlock(int key)
Definition: osdInterrupt.c:41
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
epicsMutexId lock
Definition: osiClockTime.c:37
epicsMutexId timeListLock
gtProvider * lastEventProvider
pvd::Status status
const char * generalTimeHighestCurrentName(void)
Return the name of the registered current time provider that has the highest priority.
epicsMutexId eventListLock
LIBCOM_API epicsUInt64 epicsMonotonicGet(void)
Fetch monotonic counter, returns the number of nanoseconds since some unspecified time...
Definition: osdMonotonic.c:29
int(* TIMECURRENTFUN)(epicsTimeStamp *pDest)
union gtProvider::@15 get
Routines to get and set EPICS environment parameters.
ELLLIST timeProviders
#define printf
Definition: epicsStdio.h:41
#define IFDEBUG(n)
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
union gtProvider::@16 getInt
#define NULL
Definition: catime.c:38
#define epicsTimeOK
Success.
Definition: epicsTime.h:339
#define NUM_TIME_EVENTS
The number of time events that are validated.
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
#define ellPrevious(PNODE)
Find the previous node in list.
Definition: ellLib.h:104
LIBCOM_API int epicsInterruptLock(void)
Definition: osdInterrupt.c:34
epicsTimeStamp eventTime[NUM_TIME_EVENTS]
epicsUInt32 secPastEpoch
seconds since 0000 Jan 1, 1990
Definition: epicsTime.h:34
unsigned long long epicsUInt64
Definition: epicsTypes.h:45
int generalTimeAddIntCurrentProvider(const char *name, int priority, TIMECURRENTFUN getTime)
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 osdTimeGetCurrent(epicsTimeStamp *pDest)
Definition: osdTime.cpp:119
#define generalTimeEventTpRegister
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
LIBCOM_API size_t epicsStdCall epicsTimeToStrftime(char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
Convert epicsTimeStamp to string. See epicsTime::strftime()
Definition: epicsTime.cpp:1120
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
int epicsTimeGetMonotonic(epicsTimeStamp *pDest)
Get monotonic time into *pDest.
LIBCOM_API int epicsStdCall epicsTimeGreaterThanEqual(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
right was not before left
Definition: epicsTime.cpp:1111
#define S_time_badArgs
Invalid arguments.
Definition: epicsTime.h:345
#define puts
Definition: epicsStdio.h:46
int ErrorCounts
#define STATIC_ASSERT(expr)
Declare a condition that should be true at compile-time.
Definition: epicsAssert.h:86
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
Get current time into *pDest.
TIMEEVENTFUN Event
#define S_time_badEvent
Bad event number.
Definition: epicsTime.h:343
const char * generalTimeEventProviderName(void)
Return the name of the provider that last returned a valid Time Event time, or NULL of none...
#define S_time_noMemory
Out of memory.
Definition: epicsTime.h:347
int generalTimeAddIntEventProvider(const char *name, int priority, TIMEEVENTFUN getEvent)
LIBCOM_API void epicsInterruptContextMessage(const char *message)
Definition: osdInterrupt.c:53
epicsTimeStamp lastProvidedBestTime
TIMECURRENTFUN Time
List node type.
Definition: ellLib.h:45
#define LAST_RESORT_PRIORITY
#define epicsTimeEventBestTime
Definition: epicsTime.h:361
void generalTime_Init(void)
Initialise the framework.
char * epicsStrDup(const char *s)
Definition: epicsString.c:233
APIs for the epicsEvent binary semaphore.
epics::pvData::PVStructurePtr dummy
Definition: pvAccess.cpp:72
#define S_time_noProvider
No time provider.
Definition: epicsTime.h:341
int epicsTimeGetCurrentInt(epicsTimeStamp *pDest)
Get current time into *pDest (ISR-safe)
void generalTimeResetErrorCounts(void)
Reset the internal counter of the number of times the time returned was earlier than when previously ...
int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int *pPrio, int ignore)
A C++ and a C facility for communication between threads.
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
int epicsStdCall epicsTimeGetEvent(epicsTimeStamp *pDest, int eventNumber)
Get time of event eventNumber into *pDest.
ELLLIST eventProviders
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
int(* TIMEEVENTFUN)(epicsTimeStamp *pDest, int event)
void ellInsert(ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode)
Inserts a node into a list immediately after a specific node.
Definition: ellLib.c:178
#define epicsTimeEventCurrentTime
Definition: epicsTime.h:360
int installLastResortEventProvider(void)
Install a Time Event time provider that returns the current time for any Time event number...
Routines for code that can&#39;t continue or return after an error.
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
List header type.
Definition: ellLib.h:56
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
int generalTimeGetErrorCounts(void)
Return the internal counter of the number of times the time returned was earlier than when previously...
int epicsTimeGetEventInt(epicsTimeStamp *pDest, int eventNumber)
Get time of event eventNumber into *pDest (ISR-safe)
gtProvider * lastTimeProvider
epicsUInt32 nsec
nanoseconds within second
Definition: epicsTime.h:35
epicsTimeStamp lastProvidedTime
long generalTimeReport(int level)
Provide information about the installed providers and their current best times.
int generalTimeRegisterEventProvider(const char *name, int priority, TIMEEVENTFUN getEvent)
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89