tree-wide: don't assume CLOCK_BOOTIME is generally available

Before we invoke now(CLOCK_BOOTTIME), let's make sure we actually have that
clock, since now() will otherwise hit an assert.

Specifically, let's refuse CLOCK_BOOTTIME early in sd-event if the kernel
doesn't actually support it.

This is a follow-up for #3037, and specifically:

https://github.com/systemd/systemd/pull/3037#issuecomment-210199167
This commit is contained in:
Lennart Poettering 2016-04-20 18:12:57 +02:00
parent f53d86c929
commit 3411372e35
5 changed files with 40 additions and 18 deletions

View File

@ -1080,22 +1080,31 @@ bool timezone_is_valid(const char *name) {
return true;
}
clockid_t clock_boottime_or_monotonic(void) {
static clockid_t clock = -1;
int fd;
bool clock_boottime_supported(void) {
static int supported = -1;
if (clock != -1)
return clock;
/* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
clock = CLOCK_MONOTONIC;
else {
safe_close(fd);
clock = CLOCK_BOOTTIME;
if (supported < 0) {
int fd;
fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
supported = false;
else {
safe_close(fd);
supported = true;
}
}
return clock;
return supported;
}
clockid_t clock_boottime_or_monotonic(void) {
if (clock_boottime_supported())
return CLOCK_BOOTTIME;
else
return CLOCK_MONOTONIC;
}
int get_timezone(char **tz) {

View File

@ -112,6 +112,7 @@ bool ntp_synced(void);
int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
bool clock_boottime_supported(void);
clockid_t clock_boottime_or_monotonic(void);
#define xstrftime(buf, fmt, tm) \

View File

@ -373,7 +373,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
* rather than the monotonic clock. */
ts_realtime = now(CLOCK_REALTIME);
ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
ts_monotonic = now(t->wake_system ? clock_boottime_or_monotonic() : CLOCK_MONOTONIC);
t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
LIST_FOREACH(value, v, t->values) {

View File

@ -1072,6 +1072,10 @@ _public_ int sd_event_add_time(
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) &&
!clock_boottime_supported())
return -EOPNOTSUPP;
if (!callback)
callback = time_exit_callback;
@ -2527,7 +2531,8 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
dual_timestamp_get(&e->timestamp);
e->timestamp_boottime = now(clock_boottime_or_monotonic());
if (clock_boottime_supported())
e->timestamp_boottime = now(CLOCK_BOOTTIME);
for (i = 0; i < m; i++) {
@ -2761,6 +2766,9 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
CLOCK_BOOTTIME,
CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP);
if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported())
return -EOPNOTSUPP;
if (!dual_timestamp_is_set(&e->timestamp)) {
/* Implicitly fall back to now() if we never ran
* before and thus have no cached time. */

View File

@ -270,8 +270,10 @@ static void test_sd_event_now(void) {
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
if (clock_boottime_supported()) {
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
}
assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
@ -280,8 +282,10 @@ static void test_sd_event_now(void) {
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
if (clock_boottime_supported()) {
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
}
assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
}