Skip to content

Commit d8a7419

Browse files
committed
session UPDATE use monotonic clock if possible
Even for cond vars using the clock pthread wait func variants. Refs CESNET/netopeer2#1338
1 parent 2f76655 commit d8a7419

File tree

11 files changed

+268
-230
lines changed

11 files changed

+268
-230
lines changed

CMakeModules/UseCompat.cmake

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Additionally, "compat.h" include directory is added and can be included.
77
#
88
# Author Michal Vasko <[email protected]>
9-
# Copyright (c) 2021 CESNET, z.s.p.o.
9+
# Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
1010
#
1111
# This source code is licensed under BSD 3-Clause License (the "License").
1212
# You may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
1515
# https://opensource.org/licenses/BSD-3-Clause
1616
#
1717
include(CheckSymbolExists)
18-
include(CheckFunctionExists)
1918
include(CheckIncludeFile)
2019
include(TestBigEndian)
2120
if(POLICY CMP0075)
@@ -29,6 +28,26 @@ macro(USE_COMPAT)
2928
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__BSD_VISIBLE=1)
3029
set(CMAKE_REQUIRED_LIBRARIES pthread)
3130

31+
check_symbol_exists(_POSIX_TIMERS "unistd.h" HAVE_CLOCK)
32+
if(NOT HAVE_CLOCK)
33+
message(FATAL_ERROR "Missing support for clock_gettime() and similar functions!")
34+
endif()
35+
36+
check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
37+
check_symbol_exists(pthread_mutex_clocklock "pthread.h" HAVE_PTHREAD_MUTEX_CLOCKLOCK)
38+
check_symbol_exists(pthread_rwlock_clockrdlock "pthread.h" HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK)
39+
check_symbol_exists(pthread_rwlock_clockwrlock "pthread.h" HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK)
40+
check_symbol_exists(pthread_cond_clockwait "pthread.h" HAVE_PTHREAD_COND_CLOCKWAIT)
41+
if(HAVE_PTHREAD_MUTEX_CLOCKLOCK)
42+
# can use CLOCK_MONOTONIC only if we have pthread_mutex_clocklock()
43+
check_symbol_exists(_POSIX_MONOTONIC_CLOCK "unistd.h" HAVE_CLOCK_MONOTONIC)
44+
endif()
45+
if(HAVE_CLOCK_MONOTONIC)
46+
set(COMPAT_CLOCK_ID "CLOCK_MONOTONIC")
47+
else()
48+
set(COMPAT_CLOCK_ID "CLOCK_REALTIME")
49+
endif()
50+
3251
check_symbol_exists(vdprintf "stdio.h;stdarg.h" HAVE_VDPRINTF)
3352
check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF)
3453
check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF)
@@ -41,8 +60,6 @@ macro(USE_COMPAT)
4160

4261
check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME)
4362

44-
check_function_exists(pthread_mutex_timedlock HAVE_PTHREAD_MUTEX_TIMEDLOCK)
45-
4663
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
4764

4865
check_include_file("stdatomic.h" HAVE_STDATOMIC)

compat/compat.c

Lines changed: 95 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @author Michal Vasko <[email protected]>
44
* @brief compatibility functions
55
*
6-
* Copyright (c) 2021 CESNET, z.s.p.o.
6+
* Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
77
*
88
* This source code is licensed under BSD 3-Clause License (the "License").
99
* You may not use this file except in compliance with the License.
@@ -28,6 +28,100 @@
2828
#include <time.h>
2929
#include <unistd.h>
3030

31+
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
32+
int
33+
pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
34+
{
35+
int64_t nsec_diff;
36+
int32_t diff;
37+
struct timespec cur, dur;
38+
int rc;
39+
40+
/* try to acquire the lock and, if we fail, sleep for 5ms. */
41+
while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {
42+
/* get time */
43+
clock_gettime(COMPAT_CLOCK_ID, &cur);
44+
45+
/* get time diff */
46+
nsec_diff = 0;
47+
nsec_diff += (((int64_t)abstime->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
48+
nsec_diff += ((int64_t)abstime->tv_nsec) - ((int64_t)cur.tv_nsec);
49+
diff = (nsec_diff ? nsec_diff / 1000000L : 0);
50+
51+
if (diff < 1) {
52+
/* timeout */
53+
break;
54+
} else if (diff < 5) {
55+
/* sleep until timeout */
56+
dur.tv_sec = 0;
57+
dur.tv_nsec = (long)diff * 1000000;
58+
} else {
59+
/* sleep 5 ms */
60+
dur.tv_sec = 0;
61+
dur.tv_nsec = 5000000;
62+
}
63+
64+
nanosleep(&dur, NULL);
65+
}
66+
67+
return rc;
68+
}
69+
70+
#endif
71+
72+
#ifndef HAVE_PTHREAD_MUTEX_CLOCKLOCK
73+
int
74+
pthread_mutex_clocklock(pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime)
75+
{
76+
/* only real time supported without this function */
77+
if (clockid != CLOCK_REALTIME) {
78+
return EINVAL;
79+
}
80+
81+
return pthread_mutex_timedlock(mutex, abstime);
82+
}
83+
84+
#endif
85+
86+
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
87+
int
88+
pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime)
89+
{
90+
/* only real time supported without this function */
91+
if (clockid != CLOCK_REALTIME) {
92+
return EINVAL;
93+
}
94+
95+
return pthread_rwlock_timedrdlock(rwlock, abstime);
96+
}
97+
98+
#endif
99+
100+
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
101+
int
102+
pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime)
103+
{
104+
/* only real time supported without this function */
105+
if (clockid != CLOCK_REALTIME) {
106+
return EINVAL;
107+
}
108+
109+
return pthread_rwlock_timedwrlock(rwlock, abstime);
110+
}
111+
112+
#endif
113+
114+
#ifndef HAVE_PTHREAD_COND_CLOCKWAIT
115+
int
116+
pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t UNUSED(clockid),
117+
const struct timespec *abstime)
118+
{
119+
/* assume the correct clock is set during cond init */
120+
return pthread_cond_timedwait(cond, mutex, abstime);
121+
}
122+
123+
#endif
124+
31125
#ifndef HAVE_VDPRINTF
32126
int
33127
vdprintf(int fd, const char *format, va_list ap)
@@ -199,52 +293,3 @@ get_current_dir_name(void)
199293
}
200294

