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);