xref: /titanic_44/usr/src/lib/libbc/libc/gen/sys5/sleep.c (revision 0523b0a4ec1f5ec136a264130012c7bb0ede01f2)
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