n-dhcp4: fallback to CLOCK_MONOTONIC for timerfd (resync with upstream)
The upstream merge request [1] was solved differently from commitf49ce41214
('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:
@@ -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
|
||||||
if ( timeout != 0
|
* systems with CLOCK_BOOTTIME support, but timerfd lacks it
|
||||||
&& client->timerfd_is_monotonic) {
|
* (in particular RHEL). Therefore, our timerfd might be on
|
||||||
uint64_t now;
|
* CLOCK_MONOTONIC.
|
||||||
|
* To account for this, we always schedule a relative timeout.
|
||||||
/* the timerfd ticks with CLOCK_MONOTONIC. Calculate and set the relative
|
* We fetch the current time and then calculate the offset
|
||||||
* timeout. */
|
* 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);
|
now = n_dhcp4_gettime(CLOCK_BOOTTIME);
|
||||||
if (timeout <= now)
|
if (now >= timeout)
|
||||||
timeout = 1;
|
offset = 1; /* 0 would disarm the timerfd */
|
||||||
else
|
else
|
||||||
timeout = timeout - now;
|
offset = 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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) { \
|
||||||
|
Reference in New Issue
Block a user