-/*
- * idle.c -- pause code for fetchmail
- *
- * For license terms, see the file COPYING in this directory.
- */
-#include "config.h"
+/*****************************************************************************
+
+NAME:
+ idle.c -- code for interruptible delays without sleep(3).
+
+ENTRY POINTS:
+ interruptible_idle() -- delay for some time, interruptible by signal.
+THEORY:
+ Sometimes you need more than one time delay per program, so alarm(3)
+won't cut it. This code illustrates time delays with select(2).
+
+AUTHOR:
+ Eric S. Raymond <esr@thyrsus.com>, 1997. This source code example
+is part of fetchmail and the Unix Cookbook, and are released under the
+MIT license. Compile with -DMAIN to build the demonstrator.
+
+******************************************************************************/
#include <stdio.h>
-#if defined(STDC_HEADERS)
#include <stdlib.h>
-#endif
-#if defined(HAVE_UNISTD_H)
#include <unistd.h>
-#endif
#include <signal.h>
#include <errno.h>
-#include <sys/time.h>
+#include <fetchmail.h> /* for ROOT_UID */
-#include "fetchmail.h"
-#include "i18n.h"
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
volatile int lastsig; /* last signal received */
* SIGALRM can hose the code (ALARM is triggered *before* pause() is called).
* This is a bit of a kluge; the real right thing would use sigprocmask(),
* sigsuspend(). This workaround lets the interval timer trigger the first
- * alarm after the required interval and will then generate alarms all 5
- * seconds, until it is certain, that the critical section (ie., the window)
- * is left.
+ * alarm after the required interval and will then generate alarms
+ * seconds until it is certain that the critical section (ie., the window)
+ * is exited.
*/
-#if defined(STDC_HEADERS)
static sig_atomic_t alarm_latch = FALSE;
-#else
-/* assume int can be written in one atomic operation on non ANSI-C systems */
-static int alarm_latch = FALSE;
-#endif
-RETSIGTYPE gotsigalrm(sig)
-int sig;
+void gotsigalrm(int sig)
{
- signal(sig, gotsigalrm);
+ set_signal_handler(sig, gotsigalrm);
lastsig = sig;
alarm_latch = TRUE;
}
#endif /* SLEEP_WITH_ALARM */
-#ifdef __EMX__
-/* Various EMX-specific definitions */
-static int itimerflag;
-
-void itimerthread(void* dummy)
-{
- if (outlevel >= O_VERBOSE)
- report(stderr,
- _("fetchmail: thread sleeping for %d sec.\n"), poll_interval);
- while(1)
- {
- _sleep2(poll_interval*1000);
- kill((getpid()), SIGALRM);
- }
-}
-#endif
-
-RETSIGTYPE donothing(int sig) {signal(sig, donothing); lastsig = sig;}
-
-int idle(int seconds)
+int interruptible_idle(int seconds)
/* time for a pause in the action; return TRUE if awakened by signal */
{
int awoken = FALSE;
- /*
- * With this simple hack, we make it possible for a foreground
- * fetchmail to wake up one in daemon mode. What we want is the
- * side effect of interrupting any sleep that may be going on,
- * forcing fetchmail to re-poll its hosts. The second line is
- * for people who think all system daemons wake up on SIGHUP.
- */
- signal(SIGUSR1, donothing);
- if (!getuid())
- signal(SIGHUP, donothing);
-
-#ifndef __EMX__
#ifdef SLEEP_WITH_ALARM /* not normally on */
/*
* We can't use sleep(3) here because we need an alarm(3)
ntimeout.it_value.tv_sec = seconds;
ntimeout.it_value.tv_usec = 0;
- siginterrupt(SIGALRM, 1);
alarm_latch = FALSE;
- signal(SIGALRM, gotsigalrm); /* first trap signals */
+ set_signal_handler(SIGALRM, gotsigalrm); /* first trap signals */
setitimer(ITIMER_REAL,&ntimeout,NULL); /* then start timer */
/* there is a very small window between the next two lines */
/* which could result in a deadlock. But this will now be */
- /* caught by periodical alarms (see it_interval) */
+ /* caught by periodic alarms (see it_interval) */
if (!alarm_latch)
pause();
/* stop timer */
ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
ntimeout.it_value.tv_sec = ntimeout.it_value.tv_usec = 0;
setitimer(ITIMER_REAL,&ntimeout,NULL); /* now stop timer */
- signal(SIGALRM, SIG_IGN);
+ set_signal_handler(SIGALRM, SIG_IGN);
}
#else
/*
{
struct timeval timeout;
- timeout.tv_sec = run.poll_interval;
+ timeout.tv_sec = seconds;
timeout.tv_usec = 0;
do {
lastsig = 0;
} while (lastsig == SIGCHLD);
}
#endif
-#else /* EMX */
- alarm_latch = FALSE;
- signal(SIGALRM, gotsigalrm);
- _beginthread(itimerthread, NULL, 32768, NULL);
- /* see similar code above */
- if (!alarm_latch)
- pause();
- signal(SIGALRM, SIG_IGN);
-#endif /* ! EMX */
- if (lastsig == SIGUSR1 || ((seconds && !getuid()) && lastsig == SIGHUP))
+ if (lastsig == SIGUSR1 || ((seconds && getuid() == ROOT_UID)
+ && lastsig == SIGHUP))
awoken = TRUE;
/* now lock out interrupts again */
- signal(SIGUSR1, SIG_IGN);
- if (!getuid())
- signal(SIGHUP, SIG_IGN);
+ set_signal_handler(SIGUSR1, SIG_IGN);
+ if (getuid() == ROOT_UID)
+ set_signal_handler(SIGHUP, SIG_IGN);
return(awoken ? lastsig : 0);
}
+#ifdef MAIN
+int main(int argc, char **argv)
+{
+ for (;;)
+ {
+ printf("How may I serve you, master?\n");
+ interruptible_idle(5);
+ }
+}
+#endif /* MAIN */
+
/* idle.c ends here */