blob: 076ddd8a6c842f389575f8f4c148790fefee22d7 [file] [log] [blame]
Upstreamcc2ee171970-01-12 13:46:40 +00001/**
2 * @file daemon/init.c
3 * Daemon set up and main loop for 2.6
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 "oprofiled.h"
15#include "opd_stats.h"
16#include "opd_sfile.h"
17#include "opd_kernel.h"
18#include "opd_trans.h"
19#include "opd_anon.h"
20#include "opd_perfmon.h"
21#include "opd_printf.h"
22
23#include "op_version.h"
24#include "op_config.h"
25#include "op_deviceio.h"
26#include "op_get_time.h"
27#include "op_libiberty.h"
28#include "op_fileio.h"
29
30#include <fcntl.h>
31#include <stdio.h>
32#include <errno.h>
33#include <stdlib.h>
34
35size_t kernel_pointer_size;
36
37static fd_t devfd;
38static char * sbuf;
39static size_t s_buf_bytesize;
40
41static void opd_sighup(void);
42static void opd_alarm(void);
43static void opd_sigterm(void);
44
45/**
46 * opd_open_files - open necessary files
47 *
48 * Open the device files and the log file,
49 * and mmap() the hash map.
50 */
51static void opd_open_files(void)
52{
53 devfd = op_open_device("/dev/oprofile/buffer");
54 if (devfd == -1) {
55 if (errno == EINVAL)
56 fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
57 "parameters. Check /var/log/messages.");
58 else
59 perror("Failed to open profile device");
60 exit(EXIT_FAILURE);
61 }
62
63 /* give output before re-opening stdout as the logfile */
64 printf("Using log file " OP_LOG_FILE "\n");
65
66 /* set up logfile */
67 close(0);
68 close(1);
69
70 if (open("/dev/null", O_RDONLY) == -1) {
71 perror("oprofiled: couldn't re-open stdin as /dev/null: ");
72 exit(EXIT_FAILURE);
73 }
74
75 opd_open_logfile();
76
77 printf("oprofiled started %s", op_get_time());
78 printf("kernel pointer size: %lu\n",
79 (unsigned long)kernel_pointer_size);
80 fflush(stdout);
81}
82
83
84/** Done writing out the samples, indicate with complete_dump file */
85static void complete_dump(void)
86{
87 FILE * status_file;
88
89retry:
90 status_file = fopen(OP_DUMP_STATUS, "w");
91
92 if (!status_file && errno == EMFILE) {
93 if (sfile_lru_clear()) {
94 printf("LRU cleared but file open fails for %s.\n",
95 OP_DUMP_STATUS);
96 abort();
97 }
98 goto retry;
99 }
100
101 if (!status_file) {
102 perror("warning: couldn't set complete_dump: ");
103 return;
104 }
105
106 fprintf(status_file, "1\n");
107 fclose(status_file);
108}
109
110
111/**
112 * opd_do_samples - process a sample buffer
113 * @param opd_buf buffer to process
114 *
115 * Process a buffer of samples.
116 *
117 * If the sample could be processed correctly, it is written
118 * to the relevant sample file.
119 */
120static void opd_do_samples(char const * opd_buf, ssize_t count)
121{
122 size_t num = count / kernel_pointer_size;
123
124 opd_stats[OPD_DUMP_COUNT]++;
125
126 verbprintf(vmisc, "Read buffer of %d entries.\n", (unsigned int)num);
127
128 opd_process_samples(opd_buf, num);
129
130 complete_dump();
131}
132
133
134/**
135 * opd_do_read - enter processing loop
136 * @param buf buffer to read into
137 * @param size size of buffer
138 *
139 * Read some of a buffer from the device and process
140 * the contents.
141 */
142static void opd_do_read(char * buf, size_t size)
143{
144 while (1) {
145 ssize_t count = -1;
146
147 /* loop to handle EINTR */
148 while (count < 0) {
149 count = op_read_device(devfd, buf, size);
150
151 /* we can lose an alarm or a hup but
152 * we don't care.
153 */
154 if (signal_alarm) {
155 signal_alarm = 0;
156 opd_alarm();
157 }
158
159 if (signal_hup) {
160 signal_hup = 0;
161 opd_sighup();
162 }
163
164 if (signal_term)
165 opd_sigterm();
166
167 if (signal_usr1) {
168 signal_usr1 = 0;
169 perfmon_start();
170 }
171
172 if (signal_usr2) {
173 signal_usr2 = 0;
174 perfmon_stop();
175 }
176 }
177
178 opd_do_samples(buf, count);
179 }
180}
181
182
183/** opd_alarm - sync files and report stats */
184static void opd_alarm(void)
185{
186 sfile_sync_files();
187 opd_print_stats();
188 alarm(60 * 10);
189}
190
191
192/** re-open files for logrotate/opcontrol --reset */
193static void opd_sighup(void)
194{
195 printf("Received SIGHUP.\n");
196 /* We just close them, and re-open them lazily as usual. */
197 sfile_close_files();
198 close(1);
199 close(2);
200 opd_open_logfile();
201}
202
203
204static void clean_exit(void)
205{
206 perfmon_exit();
207 unlink(OP_LOCK_FILE);
208}
209
210
211static void opd_sigterm(void)
212{
213 opd_print_stats();
214 printf("oprofiled stopped %s", op_get_time());
215 exit(EXIT_FAILURE);
216}
217
218
219static void opd_26_init(void)
220{
221 size_t i;
222 size_t opd_buf_size;
223
224 opd_create_vmlinux(vmlinux, kernel_range);
225
226 opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size", 1);
227 kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size", 1);
228
229 s_buf_bytesize = opd_buf_size * kernel_pointer_size;
230
231 sbuf = xmalloc(s_buf_bytesize);
232
233 opd_reread_module_info();
234
235 for (i = 0; i < OPD_MAX_STATS; i++)
236 opd_stats[i] = 0;
237
238 perfmon_init();
239
240 cookie_init();
241 sfile_init();
242 anon_init();
243
244 /* must be /after/ perfmon_init() at least */
245 if (atexit(clean_exit)) {
246 perfmon_exit();
247 perror("oprofiled: couldn't set exit cleanup: ");
248 exit(EXIT_FAILURE);
249 }
250}
251
252
253static void opd_26_start(void)
254{
255 opd_open_files();
256
257 /* simple sleep-then-process loop */
258 opd_do_read(sbuf, s_buf_bytesize);
259}
260
261
262static void opd_26_exit(void)
263{
264 opd_print_stats();
265 printf("oprofiled stopped %s", op_get_time());
266
267 free(sbuf);
268 free(vmlinux);
269 /* FIXME: free kernel images, sfiles etc. */
270}
271
272struct oprofiled_ops opd_26_ops = {
273 .init = opd_26_init,
274 .start = opd_26_start,
275 .exit = opd_26_exit,
276};