This is Unofficial EPICS BASE Doxygen Site
osiClockTime.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * EPICS BASE is distributed subject to a Software License Agreement found
5 * in file LICENSE that is included with this distribution.
6 \*************************************************************************/
7 
8 #include <stddef.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 
13 #include "epicsEvent.h"
14 #include "epicsExit.h"
15 #include "epicsMutex.h"
16 #include "epicsThread.h"
17 #include "errlog.h"
18 #include "epicsGeneralTime.h"
19 #include "generalTimeSup.h"
20 #include "iocsh.h"
21 #include "osiClockTime.h"
22 #include "taskwd.h"
23 
24 #define NSEC_PER_SEC 1000000000
25 #define ClockTimeSyncInterval_initial 1.0
26 #define ClockTimeSyncInterval_normal 60.0
27 
28 
29 static struct {
31  int synchronized;
38 } ClockTimePvt;
39 
41 
42 
43 #if defined(CLOCK_REALTIME) && !defined(_WIN32) && !defined(__APPLE__)
44 /* This code is not used on systems without Posix CLOCK_REALTIME,
45  * but the only way to detect that is from the OS headers, so the
46  * Makefile can't exclude compiling this file on those systems.
47  */
48 
49 /* Forward references */
50 
52 
53 #if defined(vxWorks) || defined(__rtems__)
54 static void ClockTimeSync(void *dummy);
55 #endif
56 
57 /* ClockTime_Report iocsh command */
58 static const iocshArg ReportArg0 = { "interest_level", iocshArgArgv};
59 static const iocshArg * const ReportArgs[1] = { &ReportArg0 };
60 static const iocshFuncDef ReportFuncDef = {"ClockTime_Report", 1, ReportArgs};
61 static void ReportCallFunc(const iocshArgBuf *args)
62 {
63  ClockTime_Report(args[0].ival);
64 }
65 
66 /* ClockTime_Shutdown iocsh command */
67 static const iocshFuncDef ShutdownFuncDef = {"ClockTime_Shutdown", 0, NULL};
68 static void ShutdownCallFunc(const iocshArgBuf *args)
69 {
71 }
72 
73 
74 /* Initialization */
75 
76 static void ClockTime_InitOnce(void *pfirst)
77 {
78  *(int *) pfirst = 1;
79 
80  ClockTimePvt.loopEvent = epicsEventMustCreate(epicsEventEmpty);
81  ClockTimePvt.lock = epicsMutexCreate();
82  ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_initial;
83 
85 
86  /* Register the iocsh commands */
87  iocshRegister(&ReportFuncDef, ReportCallFunc);
88  iocshRegister(&ShutdownFuncDef, ShutdownCallFunc);
89 
90  /* Register as a time provider */
93 }
94 
96 {
97  int firstTime = 0;
98 
99  epicsThreadOnce(&onceId, ClockTime_InitOnce, &firstTime);
100 
101  if (synchronize == CLOCKTIME_SYNC) {
102  if (ClockTimePvt.synchronize == CLOCKTIME_NOSYNC) {
103 
104 #if defined(vxWorks) || defined(__rtems__)
105  /* Start synchronizing */
106  ClockTimePvt.synchronize = synchronize;
107 
110  ClockTimeSync, NULL);
111 #else
112  errlogPrintf("Clock synchronization must be performed by the OS\n");
113 #endif
114 
115  }
116  else {
117  /* No change, sync thread should already be running */
118  }
119  }
120  else {
121  if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) {
122  /* Turn off synchronization thread */
124  }
125  else {
126  /* No synchronization thread */
127  if (firstTime)
128  osdTimeGetCurrent(&ClockTimePvt.startTime);
129  }
130  }
131 }
132 
133 
134 /* Shutdown */
135 
136 void ClockTime_Shutdown(void *dummy)
137 {
138  ClockTimePvt.synchronize = CLOCKTIME_NOSYNC;
139  epicsEventSignal(ClockTimePvt.loopEvent);
140 }
141 
143 {
144  *pDest = ClockTimePvt.startTime;
145 }
146 
147 
148 /* Synchronization thread */
149 
150 #if defined(vxWorks) || defined(__rtems__)
151 CLOCKTIME_SYNCHOOK ClockTime_syncHook = NULL;
152 
153 static void ClockTimeSync(void *dummy)
154 {
155  taskwdInsert(0, NULL, NULL);
156 
157  for (epicsEventWaitWithTimeout(ClockTimePvt.loopEvent,
158  ClockTimePvt.ClockTimeSyncInterval);
159  ClockTimePvt.synchronize == CLOCKTIME_SYNC;
160  epicsEventWaitWithTimeout(ClockTimePvt.loopEvent,
161  ClockTimePvt.ClockTimeSyncInterval)) {
162  epicsTimeStamp timeNow;
163  int priority;
164 
165  if (generalTimeGetExceptPriority(&timeNow, &priority,
167  struct timespec clockNow;
168 
169  epicsTimeToTimespec(&clockNow, &timeNow);
170  if (clock_settime(CLOCK_REALTIME, &clockNow)) {
171  errlogPrintf("ClockTimeSync: clock_settime failed\n");
172  continue;
173  }
174 
175  epicsMutexMustLock(ClockTimePvt.lock);
176  if (!ClockTimePvt.synchronized) {
177  ClockTimePvt.startTime = timeNow;
178  ClockTimePvt.synchronized = 1;
179  }
180  ClockTimePvt.syncFromPriority = priority;
181  ClockTimePvt.syncTime = timeNow;
182  epicsMutexUnlock(ClockTimePvt.lock);
183 
184  if (ClockTime_syncHook)
185  ClockTime_syncHook(1);
186 
187  ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_normal;
188  }
189  }
190 
191  ClockTimePvt.synchronized = 0;
192  if (ClockTime_syncHook)
193  ClockTime_syncHook(0);
194  taskwdRemove(0);
195 }
196 #endif
197 
198 
199 /* Time Provider Routine */
200 
202 {
203  struct timespec clockNow;
204 
205  /* If a Hi-Res clock is available and works, use it */
206  #ifdef CLOCK_REALTIME_HR
207  clock_gettime(CLOCK_REALTIME_HR, &clockNow) &&
208  /* Note: Uses the lo-res clock below if the above call fails */
209  #endif
210  clock_gettime(CLOCK_REALTIME, &clockNow);
211 
212  if (!ClockTimePvt.synchronized &&
213  clockNow.tv_sec < POSIX_TIME_AT_EPICS_EPOCH) {
214  clockNow.tv_sec = POSIX_TIME_AT_EPICS_EPOCH + 86400;
215  clockNow.tv_nsec = 0;
216 
217 #if defined(vxWorks) || defined(__rtems__)
218  clock_settime(CLOCK_REALTIME, &clockNow);
219  errlogPrintf("WARNING: OS Clock time was read before being set.\n"
220  "Using 1990-01-02 00:00:00.000000 UTC\n");
221 #else
222  errlogPrintf("WARNING: OS Clock pre-dates the EPICS epoch!\n"
223  "Using 1990-01-02 00:00:00.000000 UTC\n");
224 #endif
225  }
226 
227  epicsTimeFromTimespec(pDest, &clockNow);
228  return 0;
229 }
230 
231 /* Used in Report function below: */
232 #define UNINIT_ERROR "initialized"
233 #else
234 #define UNINIT_ERROR "available"
235 #endif /* CLOCK_REALTIME && !WIN32 */
236 
237 /* Allow the following report routine to be compiled anyway
238  * to avoid getting a build warning from ranlib.
239  */
240 
241 /* Status Report */
242 
243 int ClockTime_Report(int level)
244 {
245  char timebuf[32];
246 
247  if (onceId == EPICS_THREAD_ONCE_INIT) {
248  puts("OS Clock driver not " UNINIT_ERROR);
249  }
250  else if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) {
251  int synchronized, syncFromPriority;
253 
254  epicsMutexMustLock(ClockTimePvt.lock);
255  synchronized = ClockTimePvt.synchronized;
256  syncFromPriority = ClockTimePvt.syncFromPriority;
257  startTime = ClockTimePvt.startTime;
258  syncTime = ClockTimePvt.syncTime;
259  epicsMutexUnlock(ClockTimePvt.lock);
260 
261  if (synchronized) {
262  printf("OS Clock driver is synchronized to a priority=%d provider\n",
263  syncFromPriority);
264  if (level) {
265  epicsTimeToStrftime(timebuf, sizeof(timebuf),
266  "%Y-%m-%d %H:%M:%S.%06f", &startTime);
267  printf("Initial sync was at %s\n", timebuf);
268  epicsTimeToStrftime(timebuf, sizeof(timebuf),
269  "%Y-%m-%d %H:%M:%S.%06f", &syncTime);
270  printf("Last successful sync was at %s\n", timebuf);
271  }
272  printf("Syncronization interval = %.0f seconds\n",
273  ClockTimePvt.ClockTimeSyncInterval);
274  }
275  else
276  printf("OS Clock driver is *not* synchronized\n");
277  }
278  else {
279  epicsTimeToStrftime(timebuf, sizeof(timebuf),
280  "%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.startTime);
281  printf("Program started at %s\n", timebuf);
282  printf("OS Clock synchronization thread not running.\n");
283  }
284  return 0;
285 }
LIBCOM_API int epicsStdCall epicsTimeFromTimespec(epicsTimeStamp *pDest, const struct timespec *pSrc)
Set epicsTimeStamp from struct timespec
Definition: epicsTime.cpp:1018
The generalTime framework provides a mechanism for several time providers to be present within the sy...
int generalTimeRegisterCurrentProvider(const char *name, int priority, TIMECURRENTFUN getTime)
void taskwdInsert(epicsThreadId tid, TASKWDFUNC callback, void *usr)
Definition: taskwd.c:176
epicsMutexId lock
Definition: osiClockTime.c:37
epicsTimeStamp syncTime
Definition: osiClockTime.c:34
void ClockTime_Init(int synchronize)
LIBCOM_API void ClockTime_GetProgramStart(epicsTimeStamp *pDest)
LIBCOM_API int epicsStdCall epicsTimeToTimespec(struct timespec *pDest, const epicsTimeStamp *pSrc)
Convert epicsTimeStamp to struct timespec
Definition: epicsTime.cpp:1008
#define printf
Definition: epicsStdio.h:41
void epicsStdCall iocshRegister(const iocshFuncDef *piocshFuncDef, iocshCallFunc func)
Definition: iocsh.cpp:111
#define NULL
Definition: catime.c:38
#define epicsTimeOK
Success.
Definition: epicsTime.h:339
epicsTimeStamp startTime
Definition: osiClockTime.c:33
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout(epicsEventId id, double timeOut)
Wait an the event or until the specified timeout period is over.
Definition: osdEvent.c:117
LIBCOM_API epicsEventId epicsEventMustCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code.
Definition: epicsEvent.cpp:106
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
#define UNINIT_ERROR
Definition: osiClockTime.c:234
int osdTimeGetCurrent(epicsTimeStamp *pDest)
Definition: osdTime.cpp:119
int syncFromPriority
Definition: osiClockTime.c:36
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
epicsEventId loopEvent
Definition: osiClockTime.c:32
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
#define puts
Definition: epicsStdio.h:46
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
Extended replacement for the Posix exit and atexit routines.
#define CLOCKTIME_SYNC
Definition: osiClockTime.h:12
#define POSIX_TIME_AT_EPICS_EPOCH
The EPICS Epoch is 00:00:00 Jan 1, 1990 UTC.
Definition: epicsTime.h:26
#define ClockTimeSyncInterval_initial
Definition: osiClockTime.c:25
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
#define LAST_RESORT_PRIORITY
APIs for the epicsEvent binary semaphore.
epics::pvData::PVStructurePtr dummy
Definition: pvAccess.cpp:72
#define CLOCKTIME_NOSYNC
Definition: osiClockTime.h:11
#define epicsThreadPriorityHigh
Definition: epicsThread.h:77
void taskwdRemove(epicsThreadId tid)
Definition: taskwd.c:206
int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int *pPrio, int ignore)
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
#define epicsMutexCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:168
void ClockTime_Shutdown(void *dummy)
Defined by POSIX Real Time.
Definition: osdTime.h:21
#define ClockTimeSyncInterval_normal
Definition: osiClockTime.c:26
#define epicsAtExit(F, A)
Convenience macro to register a function and context value to be run when the process exits...
Definition: epicsExit.h:70
int ClockTime_Report(int level)
Definition: osiClockTime.c:243
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
double ClockTimeSyncInterval
Definition: osiClockTime.c:35
int synchronize
Definition: osiClockTime.c:30
Definition: iocsh.h:56