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