session UPDATE use monotonic clock if possible

Even for cond vars using the clock pthread wait
func variants.
Refs cesnet/netopeer2#1338
diff --git a/CMakeModules/UseCompat.cmake b/CMakeModules/UseCompat.cmake
index 7d7a338..3d8ad7a 100644
--- a/CMakeModules/UseCompat.cmake
+++ b/CMakeModules/UseCompat.cmake
@@ -6,7 +6,7 @@
 # Additionally, "compat.h" include directory is added and can be included.
 #
 # Author Michal Vasko <mvasko@cesnet.cz>
-#  Copyright (c) 2021 CESNET, z.s.p.o.
+#  Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
 #
 # This source code is licensed under BSD 3-Clause License (the "License").
 # You may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
 #     https://opensource.org/licenses/BSD-3-Clause
 #
 include(CheckSymbolExists)
-include(CheckFunctionExists)
 include(CheckIncludeFile)
 include(TestBigEndian)
 if(POLICY CMP0075)
@@ -29,6 +28,26 @@
     list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__BSD_VISIBLE=1)
     set(CMAKE_REQUIRED_LIBRARIES pthread)
 
+    check_symbol_exists(_POSIX_TIMERS "unistd.h" HAVE_CLOCK)
+    if(NOT HAVE_CLOCK)
+        message(FATAL_ERROR "Missing support for clock_gettime() and similar functions!")
+    endif()
+
+    check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
+    check_symbol_exists(pthread_mutex_clocklock "pthread.h" HAVE_PTHREAD_MUTEX_CLOCKLOCK)
+    check_symbol_exists(pthread_rwlock_clockrdlock "pthread.h" HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK)
+    check_symbol_exists(pthread_rwlock_clockwrlock "pthread.h" HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK)
+    check_symbol_exists(pthread_cond_clockwait "pthread.h" HAVE_PTHREAD_COND_CLOCKWAIT)
+    if(HAVE_PTHREAD_MUTEX_CLOCKLOCK)
+        # can use CLOCK_MONOTONIC only if we have pthread_mutex_clocklock()
+        check_symbol_exists(_POSIX_MONOTONIC_CLOCK "unistd.h" HAVE_CLOCK_MONOTONIC)
+    endif()
+    if(HAVE_CLOCK_MONOTONIC)
+        set(COMPAT_CLOCK_ID "CLOCK_MONOTONIC")
+    else()
+        set(COMPAT_CLOCK_ID "CLOCK_REALTIME")
+    endif()
+
     check_symbol_exists(vdprintf "stdio.h;stdarg.h" HAVE_VDPRINTF)
     check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF)
     check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF)
@@ -41,8 +60,6 @@
 
     check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME)
 
-    check_function_exists(pthread_mutex_timedlock HAVE_PTHREAD_MUTEX_TIMEDLOCK)
-
     TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
 
     check_include_file("stdatomic.h" HAVE_STDATOMIC)
diff --git a/compat/compat.c b/compat/compat.c
index bf75c74..4491680 100644
--- a/compat/compat.c
+++ b/compat/compat.c
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief compatibility functions
  *
- * Copyright (c) 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -28,6 +28,100 @@
 #include <time.h>
 #include <unistd.h>
 
+#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
+int
+pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+    int64_t nsec_diff;
+    int32_t diff;
+    struct timespec cur, dur;
+    int rc;
+
+    /* try to acquire the lock and, if we fail, sleep for 5ms. */
+    while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {
+        /* get time */
+        clock_gettime(COMPAT_CLOCK_ID, &cur);
+
+        /* get time diff */
+        nsec_diff = 0;
+        nsec_diff += (((int64_t)abstime->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
+        nsec_diff += ((int64_t)abstime->tv_nsec) - ((int64_t)cur.tv_nsec);
+        diff = (nsec_diff ? nsec_diff / 1000000L : 0);
+
+        if (diff < 1) {
+            /* timeout */
+            break;
+        } else if (diff < 5) {
+            /* sleep until timeout */
+            dur.tv_sec = 0;
+            dur.tv_nsec = (long)diff * 1000000;
+        } else {
+            /* sleep 5 ms */
+            dur.tv_sec = 0;
+            dur.tv_nsec = 5000000;
+        }
+
+        nanosleep(&dur, NULL);
+    }
+
+    return rc;
+}
+
+#endif
+
+#ifndef HAVE_PTHREAD_MUTEX_CLOCKLOCK
+int
+pthread_mutex_clocklock(pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime)
+{
+    /* only real time supported without this function */
+    if (clockid != CLOCK_REALTIME) {
+        return EINVAL;
+    }
+
+    return pthread_mutex_timedlock(mutex, abstime);
+}
+
+#endif
+
+#ifndef HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
+int
+pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime)
+{
+    /* only real time supported without this function */
+    if (clockid != CLOCK_REALTIME) {
+        return EINVAL;
+    }
+
+    return pthread_rwlock_timedrdlock(rwlock, abstime);
+}
+
+#endif
+
+#ifndef HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
+int
+pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime)
+{
+    /* only real time supported without this function */
+    if (clockid != CLOCK_REALTIME) {
+        return EINVAL;
+    }
+
+    return pthread_rwlock_timedwrlock(rwlock, abstime);
+}
+
+#endif
+
+#ifndef HAVE_PTHREAD_COND_CLOCKWAIT
+int
+pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t UNUSED(clockid),
+        const struct timespec *abstime)
+{
+    /* assume the correct clock is set during cond init */
+    return pthread_cond_timedwait(cond, mutex, abstime);
+}
+
+#endif
+
 #ifndef HAVE_VDPRINTF
 int
 vdprintf(int fd, const char *format, va_list ap)
