home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / posix / sleep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-02  |  5.2 KB  |  174 lines

  1. /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <signal.h>
  21. #include <time.h>
  22. #include <unistd.h>
  23. #include <errno.h>
  24.  
  25. /* SIGALRM signal handler for `sleep'.  This does nothing but return,
  26.    but SIG_IGN isn't supposed to break `pause'.  */
  27. static void
  28. DEFUN(sleep_handler, (sig), int sig)
  29. {
  30.   return;
  31. }
  32.  
  33. /* Make the process sleep for SECONDS seconds, or until a signal arrives
  34.    and is not ignored.  The function returns the number of seconds less
  35.    than SECONDS which it actually slept (zero if it slept the full time).
  36.    If a signal handler does a `longjmp' or modifies the handling of the
  37.    SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
  38.    signal afterwards is undefined.  There is no return value to indicate
  39.    error, but if `sleep' returns SECONDS, it probably didn't work.  */
  40. unsigned int
  41. DEFUN(sleep, (seconds), unsigned int seconds)
  42. {
  43.   unsigned int remaining, slept, realslept;
  44.   time_t before, after;
  45.   int save = errno;
  46. #ifdef _POSIX_SOURCE
  47.   sigset_t set, oset;
  48.   struct sigaction action, oldaction;
  49. #else /* _POSIX_SOURCE */
  50. #ifdef _BSD_SOURCE
  51.   int oldmask;
  52. #endif /* _BSD_SOURCE */
  53.   __sighandler_t handler;
  54. #endif /* _POSIX_SOURCE */
  55.  
  56.   if (!seconds) return 0;
  57.  
  58.   /* We want to block SIGALRM if possible. We
  59.    * unblock it later. A SIGALRM may occur after
  60.    * the singal handler has been installed but before
  61.    * we pause.
  62.    */
  63. #ifdef _POSIX_SOURCE
  64.   __sigemptyset (&set);
  65.   __sigaddset (&set, SIGALRM);
  66.   if (__sigprocmask (SIG_BLOCK, &set, &oset) < 0)
  67.     return seconds;
  68.  
  69.   action.sa_handler = sleep_handler;
  70.   __sigemptyset (&action.sa_mask);
  71.   action.sa_flags = 0;
  72.   if (__sigaction (SIGALRM, &action, &oldaction) < 0)
  73.     return seconds;
  74. #else /* _POSIX_SOURCE */
  75.  
  76. #ifdef _BSD_SOURCE
  77.   if ((oldmask = __sigblock (SIGALRM)) < 0)
  78.     return seconds;
  79. #endif /* _BSD_SOURCE */
  80.  
  81.   handler = signal (SIGALRM, sleep_handler);
  82.   if (handler == SIG_ERR)
  83.     return seconds;
  84. #endif /* _POSIX_SOURCE */
  85.  
  86.   before = time ((time_t *) NULL);
  87.  
  88.   /* return value is the time left for alarm if it was set before. if
  89.    * it returns 0, what does that mean? we assume no alarm was set
  90.    * before.
  91.    */
  92.   remaining = alarm (seconds);
  93.  
  94.   if (remaining && remaining < seconds) {
  95.     /* What if the previous alarm is about to expire. We reinstall
  96.      * the old handler and set previous alarm.
  97.      */
  98. #ifdef _POSIX_SOURCE
  99.     (void) __sigaction (SIGALRM, &oldaction, (struct sigaction *) NULL);
  100.     alarm (remaining);
  101.     /* Unblock SIGALRM with old signal mask and pause. It'd better
  102.      * not block it. */
  103.     sigsuspend (&oset);
  104. #else /* _POSIX_SOURCE */
  105.     (void) signal (SIGALRM, handler);
  106.     alarm (remaining);
  107.  
  108. #ifdef _BSD_SOURCE
  109.     /* Unblock SIGALRM with old signal mask and pause. It'd better
  110.      * not block it. */
  111.     __sigpause (oldmask);
  112. #else /* _BSD_SOURCE */
  113.     (void) pause ();
  114. #endif /* _BSD_SOURCE */
  115.  
  116. #endif /* _POSIX_SOURCE */
  117.     after = time ((time_t *) NULL);
  118.   }
  119.   else {
  120. #ifdef _POSIX_SOURCE
  121.     /* Unblock SIGALRM with old signal mask and pause. It'd better
  122.      * not block it. */
  123.     sigsuspend (&oset);
  124.     after = time ((time_t *) NULL);
  125.     (void) __sigaction (SIGALRM, &oldaction, (struct sigaction *) NULL);
  126. #else /* _POSIX_SOURCE */
  127.  
  128. #ifdef _BSD_SOURCE
  129.     /* Unblock SIGALRM with old signal mask and pause. It'd better
  130.      * not block it. */
  131.     __sigpause (oldmask);
  132. #else /* _BSD_SOURCE */
  133.     (void) pause ();
  134. #endif /* _BSD_SOURCE */
  135.  
  136.     after = time ((time_t *) NULL);
  137.     (void) signal (SIGALRM, handler);
  138. #endif /* _POSIX_SOURCE */
  139.   }
  140.  
  141.   realslept = after - before;
  142.   slept = realslept > seconds ? 0 : seconds - realslept;
  143.  
  144.   /* If we have called alarm () before which is scheduled to go
  145.    * off after sleep (seconds), we should call alarm () again.
  146.    * If sleep () is interrupted by a signal, we should turn off
  147.    * the alarm (call alarm (0)).
  148.    */
  149.   alarm (realslept > remaining ? 0 : remaining - realslept);
  150.  
  151.   /* We have to restore the old mask since sigsuspend () will
  152.    * restore the previous mask with SIGALRM mask. We have to do it
  153.    * just before we leave. We should get another SIGALRM in sleep.c.
  154.    * Am I wrong? H.J.
  155.    */
  156. #ifdef _POSIX_SOURCE
  157.   __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
  158. #else /* _POSIX_SOURCE */
  159.  
  160. #ifdef _BSD_SOURCE
  161.   __sigsetmask (oldmask);
  162. #endif /* _BSD_SOURCE */
  163.  
  164. #endif /* _POSIX_SOURCE */
  165.  
  166.   /* Restore the `errno' value we started with. Some of
  167.    * the calls we made might have failed, but we didn't
  168.    * care.
  169.    */
  170.   errno = save;
  171.  
  172.   return slept;
  173. }
  174.