diff options
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | src/satd-diminished.c | 27 | ||||
-rw-r--r-- | src/satd-timer.c | 98 |
3 files changed, 124 insertions, 4 deletions
diff --git a/Makefile.in b/Makefile.in index 5214a3a..12c0d03 100644 --- a/Makefile.in +++ b/Makefile.in @@ -57,7 +57,7 @@ _VERSION = 1.0 _C_STD = c99 _PEDANTIC = yes _BIN = sat satq satrm satr satd -_LIBEXEC = satd-add satd-list satd-rm satd-run satd-diminished +_LIBEXEC = satd-add satd-list satd-rm satd-run satd-diminished satd-timer _OBJ_sat = sat client parse_time _OBJ_satq = satq client _OBJ_satrm = satrm client @@ -68,6 +68,7 @@ _OBJ_satd-list = satd-list daemon _OBJ_satd-rm = satd-rm daemon _OBJ_satd-run = satd-run daemon _OBJ_satd-diminished = satd-diminished +_OBJ_satd-timer = satd-timer daemon _HEADER_DIRLEVELS = 1 _CPPFLAGS = -D'PACKAGE="$(PKGNAME)"' -D'PROGRAM_VERSION="$(_VERSION)"' diff --git a/src/satd-diminished.c b/src/satd-diminished.c index 059ca83..a0fbd8b 100644 --- a/src/satd-diminished.c +++ b/src/satd-diminished.c @@ -150,6 +150,28 @@ is_timer_set(int fd) /** + * If a timer has expired, unset it. + * + * @param fd The file descriptor of the timer. + * @param fdset Set that shall contain `fd` iff it has expired. + * @return 0 on sucess, -1 on error. + */ +static int +test_timer(int fd, const fd_set *fdset) +{ + int64_t _overrun; + struct itimerspec spec = { + .it_interval.tv_sec = 0, .it_value.tv_sec = 0, + .it_interval.tv_nsec = 0, .it_value.tv_nsec = 0, + }; + if (!FD_ISSET(BOOT_FILENO, fdset)) return 0; + if (read(BOOT_FILENO, &_overrun, (size_t)8) < 8) return -1; + if (timer_pid == NO_TIMER_SPAWED) return 0; + return timerfd_settime(fd, TFD_TIMER_ABSTIME, &spec, NULL); +} + + +/** * The sat daemon. * * @param argc Should be 3. @@ -165,7 +187,6 @@ main(int argc, char *argv[], char *envp[]) int fd = -1, rc = 0, accepted = 0, r; unsigned char type; fd_set fdset; - int64_t _overrun; /* Set up signal handlers. */ t (signal(SIGHUP, sighandler) == SIG_ERR); @@ -193,8 +214,8 @@ not_done: if (select(REAL_FILENO + 1, &fdset, NULL, NULL, NULL) == -1) { t (errno != EINTR); } - if (FD_ISSET(BOOT_FILENO, &fdset)) t (read(BOOT_FILENO, &_overrun, (size_t)8) < 8); - if (FD_ISSET(REAL_FILENO, &fdset)) t (read(REAL_FILENO, &_overrun, (size_t)8) < 8); + t (test_timer(BOOT_FILENO, &fdset)); + t (test_timer(REAL_FILENO, &fdset)); if (!FD_ISSET(SOCK_FILENO, &fdset)) goto again; if (fd = accept(SOCK_FILENO, NULL, NULL), fd == -1) { diff --git a/src/satd-timer.c b/src/satd-timer.c new file mode 100644 index 0000000..4550465 --- /dev/null +++ b/src/satd-timer.c @@ -0,0 +1,98 @@ +/** + * Copyright © 2015 Mattias Andrée <maandree@member.fsf.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "daemon.h" +#include <time.h> +#include <sys/timerfd.h> + + + +/** + * Pretty self-explanatory. + */ +#ifdef __GNUC__ +__attribute__((__pure__)) +#endif +static inline int +timecmp(const struct timespec *a, const struct timespec *b) +{ + if (a->tv_sec != b->tv_sec) return (a->tv_sec < b->tv_sec ? -1 : +1); + if (a->tv_nsec != b->tv_nsec) return (a->tv_nsec < b->tv_nsec ? -1 : +1); + return 0; +} + + +/** + * Subroutine to the sat daemon: list jobs. + * + * @param argc Should be 3. + * @param argv The name of the process, the pathname of the socket, + * and the pathname to the state file. + * @return 0 The process was successful. + * @return 1 The process failed queuing the job. + */ +int +main(int argc, char *argv[]) +{ +#define TIME(job, suffix) ((job)->clk == CLOCK_BOOTTIME ? &boot##suffix : &real##suffix) + + char jobno[3 * sizeof(size_t) + 1]; + struct itimerspec bootspec; + struct itimerspec realspec; + struct timespec bootnow; + struct timespec realnow; + struct job **jobs = NULL; + struct job **job; + int rc = 0; + + /* Get current expiration time. */ + t (timerfd_gettime(BOOT_FILENO, &bootspec)); + t (timerfd_gettime(REAL_FILENO, &realspec)); + + /* Run expired jobs, and find new expiration times. */ + t (clock_gettime(CLOCK_BOOTTIME, &bootnow)); + t (clock_gettime(CLOCK_REALTIME, &realnow)); + t (!(jobs = get_jobs())); + for (job = jobs; *job; job++) { + if (timecmp(&(job[0]->ts), TIME(*job, now)) >= 0) { + sprintf(jobno, "%zu", job[0]->no); + remove_job(jobno, 2); + } else if (timecmp(&(job[0]->ts), &(TIME(*job, spec)->it_value)) > 0) { + TIME(*job, spec)->it_value = job[0]->ts; + } + } + + /* Update expiration time. */ + t (timerfd_settime(BOOT_FILENO, TFD_TIMER_ABSTIME, &bootspec, NULL)); + t (timerfd_settime(REAL_FILENO, TFD_TIMER_ABSTIME, &realspec, NULL)); + +done: + for (job = jobs; *job; job++) + free(*job); + free(jobs); + return rc; +fail: + perror(argv[0]); + rc = 1; + goto done; + (void) argc; +} + |