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