summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorSimon Rettberg2017-10-19 13:41:51 +0200
committerSimon Rettberg2017-10-19 13:41:51 +0200
commitf366a2b2e8499c94521475ffa6bca998a3aaadd0 (patch)
treedc98bfdfd01f5c36e2677afddab116d5c78deb53 /src/shared
parent[SERVER] More tweaks to alt-server selection wrt proxy cycles (diff)
downloaddnbd3-f366a2b2e8499c94521475ffa6bca998a3aaadd0.tar.gz
dnbd3-f366a2b2e8499c94521475ffa6bca998a3aaadd0.tar.xz
dnbd3-f366a2b2e8499c94521475ffa6bca998a3aaadd0.zip
[SERVER] Use monotonic clock for measuring time
Introduces new shared source unit timing.[ch] Closes #3214
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/timing.c21
-rw-r--r--src/shared/timing.h139
2 files changed, 160 insertions, 0 deletions
diff --git a/src/shared/timing.c b/src/shared/timing.c
new file mode 100644
index 0000000..4ca1002
--- /dev/null
+++ b/src/shared/timing.c
@@ -0,0 +1,21 @@
+#include "timing.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+struct timespec basetime;
+
+void timing_abort()
+{
+ printf( "Cannot get CLOCK_MONOTONIC(_RAW), errno=%d\n", errno );
+ exit( 1 );
+}
+
+void timing_setBase()
+{
+ if ( clock_gettime( BEST_CLOCK_SOURCE, &basetime ) == -1 ) {
+ memset( &basetime, 0, sizeof(basetime) );
+ }
+}
+
diff --git a/src/shared/timing.h b/src/shared/timing.h
new file mode 100644
index 0000000..a8a51a4
--- /dev/null
+++ b/src/shared/timing.h
@@ -0,0 +1,139 @@
+#ifndef _D_TIMING_H
+#define _D_TIMING_H
+
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309L
+#endif
+
+#include <time.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef CLOCK_MONOTONIC_RAW
+#define BEST_CLOCK_SOURCE CLOCK_MONOTONIC_RAW
+#else
+#define BEST_CLOCK_SOURCE CLOCK_MONOTONIC
+#endif
+
+typedef struct timespec ticks;
+
+extern struct timespec basetime;
+
+/**
+ * Assign src to dst while adding secs seconds.
+ */
+#define timing_set(dst,src,secs) do { (dst)->tv_sec = (src)->tv_sec + secs; (dst)->tv_nsec = (src)->tv_nsec; } while (0)
+
+/**
+ * Define variable now, initialize to timing_get.
+ */
+#define declare_now ticks now; timing_get( &now )
+
+/**
+ * Call this once to calibrate on startup.
+ * Although overflows of CLOCK_MONOTONIC(_RAW) should
+ * by definition never happen, we still have a fixed size
+ * int that could at some point. By forcing the counter
+ * to start at 0 on startup the point of overflow
+ * will be very far in the future (decades for 32bit time_t,
+ * end of universe for 64bit).
+ */
+void timing_setBase();
+
+/**
+ * Internal, do not use. Moved to another function
+ * to prevent inlining of error handling code, which
+ * should be very unlikely to ever trigger.
+ */
+_Noreturn void timing_abort();
+
+/**
+ * Get current time. Shortcut for clock_gettime with error check.
+ */
+static inline void timing_get(ticks* retval)
+{
+ if ( clock_gettime( BEST_CLOCK_SOURCE, retval ) == -1 ) timing_abort();
+ retval->tv_sec -= basetime.tv_sec;
+}
+
+/**
+ * Get a ticks instance somewhere in the future.
+ * Useful for timeouts.
+ */
+static inline void timing_gets(ticks* retval, uint32_t addSeconds)
+{
+ timing_get( retval );
+ retval->tv_sec += addSeconds;
+}
+
+/**
+ * Check whether given timeout is reached.
+ * Might trigger up to one second early.
+ */
+static inline bool timing_reached(const ticks* timeout, const ticks* now)
+{
+ return now->tv_sec >= timeout->tv_sec;
+}
+#define timing_1le2(one,two) timing_reached(one,two)
+
+/**
+ * Precise check whether given timeout has been reached.
+ */
+static inline bool timing_reachedPrecise(const ticks* timeout, const ticks* now)
+{
+ return now->tv_sec > timeout->tv_sec
+ || (now->tv_sec == timeout->tv_sec && now->tv_nsec > timeout->tv_nsec);
+}
+
+/**
+ * Shortcut for above. Useful if not used in loop.
+ * Might trigger up to one second early.
+ */
+static inline bool timing_isReached(const ticks* timeout)
+{
+ ticks now;
+ timing_get( &now );
+ return timing_reached( timeout, &now );
+}
+/**
+ * Shortcut for above. Useful if not used in loop.
+ */
+static inline bool timing_isReachedPrecise(const ticks* timeout)
+{
+ ticks now;
+ timing_get( &now );
+ return timing_reachedPrecise( timeout, &now );
+}
+
+
+/**
+ * Get difference between two ticks, rounded down to seconds.
+ * Make sure you pass the arguments in the proper order. If
+ * end is before start, 0 will always be returned.
+ */
+static inline uint32_t timing_diff(const ticks *start, const ticks *end)
+{
+ if ( end->tv_sec <= start->tv_sec ) return 0;
+ return (uint32_t)( ( end->tv_sec - start->tv_sec )
+ + ( start->tv_nsec > end->tv_nsec ? -1 : 0 ) );
+}
+
+/**
+ * Get difference between two ticks, rounded down to milliseconds.
+ * Same as above; passing arguments in reverse will always return 0.
+ */
+static inline uint64_t timing_diffMs(const ticks *start, const ticks *end)
+{
+ if ( end->tv_sec < start->tv_sec ) return 0;
+ uint64_t diff = (uint64_t)( end->tv_sec - start->tv_sec ) * 1000;
+ if ( start->tv_nsec >= end->tv_nsec ) {
+ if ( diff == 0 ) return 0;
+ diff -= (start->tv_nsec - end->tv_nsec) / 1000000;
+ } else {
+ diff += (end->tv_nsec - start->tv_nsec) / 1000000;
+ }
+ return diff;
+}
+
+
+#endif