Hello Thomas, et al, Following on from our discussion of read() on a timerfd [1], I happened to remember a Debian bug report [2] that points out that timer_settime() can fail with the error ECANCELED, which is both surprising and odd (because despite the error, the timer does get updated). The relevant kernel code (I think, from your commit [3]) seems to be the following in timerfd_setup(): if (texp != 0) { if (flags & TFD_TIMER_ABSTIME) texp = timens_ktime_to_host(clockid, texp); if (isalarm(ctx)) { if (flags & TFD_TIMER_ABSTIME) alarm_start(&ctx->t.alarm, texp); else alarm_start_relative(&ctx->t.alarm, texp); } else { hrtimer_start(&ctx->t.tmr, texp, htmode); } if (timerfd_canceled(ctx)) return -ECANCELED; } Using a small test program [4] shows the behavior. The program loops, repeatedly calling timerfd_settime() (with a delay of a few seconds before each call). In another terminal window, enter the following command a few times: $ sudo date -s "5 seconds" # Add 5 secs to wall-clock time I see behavior as follows (the /sudo date -s "5 seconds"/ command was executed before loop iterations 0, 2, and 4): [[ $ ./timerfd_settime_ECANCELED 0 Current time is 1585729978 secs, 868510078 nsecs Timer value is now 0 secs, 0 nsecs timerfd_settime() succeeded Timer value is now 9 secs, 999991977 nsecs 1 Current time is 1585729982 secs, 716339545 nsecs Timer value is now 6 secs, 152167990 nsecs timerfd_settime() succeeded Timer value is now 9 secs, 999992940 nsecs 2 Current time is 1585729991 secs, 567377831 nsecs Timer value is now 1 secs, 148959376 nsecs timerfd_settime: Operation canceled Timer value is now 9 secs, 999976294 nsecs 3 Current time is 1585729995 secs, 405385503 nsecs Timer value is now 6 secs, 161989917 nsecs timerfd_settime() succeeded Timer value is now 9 secs, 999993317 nsecs 4 Current time is 1585730004 secs, 225036165 nsecs Timer value is now 1 secs, 180346909 nsecs timerfd_settime: Operation canceled Timer value is now 9 secs, 999984345 nsecs ]] I note from the above. (1) If the wall-clock is changed before the first timerfd_settime() call, the call succeeds. This is of course expected. (2) If the wall-clock is changed after a timerfd_settime() call, then the next timerfd_settime() call fails with ECANCELED. (3) Even if the timerfd_settime() call fails, the timer is still updated(!). Some questions: (a) What is the rationale for timerfd_settime() failing with ECANCELED in this case? (Currently, the manual page says nothing about this.) (b) It seems at the least surprising, but more likely a bug, that timerfd_settime() fails with ECANCELED while at the same time successfully updating the timer value. Your thoughts? Thanks, Michael [1] https://lore.kernel.org/lkml/3cbd0919-c82a-cb21-c10f-0498433ba5d1@xxxxxxxxx/ [2] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=947091 [3] commit 99ee5315dac6211e972fa3f23bcc9a0343ff58c4 Author: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Date: Wed Apr 27 14:16:42 2011 +0200 timerfd: Allow timers to be cancelled when clock was set [4] /* timerfd_settime_ECANCELED.c */ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <inttypes.h> #include <sys/timerfd.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { struct itimerspec ts, gts; struct timespec start; int tfd = timerfd_create(CLOCK_REALTIME, 0); if (tfd == -1) errExit("timerfd_create"); ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 10; int flags = TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET; for (long j ; ; j++) { /* Inject a delay into each loop, by calling getppid() many times */ for (int k = 0; k < 10000000; k++) getppid(); if (j % 1 == 0) printf("%ld\n", j); /* Display the current wall-clock time */ if (clock_gettime(CLOCK_REALTIME, &start) == -1) errExit("clock_gettime"); printf("Current time is %ld secs, %ld nsecs\n", start.tv_sec, start.tv_nsec); /* Before resetting the timer, retrieve its current value so that after the timerfd_settime() call, we can see whether the the value has changed */ if (timerfd_gettime(tfd, >s) == -1) perror("timerfd_gettime"); printf("Timer value is now %ld secs, %ld nsecs\n", gts.it_value.tv_sec, gts.it_value.tv_nsec); /* Reset the timer to now + 10 secs */ ts.it_value.tv_sec = start.tv_sec + 10; ts.it_value.tv_nsec = start.tv_nsec; if (timerfd_settime(tfd, flags, &ts, NULL) == -1) perror("timerfd_settime"); else printf("timerfd_settime() succeeded\n"); /* Display the timer value once again */ if (timerfd_gettime(tfd, >s) == -1) perror("timerfd_gettime"); printf("Timer value is now %ld secs, %ld nsecs\n", gts.it_value.tv_sec, gts.it_value.tv_nsec); printf("\n"); } }