Home | History | Annotate | Download | only in btt
      1 /*
      2  * blktrace output analysis: generate a timeline & gather statistics
      3  *
      4  * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle (at) hp.com>
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19  *
     20  */
     21 #include <errno.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <sys/time.h>
     28 #include <sys/resource.h>
     29 #include <fcntl.h>
     30 
     31 #define INLINE_DECLARE
     32 #include "globals.h"
     33 
     34 struct file_info {
     35 	struct list_head head;
     36 	FILE *ofp;
     37 	char *oname;
     38 };
     39 
     40 struct buf_info {
     41 	struct list_head head;
     42 	void *buf;
     43 };
     44 
     45 LIST_HEAD(files_to_clean);
     46 LIST_HEAD(all_bufs);
     47 
     48 static void clean_files(void)
     49 {
     50 	struct list_head *p, *q;
     51 
     52 	list_for_each_safe(p, q, &files_to_clean) {
     53 		struct stat buf;
     54 		struct file_info *fip = list_entry(p, struct file_info, head);
     55 
     56 		fclose(fip->ofp);
     57 		if (!stat(fip->oname, &buf) && (buf.st_size == 0))
     58 			unlink(fip->oname);
     59 
     60 		list_del(&fip->head);
     61 		free(fip->oname);
     62 		free(fip);
     63 	}
     64 }
     65 
     66 static void clean_bufs(void)
     67 {
     68 	struct list_head *p, *q;
     69 
     70 	list_for_each_safe(p, q, &all_bufs) {
     71 		struct buf_info *bip = list_entry(p, struct buf_info, head);
     72 
     73 		list_del(&bip->head);
     74 		free(bip->buf);
     75 		free(bip);
     76 	}
     77 }
     78 
     79 #ifndef _ANDROID_
     80 /*
     81  * Due to the N(devs) parts of a lot of the output features provided
     82  * by btt, it will fail opens on large(ish) systems. Here we try to
     83  * keep bumping our open file limits, and if those fail, we return NULL.
     84  *
     85  * Root users will probably be OK with this, others...
     86  */
     87 static int increase_limit(int resource, rlim_t increase)
     88 {
     89 	struct rlimit rlim;
     90 	int save_errno = errno;
     91 
     92 	if (!getrlimit(resource, &rlim)) {
     93 		rlim.rlim_cur += increase;
     94 		if (rlim.rlim_cur >= rlim.rlim_max)
     95 			rlim.rlim_max = rlim.rlim_cur + increase;
     96 
     97 		if (!setrlimit(resource, &rlim))
     98 			return 1;
     99 	}
    100 
    101 	errno = save_errno;
    102 	return 0;
    103 }
    104 #endif
    105 
    106 static int handle_open_failure(void)
    107 {
    108 	if (errno == ENFILE || errno == EMFILE)
    109 #ifndef _ANDROID_
    110 		return increase_limit(RLIMIT_NOFILE, 16);
    111 #else
    112 		return -ENOSYS;
    113 #endif
    114 
    115 	return 0;
    116 }
    117 
    118 void add_file(FILE *fp, char *oname)
    119 {
    120 	struct file_info *fip = malloc(sizeof(*fip));
    121 
    122 	fip->ofp = fp;
    123 	fip->oname = oname;
    124 	list_add_tail(&fip->head, &files_to_clean);
    125 }
    126 
    127 void add_buf(void *buf)
    128 {
    129 	struct buf_info *bip = malloc(sizeof(*bip));
    130 
    131 	bip->buf = buf;
    132 	list_add_tail(&bip->head, &all_bufs);
    133 }
    134 
    135 void clean_allocs(void)
    136 {
    137 	clean_files();
    138 	clean_bufs();
    139 }
    140 
    141 char *make_dev_hdr(char *pad, size_t len, struct d_info *dip, int add_parens)
    142 {
    143 	if (dip->devmap)
    144 		snprintf(pad, len, "%s", dip->devmap);
    145 	else if (add_parens)
    146 		snprintf(pad, len, "(%3d,%3d)",
    147 			 MAJOR(dip->device), MINOR(dip->device));
    148 	else
    149 		snprintf(pad, len, "%d,%d",
    150 			 MAJOR(dip->device), MINOR(dip->device));
    151 
    152 	return pad;
    153 }
    154 
    155 FILE *my_fopen(const char *path, const char *mode)
    156 {
    157 	FILE *fp;
    158 
    159 	do {
    160 		fp = fopen(path, mode);
    161 	} while (fp == NULL && handle_open_failure());
    162 
    163 	return fp;
    164 }
    165 
    166 int my_open(const char *path, int flags)
    167 {
    168 	int fd;
    169 
    170 	do {
    171 		fd = open(path, flags);
    172 	} while (fd < 0 && handle_open_failure());
    173 
    174 	return fd;
    175 }
    176 
    177 void dbg_ping(void) {}
    178