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> 33*4944376cSJohn Levon #include <langinfo.h> 3400c76d6fStc35445 3500c76d6fStc35445 extern char *cmdname; 3600c76d6fStc35445 extern int caught_cont; 3700c76d6fStc35445 38*4944376cSJohn Levon uint_t timestamp_fmt = NODATE; 39*4944376cSJohn Levon 4000c76d6fStc35445 /*PRINTFLIKE2*/ 4100c76d6fStc35445 void 4200c76d6fStc35445 fail(int do_perror, char *message, ...) 4300c76d6fStc35445 { 4400c76d6fStc35445 va_list args; 4500c76d6fStc35445 int save_errno = errno; 4600c76d6fStc35445 4700c76d6fStc35445 va_start(args, message); 4800c76d6fStc35445 (void) fprintf(stderr, "%s: ", cmdname); 4900c76d6fStc35445 (void) vfprintf(stderr, message, args); 5000c76d6fStc35445 va_end(args); 5100c76d6fStc35445 if (do_perror) 5200c76d6fStc35445 (void) fprintf(stderr, ": %s", strerror(save_errno)); 5300c76d6fStc35445 (void) fprintf(stderr, "\n"); 5400c76d6fStc35445 exit(2); 5500c76d6fStc35445 } 5600c76d6fStc35445 5700c76d6fStc35445 /* 5800c76d6fStc35445 * Sleep until *wakeup + interval, keeping cadence where desired 5900c76d6fStc35445 * 6000c76d6fStc35445 * *wakeup - The time we last wanted to wake up. Updated. 6100c76d6fStc35445 * interval - We want to sleep until *wakeup + interval 6200c76d6fStc35445 * forever - Running for infinite periods, so cadence not important 6300c76d6fStc35445 * *caught_cont - Global set by signal handler if we got a SIGCONT 6400c76d6fStc35445 */ 6500c76d6fStc35445 void 6600c76d6fStc35445 sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever, 6700c76d6fStc35445 int *caught_cont) 6800c76d6fStc35445 { 6900c76d6fStc35445 hrtime_t now, pause, pause_left; 7000c76d6fStc35445 struct timespec pause_tv; 7100c76d6fStc35445 int status; 7200c76d6fStc35445 7300c76d6fStc35445 now = gethrtime(); 7400c76d6fStc35445 pause = *wakeup + interval - now; 7500c76d6fStc35445 7600c76d6fStc35445 if (pause <= 0 || pause < (interval / 4)) 7700c76d6fStc35445 if (forever || *caught_cont) { 7800c76d6fStc35445 /* Reset our cadence (see comment below) */ 7900c76d6fStc35445 *wakeup = now + interval; 8000c76d6fStc35445 pause = interval; 8100c76d6fStc35445 } else { 8200c76d6fStc35445 /* 8300c76d6fStc35445 * If we got here, then the time between the 8400c76d6fStc35445 * output we just did, and the scheduled time 8500c76d6fStc35445 * for the next output is < 1/4 of our requested 8600c76d6fStc35445 * interval AND the number of intervals has been 8700c76d6fStc35445 * requested AND we have never caught a SIGCONT 8800c76d6fStc35445 * (so we have never been suspended). In this 8900c76d6fStc35445 * case, we'll try to stay to the desired 9000c76d6fStc35445 * cadence, and we will pause for 1/2 the normal 9100c76d6fStc35445 * interval this time. 9200c76d6fStc35445 */ 9300c76d6fStc35445 pause = interval / 2; 9400c76d6fStc35445 *wakeup += interval; 9500c76d6fStc35445 } 9600c76d6fStc35445 else 9700c76d6fStc35445 *wakeup += interval; 9800c76d6fStc35445 if (pause < 1000) 9900c76d6fStc35445 /* Near enough */ 10000c76d6fStc35445 return; 10100c76d6fStc35445 10200c76d6fStc35445 /* Now do the actual sleep */ 10300c76d6fStc35445 pause_left = pause; 10400c76d6fStc35445 do { 10500c76d6fStc35445 pause_tv.tv_sec = pause_left / NANOSEC; 10600c76d6fStc35445 pause_tv.tv_nsec = pause_left % NANOSEC; 10700c76d6fStc35445 status = nanosleep(&pause_tv, (struct timespec *)NULL); 10800c76d6fStc35445 if (status < 0) 10900c76d6fStc35445 if (errno == EINTR) { 11000c76d6fStc35445 now = gethrtime(); 11100c76d6fStc35445 pause_left = *wakeup - now; 11200c76d6fStc35445 if (pause_left < 1000) 11300c76d6fStc35445 /* Near enough */ 11400c76d6fStc35445 return; 11500c76d6fStc35445 } else { 11600c76d6fStc35445 fail(1, "nanosleep failed"); 11700c76d6fStc35445 } 11800c76d6fStc35445 } while (status != 0); 11900c76d6fStc35445 } 12000c76d6fStc35445 12100c76d6fStc35445 /* 12200c76d6fStc35445 * Signal handler - so we can be aware of SIGCONT 12300c76d6fStc35445 */ 12400c76d6fStc35445 void 12500c76d6fStc35445 cont_handler(int sig_number) 12600c76d6fStc35445 { 12700c76d6fStc35445 /* Re-set the signal handler */ 12800c76d6fStc35445 (void) signal(sig_number, cont_handler); 12900c76d6fStc35445 caught_cont = 1; 13000c76d6fStc35445 } 131*4944376cSJohn Levon 132*4944376cSJohn Levon /* 133*4944376cSJohn Levon * Print timestamp as decimal reprentation of time_t value (-T u was specified) 134*4944376cSJohn Levon * or in date(1) format (-T d was specified). 135*4944376cSJohn Levon */ 136*4944376cSJohn Levon void 137*4944376cSJohn Levon print_timestamp(void) 138*4944376cSJohn Levon { 139*4944376cSJohn Levon time_t t = time(NULL); 140*4944376cSJohn Levon static char *fmt = NULL; 141*4944376cSJohn Levon 142*4944376cSJohn Levon /* We only need to retrieve this once per invocation */ 143*4944376cSJohn Levon if (fmt == NULL) 144*4944376cSJohn Levon fmt = nl_langinfo(_DATE_FMT); 145*4944376cSJohn Levon 146*4944376cSJohn Levon if (timestamp_fmt == UDATE) { 147*4944376cSJohn Levon (void) printf("%ld\n", t); 148*4944376cSJohn Levon } else if (timestamp_fmt == DDATE) { 149*4944376cSJohn Levon char dstr[64]; 150*4944376cSJohn Levon int len; 151*4944376cSJohn Levon 152*4944376cSJohn Levon len = strftime(dstr, sizeof (dstr), fmt, localtime(&t)); 153*4944376cSJohn Levon if (len > 0) 154*4944376cSJohn Levon (void) printf("%s\n", dstr); 155*4944376cSJohn Levon } 156*4944376cSJohn Levon } 157