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