• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
op_open_files(void)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  */
opd_shutdown(struct op_buffer_head * buf,size_t size,struct op_note * nbuf,size_t nsize)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  */
opd_do_read(struct op_buffer_head * buf,size_t size,struct op_note * nbuf,size_t nsize)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  */
opd_do_notes(struct op_note const * opd_buf,size_t count)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  */
opd_do_samples(struct op_buffer_head const * opd_buf)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  */
opd_alarm(void)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 */
opd_sighup(void)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 
clean_exit(void)309 static void clean_exit(void)
310 {
311 	opd_cleanup_hash_name();
312 	op_free_events();
313 	unlink(op_lock_file);
314 }
315 
316 
opd_sigterm(void)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 
opd_24_init(void)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 
opd_24_start(void)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 
opd_24_exit(void)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