@@ -199,52 +293,3 @@
 }
 
 #endif
-
-#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
-int
-pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
-{
-    int64_t nsec_diff;
-    int32_t diff;
-    struct timespec cur, dur;
-    int rc;
-
-    /* try to acquire the lock and, if we fail, sleep for 5ms. */
-    while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {
-        /* get real time */
-#ifdef CLOCK_REALTIME
-        clock_gettime(CLOCK_REALTIME, &cur);
-#else
-        struct timeval tv;
-
-        gettimeofday(&tv, NULL);
-        cur.tv_sec = (time_t)tv.tv_sec;
-        cur.tv_nsec = 1000L * (long)tv.tv_usec;
-#endif
-
-        /* get time diff */
-        nsec_diff = 0;
-        nsec_diff += (((int64_t)abstime->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
-        nsec_diff += ((int64_t)abstime->tv_nsec) - ((int64_t)cur.tv_nsec);
-        diff = (nsec_diff ? nsec_diff / 1000000L : 0);
-
-        if (diff < 1) {
-            /* timeout */
-            break;
-        } else if (diff < 5) {
-            /* sleep until timeout */
-            dur.tv_sec = 0;
-            dur.tv_nsec = (long)diff * 1000000;
-        } else {
-            /* sleep 5 ms */
-            dur.tv_sec = 0;
-            dur.tv_nsec = 5000000;
-        }
-
-        nanosleep(&dur, NULL);
-    }
-
-    return rc;
-}
-
-#endif
diff --git a/compat/compat.h.in b/compat/compat.h.in
index acc5fc7..61a2a23 100644
--- a/compat/compat.h.in
+++ b/compat/compat.h.in
@@ -3,7 +3,7 @@
  * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief compatibility functions header
  *
- * Copyright (c) 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
 #ifndef _COMPAT_H_
 #define _COMPAT_H_
 
+#include <alloca.h>
 #include <limits.h>
 #include <pthread.h>
 #include <stdarg.h>
@@ -48,6 +49,13 @@
 # define _PACKED
 #endif
 
+#define COMPAT_CLOCK_ID @COMPAT_CLOCK_ID@
+#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
+#cmakedefine HAVE_PTHREAD_MUTEX_CLOCKLOCK
+#cmakedefine HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
+#cmakedefine HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
+#cmakedefine HAVE_PTHREAD_COND_CLOCKWAIT
+
 #cmakedefine HAVE_VDPRINTF
 #cmakedefine HAVE_ASPRINTF
 #cmakedefine HAVE_VASPRINTF
@@ -57,7 +65,6 @@
 #cmakedefine HAVE_STRDUPA
 #cmakedefine HAVE_STRCHRNUL
 #cmakedefine HAVE_GET_CURRENT_DIR_NAME
-#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
 
 #ifndef bswap64
 #define bswap64(val) \
@@ -87,6 +94,10 @@
 
 # define ATOMIC_T atomic_uint_fast32_t
 # define ATOMIC_T_MAX UINT_FAST32_MAX
+# define ATOMIC64_T atomic_uint_fast64_t
+# define ATOMIC64_T_MAX UINT_FAST64_MAX
+
+# define ATOMIC_PTR_T atomic_uintptr_t
 
 # define ATOMIC_STORE_RELAXED(var, x) atomic_store_explicit(&(var), x, memory_order_relaxed)
 # define ATOMIC_LOAD_RELAXED(var) atomic_load_explicit(&(var), memory_order_relaxed)
@@ -94,11 +105,20 @@
 # define ATOMIC_ADD_RELAXED(var, x) atomic_fetch_add_explicit(&(var), x, memory_order_relaxed)
 # define ATOMIC_DEC_RELAXED(var) atomic_fetch_sub_explicit(&(var), 1, memory_order_relaxed)
 # define ATOMIC_SUB_RELAXED(var, x) atomic_fetch_sub_explicit(&(var), x, memory_order_relaxed)
+# define ATOMIC_COMPARE_EXCHANGE_RELAXED(var, exp, des, result) \
+        result = atomic_compare_exchange_strong_explicit(&(var), &(exp), des, memory_order_relaxed, memory_order_relaxed)
+
+# define ATOMIC_PTR_STORE_RELAXED(var, x) atomic_store_explicit(&(var), (uintptr_t)(x), memory_order_relaxed)
+# define ATOMIC_PTR_LOAD_RELAXED(var) ((void *)atomic_load_explicit(&(var), memory_order_relaxed))
 #else
 # include <stdint.h>
 
 # define ATOMIC_T uint32_t
 # define ATOMIC_T_MAX UINT32_MAX
+# define ATOMIC64_T uint64_t
+# define ATOMIC64_T_MAX UINT64_MAX
+
+# define ATOMIC_PTR_T void *
 
 # define ATOMIC_STORE_RELAXED(var, x) ((var) = (x))
 # define ATOMIC_LOAD_RELAXED(var) (var)
@@ -106,6 +126,35 @@
 # define ATOMIC_ADD_RELAXED(var, x) __sync_fetch_and_add(&(var), x)
 # define ATOMIC_DEC_RELAXED(var) __sync_fetch_and_sub(&(var), 1)
 # define ATOMIC_SUB_RELAXED(var, x) __sync_fetch_and_sub(&(var), x)
+# define ATOMIC_COMPARE_EXCHANGE_RELAXED(var, exp, des, result) \
+        { \
+            ATOMIC_T __old = __sync_val_compare_and_swap(&(var), exp, des); \
+            result = ATOMIC_LOAD_RELAXED(__old) == ATOMIC_LOAD_RELAXED(exp) ? 1 : 0; \
+            ATOMIC_STORE_RELAXED(exp, ATOMIC_LOAD_RELAXED(__old)); \
+        }
+
+# define ATOMIC_PTR_STORE_RELAXED(var, x) ((var) = (x))
+# define ATOMIC_PTR_LOAD_RELAXED(var) (var)
+#endif
+
+#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
+int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
+#endif
+
+#ifndef HAVE_PTHREAD_MUTEX_CLOCKLOCK
+int pthread_mutex_clocklock(pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime);
+#endif
+
+#ifndef HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
+int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime);
+#endif
+
+#ifndef HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
+int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime);
+#endif
+
+#ifndef HAVE_PTHREAD_COND_CLOCKWAIT
+int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime);
 #endif
 
 #ifndef HAVE_VDPRINTF
