From ae9660de4bd0ccb65f1005ced56bb6e05d50bf11 Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Sat, 14 Mar 2015 16:39:35 +0100 Subject: [PATCH] Use CLOCK_MONOTONIC rather than CLOCK_REALTIME This changes the clock used internally by ORTE for timestamps in the protocol and for timing of internal operations. Previously, CLOCK_REALTIME was used, probably because it is the default clock used by pthread_cond_timedwait(). Using CLOCK_REALTIME has the disadvantage that the time can "jump", e.g. when the clock is adjusted by ntpdate. This causes the applications to stop publishing, which results in them disappearing from the domain even through their processes still run. The solution implemented in this commit is to switch the clock to CLOCK_MONOTONIC, which does not jump. This should have no effect at the protocol level, because the semantic of timestamps is not defined in the spec. This was also tested by running the implementations with and without this change against each other. In future, it might be a good idea to use different clocks for timestamps in the protocol and for timing of internal operations (e.g. ORTEAppSendThread()). I'm not sure what happens in the following two cases: 1) When one node is suspended to RAM/disk, CLOCK_MONOTONIC stops for the time of suspension and it is not clear to me what other nodes that run continuously do when the suspended node resumes. 2) When a node is rebooted, the monotonic clock starts from zero, i.e. there is a "jump". I'm not sure, whether IDs of the application before and after reboot will be different. UDP ports, that are a part of the ID should be randomized, but the question is how good this randomization is. If the ID is the same before and after reboot some problems might also appear. --- configure.ac | 4 ++++ orte/include/orte/orte_config_omk_linux.h | 21 +++++++++++++++++---- orte/liborte/ORTEDomain.c | 9 ++++++++- orte/liborte/RTPSCSTWriter.c | 7 ++++++- orte/liborte/htimerNtp.c | 12 ++++++++++-- 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 86f3c44..a6b9b7f 100644 --- a/configure.ac +++ b/configure.ac @@ -143,6 +143,10 @@ if test -z "${CONFIG_ORTE_RT}" ; then ) fi +AC_CHECK_FUNCS([pthread_condattr_setclock]) +AC_CHECK_LIB([rt], [clock_gettime]) +AC_CHECK_DECLS([CLOCK_MONOTONIC], [], [], [[#include ]]) + ############################### # enable GNU source AH_VERBATIM([_GNU_SOURCE],[ diff --git a/orte/include/orte/orte_config_omk_linux.h b/orte/include/orte/orte_config_omk_linux.h index 5562fca..7e80311 100644 --- a/orte/include/orte/orte_config_omk_linux.h +++ b/orte/include/orte/orte_config_omk_linux.h @@ -44,11 +44,15 @@ /* #undef HAVE_ASM_BYTEORDER_H */ /* Define to 1 if you have the header file. */ -/* #undef HAVE_BYTESWAP_H */ +#define HAVE_BYTESWAP_H 1 /* Define to 1 if you have the header file. */ #define HAVE_CTYPE_H 1 +/* Define to 1 if you have the declaration of `CLOCK_MONOTONIC', and to 0 if + you don't. */ +#define HAVE_DECL_CLOCK_MONOTONIC 1 + /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 @@ -73,6 +77,9 @@ /* Define for ORTE getopt_long self implemetation */ /* #undef HAVE_GETPOT_LONG_ORTE */ +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef HAVE_GETTIMEOFDAY */ + /* Define to 1 if you have the header file. */ #define HAVE_IFADDRS_H 1 @@ -91,6 +98,9 @@ /* Define to 1 if you have the `pthread' library (-lpthread). */ #define HAVE_LIBPTHREAD 1 +/* Define to 1 if you have the `rt' library (-lrt). */ +#define HAVE_LIBRT 1 + /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ @@ -142,6 +152,9 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_ONETD_H */ +/* Define to 1 if you have the `pthread_condattr_setclock' function. */ +#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1 + /* Define to 1 if you have the header file. */ #define HAVE_PTHREAD_H 1 @@ -157,6 +170,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 +/* Define to 1 if you have the `sigwaitinfo' function. */ +#define HAVE_SIGWAITINFO 1 + /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 @@ -224,9 +240,6 @@ */ #define LT_OBJDIR ".libs/" -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - /* Define to the address where bug reports for this package should be sent. */ #define ORTE_PACKAGE_BUGREPORT "orte@rtime.felk.cvut.cz" diff --git a/orte/liborte/ORTEDomain.c b/orte/liborte/ORTEDomain.c index 533cc73..31c1a3f 100644 --- a/orte/liborte/ORTEDomain.c +++ b/orte/liborte/ORTEDomain.c @@ -193,6 +193,7 @@ ORTEDomainCreate(int domain, ORTEDomainProp *prop, int i; uint16_t port = 0; int errno_save = 0; + pthread_condattr_t attr; debug(30, 2) ("ORTEDomainCreate: %s compiled: %s,%s\n", ORTE_PACKAGE_STRING, __DATE__, __TIME__); @@ -220,11 +221,16 @@ ORTEDomainCreate(int domain, ORTEDomainProp *prop, d->taskRecvMulticastUserdata.sock.port = 0; d->taskSend.sock.port = 0; //init structure objectEntry + pthread_condattr_init(&attr); +#if defined HAVE_PTHREAD_CONDATTR_SETCLOCK && HAVE_DECL_CLOCK_MONOTONIC + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) + goto err_free; +#endif ObjectEntryHID_init_root_field(&d->objectEntry); pthread_rwlock_init(&d->objectEntry.objRootLock, NULL); htimerRoot_init_queue(&d->objectEntry); pthread_rwlock_init(&d->objectEntry.htimRootLock, NULL); - pthread_cond_init(&d->objectEntry.htimSendCond, NULL); + pthread_cond_init(&d->objectEntry.htimSendCond, &attr); pthread_mutex_init(&d->objectEntry.htimSendMutex, NULL); d->objectEntry.htimSendCondValue = 0; d->objectEntry.htimNeedWakeUp = ORTE_TRUE; @@ -757,6 +763,7 @@ err_domainProp: pthread_mutex_destroy(&d->objectEntry.htimSendMutex); pthread_rwlock_destroy(&d->objectEntry.htimRootLock); pthread_rwlock_destroy(&d->objectEntry.objRootLock); +err_free: FREE(d); errno = errno_save; return NULL; diff --git a/orte/liborte/RTPSCSTWriter.c b/orte/liborte/RTPSCSTWriter.c index 6f4dfba..df3d8fe 100644 --- a/orte/liborte/RTPSCSTWriter.c +++ b/orte/liborte/RTPSCSTWriter.c @@ -70,7 +70,12 @@ CSTWriterInit(ORTEDomain *d, CSTWriter *cstWriter, ObjectEntryOID *object, cstWriter->domain = d; cstWriter->typeRegister = typeRegister; if ((cstWriter->guid.oid & 0x07) == OID_PUBLICATION) { - pthread_cond_init(&cstWriter->condCSChangeDestroyed, NULL); + pthread_condattr_t attr; + pthread_condattr_init(&attr); +#if defined HAVE_PTHREAD_CONDATTR_SETCLOCK && HAVE_DECL_CLOCK_MONOTONIC + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); +#endif + pthread_cond_init(&cstWriter->condCSChangeDestroyed, &attr); pthread_mutex_init(&cstWriter->mutexCSChangeDestroyed, NULL); cstWriter->condValueCSChangeDestroyed = 0; } diff --git a/orte/liborte/htimerNtp.c b/orte/liborte/htimerNtp.c index bf73b1d..57facaf 100644 --- a/orte/liborte/htimerNtp.c +++ b/orte/liborte/htimerNtp.c @@ -260,18 +260,26 @@ getActualNtpTime(void) { NtpTime result; +#if HAVE_DECL_CLOCK_MONOTONIC + struct timespec time; + + clock_gettime(CLOCK_MONOTONIC, &time); + /* FIXME: Introduce NtpTimeAssembFromNs ather than using division. */ + NtpTimeAssembFromUs(result, time.tv_sec, time.tv_nsec / 1000); +#else /* !HAVE_DECL_CLOCK_MONOTONIC */ #ifndef CONFIG_ORTE_RT struct timeval time; gettimeofday(&time, NULL); NtpTimeAssembFromUs(result, time.tv_sec, time.tv_usec); NtpTimeAssembFromUs(result, time.tv_sec, time.tv_usec); -#else +#else /* !CONFIG_ORTE_RT */ struct timespec time; clock_gettime(CLOCK_REALTIME, &time); time.tv_nsec /= 1000; //conver to us NtpTimeAssembFromUs(result, time.tv_sec, time.tv_nsec); -#endif +#endif /* CONFIG_ORTE_RT */ +#endif /* HAVE_DECL_CLOCK_MONOTONIC */ return result; } -- 2.39.2