Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 May 1997 17:40:27 +0800
From:      Peter Wemm <peter@spinner.DIALix.COM>
To:        =?KOI8-R?B?4c7E0sXKIP7F0s7P1w==?= <ache@nagual.pp.ru>
Cc:        Bruce Evans <bde@zeta.org.au>, peter@FreeBSD.ORG, cvs-all@FreeBSD.ORG, cvs-committers@FreeBSD.ORG, cvs-lib@FreeBSD.ORG
Subject:   Re: cvs commit: src/lib/libc/gen sleep.c 
Message-ID:  <199705180940.RAA06430@spinner.DIALix.COM>
In-Reply-To: Your message of "Sun, 18 May 1997 13:04:48 %2B0400." <Pine.BSF.3.96.970518125858.1211A-100000@nagual.pp.ru> 

next in thread | previous in thread | raw e-mail | index | archive | help
=?KOI8-R?B?4c7E0sXKIP7F0s7P1w==?= wrote:
> On Sun, 18 May 1997, Peter Wemm wrote:
> 
> > My current version is compatable with this, *except* that it doesn't seem 
> > convenient to mask SIGALRM while preparing to call nanosleep().  Doing a 
> > longjump out of the signal handler seems like overkill...
> > 
> > I'm using this at present:
> 
> Good news, this variant works with Apache, lets commit it.

I'm not sure why this happens, but I suspect it's because we are eating 
the signal and not letting the apache timeout() function get called - it 
does longjumps and a whole heap of other stuff.  With using the old sleep 
code, the apache SIGALRM handler was blocked, but the original nanosleep 
version was allowing the apache timeout() to be called as an interrupt 
within sleep(3).  This is probably a bad assumption on apache's behalf if 
it depends on sleep() overriding it's SIGALRM handler...

> BTW, I see race condition when SIGALRM comes inside sleep() code
> before nanosleep() call. It can be blocked before, but how to unblock it
> inside nanosleep()? 

The only way I can think of to get out of this is to use a longjmp from 
the signal handler and restore the signal masks....  *shudder*...

eg, something roughly like this:

static struct jmpbuf slpjmp;
static void
sleephandler()
{
	longjump(&slpjmp, 1);
}
unsigned int
sleep(seconds)
        unsigned int seconds;
{
        struct timespec time_to_sleep;
        struct timespec time_remaining;
        struct sigvec vec, ovec;
 
        if (seconds != 0) {
                time_to_sleep.tv_sec = seconds;
                time_to_sleep.tv_nsec = 0;
		.. mask SIGALRM ..
                setvec(vec, sleephandler);
               	(void) sigvec(SIGALRM, &vec, &ovec);
		if (setjmp(&jmpbuf) == 0) {
			.. unmask SIGALRM ..
                	nanosleep(&time_to_sleep, &time_remaining);
                	(void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
                	seconds = time_remaining.tv_sec;
                	if (time_remaining.tv_nsec > 0)
                        	seconds++;      /* round up */
		} else {
			.. calculate elapsed time ..
		}
		(void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
		.. unmask SIGALRM ..
        }
        return (seconds);
}
.. but this has several problems..
1: it's starting to get messy with lots of syscalls.
2: it doesn't deal with an aborted nanosleep() due to SIGALRM. It'd have 
to calculate the elapsed time itself by calling gettimeofday or 
clock_gettime() before and after.  It'd also suffer from time adjustments 
and contribute to the mess.

I'm not sure how apache would deal with loosing a SIGALRM which isn't 
going to reset it's alarm() handler...  But I don't think that what the new 
version is doing is any worse than the old code..

On the other hand, perhaps we could change the nanosleep syscall so that 
it takes a mask argument and handle the differences in the libc wrapper 
and have sleep(3) do this:


   sigprocmask(SIG_BLOCK, ..SIGALRM.., &oset);
   ...
   setsignal(SIGALRM, sleephandler);
   ...
   nanosleep_mask(&time, &remaining, &oset);
   ...

and have nanosleep(ts1, ts2) be implemented as nanosleep_mask(ts1, ts2, 
NULL);

> -- 
> Andrey A. Chernov
> <ache@null.net>
> http://www.nagual.pp.ru/~ache/

Cheers,
-Peter





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