+static int manager_setup_time_change(Manager *m) {
+ struct epoll_event ev;
+ struct itimerspec its;
+
+ assert(m);
+ assert(m->time_change_watch.type == WATCH_INVALID);
+
+ /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
+ * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
+
+ m->time_change_watch.type = WATCH_TIME_CHANGE;
+ m->time_change_watch.fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (m->time_change_watch.fd < 0) {
+ log_error("Failed to create timerfd: %m");
+ return -errno;
+ }
+
+ zero(its);
+
+ /* We only care for the cancellation event, hence we set the
+ * timeout to the latest possible value. */
+ assert_cc(sizeof(time_t) == sizeof(long));
+ its.it_value.tv_sec = LONG_MAX;
+
+ if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
+ log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
+ close_nointr_nofail(m->time_change_watch.fd);
+ watch_init(&m->time_change_watch);
+ return 0;
+ }
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.ptr = &m->time_change_watch;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->time_change_watch.fd, &ev) < 0) {
+ log_error("Failed to add timer change fd to epoll: %m");
+ return -errno;
+ }
+
+ log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
+
+ return 0;
+}
+