n-dhcp4: fallback to CLOCK_MONOTONIC for timerfd (resync with upstream)

The upstream merge request [1] was solved differently from
commit f49ce41214 ('client: fallback to CLOCK_MONOTONIC for timerfd').

Resync with upstream.

[1] https://github.com/nettools/n-dhcp4/pull/13
[2] a0bb7c69a1
This commit is contained in:
Thomas Haller
2020-03-18 16:00:58 +01:00
parent 6c837a366b
commit a6574b7124
2 changed files with 27 additions and 28 deletions

View File

@@ -388,14 +388,10 @@ _c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *co
return -errno; return -errno;
client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK); client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
if (client->fd_timer < 0) { if (client->fd_timer < 0 && errno == EINVAL)
if (errno != EINVAL)
return -errno;
client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (client->fd_timer < 0) if (client->fd_timer < 0)
return -errno; return -errno;
client->timerfd_is_monotonic = true;
}
ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER; ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev); r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
@@ -498,41 +494,45 @@ int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigne
* must be called whenever a timeout on @client might have changed. * must be called whenever a timeout on @client might have changed.
*/ */
void n_dhcp4_client_arm_timer(NDhcp4Client *client) { void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
uint64_t timeout = 0; uint64_t now, offset, timeout = 0;
int r; int r;
if (client->current_probe) if (client->current_probe)
n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout); n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout);
if (timeout != client->scheduled_timeout) { if (timeout != client->scheduled_timeout) {
uint64_t scheduled_timeout = timeout; /*
int flags = TFD_TIMER_ABSTIME; * Across our codebase, timeouts are specified as absolute
* timestamps on CLOCK_BOOTTIME. Unfortunately, there are
* systems with CLOCK_BOOTTIME support, but timerfd lacks it
* (in particular RHEL). Therefore, our timerfd might be on
* CLOCK_MONOTONIC.
* To account for this, we always schedule a relative timeout.
* We fetch the current time and then calculate the offset
* which we then schedule as relative timeout on the timerfd.
* This works regardless which clock the timerfd runs on.
* Once we no longer support CLOCK_MONOTONIC as fallback, we
* can simply switch to TFD_TIMER_ABSTIME here and specify
* `timeout` directly as value.
*/
now = n_dhcp4_gettime(CLOCK_BOOTTIME);
if (now >= timeout)
offset = 1; /* 0 would disarm the timerfd */
else
offset = timeout - now;
if ( timeout != 0
&& client->timerfd_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, r = timerfd_settime(client->fd_timer,
flags, 0,
&(struct itimerspec){ &(struct itimerspec){
.it_value = { .it_value = {
.tv_sec = timeout / UINT64_C(1000000000), .tv_sec = offset / UINT64_C(1000000000),
.tv_nsec = timeout % UINT64_C(1000000000), .tv_nsec = offset % UINT64_C(1000000000),
}, },
}, },
NULL); NULL);
c_assert(r >= 0); c_assert(r >= 0);
client->scheduled_timeout = scheduled_timeout; client->scheduled_timeout = timeout;
} }
} }

View File

@@ -332,7 +332,6 @@ struct NDhcp4Client {
uint64_t scheduled_timeout; uint64_t scheduled_timeout;
bool preempted : 1; bool preempted : 1;
bool timerfd_is_monotonic : 1;
}; };
#define N_DHCP4_CLIENT_NULL(_x) { \ #define N_DHCP4_CLIENT_NULL(_x) { \