]> git.ipfire.org Git - thirdparty/systemd.git/commit - src/core/timer.c
core: Detect initial timer state from serialized data
authorMichal Koutný <mkoutny@suse.com>
Fri, 2 Nov 2018 19:56:08 +0000 (20:56 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 21 Nov 2018 10:28:33 +0000 (11:28 +0100)
commitaa1f95d2647197eca84c33a0f10adaeada08467d
treeef2e4208a68d1b5cc43db4fde64cf752debcb715
parentb390455cbb3ab1288aff0eb988f5d73da3f52142
core: Detect initial timer state from serialized data

We keep a mark whether a single-shot timer was triggered in the caller's
variable initial. When such a timer elapses while we are
serializing/deserializing the inner state, we consider the timer
incorrectly as elapsed and don't trigger it later.

This patch exploits last_trigger timestamp that we already serialize,
hence we can eliminate the argument initial completely.

A reproducer for OnBootSec= timers:
        cat >repro.c <<EOD
        /*
         * Compile: gcc repro.c -o repro
         * Run: ./repro
         */
        #include <errno.h>
        #include <fcntl.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <sys/stat.h>
        #include <sys/types.h>
        #include <time.h>
        #include <unistd.h>

        int main(int argc, char *argv[]) {
         char command[1024];
         int pause;

         struct timespec now;

         while (1) {
         usleep(rand() % 200000); // prevent periodic repeats
                clock_gettime(CLOCK_MONOTONIC, &now);
         printf("%i\n", now.tv_sec);

         system("rm -f $PWD/mark");
         snprintf(command, 1024, "systemd-run --user --on-boot=%i --timer-property=AccuracySec=100ms "
         "touch $PWD/mark", now.tv_sec + 1);
         system(command);
         system("systemctl --user list-timers");
         pause = (1000000000 - now.tv_nsec)/1000 - 70000; // fiddle to hit the middle of reloading
         usleep(pause > 0 ? pause : 0);
         system("systemctl --user daemon-reload");
         sync();
         sleep(2);
         if (open("./mark", 0) < 0)
         if (errno == ENOENT) {
         printf("mark file does not exist\n");
         break;
         }
         }

         return 0;
        }
        EOD
src/core/timer.c