[net.sources] fsleep

donn@utah-gr.UUCP (Donn Seeley) (04/29/85)

/*
 * fsleep( d ) -- Sleep for d seconds, where d is a double.  Like sleep()
 *	but with a finer grain.  Uses the 4.2 BSD interval timer.
 *
 * Author:	Donn Seeley, UCSD Chemistry Dept., sdchema!donn
 * Date:	Wed Apr 25 03:28:14 PST 1984
 * Remarks:
 *	If an alarm clock has gone off for the caller and alarms are being
 *		blocked, the alarm is lost.  You'd think with all those new
 *		system calls, there would be a way to find out what signals
 *		have arrived without actually taking them...
 *	You must define SLEEPBUG when compiling to get the 'feature' of
 *		sleep() that signals other than alarms won't terminate
 *		the sleep.
 */

# include	<signal.h>
# include	<sys/time.h>

# define	mask(s)		(1 << ((s) - 1))

# ifdef	SLEEPBUG
static int	beep;
# endif	SLEEPBUG

fsleep( d )
	double			d;
{
	struct itimerval	oldalarm, newalarm;
	struct sigvec		oldvec, newvec;
	int			_fsleep_handler();
	int			savemask;
	int			wasblocked	= 0;
	int			alarmpending	= 0;

	/*
	 * Sanity check.
	 */
	if ( d <= 0.0 )
		return;

	/*
	 * Block the alarm signal.
	 */
	savemask	= sigblock( mask( SIGALRM ) );
	wasblocked	= savemask & mask( SIGALRM );

	/*
	 * Get the old alarm time, set up the new one.
	 */
	newalarm.it_value.tv_sec	= (long) d;
	newalarm.it_value.tv_usec	=
		(long) ((d - (double) newalarm.it_value.tv_sec) * 1000000.0);
	timerclear( &newalarm.it_interval );
	if ( setitimer( ITIMER_REAL, &newalarm, &oldalarm ) < 0 ) {
		/*
		 * Illegal sleep time.
		 */
		(void) setitimer( ITIMER_REAL, &oldalarm, (struct itimerval *) 0 );
		(void) sigsetmask( savemask );
		return;
	}

	/*
	 * Was there an alarm out there already?
	 */
	if ( timerisset( &oldalarm.it_value ) )
		++alarmpending;
	else if ( timerisset( &oldalarm.it_interval ) ) {
		/*
		 * Paranoia.
		 */
		++alarmpending;
		oldalarm.it_value.tv_usec	= 11000;
	}

	/*
	 * If an old alarm would come while we slept, shorten the sleep.
	 */
	if ( alarmpending &&
	     ! timercmp( &oldalarm.it_value, &newalarm.it_value, > ) ) {
		(void) setitimer( ITIMER_REAL, &oldalarm, (struct itimerval *) 0 );
		if ( ! wasblocked ) {
			/*
			 * Just take the old alarm and return.
			 */
			sigpause( savemask );
			(void) sigsetmask( savemask );
			return;
		}
		/*
		 * Alarms are being blocked by the caller -- arrange to queue
		 * an alarm for the caller when the sleep finishes.
		 */
		newalarm.it_value	= oldalarm.it_value;
		{
			struct timeval	t;

			timerclear( &t );
			t.tv_usec		= 11000;
			timevaladd( &oldalarm.it_value, &t );
		}
	}

	/*
	 * Get the old signal handler, set up the new one.
	 */
	newvec.sv_handler	= _fsleep_handler;
	newvec.sv_mask		= savemask;
	newvec.sv_onstack	= 0;
	(void) sigvec( SIGALRM, &newvec, &oldvec );

	/*
	 * Pause for the alarm.
	 */
# ifdef	SLEEPBUG
	/*
	 * Duplicate disgusting sleep() behavior of only breaking for alarms.
	 */
	beep			= 0;
	while ( ! beep )
# endif	SLEEPBUG
		sigpause( savemask & ~ mask( SIGALRM ) );

	/*
	 * Reset the old signal handler and alarm.
	 */
	sigvec( SIGALRM, &oldvec, (struct sigvec *) 0 );
	if ( alarmpending ) {
		timevalsub( &oldalarm.it_value, &newalarm.it_value );
		(void) setitimer( ITIMER_REAL, (struct itimerval *) 0, &newalarm );
		timevaladd( &oldalarm.it_value, &newalarm.it_value );
		(void) setitimer( ITIMER_REAL, &oldalarm, (struct itimerval *) 0 );
	}

	/*
	 * Reset the mask and return.  This unblocks the alarm if it was
	 *	unblocked previously, allowing any old alarm to arrive.
	 */
	(void) sigsetmask( savemask );
	return;
}