201295
#endif
202-
203-
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
204-
int
205-
pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
206-
{
207-
int64_t nsec_diff;
208-
int32_t diff;
209-
struct timespec cur, dur;
210-
int rc;
211-
212-
/* try to acquire the lock and, if we fail, sleep for 5ms. */
213-
while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {
214-
/* get real time */
215-
#ifdef CLOCK_REALTIME
216-
clock_gettime(CLOCK_REALTIME, &cur);
217-
#else
218-
struct timeval tv;
219-
220-
gettimeofday(&tv, NULL);
221-
cur.tv_sec = (time_t)tv.tv_sec;
222-
cur.tv_nsec = 1000L * (long)tv.tv_usec;
223-
#endif
224-
225-
/* get time diff */
226-
nsec_diff = 0;
227-
nsec_diff += (((int64_t)abstime->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
228-
nsec_diff += ((int64_t)abstime->tv_nsec) - ((int64_t)cur.tv_nsec);
229-
diff = (nsec_diff ? nsec_diff / 1000000L : 0);
230-
231-
if (diff < 1) {
232-
/* timeout */
233-
break;
234-
} else if (diff < 5) {
235-
/* sleep until timeout */
236-
dur.tv_sec = 0;
237-
dur.tv_nsec = (long)diff * 1000000;
238-
} else {
239-
/* sleep 5 ms */
240-
dur.tv_sec = 0;
241-
dur.tv_nsec = 5000000;
242-
}
243-
244-
nanosleep(&dur, NULL);
245-
}
246-
247-
return rc;
248-
}
249-
250-
#endif

compat/compat.h.in

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @author Michal Vasko <[email protected]>
44
* @brief compatibility functions header
55
*
6-
* Copyright (c) 2021 CESNET, z.s.p.o.
6+
* Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
77
*
88
* This source code is licensed under BSD 3-Clause License (the "License").
99
* You may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
1515
#ifndef _COMPAT_H_
1616
#define _COMPAT_H_
1717

18+
#include <alloca.h>
1819
#include <limits.h>
1920
#include <pthread.h>
2021
#include <stdarg.h>
@@ -48,6 +49,13 @@
4849
# define _PACKED
4950
#endif
5051

52+
#define COMPAT_CLOCK_ID @COMPAT_CLOCK_ID@
53+
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
54+
#cmakedefine HAVE_PTHREAD_MUTEX_CLOCKLOCK
55+
#cmakedefine HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
56+
#cmakedefine HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
57+
#cmakedefine HAVE_PTHREAD_COND_CLOCKWAIT
58+
5159
#cmakedefine HAVE_VDPRINTF
5260
#cmakedefine HAVE_ASPRINTF
5361
#cmakedefine HAVE_VASPRINTF
@@ -57,7 +65,6 @@
5765
#cmakedefine HAVE_STRDUPA
5866
#cmakedefine HAVE_STRCHRNUL
5967
#cmakedefine HAVE_GET_CURRENT_DIR_NAME
60-
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
6168

6269
#ifndef bswap64
6370
#define bswap64(val) \
@@ -87,25 +94,67 @@
8794

8895
# define ATOMIC_T atomic_uint_fast32_t
8996
# define ATOMIC_T_MAX UINT_FAST32_MAX
97+
# define ATOMIC64_T atomic_uint_fast64_t
98+
# define ATOMIC64_T_MAX UINT_FAST64_MAX
99+
100+
# define ATOMIC_PTR_T atomic_uintptr_t
90101

91102
# define ATOMIC_STORE_RELAXED(var, x) atomic_store_explicit(&(var), x, memory_order_relaxed)
92103
# define ATOMIC_LOAD_RELAXED(var) atomic_load_explicit(&(var), memory_order_relaxed)
93104
# define ATOMIC_INC_RELAXED(var) atomic_fetch_add_explicit(&(var), 1, memory_order_relaxed)
94105
# define ATOMIC_ADD_RELAXED(var, x) atomic_fetch_add_explicit(&(var), x, memory_order_relaxed)
95106
# define ATOMIC_DEC_RELAXED(var) atomic_fetch_sub_explicit(&(var), 1, memory_order_relaxed)
96107
# define ATOMIC_SUB_RELAXED(var, x) atomic_fetch_sub_explicit(&(var), x, memory_order_relaxed)
108+
# define ATOMIC_COMPARE_EXCHANGE_RELAXED(var, exp, des, result) \
109+
result = atomic_compare_exchange_strong_explicit(&(var), &(exp), des, memory_order_relaxed, memory_order_relaxed)
110+
111+
# define ATOMIC_PTR_STORE_RELAXED(var, x) atomic_store_explicit(&(var), (uintptr_t)(x), memory_order_relaxed)
112+
# define ATOMIC_PTR_LOAD_RELAXED(var) ((void *)atomic_load_explicit(&(var), memory_order_relaxed))
97113
#else
98114
# include <stdint.h>
99115

100116
# define ATOMIC_T uint32_t
101117
# define ATOMIC_T_MAX UINT32_MAX
118+
# define ATOMIC64_T uint64_t
119+
# define ATOMIC64_T_MAX UINT64_MAX
120+
121+
# define ATOMIC_PTR_T void *
102122

103123
# define ATOMIC_STORE_RELAXED(var, x) ((var) = (x))
104124
# define ATOMIC_LOAD_RELAXED(var) (var)
105125
# define ATOMIC_INC_RELAXED(var) __sync_fetch_and_add(&(var), 1)
106126
# define ATOMIC_ADD_RELAXED(var, x) __sync_fetch_and_add(&(var), x)
107127
# define ATOMIC_DEC_RELAXED(var) __sync_fetch_and_sub(&(var), 1)
108128
# define ATOMIC_SUB_RELAXED(var, x) __sync_fetch_and_sub(&(var), x)
129+
# define ATOMIC_COMPARE_EXCHANGE_RELAXED(var, exp, des, result) \
130+
{ \
131+
ATOMIC_T __old = __sync_val_compare_and_swap(&(var), exp, des); \
132+
result = ATOMIC_LOAD_RELAXED(__old) == ATOMIC_LOAD_RELAXED(exp) ? 1 : 0; \
133+
ATOMIC_STORE_RELAXED(exp, ATOMIC_LOAD_RELAXED(__old)); \
134+
}
135+
136+
# define ATOMIC_PTR_STORE_RELAXED(var, x) ((var) = (x))
137+
# define ATOMIC_PTR_LOAD_RELAXED(var) (var)
138+
#endif
139+
140+
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
141+
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
142+
#endif
143+
144+
#ifndef HAVE_PTHREAD_MUTEX_CLOCKLOCK
145+
int pthread_mutex_clocklock(pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime);
146+
#endif
147+
148+
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
149+
int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime);
150+
#endif
151+
152+
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
153+
int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime);
154+
#endif
155+
156+
#ifndef HAVE_PTHREAD_COND_CLOCKWAIT
157+
int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime);
109158
#endif
110159

