chiark / gitweb /
tree-wide: don't assume CLOCK_BOOTIME is generally available
authorLennart Poettering <lennart@poettering.net>
Wed, 20 Apr 2016 16:12:57 +0000 (18:12 +0200)
committerSven Eden <yamakuzure@gmx.net>
Fri, 16 Jun 2017 08:12:58 +0000 (10:12 +0200)
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/elogind/elogind/pull/3037#issuecomment-210199167

src/basic/time-util.c
src/libelogind/sd-event/sd-event.c

index f2c245e..2a3957d 100644 (file)
@@ -1075,22 +1075,31 @@ bool timezone_is_valid(const char *name) {
         return true;
 }
 
-clockid_t clock_boottime_or_monotonic(void) {
-        static clockid_t clock = -1;
-        int fd;
-
-        if (clock != -1)
-                return clock;
-
-        fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
-        if (fd < 0)
-                clock = CLOCK_MONOTONIC;
-        else {
-                safe_close(fd);
-                clock = CLOCK_BOOTTIME;
+bool clock_boottime_supported(void) {
+        static int supported = -1;
+
+        /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
+
+        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) {
index 52ecb87..d76f01b 100644 (file)
@@ -1074,6 +1074,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;
 
@@ -2547,7 +2551,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++) {
 
@@ -2786,6 +2791,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. */