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
sleep(unsigned n)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
sleepx(void)111 sleepx(void)
112 {
113 }
114