Skip to content

Commit

Permalink
feat(el): Allow setting custom clock sources for each EventLoop
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfr committed Aug 30, 2023
1 parent 43738f3 commit cc18714
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 16 deletions.
52 changes: 49 additions & 3 deletions arch/eventloop_posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,34 @@ UA_EventLoopPOSIX_start(UA_EventLoopPOSIX *el) {
UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"Starting the EventLoop");

/* Setting the clock source */
const UA_Int32 *cs = (const UA_Int32*)
UA_KeyValueMap_getScalar(&el->eventLoop.params,
UA_QUALIFIEDNAME(0, "clock-source"),
&UA_TYPES[UA_TYPES_INT32]);
const UA_Int32 *csm = (const UA_Int32*)
UA_KeyValueMap_getScalar(&el->eventLoop.params,
UA_QUALIFIEDNAME(0, "clock-source-monotonic"),
&UA_TYPES[UA_TYPES_INT32]);
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
el->clockSource = CLOCK_REALTIME;
if(cs)
el->clockSource = *cs;

# ifdef CLOCK_MONOTONIC_RAW
el->clockSourceMonotonic = CLOCK_MONOTONIC_RAW;
# else
el->clockSourceMonotonic = CLOCK_MONOTONIC;
# endif
if(csm)
el->clockSourceMonotonic = *csm;
#else
if(cs || csm) {
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
"Eventloop\t| Cannot set a custom clock source");
}
#endif

#ifdef UA_HAVE_EPOLL
el->epollfd = epoll_create1(0);
if(el->epollfd == -1) {
Expand Down Expand Up @@ -366,21 +394,39 @@ UA_EventLoopPOSIX_deregisterEventSource(UA_EventLoopPOSIX *el,
/* Time Domain */
/***************/

/* No special synchronization with an external source, just use the globally
* defined functions. */

static UA_DateTime
UA_EventLoopPOSIX_DateTime_now(UA_EventLoop *el) {
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
struct timespec ts;
int res = clock_gettime(pel->clockSource, &ts);
if(UA_UNLIKELY(res != 0))
return 0;
return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
return UA_DateTime_now();
#endif
}

static UA_DateTime
UA_EventLoopPOSIX_DateTime_nowMonotonic(UA_EventLoop *el) {
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
struct timespec ts;
int res = clock_gettime(pel->clockSourceMonotonic, &ts);
if(UA_UNLIKELY(res != 0))
return 0;
/* Also add the unix epoch for the monotonic clock. So we get a "normal"
* output when a "normal" source is configured. */
return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
return UA_DateTime_nowMonotonic();
#endif
}

static UA_Int64
UA_EventLoopPOSIX_DateTime_localTimeUtcOffset(UA_EventLoop *el) {
/* TODO: Fix for custom clock sources */
return UA_DateTime_localTimeUtcOffset();
}

Expand Down
6 changes: 6 additions & 0 deletions arch/eventloop_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ typedef struct {
* "run" method */
UA_Boolean executing;

#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
/* Clocks for the eventloop's time domain */
UA_Int32 clockSource;
UA_Int32 clockSourceMonotonic;
#endif

#if defined(UA_HAVE_EPOLL)
UA_FD epollfd;
#else
Expand Down
42 changes: 29 additions & 13 deletions include/open62541/plugin/eventloop.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,25 @@ struct UA_EventLoop {
/* EventLoop Time Domain
* ~~~~~~~~~~~~~~~~~~~~~
* Each EventLoop instance can manage its own time domain. This affects the
* execution of timed/cyclic callbacks and time-based sending of network
* packets (if this is implemented). Managing independent time domains is
* important when different parts of a system a synchronized to different
* external (network-wide) clocks.
* execution of timed callbacks and time-based sending of network packets.
* Managing independent time domains is important when different parts of
* the same system are synchronized to different external master clocks.
*
* Each EventLoop uses a "normal" and a "monotonic" clock. The monotonic
* clock does not (necessarily) conform to the current wallclock date. But
* its time intervals are more precise. So it is used for all internally
* scheduled events of the EventLoop (e.g. timed callbacks and time-based
* sending of network packets). The normal and monotonic clock sources can
* be configured via parameters before starting the EventLoop. See the
* architecture-specific documentation for that.
*
* Note that the logger configured in the EventLoop generates timestamps
* internally as well. If the logger uses a different time domain than the
* independently. If the logger uses a different time domain than the
* EventLoop, discrepancies may appear in the logs.
*
* The time domain of the EventLoop is exposed via the following functons.
* See `open62541/types.h` for the documentation of their equivalent
* globally defined functions. */
* The EventLoop clocks can be read via the following functons. See
* `open62541/types.h` for the documentation of their equivalent globally
* defined functions. */

UA_DateTime (*dateTime_now)(UA_EventLoop *el);
UA_DateTime (*dateTime_nowMonotonic)(UA_EventLoop *el);
Expand Down Expand Up @@ -420,13 +427,22 @@ struct UA_InterruptManager {
(*deregisterInterrupt)(UA_InterruptManager *im, uintptr_t interruptHandle);
};

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32)

/**
* POSIX-Specific Implementation
* POSIX EventLop Implementation
* -----------------------------
* The POSIX compatibility of WIN32 is 'close enough'. So a joint implementation
* is provided. */

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32)
* The POSIX compatibility of Win32 is 'close enough'. So a joint implementation
* is provided.
*
* Configuration parameters (only Linux and BSDs, must be set before start to
* take effect):
* - 0:clock-source [int32]: Clock source (default: CLOCK_REALTIME).
* - 0:clock-source-monotonic [int32]: Clock source used for time intervals. A
* non-monotonic source can be used as well. But expect accordingly longer
* sleep-times for timed events when the clock is set to the past. See the
* man-page of "clock_gettime" on how to get a clock source id for a
* character-device such as /dev/ptp0. (default: CLOCK_MONOTONIC_RAW)*/

UA_EXPORT UA_EventLoop *
UA_EventLoop_new_POSIX(const UA_Logger *logger);
Expand Down

0 comments on commit cc18714

Please sign in to comment.