blob: b2cd013a9c89a28269f6cc9410889b9efb889873 [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
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
39fd_t hashmapdevfd;
40
41int cpu_number;
42
43static fd_t devfd;
44static fd_t notedevfd;
45static struct op_buffer_head * sbuf;
46static size_t s_buf_bytesize;
47static struct op_note * nbuf;
48static size_t n_buf_bytesize;
49
50static void opd_sighup(void);
51static void opd_alarm(void);
52static 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 */
61static 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
110static void opd_do_samples(struct op_buffer_head const * buf);
111static 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 */
120static 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 */
165static 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 */
212static 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 */
262static 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 */
285static 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 */
298static 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
309static void clean_exit(void)
310{
311 opd_cleanup_hash_name();
312 op_free_events();
313 unlink(op_lock_file);
314}
315
316
317static 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
325static 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
357static 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
369static 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
383struct oprofiled_ops opd_24_ops = {
384 .init = opd_24_init,
385 .start = opd_24_start,
386 .exit = opd_24_exit
387};