1/* 2 * Copyright (c) 2008, 2009 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <stdbool.h> 26#include <inttypes.h> 27#include <string.h> 28#include <curses.h> 29#include <unistd.h> 30#include <signal.h> 31#include <sys/select.h> 32#include <fcntl.h> 33#include <sys/ioctl.h> 34#include <termios.h> 35 36#include "libtop.h" 37#include "top.h" 38#include "log.h" 39#include "userinput.h" 40#include "preferences.h" 41#include "options.h" 42#include "logging.h" 43#include "sig.h" 44 45const libtop_tsamp_t *tsamp; 46 47static volatile sig_atomic_t resized = 1; 48 49static int cached_lines = 0, cached_columns = 0; 50 51static void init(void); 52 53enum { 54 MICROSECONDS = 1000000 55}; 56 57static void event_loop(void *tinst) { 58 sigset_t sset, oldsset; 59 int samples; 60 struct timeval before, now, tlimit; 61 62 if(sigemptyset(&sset)) { 63 perror("sigemptyset"); 64 exit(EXIT_FAILURE); 65 } 66 67 if(sigaddset(&sset, SIGWINCH)) { 68 perror("sigaddset"); 69 exit(EXIT_FAILURE); 70 } 71 72 if(-1 == gettimeofday(&before, NULL)) 73 perror("gettimeofday"); 74 75 while(1) { 76 bool sleep_expired = false; 77 fd_set fset; 78 int ready; 79 80 FD_ZERO(&fset); 81 FD_SET(STDIN_FILENO, &fset); 82 83 tlimit.tv_sec = top_prefs_get_sleep(); 84 tlimit.tv_usec = 0; 85 86 ready = select(STDIN_FILENO + 1, &fset, NULL, NULL, &tlimit); 87 88 if(-1 == gettimeofday(&now, NULL)) 89 perror("gettimeofday"); 90 91 if(now.tv_sec >= (before.tv_sec + tlimit.tv_sec)) { 92 /* 93 * The sleep has expired, so we should insert new 94 * data for all stats. This is different than just 95 * the case where we handle user input and the rest 96 * of the data is awaiting a sleep interval update. 97 */ 98 sleep_expired = true; 99 before = now; 100 } 101 102 if(sleep_expired) { 103 samples = top_prefs_get_samples(); 104 105 if(samples > -1) { 106 /* Samples was set in the preferences. */ 107 if(0 == samples) { 108 /* We had N samples and now it's time to exit. */ 109 endwin(); 110 exit(EXIT_SUCCESS); 111 } 112 113 top_prefs_set_samples(samples - 1); 114 } 115 } 116 117 if(top_signal_is_exit_set()) { 118 exit(EXIT_SUCCESS); 119 } 120 121 if(ready && FD_ISSET(STDIN_FILENO, &fset)) 122 (void)user_input_process(tinst); 123 124 if(sleep_expired) 125 top_insert(tinst); 126 127 /* Block SIGWINCH signals while we are in a relayout. */ 128 if(-1 == sigprocmask(SIG_BLOCK, &sset, &oldsset)) { 129 perror("sigprocmask"); 130 exit(EXIT_FAILURE); 131 } 132 133 if(top_need_relayout() 134 || resized || LINES != cached_lines || COLS != cached_columns) { 135 cached_lines = LINES; 136 cached_columns = COLS; 137 138 if(top_layout(tinst)) { 139 resized = 1; 140 } else { 141 resized = 0; 142 } 143 } 144 145 if(-1 == sigprocmask(SIG_SETMASK, &oldsset, NULL)) { 146 perror("sigprocmask"); 147 exit(EXIT_FAILURE); 148 } 149 150 top_draw(tinst); 151 } 152} 153 154void exit_handler(void) { 155 endwin(); 156} 157 158void init(void) { 159 if(NULL == initscr()) { 160 fprintf(stderr, "error: unable to initscr!\n"); 161 exit(EXIT_FAILURE); 162 } 163 164 atexit(exit_handler); 165 166 if(ERR == cbreak() /* disable line buffering */ 167 || ERR == noecho() /* disable echoing what the user types */ 168 || ERR == nonl() /* no newline */ 169 || ERR == intrflush(stdscr, FALSE) 170 || ERR == meta(stdscr, TRUE) 171 || ERR == keypad(stdscr, TRUE)) { 172 fprintf(stderr, "error: initializing curses\n"); 173 exit(EXIT_FAILURE); 174 } 175 176 timeout(0); 177} 178 179int main(int argc, char *argv[]) { 180 void *tinst; 181 182 top_prefs_init(); 183 top_options_init(); 184 185 if(top_options_parse(argc, argv)) { 186 top_options_usage(stderr, argv[0]); 187 return EXIT_FAILURE; 188 } 189 190 if(top_prefs_get_samples() > -1) 191 top_prefs_set_logging_mode(true); 192 193 if(!top_prefs_get_logging_mode()) 194 init(); 195 196 top_signal_init(); 197 198 if(libtop_init(NULL, NULL)) { 199 endwin(); 200 fprintf(stderr, "libtop_init failed!\n"); 201 return EXIT_FAILURE; 202 } 203 204 if(top_prefs_get_frameworks() 205 && libtop_set_interval(top_prefs_get_frameworks_interval())) { 206 endwin(); 207 fprintf(stderr, "error: setting framework update interval.\n"); 208 exit(EXIT_FAILURE); 209 } 210 211 tinst = top_create(stdscr); 212 213 if(!top_prefs_get_logging_mode()) { 214 top_insert(tinst); 215 top_layout(tinst); 216 top_draw(tinst); 217 event_loop(tinst); 218 } else { 219 top_logging_loop(tinst); 220 } 221 222 return EXIT_SUCCESS; 223} 224