1 /* 2 * Copyright 1986 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1980 Regents of the University of California. 8 * All rights reserved. The Berkeley software License Agreement 9 * specifies the terms and conditions for redistribution. 10 */ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 13 14 #include <sys/time.h> 15 #include <signal.h> 16 17 #define setvec(vec, a) \ 18 vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 19 20 static void sleepx(void); 21 22 /* 23 * sleep(n) 24 * 25 * return 0 if n seconds passed 26 * return n - t if t seconds passed 27 * 28 * this code is gross and works just barely. 29 * it would be nice if someone rewrote it. 30 */ 31 unsigned 32 sleep(unsigned n) 33 { 34 int omask; 35 struct itimerval new, old, zero; 36 struct itimerval *newp = &new; 37 struct timeval left_over; 38 int alrm_flg; 39 struct sigvec vec, ovec; 40 41 if (n == 0) 42 return(0); 43 timerclear(&newp->it_interval); 44 timerclear(&newp->it_value); 45 if (setitimer(ITIMER_REAL, newp, &old) < 0) 46 return(n); 47 newp->it_value.tv_sec = n; 48 alrm_flg = 0; 49 timerclear(&left_over); 50 if (timerisset(&old.it_value)) { 51 if (timercmp(&old.it_value, &newp->it_value, >)) { 52 old.it_value.tv_sec -= newp->it_value.tv_sec; 53 ++alrm_flg; 54 } else { 55 left_over.tv_sec = newp->it_value.tv_sec 56 - old.it_value.tv_sec; 57 if (old.it_value.tv_usec != 0) { 58 left_over.tv_sec--; 59 left_over.tv_usec = 1000000 60 - old.it_value.tv_usec; 61 } 62 newp->it_value = old.it_value; 63 timerclear(&old.it_value); 64 --alrm_flg; 65 } 66 } 67 if (alrm_flg >= 0) { 68 setvec(vec, sleepx); 69 (void) sigvec(SIGALRM, &vec, &ovec); 70 } 71 omask = sigblock(sigmask(SIGALRM)); 72 (void) setitimer(ITIMER_REAL, newp, (struct itimerval *)0); 73 sigpause(omask &~ sigmask(SIGALRM)); 74 timerclear(&zero.it_value); 75 timerclear(&zero.it_interval); 76 (void) setitimer(ITIMER_REAL, &zero, newp); 77 if (alrm_flg >= 0) 78 (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); 79 (void) sigsetmask(omask); 80 if (alrm_flg > 0 || (alrm_flg < 0 && timerisset(&newp->it_value))) { 81 struct itimerval reset; 82 83 /* 84 * I use reset instead of what new points to because the 85 * code that calculates the return value depends on the 86 * old value of *newp. 87 */ 88 reset = *newp; 89 newp = &reset; 90 newp->it_value.tv_usec += old.it_value.tv_usec; 91 newp->it_value.tv_sec += old.it_value.tv_sec; 92 if (newp->it_value.tv_usec >= 1000000) { 93 newp->it_value.tv_usec -= 1000000; 94 newp->it_value.tv_sec++; 95 } 96 (void) setitimer(ITIMER_REAL, newp, (struct itimerval *)0); 97 newp = &new; 98 } 99 left_over.tv_sec += newp->it_value.tv_sec; 100 left_over.tv_usec += newp->it_value.tv_usec; 101 if (left_over.tv_usec >= 1000000) { 102 left_over.tv_sec++; 103 left_over.tv_usec -= 1000000; 104 } 105 if (left_over.tv_usec >= 500000) 106 left_over.tv_sec++; 107 return(left_over.tv_sec); 108 } 109 110 static void 111 sleepx(void) 112 { 113 } 114