Merge development branches into libcom/master
This commit is contained in:
Vendored
+1
@@ -65,6 +65,7 @@ epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH;
|
||||
epicsShareExtern const ENV_PARAM EPICS_TIMEZONE;
|
||||
epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_IGNORE_SERVERS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_INET;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_LIMIT;
|
||||
|
||||
@@ -119,6 +119,7 @@ Com_SRCS += osdMutex.c
|
||||
Com_SRCS += osdSpin.c
|
||||
Com_SRCS += osdEvent.c
|
||||
Com_SRCS += osdTime.cpp
|
||||
Com_SRCS += osdMonotonic.c
|
||||
Com_SRCS += osdProcess.c
|
||||
Com_SRCS += osdNetIntf.c
|
||||
Com_SRCS += osdMessageQueue.c
|
||||
|
||||
@@ -258,6 +258,17 @@ epicsShareFunc void epicsShareAPI epicsTimeShow (
|
||||
epicsShareFunc int epicsShareAPI epicsTime_localtime ( const time_t * clock, struct tm * result );
|
||||
epicsShareFunc int epicsShareAPI epicsTime_gmtime ( const time_t * clock, struct tm * result );
|
||||
|
||||
/* Advertised monotonic counter resolution (may not be accurate).
|
||||
* Minimum non-zero difference between two calls to epicsMonotonicGet()
|
||||
*/
|
||||
epicsShareFunc epicsUInt64 epicsMonotonicResolution(void);
|
||||
/* Fetch monotonic counter, return is nano-seconds since an unspecified time */
|
||||
epicsShareFunc epicsUInt64 epicsMonotonicGet(void);
|
||||
|
||||
#ifdef EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
epicsShareFunc void osdMonotonicInit(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2017 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
/* see https://developer.apple.com/library/content/qa/qa1398/_index.html */
|
||||
static mach_timebase_info_data_t tbinfo;
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
(void)mach_timebase_info(&tbinfo);
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return 1e-9 * tbinfo.numer / tbinfo.denom;
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
uint64_t val = mach_absolute_time();
|
||||
return val * tbinfo.numer / tbinfo.denom;
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <mach/mach.h>
|
||||
#include <mach/clock.h>
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "osiSock.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -45,6 +46,8 @@ static int timeRegister(void)
|
||||
|
||||
generalTimeCurrentTpRegister("MachTime", \
|
||||
LAST_RESORT_PRIORITY, osdTimeGetCurrent);
|
||||
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include <epicsStdio.h>
|
||||
#include <rtems.h>
|
||||
#include <errno.h>
|
||||
@@ -37,6 +38,8 @@ void osdTimeRegister(void)
|
||||
/* Init NTP first so it can be used to sync ClockTime */
|
||||
NTPTime_Init(100);
|
||||
ClockTime_Init(CLOCKTIME_SYNC);
|
||||
|
||||
osdMonotonicInit();
|
||||
}
|
||||
|
||||
int osdNTPGet(struct timespec *ts)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
static unsigned char osdUsePrefCounter;
|
||||
static epicsUInt64 osdMonotonicResolution;
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
LARGE_INTEGER freq, val;
|
||||
|
||||
if(!QueryPerformanceFrequency(&freq) ||
|
||||
!QueryPerformanceCounter(&val))
|
||||
{
|
||||
double period = 1.0/freq.QuadPart;
|
||||
osdMonotonicResolution = period*1e9;
|
||||
osdUsePrefCounter = 1;
|
||||
} else {
|
||||
osdMonotonicResolution = 1e6; /* 1 ms TODO place holder */
|
||||
}
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return osdMonotonicResolution;
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
LARGE_INTEGER val;
|
||||
if(osdUsePrefCounter) {
|
||||
if(!QueryPerformanceCounter(&val)) {
|
||||
errMessage(errlogMinor, "Warning: failed to fetch performance counter\n");
|
||||
return 0;
|
||||
} else
|
||||
return val.QuadPart;
|
||||
} else {
|
||||
epicsUInt64 ret = GetTickCount();
|
||||
ret *= 1000000;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
// EPICS
|
||||
//
|
||||
#define epicsExportSharedSymbols
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
#include "epicsTimer.h"
|
||||
@@ -106,6 +107,8 @@ static int timeRegister(void)
|
||||
generalTimeCurrentTpRegister("PerfCounter", 150, osdTimeGetCurrent);
|
||||
|
||||
pCurrentTime->startPLL ();
|
||||
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#import <mach/mach_time.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return 1; /* TODO, how to find ? */
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
uint64_t val = mach_absolute_time(), ret;
|
||||
absolutetime_to_nanoseconds(val, &ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
static clockid_t osdMonotonicID;
|
||||
static epicsUInt64 osdMonotonicResolution;
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
unsigned i;
|
||||
clockid_t ids[] = {
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
CLOCK_MONOTONIC_RAW, /* Linux specific */
|
||||
#endif
|
||||
#ifdef CLOCK_HIGHRES
|
||||
CLOCK_HIGHRES, /* solaris specific */
|
||||
#endif
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
CLOCK_MONOTONIC, /* Linux, RTEMS, and probably others */
|
||||
#endif
|
||||
/* fallback and vxWorks, not actually monotonic, but always available */
|
||||
CLOCK_REALTIME
|
||||
};
|
||||
|
||||
for(i=0; i<NELEMENTS(ids); i++) {
|
||||
epicsUInt64 res;
|
||||
struct timespec ts;
|
||||
int ret = clock_getres(ids[i], &ts);
|
||||
if(ret) continue;
|
||||
|
||||
res = ts.tv_sec;
|
||||
res *= 1000000000;
|
||||
res += ts.tv_nsec;
|
||||
|
||||
/* fetch the time once to see that it actually succeeds */
|
||||
ret = clock_gettime(ids[i], &ts);
|
||||
if(ret) continue;
|
||||
|
||||
osdMonotonicID = ids[i];
|
||||
osdMonotonicResolution = res;
|
||||
return;
|
||||
}
|
||||
|
||||
errMessage(errlogMinor, "Warning: failed to setup monotonic time source\n");
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return osdMonotonicResolution;
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
int ret = clock_gettime(osdMonotonicID, &ts);
|
||||
if(ret) {
|
||||
errlogPrintf("Warning: failed to fetch monotonic time %d %d\n",
|
||||
(int)osdMonotonicID, ret);
|
||||
return 0;
|
||||
} else {
|
||||
epicsUInt64 ret = ts.tv_sec;
|
||||
ret *= 1000000000;
|
||||
ret += ts.tv_nsec;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "osiSock.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -56,6 +57,8 @@ int clock_settime(clockid_t clock, const timespec *tp)
|
||||
static int timeRegister(void)
|
||||
{
|
||||
TIME_INIT;
|
||||
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsTime.h"
|
||||
|
||||
|
||||
#define NS_PER_SEC 1000000000
|
||||
|
||||
union timebase {
|
||||
UINT32 u32[2]; /* vxTimeBaseGet() */
|
||||
INT64 i64; /* pentiumTscGet64() */
|
||||
UINT64 u64; /* epicsMonotonicGet() */
|
||||
};
|
||||
|
||||
|
||||
#if CPU_FAMILY == PPC
|
||||
#include <arch/ppc/vxPpcLib.h>
|
||||
#include "epicsFindSymbol.h"
|
||||
|
||||
/* On PowerPC the timebase counter runs at a rate related to the
|
||||
* bus clock and its frequency should always fit into a UINT32.
|
||||
*/
|
||||
|
||||
static epicsUInt32 ticksPerSec;
|
||||
|
||||
#define TIMEBASEGET(TB) \
|
||||
vxTimeBaseGet(&TB.u32[0], &TB.u32[1])
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
typedef epicsUInt32 (*sysTimeBaseFreq_t)(void);
|
||||
sysTimeBaseFreq_t sysTimeBaseFreq =
|
||||
(sysTimeBaseFreq_t) epicsFindSymbol("_sysTimeBaseFreq");
|
||||
|
||||
if (sysTimeBaseFreq) {
|
||||
ticksPerSec = sysTimeBaseFreq();
|
||||
|
||||
if (!ticksPerSec)
|
||||
printf("Warning: Failed to set up monotonic time source.\n");
|
||||
/* Warn here only if the BSP routine exists but returned 0 */
|
||||
}
|
||||
else
|
||||
ticksPerSec = 0; /* Warn on first use */
|
||||
}
|
||||
|
||||
|
||||
#elif CPU_FAMILY == I80X86
|
||||
|
||||
#include <arch/i86/pentiumLib.h>
|
||||
#include <hwif/cpu/arch/i86/vxCpuIdLib.h>
|
||||
|
||||
/* On Intel the timebase counter frequency is returned by the OS as a
|
||||
* UINT64. Some CPUs may count at multi-GHz rates so we need 64 bits.
|
||||
*/
|
||||
|
||||
static epicsUInt64 ticksPerSec;
|
||||
|
||||
#define TIMEBASEGET(TB) \
|
||||
pentiumTscGet64(&TB.i64)
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
ticksPerSec = vxCpuIdGetFreq();
|
||||
|
||||
if (!ticksPerSec)
|
||||
printf("Warning: Failed to set up monotonic time source.\n");
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#error This CPU family not supported yet!
|
||||
#endif
|
||||
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
if (!ticksPerSec)
|
||||
return 0;
|
||||
|
||||
return NS_PER_SEC / ticksPerSec;
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
union timebase tbNow;
|
||||
|
||||
if (!ticksPerSec) {
|
||||
static int warned = 0;
|
||||
|
||||
if (!warned) {
|
||||
printf("Warning: Monotonic time source is not available.\n");
|
||||
warned = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TIMEBASEGET(tbNow);
|
||||
/* Using a long double for the calculation below to preserve
|
||||
* as many bits in the mantissa as possible.
|
||||
*/
|
||||
return ((long double) tbNow.u64) * NS_PER_SEC / ticksPerSec;
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "osiNTPTime.h"
|
||||
#include "osiClockTime.h"
|
||||
@@ -63,6 +64,7 @@ static int timeRegister(void)
|
||||
} else {
|
||||
ClockTime_Init(CLOCKTIME_NOSYNC);
|
||||
}
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
+44
-1
@@ -38,12 +38,53 @@ static const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
static const unsigned nSecPerSec = 1000u * uSecPerSec;
|
||||
static const double precisionEPICS = 1.0 / nSecPerSec;
|
||||
|
||||
static void crossCheck(double delay)
|
||||
{
|
||||
double mindelta = 2*epicsMonotonicResolution()*1e-9,
|
||||
tres = epicsThreadSleepQuantum();
|
||||
epicsUInt64 A = epicsMonotonicGet();
|
||||
epicsThreadSleep(delay);
|
||||
epicsUInt64 B = epicsMonotonicGet();
|
||||
|
||||
double actual = (B-A)*1e-9, percent;
|
||||
|
||||
if(mindelta<tres*2)
|
||||
mindelta = tres*2;
|
||||
if(delay<mindelta)
|
||||
delay = mindelta;
|
||||
|
||||
percent = (delay-actual)/delay*100.0;
|
||||
|
||||
testOk(fabs(percent)<1000.0, "crossCheck(%f) actual %f (%f %%)",
|
||||
delay, actual, percent);
|
||||
}
|
||||
|
||||
static void testMonotonic()
|
||||
{
|
||||
crossCheck(2.1); /* greater than 2 so that seconds value is different */
|
||||
crossCheck(0.1);
|
||||
crossCheck(0.01);
|
||||
crossCheck(0.001);
|
||||
crossCheck(epicsThreadSleepQuantum());
|
||||
|
||||
testDiag("Resolution %u ns", (unsigned)epicsMonotonicResolution());
|
||||
|
||||
epicsUInt64 A = epicsMonotonicGet();
|
||||
epicsThreadSleep(0.0);
|
||||
epicsUInt64 B = epicsMonotonicGet();
|
||||
testDiag("epicsThreadSleep(0.0) Delta %u ns", (unsigned)(B-A));
|
||||
|
||||
A = epicsMonotonicGet();
|
||||
B = epicsMonotonicGet();
|
||||
testDiag("Small Delta %u ns", (unsigned)(B-A));
|
||||
}
|
||||
|
||||
MAIN(epicsTimeTest)
|
||||
{
|
||||
const int wasteTime = 100000;
|
||||
const int nTimes = 10;
|
||||
|
||||
testPlan(17 + nTimes * 19);
|
||||
testPlan(22 + nTimes * 19);
|
||||
|
||||
try {
|
||||
const epicsTimeStamp epochTS = {0, 0};
|
||||
@@ -241,5 +282,7 @@ MAIN(epicsTimeTest)
|
||||
testFail("OS time_t conversion exception for value 10 years hence");
|
||||
}
|
||||
|
||||
testMonotonic();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user