Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 21 Jul 1996 12:30:11 +0000 ()
From:      James Raynard <fcurrent@jraynard.demon.co.uk>
To:        Adam David <adam@veda.is>
Cc:        freebsd-current@freebsd.org
Subject:   Re: missed SIGALRM
Message-ID:  <199607211230.MAA00718@jraynard.demon.co.uk>
In-Reply-To: <199607202348.XAA06918@veda.is> from "Adam David" at Jul 20, 96 11:48:22 pm

next in thread | previous in thread | raw e-mail | index | archive | help
> 
> 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 <signal.h>
#include <stdio.h>
#include <unistd.h>

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;
}





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199607211230.MAA00718>