111160
#ifndef HAVE_VDPRINTF
@@ -151,8 +200,4 @@ char *strchrnul(const char *s, int c);
151200
char *get_current_dir_name(void);
152201
#endif
153202

154-
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
155-
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
156-
#endif
157-
158203
#endif /* _COMPAT_H_ */

src/io.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
105105
return 0;
106106
}
107107

108-
nc_gettimespec_mono_add(&ts_inact_timeout, inact_timeout);
108+
nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
109109
do {
110110
interrupted = 0;
111111
switch (session->ti_type) {
@@ -210,8 +210,8 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
210210
if (!interrupted) {
211211
usleep(NC_TIMEOUT_STEP);
212212
}
213-
if ((nc_difftimespec_mono_cur(&ts_inact_timeout) < 1) || (nc_difftimespec_mono_cur(ts_act_timeout) < 1)) {
214-
if (nc_difftimespec_mono_cur(&ts_inact_timeout) < 1) {
213+
if ((nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) || (nc_timeouttime_cur_diff(ts_act_timeout) < 1)) {
214+
if (nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) {
215215
ERR(session, "Inactive read timeout elapsed.");
216216
} else {
217217
ERR(session, "Active read timeout elapsed.");
@@ -225,7 +225,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
225225
readd += r;
226226

227227
/* reset inactive timeout */
228-
nc_gettimespec_mono_add(&ts_inact_timeout, inact_timeout);
228+
nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
229229
}
230230

231231
} while (readd < count);
@@ -360,7 +360,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
360360
goto cleanup;
361361
}
362362

363-
nc_gettimespec_mono_add(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
363+
nc_timeouttime_get(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
364364

365365
if (!io_locked) {
366366
/* SESSION IO LOCK */

0 commit comments

Comments
 (0)