diff --git a/src/Makefile.am b/src/Makefile.am index 6e2a51c..bbbfd8a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,7 +34,7 @@ AM_CFLAGS += -Wno-unused-result -Wno-unused-parameter -fno-strict-ali AM_CPPFLAGS = -DSYSCONFDIR=\"@sysconfdir@\" -DRUNSTATEDIR=\"@runstatedir@\" AM_CPPFLAGS += -D_BSD_SOURCE -D_DEFAULT_SOURCE -syslogd_SOURCES = syslogd.c syslogd.h socket.c socket.h syslog.h queue.h compat.h +syslogd_SOURCES = syslogd.c syslogd.h socket.c socket.h syslog.h timer.c timer.h queue.h compat.h syslogd_CPPFLAGS = $(AM_CPPFLAGS) -D_XOPEN_SOURCE=600 syslogd_LDADD = $(LIBS) $(LIBOBJS) diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..06fffb1 --- /dev/null +++ b/src/timer.c @@ -0,0 +1,221 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (C) 2017-2019 Joachim Nilsson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "queue.h" +#include "socket.h" + +struct timer { + LIST_ENTRY(timer) tmr_link; + + int tmr_period; /* period time in seconds */ + time_t tmr_timeout; + + void (*tmr_cb)(void *arg); + void *tmr_arg; +}; + +static LIST_HEAD(, timer) tmr_head = LIST_HEAD_INITIALIZER(); + +static struct timespec now; +static int timer_fd[2]; + +/* + * what time is it? + */ +int timer_update(void) +{ + return clock_gettime(CLOCK_MONOTONIC, &now); +} + +time_t timer_now(void) +{ + return now.tv_sec; +} + +/* + * create periodic timer (seconds) + */ +int timer_add(int period, void (*cb)(void *), void *arg) +{ + struct timer *tmr; + + tmr = calloc(1, sizeof(*tmr)); + if (!tmr) + return -1; + + tmr->tmr_period = period; + tmr->tmr_cb = cb; + tmr->tmr_arg = arg; + + LIST_INSERT_HEAD(&tmr_head, tmr, tmr_link); + + return 0; +} + +static int __timer_start(void) +{ + struct timer *next, *tmr; + time_t sec; + + LIST_FOREACH(tmr, &tmr_head, tmr_link) { + if (tmr->tmr_timeout == 0) + tmr->tmr_timeout = timer_now() + tmr->tmr_period; + } + + next = LIST_FIRST(&tmr_head); + LIST_FOREACH(tmr, &tmr_head, tmr_link) { + if (next->tmr_timeout > tmr->tmr_timeout) + next = tmr; + } + + sec = next->tmr_timeout - timer_now(); + if (sec <= 0) + sec = 1; + + return alarm(sec); +} + +/* + * start timers + */ +int timer_start(void) +{ + if (LIST_EMPTY(&tmr_head)) + return -1; + + timer_update(); + + return __timer_start(); +} + +/* + * callback for activity on pipe + */ +static void timer_cb(int sd, void *arg) +{ + struct timer *tmr; + char dummy; + + (void)read(sd, &dummy, 1); + + timer_update(); + + LIST_FOREACH(tmr, &tmr_head, tmr_link) { + if (tmr->tmr_timeout > timer_now()) + continue; + + if (tmr->tmr_cb) + tmr->tmr_cb(tmr->tmr_arg); + tmr->tmr_timeout = 0; + } + + __timer_start(); +} + +/* + * Write to pipe to create an event on SIGALRM + */ +static void sigalarm_handler(int signo) +{ + (void)signo; + (void)write(timer_fd[1], "!", 1); +} + +/* + * register signal pipe and callback + */ +int timer_init(void) +{ + static int initialized = 0; + struct sigaction sa; + int rc; + + if (initialized) + return 0; + + if (pipe(timer_fd)) { + warn("pipe()"); + return -1; + } + + sa.sa_handler = sigalarm_handler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGALRM, &sa, NULL)) { + warn("sigaction()"); + goto err; + } + + rc = socket_register(timer_fd[0], NULL, timer_cb, NULL); + if (rc < 0) { + warn("socket_register()"); + goto err; + } + + initialized = 1; + + return 0; +err: + close(timer_fd[0]); + close(timer_fd[1]); + + return -1; +} + +/* + * deregister signal pipe and callbacks + */ +void timer_exit(void) +{ + struct timer *tmr, *tmp; + + alarm(0); + + close(timer_fd[0]); + close(timer_fd[1]); + + LIST_FOREACH_SAFE(tmr, &tmr_head, tmr_link, tmp) { + LIST_REMOVE(tmr, tmr_link); + free(tmr); + } +} + +/** + * Local Variables: + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..d573b45 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (C) 2017-2019 Joachim Nilsson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SYSKLOGD_TIMER_H_ +#define SYSKLOGD_TIMER_H_ + +int timer_add (int period, void (*cb)(void *), void *arg); + +int timer_start (void); + +int timer_update (void); +time_t timer_now (void); + +int timer_init (void); +void timer_exit (void); + +#endif /* SYSKLOGD_TIMER_H_ */