xref: /titanic_53/usr/src/cmd/stat/common/common.c (revision 26fd77009b17f8c8fb32eb362584cfd635e87ad9)
100c76d6fStc35445 /*
200c76d6fStc35445  * CDDL HEADER START
300c76d6fStc35445  *
400c76d6fStc35445  * The contents of this file are subject to the terms of the
500c76d6fStc35445  * Common Development and Distribution License (the "License").
600c76d6fStc35445  * You may not use this file except in compliance with the License.
700c76d6fStc35445  *
800c76d6fStc35445  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
900c76d6fStc35445  * or http://www.opensolaris.org/os/licensing.
1000c76d6fStc35445  * See the License for the specific language governing permissions
1100c76d6fStc35445  * and limitations under the License.
1200c76d6fStc35445  *
1300c76d6fStc35445  * When distributing Covered Code, include this CDDL HEADER in each
1400c76d6fStc35445  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1500c76d6fStc35445  * If applicable, add the following below this CDDL HEADER, with the
1600c76d6fStc35445  * fields enclosed by brackets "[]" replaced with your own identifying
1700c76d6fStc35445  * information: Portions Copyright [yyyy] [name of copyright owner]
1800c76d6fStc35445  *
1900c76d6fStc35445  * CDDL HEADER END
2000c76d6fStc35445  */
2100c76d6fStc35445 /*
22*4944376cSJohn Levon  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2300c76d6fStc35445  * Use is subject to license terms.
2400c76d6fStc35445  */
2500c76d6fStc35445 
2600c76d6fStc35445 #include "statcommon.h"
2700c76d6fStc35445 
2800c76d6fStc35445 #include <stdarg.h>
2900c76d6fStc35445 #include <signal.h>
3000c76d6fStc35445 #include <errno.h>
3100c76d6fStc35445 #include <string.h>
3200c76d6fStc35445 #include <stdlib.h>
3300c76d6fStc35445 
3400c76d6fStc35445 extern char *cmdname;
3500c76d6fStc35445 extern int caught_cont;
3600c76d6fStc35445 
3700c76d6fStc35445 /*PRINTFLIKE2*/
3800c76d6fStc35445 void
fail(int do_perror,char * message,...)3900c76d6fStc35445 fail(int do_perror, char *message, ...)
4000c76d6fStc35445 {
4100c76d6fStc35445 	va_list args;
4200c76d6fStc35445 	int save_errno = errno;
4300c76d6fStc35445 
4400c76d6fStc35445 	va_start(args, message);
4500c76d6fStc35445 	(void) fprintf(stderr, "%s: ", cmdname);
4600c76d6fStc35445 	(void) vfprintf(stderr, message, args);
4700c76d6fStc35445 	va_end(args);
4800c76d6fStc35445 	if (do_perror)
4900c76d6fStc35445 		(void) fprintf(stderr, ": %s", strerror(save_errno));
5000c76d6fStc35445 	(void) fprintf(stderr, "\n");
5100c76d6fStc35445 	exit(2);
5200c76d6fStc35445 }
5300c76d6fStc35445 
5400c76d6fStc35445 /*
5500c76d6fStc35445  * Sleep until *wakeup + interval, keeping cadence where desired
5600c76d6fStc35445  *
5700c76d6fStc35445  * *wakeup -	The time we last wanted to wake up. Updated.
5800c76d6fStc35445  * interval -	We want to sleep until *wakeup + interval
5900c76d6fStc35445  * forever -	Running for infinite periods, so cadence not important
6000c76d6fStc35445  * *caught_cont - Global set by signal handler if we got a SIGCONT
6100c76d6fStc35445  */
6200c76d6fStc35445 void
sleep_until(hrtime_t * wakeup,hrtime_t interval,int forever,int * caught_cont)6300c76d6fStc35445 sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever,
6400c76d6fStc35445     int *caught_cont)
6500c76d6fStc35445 {
6600c76d6fStc35445 	hrtime_t now, pause, pause_left;
6700c76d6fStc35445 	struct timespec pause_tv;
6800c76d6fStc35445 	int status;
6900c76d6fStc35445 
7000c76d6fStc35445 	now = gethrtime();
7100c76d6fStc35445 	pause = *wakeup + interval - now;
7200c76d6fStc35445 
7300c76d6fStc35445 	if (pause <= 0 || pause < (interval / 4))
7400c76d6fStc35445 		if (forever || *caught_cont) {
7500c76d6fStc35445 			/* Reset our cadence (see comment below) */
7600c76d6fStc35445 			*wakeup = now + interval;
7700c76d6fStc35445 			pause = interval;
7800c76d6fStc35445 		} else {
7900c76d6fStc35445 			/*
8000c76d6fStc35445 			 * If we got here, then the time between the
8100c76d6fStc35445 			 * output we just did, and the scheduled time
8200c76d6fStc35445 			 * for the next output is < 1/4 of our requested
8300c76d6fStc35445 			 * interval AND the number of intervals has been
8400c76d6fStc35445 			 * requested AND we have never caught a SIGCONT
8500c76d6fStc35445 			 * (so we have never been suspended).  In this
8600c76d6fStc35445 			 * case, we'll try to stay to the desired
8700c76d6fStc35445 			 * cadence, and we will pause for 1/2 the normal
8800c76d6fStc35445 			 * interval this time.
8900c76d6fStc35445 			 */
9000c76d6fStc35445 			pause = interval / 2;
9100c76d6fStc35445 			*wakeup += interval;
9200c76d6fStc35445 		}
9300c76d6fStc35445 	else
9400c76d6fStc35445 		*wakeup += interval;
9500c76d6fStc35445 	if (pause < 1000)
9600c76d6fStc35445 		/* Near enough */
9700c76d6fStc35445 		return;
9800c76d6fStc35445 
9900c76d6fStc35445 	/* Now do the actual sleep */
10000c76d6fStc35445 	pause_left = pause;
10100c76d6fStc35445 	do {
10200c76d6fStc35445 		pause_tv.tv_sec = pause_left / NANOSEC;
10300c76d6fStc35445 		pause_tv.tv_nsec = pause_left % NANOSEC;
10400c76d6fStc35445 		status = nanosleep(&pause_tv, (struct timespec *)NULL);
10500c76d6fStc35445 		if (status < 0)
10600c76d6fStc35445 			if (errno == EINTR) {
10700c76d6fStc35445 				now = gethrtime();
10800c76d6fStc35445 				pause_left = *wakeup - now;
10900c76d6fStc35445 				if (pause_left < 1000)
11000c76d6fStc35445 					/* Near enough */
11100c76d6fStc35445 					return;
11200c76d6fStc35445 			} else {
11300c76d6fStc35445 				fail(1, "nanosleep failed");
11400c76d6fStc35445 			}
11500c76d6fStc35445 	} while (status != 0);
11600c76d6fStc35445 }
11700c76d6fStc35445 
11800c76d6fStc35445 /*
11900c76d6fStc35445  * Signal handler - so we can be aware of SIGCONT
12000c76d6fStc35445  */
12100c76d6fStc35445 void
cont_handler(int sig_number)12200c76d6fStc35445 cont_handler(int sig_number)
12300c76d6fStc35445 {
12400c76d6fStc35445 	/* Re-set the signal handler */
12500c76d6fStc35445 	(void) signal(sig_number, cont_handler);
12600c76d6fStc35445 	caught_cont = 1;
12700c76d6fStc35445 }
128