@@ -151,8 +200,4 @@
 char *get_current_dir_name(void);
 #endif
 
-#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
-int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
-#endif
-
 #endif /* _COMPAT_H_ */
diff --git a/src/io.c b/src/io.c
index 5b2ed8b..d0c4c5c 100644
--- a/src/io.c
+++ b/src/io.c
@@ -105,7 +105,7 @@
         return 0;
     }
 
-    nc_gettimespec_mono_add(&ts_inact_timeout, inact_timeout);
+    nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
     do {
         interrupted = 0;
         switch (session->ti_type) {
@@ -210,8 +210,8 @@
             if (!interrupted) {
                 usleep(NC_TIMEOUT_STEP);
             }
-            if ((nc_difftimespec_mono_cur(&ts_inact_timeout) < 1) || (nc_difftimespec_mono_cur(ts_act_timeout) < 1)) {
-                if (nc_difftimespec_mono_cur(&ts_inact_timeout) < 1) {
+            if ((nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) || (nc_timeouttime_cur_diff(ts_act_timeout) < 1)) {
+                if (nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) {
                     ERR(session, "Inactive read timeout elapsed.");
                 } else {
                     ERR(session, "Active read timeout elapsed.");
@@ -225,7 +225,7 @@
             readd += r;
 
             /* reset inactive timeout */
-            nc_gettimespec_mono_add(&ts_inact_timeout, inact_timeout);
+            nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
         }
 
     } while (readd < count);
@@ -360,7 +360,7 @@
         goto cleanup;
     }
 
-    nc_gettimespec_mono_add(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
+    nc_timeouttime_get(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
 
     if (!io_locked) {
         /* SESSION IO LOCK */
diff --git a/src/session.c b/src/session.c
index 274c40d..8ebb83a 100644
--- a/src/session.c
+++ b/src/session.c
@@ -4,7 +4,7 @@
  * @brief libnetconf2 - general session functions
  *
  * @copyright
- * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -56,112 +56,55 @@
 
 extern struct nc_server_opts server_opts;
 
-int
-nc_gettimespec_real_add(struct timespec *ts, uint32_t msec)
+void
+nc_timeouttime_get(struct timespec *ts, uint32_t add_ms)
 {
-#ifdef CLOCK_REALTIME
+    if (clock_gettime(COMPAT_CLOCK_ID, ts) == -1) {
+        ERR(NULL, "clock_gettime() failed (%s).", strerror(errno));
+        return;
+    }
+
+    if (!add_ms) {
+        return;
+    }
+
+    assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
+
+    ts->tv_sec += add_ms / 1000;
+    ts->tv_nsec += (add_ms % 1000) * 1000000L;
+
+    if (ts->tv_nsec >= 1000000000L) {
+        ++ts->tv_sec;
+        ts->tv_nsec -= 1000000000L;
+    } else if (ts->tv_nsec < 0) {
+        --ts->tv_sec;
+        ts->tv_nsec += 1000000000L;
+    }
+
+    assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
+}
+
+int32_t
+nc_timeouttime_cur_diff(const struct timespec *ts)
+{
+    struct timespec cur;
+    int64_t nsec_diff = 0;
+
+    nc_timeouttime_get(&cur, 0);
+
+    nsec_diff += (((int64_t)ts->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
+    nsec_diff += ((int64_t)ts->tv_nsec) - ((int64_t)cur.tv_nsec);
+
+    return nsec_diff / 1000000L;
+}
+
+void
+nc_realtime_get(struct timespec *ts)
+{
     if (clock_gettime(CLOCK_REALTIME, ts)) {
-        return -1;
+        ERR(NULL, "clock_gettime() failed (%s).", strerror(errno));
+        return;
     }
-#else
-    int rc;
-    struct timeval tv;
-
-    rc = gettimeofday(&tv, NULL);
-    if (rc) {
-        return -1;
-    } else {
-        ts->tv_sec = (time_t)tv.tv_sec;
-        ts->tv_nsec = 1000L * (long)tv.tv_usec;
-    }
-#endif
-
-    if (!msec) {
-        return 0;
-    }
-
-    assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
-
-    ts->tv_sec += msec / 1000;
-    ts->tv_nsec += (msec % 1000) * 1000000L;
-
-    if (ts->tv_nsec >= 1000000000L) {
-        ++ts->tv_sec;
-        ts->tv_nsec -= 1000000000L;
-    } else if (ts->tv_nsec < 0) {
-        --ts->tv_sec;
-        ts->tv_nsec += 1000000000L;
-    }
-
-    assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
-    return 0;
-}
-
-int
-nc_gettimespec_mono_add(struct timespec *ts, uint32_t msec)
-{
-#ifdef CLOCK_MONOTONIC_RAW
-    if (clock_gettime(CLOCK_MONOTONIC_RAW, ts)) {
-        return -1;
-    }
-#elif defined (CLOCK_MONOTONIC)
-    if (clock_gettime(CLOCK_MONOTONIC, ts)) {
-        return -1;
-    }
-#else
-    /* no monotonic clock available, return real time */
-    if (nc_gettimespec_real_add(ts, 0)) {
-        return -1;
-    }
-#endif
-
-    if (!msec) {
-        return 0;
-    }
-
-    assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
-
-    ts->tv_sec += msec / 1000;
-    ts->tv_nsec += (msec % 1000) * 1000000L;
-
-    if (ts->tv_nsec >= 1000000000L) {
-        ++ts->tv_sec;
-        ts->tv_nsec -= 1000000000L;
-    } else if (ts->tv_nsec < 0) {
-        --ts->tv_sec;
-        ts->tv_nsec += 1000000000L;
-    }
-
-    assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
-    return 0;
-}
-
-int32_t
-nc_difftimespec_real_cur(const struct timespec *ts)
-{
-    struct timespec cur;
-    int64_t nsec_diff = 0;
-
-    nc_gettimespec_real_add(&cur, 0);
-
-    nsec_diff += (((int64_t)ts->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
-    nsec_diff += ((int64_t)ts->tv_nsec) - ((int64_t)cur.tv_nsec);
-
-    return nsec_diff / 1000000L;
-}
-
-int32_t
-nc_difftimespec_mono_cur(const struct timespec *ts)
-{
-    struct timespec cur;
-    int64_t nsec_diff = 0;
-
-    nc_gettimespec_mono_add(&cur, 0);
-
-    nsec_diff += (((int64_t)ts->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
-    nsec_diff += ((int64_t)ts->tv_nsec) - ((int64_t)cur.tv_nsec);
-
-    return nsec_diff / 1000000L;
 }
 
 const char *
@@ -277,13 +220,14 @@
     }
 
     if (timeout > 0) {
-        nc_gettimespec_real_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
 
         /* LOCK */
-        ret = pthread_mutex_timedlock(&session->opts.server.rpc_lock, &ts_timeout);
+        ret = pthread_mutex_clocklock(&session->opts.server.rpc_lock, COMPAT_CLOCK_ID, &ts_timeout);
         if (!ret) {
             while (session->opts.server.rpc_inuse) {
-                ret = pthread_cond_timedwait(&session->opts.server.rpc_cond, &session->opts.server.rpc_lock, &ts_timeout);
+                ret = pthread_cond_clockwait(&session->opts.server.rpc_cond, &session->opts.server.rpc_lock,
+                        COMPAT_CLOCK_ID, &ts_timeout);
                 if (ret) {
                     pthread_mutex_unlock(&session->opts.server.rpc_lock);
                     break;
@@ -353,10 +297,10 @@
     assert(session->opts.server.rpc_inuse);
 
     if (timeout > 0) {
-        nc_gettimespec_real_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
 
         /* LOCK */
-        ret = pthread_mutex_timedlock(&session->opts.server.rpc_lock, &ts_timeout);
+        ret = pthread_mutex_clocklock(&session->opts.server.rpc_lock, COMPAT_CLOCK_ID, &ts_timeout);
     } else if (!timeout) {
         /* LOCK */
         ret = pthread_mutex_trylock(&session->opts.server.rpc_lock);
@@ -396,9 +340,9 @@
     struct timespec ts_timeout;
 
     if (timeout > 0) {
-        nc_gettimespec_real_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
 
-        ret = pthread_mutex_timedlock(session->io_lock, &ts_timeout);
+        ret = pthread_mutex_clocklock(session->io_lock, COMPAT_CLOCK_ID, &ts_timeout);
     } else if (!timeout) {
         ret = pthread_mutex_trylock(session->io_lock);
     } else { /* timeout == -1 */
@@ -445,14 +389,14 @@
 
     if (*timeout > 0) {
         /* get current time */
-        nc_gettimespec_real_add(&ts_start, 0);
+        nc_timeouttime_get(&ts_start, 0);
 
-        nc_gettimespec_real_add(&ts_timeout, *timeout);
+        nc_timeouttime_get(&ts_timeout, *timeout);
 
-        ret = pthread_mutex_timedlock(&session->opts.client.msgs_lock, &ts_timeout);
+        ret = pthread_mutex_clocklock(&session->opts.client.msgs_lock, COMPAT_CLOCK_ID, &ts_timeout);
         if (!ret) {
             /* update timeout based on what was elapsed */
-            diff_msec = nc_difftimespec_real_cur(&ts_start);
+            diff_msec = nc_timeouttime_cur_diff(&ts_start);
             *timeout -= diff_msec;
         }
     } else if (!*timeout) {
@@ -868,10 +812,10 @@
         ATOMIC_STORE_RELAXED(session->opts.client.ntf_thread_running, 0);
 
         /* wait for them */
-        nc_gettimespec_mono_add(&ts, NC_SESSION_FREE_LOCK_TIMEOUT);
+        nc_timeouttime_get(&ts, NC_SESSION_FREE_LOCK_TIMEOUT);
         while (ATOMIC_LOAD_RELAXED(session->opts.client.ntf_thread_count)) {
             usleep(NC_TIMEOUT_STEP);
-            if (nc_difftimespec_mono_cur(&ts) < 1) {
+            if (nc_timeouttime_cur_diff(&ts) < 1) {
                 ERR(session, "Waiting for notification thread exit failed (timed out).");
                 break;
             }
@@ -972,12 +916,12 @@
     if ((session->side == NC_SERVER) && (session->flags & NC_SESSION_CH_THREAD)) {
         pthread_cond_signal(&session->opts.server.ch_cond);
 
-        nc_gettimespec_real_add(&ts, NC_SESSION_FREE_LOCK_TIMEOUT);
+        nc_timeouttime_get(&ts, NC_SESSION_FREE_LOCK_TIMEOUT);
 
         /* wait for CH thread to actually wake up and terminate */
         r = 0;
         while (!r && (session->flags & NC_SESSION_CH_THREAD)) {
-            r = pthread_cond_timedwait(&session->opts.server.ch_cond, &session->opts.server.ch_lock, &ts);
+            r = pthread_cond_clockwait(&session->opts.server.ch_cond, &session->opts.server.ch_lock, COMPAT_CLOCK_ID, &ts);
         }
         if (r) {
             ERR(session, "Waiting for Call Home thread failed (%s).", strerror(r));
diff --git a/src/session_client_ssh.c b/src/session_client_ssh.c
index bd172e8..647a526 100644
--- a/src/session_client_ssh.c
+++ b/src/session_client_ssh.c
@@ -1176,10 +1176,10 @@
 
     ssh_sess = session->ti.libssh.session;
 
-    nc_gettimespec_mono_add(&ts_timeout, NC_TRANSPORT_TIMEOUT);
+    nc_timeouttime_get(&ts_timeout, NC_TRANSPORT_TIMEOUT);
     while ((ret = ssh_connect(ssh_sess)) == SSH_AGAIN) {
         usleep(NC_TIMEOUT_STEP);
-        if (nc_difftimespec_mono_cur(&ts_timeout) < 1) {
+        if (nc_timeouttime_cur_diff(&ts_timeout) < 1) {
             break;
         }
     }
@@ -1198,11 +1198,11 @@
     }
 
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     while ((ret_auth = ssh_userauth_none(ssh_sess, NULL)) == SSH_AUTH_AGAIN) {
         usleep(NC_TIMEOUT_STEP);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             break;
         }
     }
@@ -1272,11 +1272,11 @@
             }
 
             if (timeout > -1) {
-                nc_gettimespec_mono_add(&ts_timeout, timeout);
+                nc_timeouttime_get(&ts_timeout, timeout);
             }
             while ((ret_auth = ssh_userauth_password(ssh_sess, session->username, s)) == SSH_AUTH_AGAIN) {
                 usleep(NC_TIMEOUT_STEP);
-                if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+                if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
                     break;
                 }
             }
@@ -1290,13 +1290,13 @@
             VRB(session, "Keyboard-interactive authentication.");
 
             if (timeout > -1) {
-                nc_gettimespec_mono_add(&ts_timeout, timeout);
+                nc_timeouttime_get(&ts_timeout, timeout);
             }
             while (((ret_auth = ssh_userauth_kbdint(ssh_sess, NULL, NULL)) == SSH_AUTH_INFO) ||
                     (ret_auth == SSH_AUTH_AGAIN)) {
                 if (ret_auth == SSH_AUTH_AGAIN) {
                     usleep(NC_TIMEOUT_STEP);
-                    if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+                    if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
                         break;
                     }
                     continue;
@@ -1323,7 +1323,7 @@
                     break;
                 }
                 if (timeout > -1) {
-                    nc_gettimespec_mono_add(&ts_timeout, timeout);
+                    nc_timeouttime_get(&ts_timeout, timeout);
                 }
             }
             break;
@@ -1354,11 +1354,11 @@
                 }
 
                 if (timeout > -1) {
-                    nc_gettimespec_mono_add(&ts_timeout, timeout);
+                    nc_timeouttime_get(&ts_timeout, timeout);
                 }
                 while ((ret_auth = ssh_userauth_try_publickey(ssh_sess, NULL, pubkey)) == SSH_AUTH_AGAIN) {
                     usleep(NC_TIMEOUT_STEP);
-                    if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+                    if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
                         break;
                     }
                 }
@@ -1390,11 +1390,11 @@
                 }
 
                 if (timeout > -1) {
-                    nc_gettimespec_mono_add(&ts_timeout, timeout);
+                    nc_timeouttime_get(&ts_timeout, timeout);
                 }
                 while ((ret_auth = ssh_userauth_publickey(ssh_sess, NULL, privkey)) == SSH_AUTH_AGAIN) {
                     usleep(NC_TIMEOUT_STEP);
-                    if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+                    if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
                         break;
                     }
                 }
@@ -1458,12 +1458,12 @@
 
     /* open a channel */
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     session->ti.libssh.channel = ssh_channel_new(ssh_sess);
     while ((ret = ssh_channel_open_session(session->ti.libssh.channel)) == SSH_AGAIN) {
         usleep(NC_TIMEOUT_STEP);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             break;
         }
     }
@@ -1481,11 +1481,11 @@
 
     /* execute the NETCONF subsystem on the channel */
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     while ((ret = ssh_channel_request_subsystem(session->ti.libssh.channel, "netconf")) == SSH_AGAIN) {
         usleep(NC_TIMEOUT_STEP);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             break;
         }
     }
diff --git a/src/session_client_tls.c b/src/session_client_tls.c
index add5871..73f8cee 100644
--- a/src/session_client_tls.c
+++ b/src/session_client_tls.c
@@ -707,11 +707,11 @@
     SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
 
     /* connect and perform the handshake */
-    nc_gettimespec_mono_add(&ts_timeout, NC_TRANSPORT_TIMEOUT);
+    nc_timeouttime_get(&ts_timeout, NC_TRANSPORT_TIMEOUT);
     tlsauth_ch = 0;
     while (((ret = SSL_connect(session->ti.tls)) != 1) && (SSL_get_error(session->ti.tls, ret) == SSL_ERROR_WANT_READ)) {
         usleep(NC_TIMEOUT_STEP);
-        if (nc_difftimespec_mono_cur(&ts_timeout) < 1) {
+        if (nc_timeouttime_cur_diff(&ts_timeout) < 1) {
             ERR(NULL, "SSL connect timeout.");
             goto fail;
         }
@@ -822,12 +822,12 @@
 
     /* connect and perform the handshake */
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     tlsauth_ch = 1;
     while (((ret = SSL_connect(tls)) == -1) && (SSL_get_error(tls, ret) == SSL_ERROR_WANT_READ)) {
         usleep(NC_TIMEOUT_STEP);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             ERR(NULL, "SSL connect timeout.");
             goto cleanup;
         }
diff --git a/src/session_p.h b/src/session_p.h
index 71f30da..aaa6cbc 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -540,40 +540,27 @@
 NC_MSG_TYPE nc_send_msg_io(struct nc_session *session, int io_timeout, struct lyd_node *op);
 
 /**
- * @brief Get the current real time if available and optionally add some time to it.
+ * @brief Get current clock (uses COMPAT_CLOCK_ID) time with an offset.
  *
- * @param[in,out] ts Timespec structure holding time.
- * @param[in] msec Time in milliseconds to be added.
- * @return 0 on success;
- * @return -1 on error.
+ * @param[out] ts Current time offset by @p add_ms.
+ * @param[in] add_ms Number of milliseconds to add.
  */
-int nc_gettimespec_real_add(struct timespec *ts, uint32_t msec);
+void nc_timeouttime_get(struct timespec *ts, uint32_t add_ms);
 
 /**
- * @brief Get the current monotonic time if available and optionally add some time to it.
- *
- * @param[in,out] ts Timespec structure holding time.
- * @param[in] msec Time in milliseconds to be added.
- * @return 0 on success;
- * @return -1 on error.
- */
-int nc_gettimespec_mono_add(struct timespec *ts, uint32_t msec);
-
-/**
- * @brief Get real time difference based on the current time.
+ * @brief Get time difference based on the current time (uses COMPAT_CLOCK_ID).
  *
  * @param[in] ts Timespec structure holding real time from which the current time is going to be subtracted.
  * @return Time difference in milliseconds.
  */
-int32_t nc_difftimespec_real_cur(const struct timespec *ts);
+int32_t nc_timeouttime_cur_diff(const struct timespec *ts);
 
 /**
- * @brief Get monotonic time difference based on the current time.
+ * @brief Get current CLOCK_REALTIME time.
  *
- * @param[in] ts Timespec structure holding monotonic time from which the current time is going to be subtracted.
- * @return Time difference in milliseconds.
+ * @param[out] ts Current real time.
  */
-int32_t nc_difftimespec_mono_cur(const struct timespec *ts);
+void nc_realtime_get(struct timespec *ts);
 
 const char *nc_keytype2str(NC_SSH_KEY_TYPE type);
 
diff --git a/src/session_server.c b/src/session_server.c
index 00ec005..55d249d 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -941,9 +941,9 @@
         return msgtype;
     }
 
-    nc_gettimespec_mono_add(&ts_cur, 0);
+    nc_timeouttime_get(&ts_cur, 0);
     (*session)->opts.server.last_rpc = ts_cur.tv_sec;
-    nc_gettimespec_real_add(&ts_cur, 0);
+    nc_realtime_get(&ts_cur);
     (*session)->opts.server.session_start = ts_cur.tv_sec;
 
     (*session)->status = NC_STATUS_RUNNING;
@@ -1021,10 +1021,10 @@
     int ret;
     struct timespec ts;
 
-    nc_gettimespec_real_add(&ts, NC_PS_LOCK_TIMEOUT);
+    nc_timeouttime_get(&ts, NC_PS_LOCK_TIMEOUT);
 
     /* LOCK */
-    ret = pthread_mutex_timedlock(&ps->lock, &ts);
+    ret = pthread_mutex_clocklock(&ps->lock, COMPAT_CLOCK_ID, &ts);
     if (ret) {
         ERR(NULL, "%s: failed to lock a pollsession (%s).", func, strerror(ret));
         return -1;
@@ -1044,9 +1044,9 @@
 
     /* is it our turn? */
     while (ps->queue[ps->queue_begin] != *id) {
-        nc_gettimespec_real_add(&ts, NC_PS_QUEUE_TIMEOUT);
+        nc_timeouttime_get(&ts, NC_PS_QUEUE_TIMEOUT);
 
-        ret = pthread_cond_timedwait(&ps->cond, &ps->lock, &ts);
+        ret = pthread_cond_clockwait(&ps->cond, &ps->lock, COMPAT_CLOCK_ID, &ts);
         if (ret) {
             /**
              * This may happen when another thread releases the lock and broadcasts the condition
@@ -1077,10 +1077,10 @@
     int ret;
     struct timespec ts;
 
-    nc_gettimespec_real_add(&ts, NC_PS_LOCK_TIMEOUT);
+    nc_timeouttime_get(&ts, NC_PS_LOCK_TIMEOUT);
 
     /* LOCK */
-    ret = pthread_mutex_timedlock(&ps->lock, &ts);
+    ret = pthread_mutex_clocklock(&ps->lock, COMPAT_CLOCK_ID, &ts);
     if (ret) {
         ERR(NULL, "%s: failed to lock a pollsession (%s).", func, strerror(ret));
         ret = -1;
@@ -1736,9 +1736,9 @@
     }
 
     /* fill timespecs */
-    nc_gettimespec_mono_add(&ts_cur, 0);
+    nc_timeouttime_get(&ts_cur, 0);
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
 
     /* poll all the sessions one-by-one */
@@ -1832,7 +1832,7 @@
         if (ret == NC_PSPOLL_TIMEOUT) {
             usleep(NC_TIMEOUT_STEP);
 
-            if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+            if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
                 /* final timeout */
                 break;
             }
@@ -2590,9 +2590,9 @@
         return msgtype;
     }
 
-    nc_gettimespec_mono_add(&ts_cur, 0);
+    nc_timeouttime_get(&ts_cur, 0);
     (*session)->opts.server.last_rpc = ts_cur.tv_sec;
-    nc_gettimespec_real_add(&ts_cur, 0);
+    nc_realtime_get(&ts_cur);
     (*session)->opts.server.session_start = ts_cur.tv_sec;
     (*session)->status = NC_STATUS_RUNNING;
 
@@ -3395,9 +3395,9 @@
         goto fail;
     }
 
-    nc_gettimespec_mono_add(&ts_cur, 0);
+    nc_timeouttime_get(&ts_cur, 0);
     (*session)->opts.server.last_rpc = ts_cur.tv_sec;
-    nc_gettimespec_real_add(&ts_cur, 0);
+    nc_realtime_get(&ts_cur);
     (*session)->opts.server.session_start = ts_cur.tv_sec;
     (*session)->status = NC_STATUS_RUNNING;
 
@@ -3473,10 +3473,10 @@
     }
 
     do {
-        nc_gettimespec_real_add(&ts, NC_CH_NO_ENDPT_WAIT);
+        nc_timeouttime_get(&ts, NC_CH_NO_ENDPT_WAIT);
 
         /* CH COND WAIT */
-        r = pthread_cond_timedwait(&session->opts.server.ch_cond, &session->opts.server.ch_lock, &ts);
+        r = pthread_cond_clockwait(&session->opts.server.ch_cond, &session->opts.server.ch_lock, COMPAT_CLOCK_ID, &ts);
         if (!r) {
             /* we were woken up, something probably happened */
             if (session->status != NC_STATUS_RUNNING) {
@@ -3505,7 +3505,7 @@
             idle_timeout = 0;
         }
 
-        nc_gettimespec_mono_add(&ts, 0);
+        nc_timeouttime_get(&ts, 0);
         if (!nc_session_get_notif_status(session) && idle_timeout && (ts.tv_sec >= session->opts.server.last_rpc + idle_timeout)) {
             VRB(session, "Call Home client \"%s\": session idle timeout elapsed.", client->name);
             session->status = NC_STATUS_INVALID;
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index 9907a33..db45b42 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -1099,7 +1099,7 @@
     }
 
     if (opts->auth_timeout) {
-        nc_gettimespec_mono_add(&ts_timeout, opts->auth_timeout * 1000);
+        nc_timeouttime_get(&ts_timeout, opts->auth_timeout * 1000);
     }
 
     /* get user's replies */
@@ -1116,7 +1116,7 @@
         }
 
         usleep(NC_TIMEOUT_STEP);
-    } while ((opts->auth_timeout) && (nc_difftimespec_mono_cur(&ts_timeout) >= 1));
+    } while ((opts->auth_timeout) && (nc_timeouttime_cur_diff(&ts_timeout) >= 1));
 
     if (!reply) {
         ERR(NULL, "Authentication timeout.");
@@ -1684,7 +1684,7 @@
     }
 
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     while (1) {
         if (!nc_session_is_connected(session)) {
@@ -1704,7 +1704,7 @@
         }
 
         usleep(NC_TIMEOUT_STEP);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             /* timeout */
             ERR(session, "Failed to start \"netconf\" SSH subsystem for too long, disconnecting.");
             break;
@@ -1794,7 +1794,7 @@
 
     /* authenticate */
     if (opts->auth_timeout) {
-        nc_gettimespec_mono_add(&ts_timeout, opts->auth_timeout * 1000);
+        nc_timeouttime_get(&ts_timeout, opts->auth_timeout * 1000);
     }
     while (1) {
         if (!nc_session_is_connected(session)) {
@@ -1820,7 +1820,7 @@
         }
 
         usleep(NC_TIMEOUT_STEP);
-        if ((opts->auth_timeout) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((opts->auth_timeout) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             /* timeout */
             break;
         }
@@ -1882,12 +1882,12 @@
     ssh_set_blocking(session->ti.libssh.session, 0);
 
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     while ((r = ssh_handle_key_exchange(session->ti.libssh.session)) == SSH_AGAIN) {
         /* this tends to take longer */
         usleep(NC_TIMEOUT_STEP * 20);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             break;
         }
     }
@@ -1973,9 +1973,9 @@
         return msgtype;
     }
 
-    nc_gettimespec_real_add(&ts_cur, 0);
+    nc_realtime_get(&ts_cur);
     new_session->opts.server.session_start = ts_cur.tv_sec;
-    nc_gettimespec_mono_add(&ts_cur, 0);
+    nc_timeouttime_get(&ts_cur, 0);
     new_session->opts.server.last_rpc = ts_cur.tv_sec;
     new_session->status = NC_STATUS_RUNNING;
     *session = new_session;
@@ -2044,9 +2044,9 @@
         return msgtype;
     }
 
-    nc_gettimespec_real_add(&ts_cur, 0);
+    nc_realtime_get(&ts_cur);
     new_session->opts.server.session_start = ts_cur.tv_sec;
-    nc_gettimespec_mono_add(&ts_cur, 0);
+    nc_timeouttime_get(&ts_cur, 0);
     new_session->opts.server.last_rpc = ts_cur.tv_sec;
     new_session->status = NC_STATUS_RUNNING;
     *session = new_session;
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index 80513d9..040836f 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -2002,11 +2002,11 @@
     pthread_setspecific(verify_key, session);
 
     if (timeout > -1) {
-        nc_gettimespec_mono_add(&ts_timeout, timeout);
+        nc_timeouttime_get(&ts_timeout, timeout);
     }
     while (((ret = SSL_accept(session->ti.tls)) == -1) && (SSL_get_error(session->ti.tls, ret) == SSL_ERROR_WANT_READ)) {
         usleep(NC_TIMEOUT_STEP);
-        if ((timeout > -1) && (nc_difftimespec_mono_cur(&ts_timeout) < 1)) {
+        if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
             ERR(session, "SSL accept timeout.");
             return 0;
         }