mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			106 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
 | |
|    This file is part of the GNU C Library.
 | |
| 
 | |
|    The GNU C Library is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU Lesser General Public
 | |
|    License as published by the Free Software Foundation; either
 | |
|    version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|    The GNU C Library is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|    Lesser General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU Lesser General Public
 | |
|    License along with the GNU C Library; if not, see
 | |
|    <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| #include <signal.h>
 | |
| #include <time.h>
 | |
| #include <unistd.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| 
 | |
| /* SIGALRM signal handler for `sleep'.  This does nothing but return,
 | |
|    but SIG_IGN isn't supposed to break `pause'.  */
 | |
| static void
 | |
| sleep_handler (int sig)
 | |
| {
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /* Make the process sleep for SECONDS seconds, or until a signal arrives
 | |
|    and is not ignored.  The function returns the number of seconds less
 | |
|    than SECONDS which it actually slept (zero if it slept the full time).
 | |
|    If a signal handler does a `longjmp' or modifies the handling of the
 | |
|    SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
 | |
|    signal afterwards is undefined.  There is no return value to indicate
 | |
|    error, but if `sleep' returns SECONDS, it probably didn't work.  */
 | |
| unsigned int
 | |
| __sleep (unsigned int seconds)
 | |
| {
 | |
|   unsigned int remaining, slept;
 | |
|   time_t before, after;
 | |
|   sigset_t set, oset;
 | |
|   struct sigaction act, oact;
 | |
|   int save = errno;
 | |
| 
 | |
|   if (seconds == 0)
 | |
|     return 0;
 | |
| 
 | |
|   /* Block SIGALRM signals while frobbing the handler.  */
 | |
|   if (sigemptyset (&set) < 0 ||
 | |
|       sigaddset (&set, SIGALRM) < 0 ||
 | |
|       sigprocmask (SIG_BLOCK, &set, &oset))
 | |
|     return seconds;
 | |
| 
 | |
|   act.sa_handler = sleep_handler;
 | |
|   act.sa_flags = 0;
 | |
|   act.sa_mask = oset;	/* execute handler with original mask */
 | |
|   if (sigaction (SIGALRM, &act, &oact) < 0)
 | |
|     return seconds;
 | |
| 
 | |
|   before = time ((time_t *) NULL);
 | |
|   remaining = alarm (seconds);
 | |
| 
 | |
|   if (remaining > 0 && remaining < seconds)
 | |
|     {
 | |
|       /* The user's alarm will expire before our own would.
 | |
| 	 Restore the user's signal action state and let his alarm happen.  */
 | |
|       (void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
 | |
|       alarm (remaining);	/* Restore sooner alarm.  */
 | |
|       sigsuspend (&oset);	/* Wait for it to go off.  */
 | |
|       after = time ((time_t *) NULL);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* Atomically restore the old signal mask
 | |
| 	 (which had better not block SIGALRM),
 | |
| 	 and wait for a signal to arrive.  */
 | |
|       sigsuspend (&oset);
 | |
| 
 | |
|       after = time ((time_t *) NULL);
 | |
| 
 | |
|       /* Restore the old signal action state.  */
 | |
|       (void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
 | |
|     }
 | |
| 
 | |
|   /* Notice how long we actually slept.  */
 | |
|   slept = after - before;
 | |
| 
 | |
|   /* Restore the user's alarm if we have not already past it.
 | |
|      If we have, be sure to turn off the alarm in case a signal
 | |
|      other than SIGALRM was what woke us up.  */
 | |
|   (void) alarm (remaining > slept ? remaining - slept : 0);
 | |
| 
 | |
|   /* Restore the original signal mask.  */
 | |
|   (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
 | |
| 
 | |
|   /* Restore the `errno' value we started with.
 | |
|      Some of the calls we made might have failed, but we didn't care.  */
 | |
|   __set_errno (save);
 | |
| 
 | |
|   return slept > seconds ? 0 : seconds - slept;
 | |
| }
 | |
| weak_alias (__sleep, sleep)
 |