From owner-freebsd-current Sun Jul 21 08:18:08 1996 Return-Path: owner-current Received: (from root@localhost) by freefall.freebsd.org (8.7.5/8.7.3) id IAA08712 for current-outgoing; Sun, 21 Jul 1996 08:18:08 -0700 (PDT) Received: from relay-5.mail.demon.net (relay-5.mail.demon.net [158.152.1.48]) by freefall.freebsd.org (8.7.5/8.7.3) with SMTP id IAA08700 for ; Sun, 21 Jul 1996 08:18:02 -0700 (PDT) Received: from post.demon.co.uk by relay-5.mail.demon.net id am26675; 21 Jul 96 16:12 +0100 Received: from jraynard.demon.co.uk ([158.152.42.77]) by relay-3.mail.demon.net id aa28232; 21 Jul 96 15:24 +0100 Received: (from fcurrent@localhost) by jraynard.demon.co.uk (8.7.5/8.6.12) id MAA00718; Sun, 21 Jul 1996 12:30:11 GMT From: James Raynard Message-Id: <199607211230.MAA00718@jraynard.demon.co.uk> Subject: Re: missed SIGALRM To: Adam David Date: Sun, 21 Jul 1996 12:30:11 +0000 () Cc: freebsd-current@freebsd.org In-Reply-To: <199607202348.XAA06918@veda.is> from "Adam David" at Jul 20, 96 11:48:22 pm X-Mailer: ELM [version 2.4 PL24 ME8a] Content-Type: text Sender: owner-current@freebsd.org X-Loop: FreeBSD.org Precedence: bulk > > I have noticed that a SIGALRM can sometimes be missed altogether under certain > conditions, perhaps as a side-effect of heavy machine load. I am looking into > this problem, and any other datapoints/suggestions are welcome. The following > program (in its more complete version) stops doing its stuff once in a while > (typically once a day or more often) and needs to be restarted as a result. > The likelihood of this occuring seems related to periods of heavy system load. Your code is vulnerable to race conditions - when the machine is heavily loaded, there may be gaps of more than one second between the times when the program is scheduled to run. Hence a SIGALRM may occur when you are in the middle of one of these function calls, leaving data (in this case tick) in an inconsistent state. Here's my suggestion (based on one of the examples in "Advanced Programming in the Unix Environment" by W. Richard Stevens). The tick variable is a sig_atomic_t type, rather than a plain int, to guarantee that writes to it will not be interrupted. The sigprocmask() function is used to block SIGALRM signals until we're ready to handle them; sigsuspend() temporarily sets the signal mask to the one before we called sigprocmask() and waits for a signal and waits for a signal to occur. When one does, the mask is reset to the one set by sigprocmask(), so that we can call get_tick() and set_tick() without having to worry about another SIGALRM occuring during the function calls. Finally, we call sigprocmask() to reset the original signal mask (not really necessary here, but a good habit to get into). #include #include #include volatile sig_atomic_t tick; void handler(int signo) { tick = 1; } void set_tick(void) { tick = 0; alarm(1); } int get_tick(void) { return tick; } int main(void) { sigset_t newmask, oldmask; if (signal(SIGALRM, handler) == SIG_ERR) perror("signal"); sigemptyset(&newmask); sigaddset(&newmask, SIGALRM); if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) perror("sigprocmask"); set_tick(); for (;;) { while (get_tick() == 0) sigsuspend(&oldmask); /* do stuff */ set_tick(); } if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) perror("sigprocmask"); return 0; }