Re: precise time values in a daemon.



The Natural Philosopher <tnp@xxxxxxxxxxxxxxx> writes:

I am wanting to write a daemon to do some monitoring, and I want to
ensure that it does its thing..which may take a variable amount of
time, at precise intervals of - say - 5 minutes.

so
while(1) {do variable time stuff - sleep 5 minutes}

is too imprecise.

But I don't want to waste cycles, checking the time..

Retrieving the current time is actually extremely quick under Linux - it
doesn't even require a system call. If you mean you don't want to poll
for the right time coming round, yeah, that would not be very efficient.

It seems that some combination of alarm() and sleep() would work, but
I a not sure how to set up a signal handler..

is it as simple as

alarm(5 minutes)
pause()

Or do I need to set up a signal handler for the interrupt?

The default behavior of SIGALRM is to terminate the process, so if you
go this route you will need to install a signal handler.

I would also like the daemon to be able to detect and act on kill
signals as well.

If you just want it to exit when SIGTERM is received you don't have to
do anything special; that's the default behavior for SIGTERM. If you
want to do some clean-up before exiting then you will need more...

I would suggest something along these lines:

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>

const int interval = 5; /* seconds between scheduled work */

/* empty handler for SIGALRM */
static void alarm_handler(int x) { }

/* handler for fatal signals */
static volatile sig_atomic_t terminated;
static void term_handler(int x) { terminated = 1; }

int main() {
time_t now, next;
sigset_t mask, oldmask;
struct sigaction sa;
/* mask out signals while working */
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGINT);
if(sigprocmask(SIG_BLOCK, &mask, &oldmask) < 0) {
perror("sigprocmask"); exit(-1);
}
/* install signal handlers */
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = alarm_handler;
if(sigaction(SIGALRM, &sa, NULL) < 0) { perror("sigaction"); exit(-1); }
sa.sa_handler = term_handler;
if(sigaction(SIGTERM, &sa, NULL) < 0) { perror("sigaction"); exit(-1); }
if(sigaction(SIGINT, &sa, NULL) < 0) { perror("sigaction"); exit(-1); }
/* set up timing */
time(&now); /* base time */
next = now + interval; /* when to next to scheduled work */
/* main loop */
while(!terminated) {
time(&now);
if(now >= next) {
next += interval;
printf("scheduled work goes here...\n");
} else {
alarm(next - now);
/* atomically restore signals and wait for one to arrive */
sigsuspend(&oldmask);
if(errno != EINTR) { perror("sigsuspend"); exit(-1); }
}
}
printf("shutdown logic goes here...\n");
return 0;
}

The reason for blocking signals and using sigsuspend() instead of
pause() is that the TERM/INT signal could arrive while pause() is not
running and therefore fail to interrupt it.

The reason for not putting the shutdown logic in the signal handler is
that there's almost nothing you can safely do in a signal handler.

--
http://www.greenend.org.uk/rjk/
.



Relevant Pages

  • Re: precise time values in a daemon.
    ... at precise intervals of - say - 5 minutes. ... Or do I need to set up a signal handler for the interrupt? ... pause() is that the TERM/INT signal could arrive while pauseis not ... The reason for not putting the shutdown logic in the signal handler is ...
    (comp.os.linux.misc)
  • Re: read-write mutex
    ... if signal handler thread catches SIGTERM it sets the variable to 1. ... If another thread reads old value (zero) it's ok, ... The question isn't whether you need a mutex or not, ...
    (comp.programming.threads)
  • Re: Why isnt SIGKILL sent to the whole process group?
    ... handler with atexit that pretty much did kill(0, SIGTERM). ... exitbeing called in the signal handler registered by the parent ...
    (comp.unix.programmer)
  • Re: Acting on SIGTERM signal under C99
    ... it is legal that the the signal handler for a ... flag in the normal program flow to terminate gracefully. ... SIGTERM; it seems that the signal handler for SIGABRT will ...
    (comp.lang.c)
  • Re: signals (again)
    ... Rather than pausing, you do a blocking read on a pipe. ... only write to the pipe from within the signal handler. ... immediately prior to the pause, ...
    (comp.lang.python)