xref: /titanic_53/usr/src/cmd/stat/common/common.c (revision 00c76d6fcc0e3d5821ed5ac5165f1835f8151454)
1*00c76d6fStc35445 /*
2*00c76d6fStc35445  * CDDL HEADER START
3*00c76d6fStc35445  *
4*00c76d6fStc35445  * The contents of this file are subject to the terms of the
5*00c76d6fStc35445  * Common Development and Distribution License (the "License").
6*00c76d6fStc35445  * You may not use this file except in compliance with the License.
7*00c76d6fStc35445  *
8*00c76d6fStc35445  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*00c76d6fStc35445  * or http://www.opensolaris.org/os/licensing.
10*00c76d6fStc35445  * See the License for the specific language governing permissions
11*00c76d6fStc35445  * and limitations under the License.
12*00c76d6fStc35445  *
13*00c76d6fStc35445  * When distributing Covered Code, include this CDDL HEADER in each
14*00c76d6fStc35445  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*00c76d6fStc35445  * If applicable, add the following below this CDDL HEADER, with the
16*00c76d6fStc35445  * fields enclosed by brackets "[]" replaced with your own identifying
17*00c76d6fStc35445  * information: Portions Copyright [yyyy] [name of copyright owner]
18*00c76d6fStc35445  *
19*00c76d6fStc35445  * CDDL HEADER END
20*00c76d6fStc35445  */
21*00c76d6fStc35445 /*
22*00c76d6fStc35445  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*00c76d6fStc35445  * Use is subject to license terms.
24*00c76d6fStc35445  */
25*00c76d6fStc35445 
26*00c76d6fStc35445 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*00c76d6fStc35445 
28*00c76d6fStc35445 #include "statcommon.h"
29*00c76d6fStc35445 
30*00c76d6fStc35445 #include <stdarg.h>
31*00c76d6fStc35445 #include <signal.h>
32*00c76d6fStc35445 #include <errno.h>
33*00c76d6fStc35445 #include <string.h>
34*00c76d6fStc35445 #include <stdlib.h>
35*00c76d6fStc35445 
36*00c76d6fStc35445 extern char *cmdname;
37*00c76d6fStc35445 extern int caught_cont;
38*00c76d6fStc35445 
39*00c76d6fStc35445 /*PRINTFLIKE2*/
40*00c76d6fStc35445 void
41*00c76d6fStc35445 fail(int do_perror, char *message, ...)
42*00c76d6fStc35445 {
43*00c76d6fStc35445 	va_list args;
44*00c76d6fStc35445 	int save_errno = errno;
45*00c76d6fStc35445 
46*00c76d6fStc35445 	va_start(args, message);
47*00c76d6fStc35445 	(void) fprintf(stderr, "%s: ", cmdname);
48*00c76d6fStc35445 	(void) vfprintf(stderr, message, args);
49*00c76d6fStc35445 	va_end(args);
50*00c76d6fStc35445 	if (do_perror)
51*00c76d6fStc35445 		(void) fprintf(stderr, ": %s", strerror(save_errno));
52*00c76d6fStc35445 	(void) fprintf(stderr, "\n");
53*00c76d6fStc35445 	exit(2);
54*00c76d6fStc35445 }
55*00c76d6fStc35445 
56*00c76d6fStc35445 /*
57*00c76d6fStc35445  * Sleep until *wakeup + interval, keeping cadence where desired
58*00c76d6fStc35445  *
59*00c76d6fStc35445  * *wakeup -	The time we last wanted to wake up. Updated.
60*00c76d6fStc35445  * interval -	We want to sleep until *wakeup + interval
61*00c76d6fStc35445  * forever -	Running for infinite periods, so cadence not important
62*00c76d6fStc35445  * *caught_cont - Global set by signal handler if we got a SIGCONT
63*00c76d6fStc35445  */
64*00c76d6fStc35445 void
65*00c76d6fStc35445 sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever,
66*00c76d6fStc35445     int *caught_cont)
67*00c76d6fStc35445 {
68*00c76d6fStc35445 	hrtime_t now, pause, pause_left;
69*00c76d6fStc35445 	struct timespec pause_tv;
70*00c76d6fStc35445 	int status;
71*00c76d6fStc35445 
72*00c76d6fStc35445 	now = gethrtime();
73*00c76d6fStc35445 	pause = *wakeup + interval - now;
74*00c76d6fStc35445 
75*00c76d6fStc35445 	if (pause <= 0 || pause < (interval / 4))
76*00c76d6fStc35445 		if (forever || *caught_cont) {
77*00c76d6fStc35445 			/* Reset our cadence (see comment below) */
78*00c76d6fStc35445 			*wakeup = now + interval;
79*00c76d6fStc35445 			pause = interval;
80*00c76d6fStc35445 		} else {
81*00c76d6fStc35445 			/*
82*00c76d6fStc35445 			 * If we got here, then the time between the
83*00c76d6fStc35445 			 * output we just did, and the scheduled time
84*00c76d6fStc35445 			 * for the next output is < 1/4 of our requested
85*00c76d6fStc35445 			 * interval AND the number of intervals has been
86*00c76d6fStc35445 			 * requested AND we have never caught a SIGCONT
87*00c76d6fStc35445 			 * (so we have never been suspended).  In this
88*00c76d6fStc35445 			 * case, we'll try to stay to the desired
89*00c76d6fStc35445 			 * cadence, and we will pause for 1/2 the normal
90*00c76d6fStc35445 			 * interval this time.
91*00c76d6fStc35445 			 */
92*00c76d6fStc35445 			pause = interval / 2;
93*00c76d6fStc35445 			*wakeup += interval;
94*00c76d6fStc35445 		}
95*00c76d6fStc35445 	else
96*00c76d6fStc35445 		*wakeup += interval;
97*00c76d6fStc35445 	if (pause < 1000)
98*00c76d6fStc35445 		/* Near enough */
99*00c76d6fStc35445 		return;
100*00c76d6fStc35445 
101*00c76d6fStc35445 	/* Now do the actual sleep */
102*00c76d6fStc35445 	pause_left = pause;
103*00c76d6fStc35445 	do {
104*00c76d6fStc35445 		pause_tv.tv_sec = pause_left / NANOSEC;
105*00c76d6fStc35445 		pause_tv.tv_nsec = pause_left % NANOSEC;
106*00c76d6fStc35445 		status = nanosleep(&pause_tv, (struct timespec *)NULL);
107*00c76d6fStc35445 		if (status < 0)
108*00c76d6fStc35445 			if (errno == EINTR) {
109*00c76d6fStc35445 				now = gethrtime();
110*00c76d6fStc35445 				pause_left = *wakeup - now;
111*00c76d6fStc35445 				if (pause_left < 1000)
112*00c76d6fStc35445 					/* Near enough */
113*00c76d6fStc35445 					return;
114*00c76d6fStc35445 			} else {
115*00c76d6fStc35445 				fail(1, "nanosleep failed");
116*00c76d6fStc35445 			}
117*00c76d6fStc35445 	} while (status != 0);
118*00c76d6fStc35445 }
119*00c76d6fStc35445 
120*00c76d6fStc35445 /*
121*00c76d6fStc35445  * Signal handler - so we can be aware of SIGCONT
122*00c76d6fStc35445  */
123*00c76d6fStc35445 void
124*00c76d6fStc35445 cont_handler(int sig_number)
125*00c76d6fStc35445 {
126*00c76d6fStc35445 	/* Re-set the signal handler */
127*00c76d6fStc35445 	(void) signal(sig_number, cont_handler);
128*00c76d6fStc35445 	caught_cont = 1;
129*00c76d6fStc35445 }
130