2 * idle.c -- pause code for fetchmail
4 * For license terms, see the file COPYING in this directory.
9 #if defined(STDC_HEADERS)
12 #if defined(HAVE_UNISTD_H)
19 #include "fetchmail.h"
22 volatile int lastsig; /* last signal received */
24 #ifdef SLEEP_WITH_ALARM
26 * The function of this variable is to remove the window during which a
27 * SIGALRM can hose the code (ALARM is triggered *before* pause() is called).
28 * This is a bit of a kluge; the real right thing would use sigprocmask(),
29 * sigsuspend(). This workaround lets the interval timer trigger the first
30 * alarm after the required interval and will then generate alarms all 5
31 * seconds, until it is certain, that the critical section (ie., the window)
34 #if defined(STDC_HEADERS)
35 static sig_atomic_t alarm_latch = FALSE;
37 /* assume int can be written in one atomic operation on non ANSI-C systems */
38 static int alarm_latch = FALSE;
41 RETSIGTYPE gotsigalrm(int sig)
43 signal(sig, gotsigalrm);
47 #endif /* SLEEP_WITH_ALARM */
50 /* Various EMX-specific definitions */
51 static int itimerflag;
53 void itimerthread(void* dummy)
55 if (outlevel >= O_VERBOSE)
57 GT_("fetchmail: thread sleeping for %d sec.\n"), poll_interval);
60 _sleep2(poll_interval*1000);
61 kill((getpid()), SIGALRM);
66 RETSIGTYPE donothing(int sig) {signal(sig, donothing); lastsig = sig;}
68 int interruptible_idle(int seconds)
69 /* time for a pause in the action; return TRUE if awakened by signal */
74 * With this simple hack, we make it possible for a foreground
75 * fetchmail to wake up one in daemon mode. What we want is the
76 * side effect of interrupting any sleep that may be going on,
77 * forcing fetchmail to re-poll its hosts. The second line is
78 * for people who think all system daemons wake up on SIGHUP.
80 signal(SIGUSR1, donothing);
82 signal(SIGHUP, donothing);
85 #ifdef SLEEP_WITH_ALARM /* not normally on */
87 * We can't use sleep(3) here because we need an alarm(3)
88 * equivalent in order to implement server nonresponse timeout.
89 * We'll just assume setitimer(2) is available since fetchmail
90 * has to have a BSDoid socket layer to work at all.
93 * This code stopped working under glibc-2, apparently due
94 * to the change in signal(2) semantics. (The siginterrupt
95 * line, added later, should fix this problem.) John Stracke
96 * <francis@netscape.com> wrote:
98 * The problem seems to be that, after hitting the interval
99 * timer while talking to the server, the process no longer
100 * responds to SIGALRM. I put in printf()s to see when it
101 * reached the pause() for the poll interval, and I checked
102 * the return from setitimer(), and everything seemed to be
103 * working fine, except that the pause() just ignored SIGALRM.
104 * I thought maybe the itimer wasn't being fired, so I hit
105 * it with a SIGALRM from the command line, and it ignored
106 * that, too. SIGUSR1 woke it up just fine, and it proceeded
107 * to repoll--but, when the dummy server didn't respond, it
108 * never timed out, and SIGALRM wouldn't make it.
110 * (continued below...)
113 struct itimerval ntimeout;
115 ntimeout.it_interval.tv_sec = 5; /* repeat alarm every 5 secs */
116 ntimeout.it_interval.tv_usec = 0;
117 ntimeout.it_value.tv_sec = seconds;
118 ntimeout.it_value.tv_usec = 0;
120 siginterrupt(SIGALRM, 1);
122 signal(SIGALRM, gotsigalrm); /* first trap signals */
123 setitimer(ITIMER_REAL,&ntimeout,NULL); /* then start timer */
124 /* there is a very small window between the next two lines */
125 /* which could result in a deadlock. But this will now be */
126 /* caught by periodical alarms (see it_interval) */
130 ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
131 ntimeout.it_value.tv_sec = ntimeout.it_value.tv_usec = 0;
132 setitimer(ITIMER_REAL,&ntimeout,NULL); /* now stop timer */
133 signal(SIGALRM, SIG_IGN);
137 * So the workaround I used is to make it sleep by using
138 * select() instead of setitimer()/pause(). select() is
139 * perfectly happy being called with a timeout and
140 * no file descriptors; it just sleeps until it hits the
141 * timeout. The only concern I had was that it might
142 * implement its timeout with SIGALRM--there are some
143 * Unices where this is done, because select() is a library
144 * function--but apparently not.
147 struct timeval timeout;
149 timeout.tv_sec = run.poll_interval;
153 select(0,0,0,0, &timeout);
154 } while (lastsig == SIGCHLD);
159 signal(SIGALRM, gotsigalrm);
160 _beginthread(itimerthread, NULL, 32768, NULL);
161 /* see similar code above */
164 signal(SIGALRM, SIG_IGN);
166 if (lastsig == SIGUSR1 || ((seconds && !getuid()) && lastsig == SIGHUP))
169 /* now lock out interrupts again */
170 signal(SIGUSR1, SIG_IGN);
172 signal(SIGHUP, SIG_IGN);
174 return(awoken ? lastsig : 0);
177 /* idle.c ends here */