diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 96f10ecfc..8a108724c 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -14,6 +14,18 @@

Changes between 3.15.2 and 3.15.3

+

Make the NTP Time provider optional on VxWorks

+ +

Recent versions of VxWorks (sometime after VxWorks 6) provide facilities for +automatically synchronizing the OS clock time with an NTP server. The EPICS time +system used to assume that it had to provide time synchronization on VxWorks, +but now it tests for the existance of either of the two OS synchronization +threads before starting the NTP time provider. It is still possible to force the +NTP provider to be started even if the OS synchronization is running by defining +the environment variable EPICS_TS_FORCE_NTPTIME in the startup script +before loading the IOC's .munch file. Forcing may be necessary if the VxWorks +image is not correctly configured with the IP address of a local NTP server.

+

Clean up after GNU readline()

If EPICS Base is built with readline support, any IOC that calls epicsExit() diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index fb38abc1f..c06a862ed 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -80,6 +80,10 @@ Com_SRCS += osiClockTime.c Com_SRCS_vxWorks += osiNTPTime.c Com_SRCS_RTEMS += osiNTPTime.c +ifeq ($(OS_CLASS),vxWorks) +osdTime.o: USR_CXXFLAGS += -DBUILD_TIME=$(shell perl -e 'print time') +endif + Com_SRCS += osdSock.c Com_SRCS += osdSockAddrReuse.cpp Com_SRCS += osiSock.c diff --git a/src/libCom/osi/os/vxWorks/osdTime.cpp b/src/libCom/osi/os/vxWorks/osdTime.cpp index eed1ad078..4db375fbb 100644 --- a/src/libCom/osi/os/vxWorks/osdTime.cpp +++ b/src/libCom/osi/os/vxWorks/osdTime.cpp @@ -1,5 +1,5 @@ /*************************************************************************\ -* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. @@ -7,11 +7,14 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> + #include #include #include #include #include +#include #include "epicsTime.h" #include "osiNTPTime.h" @@ -21,6 +24,9 @@ #define NTP_REQUEST_TIMEOUT 4 /* seconds */ +static char sntp_sync_task[] = "ipsntps"; +static char ntp_daemon[] = "ipntpd"; + static const char *pserverAddr = NULL; extern char* sysBootLine; @@ -30,18 +36,40 @@ static int timeRegister(void) if (getenv("TIMEZONE") == NULL) { const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE); if (timezone == NULL) { - printf("NTPTime_Init: No Time Zone Information\n"); + printf("timeRegister: No Time Zone Information\n"); } else { epicsEnvSet("TIMEZONE", timezone); } } - NTPTime_Init(100); /* init NTP first so it can be used to sync SysTime */ - ClockTime_Init(CLOCKTIME_SYNC); + // Define EPICS_TS_FORCE_NTPTIME to force use of NTPTime provider + bool useNTP = getenv("EPICS_TS_FORCE_NTPTIME") != NULL; + + if (!useNTP && + (taskNameToId(sntp_sync_task) != ERROR || + taskNameToId(ntp_daemon) != ERROR)) { + // A VxWorks 6 SNTP/NTP sync task is running + struct timespec clockNow; + + useNTP = clock_gettime(CLOCK_REALTIME, &clockNow) != OK || + clockNow.tv_sec < BUILD_TIME; + // Assumes VxWorks and the host OS have the same epoch + } + + if (useNTP) { + // Start NTP first so it can be used to sync SysTime + NTPTime_Init(100); + ClockTime_Init(CLOCKTIME_SYNC); + } else { + ClockTime_Init(CLOCKTIME_NOSYNC); + } return 1; } static int done = timeRegister(); + +// Routines for NTPTime provider + int osdNTPGet(struct timespec *ts) { return sntpcTimeGet(const_cast(pserverAddr), @@ -54,6 +82,7 @@ void osdNTPInit(void) if (!pserverAddr) { /* use the boot host */ BOOT_PARAMS bootParms; static char host_addr[BOOT_ADDR_LEN]; + bootStringToStruct(sysBootLine, &bootParms); /* bootParms.had = host IP address */ strncpy(host_addr, bootParms.had, BOOT_ADDR_LEN); @@ -63,10 +92,13 @@ void osdNTPInit(void) void osdNTPReport(void) { - printf("NTP Server = %s\n", pserverAddr); + if (pserverAddr) + printf("NTP Server = %s\n", pserverAddr); } +// Other Time Routines + // vxWorks localtime_r returns different things in different versions. // It can't fail though, so we just ignore the return value. int epicsTime_localtime(const time_t *clock, struct tm *result) diff --git a/src/libCom/osi/osiClockTime.c b/src/libCom/osi/osiClockTime.c index ec4e8a5aa..6f1e09b14 100644 --- a/src/libCom/osi/osiClockTime.c +++ b/src/libCom/osi/osiClockTime.c @@ -70,37 +70,54 @@ static void ShutdownCallFunc(const iocshArgBuf *args) /* Initialization */ -static void ClockTime_InitOnce(void *psync) +static void ClockTime_InitOnce(void *pfirst) { - ClockTimePvt.synchronize = *(int *)psync; + *(int *) pfirst = 1; + ClockTimePvt.loopEvent = epicsEventMustCreate(epicsEventEmpty); ClockTimePvt.lock = epicsMutexCreate(); - if (ClockTimePvt.synchronize) { - /* Start the sync thread */ - epicsThreadCreate("ClockTimeSync", epicsThreadPriorityHigh, - epicsThreadGetStackSize(epicsThreadStackSmall), - ClockTimeSync, NULL); - } - else { - ClockTimeGetCurrent(&ClockTimePvt.startTime); - } - epicsAtExit(ClockTime_Shutdown, NULL); /* Register the iocsh commands */ iocshRegister(&ReportFuncDef, ReportCallFunc); - if (ClockTimePvt.synchronize) - iocshRegister(&ShutdownFuncDef, ShutdownCallFunc); + iocshRegister(&ShutdownFuncDef, ShutdownCallFunc); - /* Finally register as a time provider */ + /* Register as a time provider */ generalTimeRegisterCurrentProvider("OS Clock", LAST_RESORT_PRIORITY, ClockTimeGetCurrent); } void ClockTime_Init(int synchronize) { - epicsThreadOnce(&onceId, ClockTime_InitOnce, &synchronize); + int firstTime = 0; + + epicsThreadOnce(&onceId, ClockTime_InitOnce, &firstTime); + + if (synchronize == CLOCKTIME_SYNC) { + if (ClockTimePvt.synchronize == CLOCKTIME_NOSYNC) { + /* Start synchronizing */ + ClockTimePvt.synchronize = synchronize; + + epicsThreadCreate("ClockTimeSync", epicsThreadPriorityHigh, + epicsThreadGetStackSize(epicsThreadStackSmall), + ClockTimeSync, NULL); + } + else { + /* No change, sync thread should already be running */ + } + } + else { + if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) { + /* Turn off synchronization thread */ + ClockTime_Shutdown(NULL); + } + else { + /* No synchronization thread */ + if (firstTime) + ClockTimeGetCurrent(&ClockTimePvt.startTime); + } + } } @@ -108,7 +125,7 @@ void ClockTime_Init(int synchronize) void ClockTime_Shutdown(void *dummy) { - ClockTimePvt.synchronize = 0; + ClockTimePvt.synchronize = CLOCKTIME_NOSYNC; epicsEventSignal(ClockTimePvt.loopEvent); } @@ -126,7 +143,7 @@ static void ClockTimeSync(void *dummy) for (epicsEventWaitWithTimeout(ClockTimePvt.loopEvent, ClockTimeSyncInterval); - ClockTimePvt.synchronize; + ClockTimePvt.synchronize == CLOCKTIME_SYNC; epicsEventWaitWithTimeout(ClockTimePvt.loopEvent, ClockTimeSyncInterval)) { epicsTimeStamp timeNow; @@ -144,8 +161,8 @@ static void ClockTimeSync(void *dummy) epicsMutexMustLock(ClockTimePvt.lock); if (!ClockTimePvt.synchronized) { - ClockTimePvt.startTime = timeNow; - ClockTimePvt.synchronized = 1; + ClockTimePvt.startTime = timeNow; + ClockTimePvt.synchronized = 1; } ClockTimePvt.syncFromPriority = priority; ClockTimePvt.syncTime = timeNow; @@ -200,29 +217,39 @@ int ClockTime_Report(int level) #ifdef CLOCK_REALTIME "initialized" #else - "included" + "available" #endif /* CLOCK_REALTIME */ ); - } else if (ClockTimePvt.synchronize) { + } + else if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) { + int synchronized, syncFromPriority; + epicsTimeStamp startTime, syncTime; + epicsMutexMustLock(ClockTimePvt.lock); - if (ClockTimePvt.synchronized) { - printf("OS Clock driver has synchronized to a priority=%d provider\n", - ClockTimePvt.syncFromPriority); + synchronized = ClockTimePvt.synchronized; + syncFromPriority = ClockTimePvt.syncFromPriority; + startTime = ClockTimePvt.startTime; + syncTime = ClockTimePvt.syncTime; + epicsMutexUnlock(ClockTimePvt.lock); + + if (synchronized) { + printf("OS Clock driver is synchronized to a priority=%d provider\n", + syncFromPriority); if (level) { epicsTimeToStrftime(timebuf, sizeof(timebuf), - "%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.startTime); + "%Y-%m-%d %H:%M:%S.%06f", &startTime); printf("Initial sync was at %s\n", timebuf); epicsTimeToStrftime(timebuf, sizeof(timebuf), - "%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.syncTime); + "%Y-%m-%d %H:%M:%S.%06f", &syncTime); printf("Last successful sync was at %s\n", timebuf); } printf("Syncronization interval = %.0f seconds\n", ClockTimeSyncInterval); - } else - printf("OS Clock driver has *not* yet synchronized\n"); - - epicsMutexUnlock(ClockTimePvt.lock); - } else { + } + else + printf("OS Clock driver is *not* synchronized\n"); + } + else { epicsTimeToStrftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S.%06f", &ClockTimePvt.startTime); printf("Program started at %s\n", timebuf);