Home | History | Annotate | Download | only in liblegacy
      1 /**
      2  * @file daemon/liblegacy/init.c
      3  * Daemon set up and main loop for 2.4
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author John Levon
      9  * @author Philippe Elie
     10  */
     11 
     12 #include "config.h"
     13 
     14 #include "opd_proc.h"
     15 #include "opd_mapping.h"
     16 #include "opd_24_stats.h"
     17 #include "opd_sample_files.h"
     18 #include "opd_image.h"
     19 #include "opd_parse_proc.h"
     20 #include "opd_kernel.h"
     21 #include "opd_printf.h"
     22 #include "oprofiled.h"
     23 
     24 #include "op_sample_file.h"
     25 #include "op_config_24.h"
     26 #include "op_interface.h"
     27 #include "op_libiberty.h"
     28 #include "op_deviceio.h"
     29 #include "op_events.h"
     30 #include "op_get_time.h"
     31 #include "op_fileio.h"
     32 
     33 #include <stdio.h>
     34 #include <errno.h>
     35 #include <fcntl.h>
     36 #include <unistd.h>
     37 #include <stdlib.h>
     38 
     39 fd_t hashmapdevfd;
     40 
     41 int cpu_number;
     42 
     43 static fd_t devfd;
     44 static fd_t notedevfd;
     45 static struct op_buffer_head * sbuf;
     46 static size_t s_buf_bytesize;
     47 static struct op_note * nbuf;
     48 static size_t n_buf_bytesize;
     49 
     50 static void opd_sighup(void);
     51 static void opd_alarm(void);
     52 static void opd_sigterm(void);
     53 
     54 
     55 /**
     56  * op_open_files - open necessary files
     57  *
     58  * Open the device files and the log file,
     59  * and mmap() the hash map.
     60  */
     61 static void op_open_files(void)
     62 {
     63 	hashmapdevfd = op_open_device(op_hash_device);
     64 	if (hashmapdevfd == -1) {
     65 		perror("Failed to open hash map device");
     66 		exit(EXIT_FAILURE);
     67 	}
     68 
     69 	notedevfd = op_open_device(op_note_device);
     70 	if (notedevfd == -1) {
     71 		if (errno == EINVAL)
     72 			fprintf(stderr, "Failed to open note device. Possibly you have passed incorrect\n"
     73 				"parameters. Check /var/log/messages.");
     74 		else
     75 			perror("Failed to open note device");
     76 		exit(EXIT_FAILURE);
     77 	}
     78 
     79 	devfd = op_open_device(op_device);
     80 	if (devfd == -1) {
     81 		if (errno == EINVAL)
     82 			fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
     83 				"parameters. Check /var/log/messages.");
     84 		else
     85 			perror("Failed to open profile device");
     86 		exit(EXIT_FAILURE);
     87 	}
     88 
     89 	opd_init_hash_map();
     90 
     91 	/* give output before re-opening stdout as the logfile */
     92 	printf("Using log file %s\n", op_log_file);
     93 
     94 	/* set up logfile */
     95 	close(0);
     96 	close(1);
     97 
     98 	if (open("/dev/null", O_RDONLY) == -1) {
     99 		perror("oprofiled: couldn't re-open stdin as /dev/null: ");
    100 		exit(EXIT_FAILURE);
    101 	}
    102 
    103 	opd_open_logfile();
    104 
    105 	printf("oprofiled started %s", op_get_time());
    106 	fflush(stdout);
    107 }
    108 
    109 
    110 static void opd_do_samples(struct op_buffer_head const * buf);
    111 static void opd_do_notes(struct op_note const * opd_buf, size_t count);
    112 
    113 /**
    114  * do_shutdown - shutdown cleanly, reading as much remaining data as possible.
    115  * @param buf  sample buffer area
    116  * @param size  size of sample buffer
    117  * @param nbuf  note buffer area
    118  * @param nsize  size of note buffer
    119  */
    120 static void opd_shutdown(struct op_buffer_head * buf, size_t size, struct op_note * nbuf, size_t nsize)
    121 {
    122 	ssize_t count = -1;
    123 	ssize_t ncount = -1;
    124 
    125 	/* the dump may have added no samples, so we must set
    126 	 * non-blocking */
    127 	if (fcntl(devfd, F_SETFL, fcntl(devfd, F_GETFL) | O_NONBLOCK) < 0) {
    128 		perror("Failed to set non-blocking read for device: ");
    129 		exit(EXIT_FAILURE);
    130 	}
    131 
    132 	/* it's always OK to read the note device */
    133 	while (ncount < 0)
    134 		ncount = op_read_device(notedevfd, nbuf, nsize);
    135 
    136 	if (ncount > 0)
    137 		opd_do_notes(nbuf, ncount);
    138 
    139 	/* read as much as we can until we have exhausted the data
    140 	 * (EAGAIN is returned).
    141 	 *
    142 	 * This will not livelock as the profiler has been partially
    143 	 * shut down by now.
    144 	 */
    145 	while (1) {
    146 		count = op_read_device(devfd, buf, size);
    147 		if (count < 0 && errno == EAGAIN)
    148 			break;
    149 		verbprintf(vmisc, "Shutting down, state %d\n", buf->state);
    150 		opd_do_samples(buf);
    151 	}
    152 }
    153 
    154 
    155 /**
    156  * opd_do_read - enter processing loop
    157  * @param buf  buffer to read into
    158  * @param size  size of buffer
    159  * @param nbuf  note buffer
    160  * @param nsize  size of note buffer
    161  *
    162  * Read some of a buffer from the device and process
    163  * the contents.
    164  */
    165 static void opd_do_read(struct op_buffer_head * buf, size_t size, struct op_note * nbuf, size_t nsize)
    166 {
    167 	while (1) {
    168 		ssize_t count = -1;
    169 		ssize_t ncount = -1;
    170 
    171 		/* loop to handle EINTR */
    172 		while (count < 0)
    173 			count = op_read_device(devfd, buf, size);
    174 
    175 		while (ncount < 0)
    176 			ncount = op_read_device(notedevfd, nbuf, nsize);
    177 
    178 		opd_do_notes(nbuf, ncount);
    179 		opd_do_samples(buf);
    180 
    181 		// we can lost a signal alarm or a signal hup but we don't
    182 		// take care.
    183 		if (signal_alarm) {
    184 			signal_alarm = 0;
    185 			opd_alarm();
    186 		}
    187 
    188 		if (signal_hup) {
    189 			signal_hup = 0;
    190 			opd_sighup();
    191 		}
    192 
    193 		if (signal_term)
    194 			opd_sigterm();
    195 
    196 		/* request to stop arrived */
    197 		if (buf->state == STOPPING) {
    198 			verbprintf(vmisc, "Shutting down by request.\n");
    199 			opd_shutdown(buf, size, nbuf, nsize);
    200 			return;
    201 		}
    202 	}
    203 }
    204 
    205 /**
    206  * opd_do_notes - process a notes buffer
    207  * @param opd_buf  buffer to process
    208  * @param count  number of bytes in buffer
    209  *
    210  * Process a buffer of notes.
    211  */
    212 static void opd_do_notes(struct op_note const * opd_buf, size_t count)
    213 {
    214 	uint i;
    215 	struct op_note const * note;
    216 
    217 	for (i = 0; i < count/sizeof(struct op_note); i++) {
    218 		note = &opd_buf[i];
    219 
    220 		opd_24_stats[OPD_NOTIFICATIONS]++;
    221 
    222 		switch (note->type) {
    223 			case OP_MAP:
    224 			case OP_EXEC:
    225 				if (note->type == OP_EXEC)
    226 					opd_handle_exec(note->pid, note->tgid);
    227 				opd_handle_mapping(note);
    228 				break;
    229 
    230 			case OP_FORK:
    231 				opd_handle_fork(note);
    232 				break;
    233 
    234 			case OP_DROP_MODULES:
    235 				opd_clear_module_info();
    236 				break;
    237 
    238 			case OP_EXIT:
    239 				opd_handle_exit(note);
    240 				break;
    241 
    242 			default:
    243 				fprintf(stderr, "Received unknown notification type %u\n", note->type);
    244 				abort();
    245 				break;
    246 		}
    247 	}
    248 }
    249 
    250 /**
    251  * opd_do_samples - process a sample buffer
    252  * @param opd_buf  buffer to process
    253  *
    254  * Process a buffer of samples.
    255  * The signals specified by the global variable maskset are
    256  * masked.
    257  *
    258  * If the sample could be processed correctly, it is written
    259  * to the relevant sample file. Additionally mapping and
    260  * process notifications are handled here.
    261  */
    262 static void opd_do_samples(struct op_buffer_head const * opd_buf)
    263 {
    264 	uint i;
    265 	struct op_sample const * buffer = opd_buf->buffer;
    266 
    267 	opd_24_stats[OPD_DUMP_COUNT]++;
    268 
    269 	verbprintf(vmisc, "Read buffer of %d entries for cpu %d.\n",
    270 		   (unsigned int)opd_buf->count, opd_buf->cpu_nr);
    271 
    272 	if (separate_cpu)
    273 		cpu_number = opd_buf->cpu_nr;
    274 	for (i = 0; i < opd_buf->count; i++) {
    275 		verbprintf(vsamples, "%.6u: EIP: 0x%.8lx pid: %.6d\n",
    276 			i, buffer[i].eip, buffer[i].pid);
    277 		opd_put_sample(&buffer[i]);
    278 	}
    279 }
    280 
    281 
    282 /**
    283  * opd_alarm - clean up old procs, msync, and report stats
    284  */
    285 static void opd_alarm(void)
    286 {
    287 	opd_sync_samples_files();
    288 
    289 	opd_age_procs();
    290 
    291 	opd_print_24_stats();
    292 
    293 	alarm(60 * 10);
    294 }
    295 
    296 
    297 /* re-open logfile for logrotate */
    298 static void opd_sighup(void)
    299 {
    300 	printf("Received SIGHUP.\n");
    301 	close(1);
    302 	close(2);
    303 	opd_open_logfile();
    304 	/* We just close them, and re-open them lazily as usual. */
    305 	opd_for_each_image(opd_close_image_samples_files);
    306 }
    307 
    308 
    309 static void clean_exit(void)
    310 {
    311 	opd_cleanup_hash_name();
    312 	op_free_events();
    313 	unlink(op_lock_file);
    314 }
    315 
    316 
    317 static void opd_sigterm(void)
    318 {
    319 	opd_print_24_stats();
    320 	printf("oprofiled stopped %s", op_get_time());
    321 	exit(EXIT_FAILURE);
    322 }
    323 
    324 
    325 static void opd_24_init(void)
    326 {
    327 	size_t i;
    328 	int opd_buf_size = OP_DEFAULT_BUF_SIZE;
    329 	int opd_note_buf_size = OP_DEFAULT_NOTE_SIZE;
    330 
    331 	if (!no_vmlinux)
    332 		opd_parse_kernel_range(kernel_range);
    333 	opd_buf_size = opd_read_fs_int(OP_MOUNT, "bufsize", 1);
    334 	opd_note_buf_size = opd_read_fs_int(OP_MOUNT, "notesize", 1);
    335 
    336 	s_buf_bytesize = sizeof(struct op_buffer_head) + opd_buf_size * sizeof(struct op_sample);
    337 
    338 	sbuf = xmalloc(s_buf_bytesize);
    339 
    340 	n_buf_bytesize = opd_note_buf_size * sizeof(struct op_note);
    341 	nbuf = xmalloc(n_buf_bytesize);
    342 
    343 	opd_init_images();
    344 	opd_init_procs();
    345 	opd_init_kernel_image();
    346 
    347 	for (i = 0; i < OPD_MAX_STATS; i++)
    348 		opd_24_stats[i] = 0;
    349 
    350 	if (atexit(clean_exit)) {
    351 		perror("oprofiled: couldn't set exit cleanup: ");
    352 		exit(EXIT_FAILURE);
    353 	}
    354 }
    355 
    356 
    357 static void opd_24_start(void)
    358 {
    359 	op_open_files();
    360 
    361 	/* yes, this is racey. */
    362 	opd_get_ascii_procs();
    363 
    364 	/* simple sleep-then-process loop */
    365 	opd_do_read(sbuf, s_buf_bytesize, nbuf, n_buf_bytesize);
    366 }
    367 
    368 
    369 static void opd_24_exit(void)
    370 {
    371 	opd_print_24_stats();
    372 	printf("oprofiled stopped %s", op_get_time());
    373 
    374 	free(sbuf);
    375 	free(nbuf);
    376 	opd_clear_module_info();
    377 	opd_proc_cleanup();
    378 	/* kernel/module image are not owned by a proc, we must cleanup them */
    379 	opd_for_each_image(opd_delete_image);
    380 }
    381 
    382 
    383 struct oprofiled_ops opd_24_ops = {
    384 	.init = opd_24_init,
    385 	.start = opd_24_start,
    386 	.exit = opd_24_exit
    387 };
    388