summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-12-15 10:33:28 +0100
committerThomas Haller <thaller@redhat.com>2019-12-15 11:29:32 +0100
commit9a7292e2c35e66ab5d2cb330bb35cc06b2cc566b (patch)
treec03b28835b8e4bdc08058106d8b59a1d1867b603
parent6c716912eb6ddcbf56feee1913bf9235deae20c0 (diff)
downloadNetworkManager-th/n-dhcp4-timerfd-monotonic.tar.gz
dhcp-4: fallback to CLOCK_MONOTONIC for timerfdth/n-dhcp4-timerfd-monotonic
RHEL7 supports clock_gettime(CLOCK_BOOTIME), but it does not support timerfd_create(CLOCK_BOOTIME). Fallback to CLOCK_MONOTONIC.
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c30
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-private.h1
2 files changed, 27 insertions, 4 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
index 5449106a9b..72f4ee04e9 100644
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ b/shared/n-dhcp4/src/n-dhcp4-client.c
@@ -388,8 +388,14 @@ _c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *co
return -errno;
client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
- if (client->fd_timer < 0)
- return -errno;
+ if (client->fd_timer < 0) {
+ if (errno != EINVAL)
+ return -errno;
+ client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+ if (client->fd_timer < 0)
+ return -errno;
+ client->timer_is_monotonic = true;
+ }
ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
@@ -499,8 +505,24 @@ void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout);
if (timeout != client->scheduled_timeout) {
+ uint64_t scheduled_timeout = timeout;
+ int flags = TFD_TIMER_ABSTIME;
+
+ if ( timeout != 0
+ && client->timer_is_monotonic) {
+ uint64_t now;
+
+ /* the timerfd ticks with CLOCK_MONOTONIC. Calculate and set the relative
+ * timeout. */
+ now = n_dhcp4_gettime(CLOCK_BOOTTIME);
+ if (timeout <= now)
+ timeout = 1;
+ else
+ timeout = timeout - now;
+ flags = 0;
+ }
r = timerfd_settime(client->fd_timer,
- TFD_TIMER_ABSTIME,
+ flags,
&(struct itimerspec){
.it_value = {
.tv_sec = timeout / UINT64_C(1000000000),
@@ -510,7 +532,7 @@ void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
NULL);
c_assert(r >= 0);
- client->scheduled_timeout = timeout;
+ client->scheduled_timeout = scheduled_timeout;
}
}
diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h
index fa2fda38de..ce6c6c0bc3 100644
--- a/shared/n-dhcp4/src/n-dhcp4-private.h
+++ b/shared/n-dhcp4/src/n-dhcp4-private.h
@@ -332,6 +332,7 @@ struct NDhcp4Client {
uint64_t scheduled_timeout;
bool preempted : 1;
+ bool timer_is_monotonic:1;
};
#define N_DHCP4_CLIENT_NULL(_x) { \