/*
 * _fsleep_handler() -- Dummy routine for handling alarms.
 */
int _fsleep_handler()
{
# ifdef	SLEEPBUG
	++beep;
# endif	SLEEPBUG
	return 0;
}



/*
 * Add and subtract routines for timevals.
 * Stolen from the kernel.
 *
 * N.B.: subtract routine doesn't deal with
 * results which are before the beginning,
 * it just gets very confused in this case.
 * Caveat emptor.
 */
timevaladd(t1, t2)
	struct timeval *t1, *t2;
{

	t1->tv_sec += t2->tv_sec;
	t1->tv_usec += t2->tv_usec;
	timevalfix(t1);
}

timevalsub(t1, t2)
	struct timeval *t1, *t2;
{

	t1->tv_sec -= t2->tv_sec;
	t1->tv_usec -= t2->tv_usec;
	timevalfix(t1);
}

timevalfix(t1)
	struct timeval *t1;
{

	if (t1->tv_usec < 0) {
		t1->tv_sec--;
		t1->tv_usec += 1000000;
	}
	if (t1->tv_usec >= 1000000) {
		t1->tv_sec++;
		t1->tv_usec -= 1000000;
	}
}

keegane@ittvax.UUCP (Edward Keegan) (04/30/85)

> /*
s


s
s
  * fsleep( d ) -- Sleep for d seconds, where d is a double.  Like sleep()
>  *	but with a finer grain.  Uses the 4.2 BSD interval timer.
>  *
>  * Author:	Donn Seeley, UCSD Chemistry Dept., sdchema!donn
>  * Date:	Wed Apr 25 03:28:14 PST 1984
>  * Remarks:
>  *	If an alarm clock has gone off for the caller and alarms are being
>  *		blocked, the alarm is lost.  You'd think with all those new
>  *		system calls, there would be a way to find out what signals
>  *		have arrived without actually taking them...
>  *	You must define SLEEPBUG when compiling to get the 'feature' of
>  *		sleep() that signals other than alarms won't terminate
>  *		the sleep.
>  */
> 
> # include	<signal.h>
> # include	<sys/time.h>
> 
> # define	mask(s)		(1 << ((s) - 1))
> 
> # ifdef	SLEEPBUG
> static int	beep;
> # endif	SLEEPBUG
> 
> fsleep( d )
> 	double			d;
> {
> 	struct itimerval	oldalarm, newalarm;
> 	struct sigvec		oldvec, newvec;
> 	int			_fsleep_handler();
> 	int			savemask;
> 	int			wasblocked	= 0;
> 	int			alarmpending	= 0;
> 
> 	/*
> 	 * Sanity check.
> 	 */
> 	if ( d <= 0.0 )
> 		return;
> 
> 	/*
> 	 * Block the alarm signal.
> 	 */
> 	savemask	= sigblock( mask( SIGALRM ) );
> 	wasblocked	= savemask & mask( SIGALRM );
> 
> 	/*
> 	 * Get the old alarm time, set up the new one.
> 	 */
> 	newalarm.it_value.tv_sec	= (long) d;
> 	newalarm.it_value.tv_usec	=
> 		(long) ((d - (double) newalarm.it_value.tv_sec) * 1000000.0);
> 	timerclear( &newalarm.it_interval );
> 	if ( setitimer( ITIMER_REAL, &newalarm, &oldalarm ) < 0 ) {
> 		/*
> 		 * Illegal sleep time.
> 		 */
> 		(void) setitimer( ITIMER_REAL, &oldalarm, (struct itimerval *) 0 );
> 		(void) sigsetmask( savemask );
> 		return;
> 	}
> 
> 	/*
> 	 * Was there an alarm out there already?
> 	 */
> 	if ( timerisset( &oldalarm.it_value ) )
> 		++alarmpending;
> 	else if ( timerisset( &oldalarm.it_interval ) ) {
> 		/*
> 		 * Paranoia.
> 		 */
> 		++alarmpending;
> 		oldalarm.it_value.tv_usec	= 11000;
> 	}
> 
> 	/*
> 	 * If an old alarm would come while we slept, shorten the sleep.
> 	 */
> 	if ( alarmpending &&
> 	     ! timercmp( &oldalarm.it_value, &newalarm.it_value, > ) ) {
> 		(void) setitimer( ITIMER_REAL, &oldalarm, (struct itimerval *) 0 );
> 		if ( ! wasblocked ) {
> 			/*
> 			 * Just take the old alarm and return.
> 			 */
> 			sigpause( savemask );
> 			(void) sigsetmask( savemask );
> 			return;
> 		}
> 		/*
> 		 * Alarms are being blocked by the caller -- arrange to queue
> 		 * an alarm for the caller when the sleep finishes.
> 		 */
> 		newalarm.it_value	= oldalarm.it_value;
> 		{
> 			struct timeval	t;
> 
> 			timerclear( &t );
> 			t.tv_usec		= 11000;
> 			timevaladd( &oldalarm.it_value, &t );
> 		}
> 	}
> 
> 	/*
> 	 * Get the old signal handler, set up the new one.
> 	 */
> 	newvec.sv_handler	= _fsleep_handler;
> 	newvec.sv_mask		= savemask;
> 	newvec.sv_onstack	= 0;
> 	(void) sigvec( SIGALRM, &newvec, &oldvec );
> 
> 	/*
> 	 * Pause for the alarm.
> 	 */
> # ifdef	SLEEPBUG
> 	/*
> 	 * Duplicate disgusting sleep() behavior of only breaking for alarms.
> 	 */
> 	beep			= 0;
> 	while ( ! beep )
> # endif	SLEEPBUG
> 		sigpause( savemask & ~ mask( SIGALRM ) );
> 
> 	/*
> 	 * Reset the old signal handler and alarm.
> 	 */
> 	sigvec( SIGALRM, &oldvec, (struct sigvec *) 0 );
> 	if ( alarmpending ) {
> 		timevalsub( &oldalarm.it_value, &newalarm.it_value );
> 		(void) setitimer( ITIMER_REAL, (struct itimerval *) 0, &newalarm );
> 		timevaladd( &oldalarm.it_value, &newalarm.it_value );
> 		(void) setitimer( ITIMER_REAL, &oldalarm, (struct itimerval *) 0 );
> 	}
> 
> 	/*
> 	 * Reset the mask and return.  This unblocks the alarm if it was
> 	 *	unblocked previously, allowing any old alarm to arrive.
> 	 */
> 	(void) sigsetmask( savemask );
> 	return;
> }
> 
> 
> 
> /*
>  * _fsleep_handler() -- Dummy routine for handling alarms.
>  */
> int _fsleep_handler()
> {
> # ifdef	SLEEPBUG
> 	++beep;
> # endif	SLEEPBUG
> 	return 0;
> }
> 
> 
> 
> /*
>  * Add and subtract routines for timevals.
>  * Stolen from the kernel.
>  *
>  * N.B.: subtract routine doesn't deal with
>  * results which are before the beginning,
>  * it just gets very confused in this case.
>  * Caveat emptor.
>  */
> timevaladd(t1, t2)
> 	struct timeval *t1, *t2;
> {
> 
> 	t1->tv_sec += t2->tv_sec;
> 	t1->tv_usec += t2->tv_usec;
> 	timevalfix(t1);
> }
> 
> timevalsub(t1, t2)
> 	struct timeval *t1, *t2;
> {
> 
> 	t1->tv_sec -= t2->tv_sec;
> 	t1->tv_usec -= t2->tv_usec;
> 	timevalfix(t1);
> }
> 
> timevalfix(t1)
> 	struct timeval *t1;
> {
> 
> 	if (t1->tv_usec < 0) {
> 		t1->tv_sec--;
> 		t1->tv_usec += 1000000;
> 	}
> 	if (t1->tv_usec >= 1000000) {
> 		t1->tv_sec++;
> 		t1->tv_usec -= 1000000;
> 	}
> }

*** REPLACE THIS LINE WITH YOUR MESSAGE ***