Re: precise time values in a daemon.



Richard Kettlewell wrote:
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.



I hoped you would jump in with something.

In between the original post and now, I was reading up on this stuff, and coming to a similar conclusion, BUT you have fleshed out the detail.

Well aware of what is safe to do inside interrupts..as you say, set a global flag is about as good as it gets :-)

Is the 'volatile' to indicate it may get affected asynchronously?

I used to do all this stuff in assembler..its curious to see how it works in 'C'




Many thanks.
.



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? ... If you just want it to exit when SIGTERM is received you don't have to ... pause() is that the TERM/INT signal could arrive while pauseis not ...
    (comp.os.linux.misc)
  • Re: __lll_mutex_lock_wait ()
    ... The most likely reason is that the heap mutex that freeis trying ... functions from a signal handler. ... In order to understand recursion you must first understand recursion. ...
    (comp.lang.cpp)
  • Re: __lll_mutex_lock_wait ()
    ... The most likely reason is that the heap mutex that freeis trying ... functions from a signal handler. ... In order to understand recursion you must first understand recursion. ...
    (comp.os.linux.development.apps)
  • 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)
  • Re: mmap unuseable for interactive application?
    ... Microsoft employee appears to be wrong to you and vice versa. ... I remove brand name stickers from my things! ... The reason that this sounds sick to me, ... signals handled by a dedicated 'signal handler executing thread', ...
    (comp.os.linux.development.apps)