Update licensing: lgplv2.1 for libs, gplv2 for programs
[ltt-control.git] / lttd / lttd.c
CommitLineData
617de8e1 1/* lttd
2 *
3 * Linux Trace Toolkit Daemon
4 *
c2ffa20f 5 * This is a simple daemon that reads a few relay+debugfs channels and save
6 * them in a trace.
617de8e1 7 *
31482529 8 * CPU hot-plugging is supported using inotify.
617de8e1 9 *
ed2849af
MD
10 * Copyright 2009-2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
617de8e1 25 */
26
0bb647f5 27#ifdef HAVE_CONFIG_H
469206ed 28#include <config.h>
0bb647f5 29#endif
30
e54e1d5d 31#define _REENTRANT
0bb647f5 32#define _GNU_SOURCE
e54e1d5d 33#include <features.h>
617de8e1 34#include <stdio.h>
1d483eea 35#include <unistd.h>
617de8e1 36#include <errno.h>
37#include <sys/types.h>
38#include <sys/stat.h>
617de8e1 39#include <stdlib.h>
40#include <dirent.h>
41#include <string.h>
90ccaa9a 42#include <fcntl.h>
43#include <sys/poll.h>
1d483eea 44#include <sys/mman.h>
45#include <signal.h>
e54e1d5d 46#include <pthread.h>
357915bb 47#include <sys/syscall.h>
48#include <unistd.h>
49#include <asm/ioctls.h>
50
51#include <linux/version.h>
1d483eea 52
53/* Relayfs IOCTL */
54#include <asm/ioctl.h>
55#include <asm/types.h>
56
57/* Get the next sub buffer that can be read. */
572db7d9 58#define RELAY_GET_SB _IOR(0xF5, 0x00,__u32)
1d483eea 59/* Release the oldest reserved (by "get") sub buffer. */
572db7d9 60#define RELAY_PUT_SB _IOW(0xF5, 0x01,__u32)
1d483eea 61/* returns the number of sub buffers in the per cpu channel. */
572db7d9
MD
62#define RELAY_GET_N_SB _IOR(0xF5, 0x02,__u32)
63/* returns the size of the current sub buffer. */
64#define RELAY_GET_SB_SIZE _IOR(0xF5, 0x03, __u32)
65/* returns the size of data to consume in the current sub-buffer. */
66#define RELAY_GET_MAX_SB_SIZE _IOR(0xF5, 0x04, __u32)
67
1d483eea 68
357915bb 69#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
7967f7c3 70#include <sys/inotify.h>
8d91577f 71#if 0 /* should now be provided by libc. */
357915bb 72/* From the inotify-tools 2.6 package */
73static inline int inotify_init (void)
74{
75 return syscall (__NR_inotify_init);
76}
77
78static inline int inotify_add_watch (int fd, const char *name, __u32 mask)
79{
80 return syscall (__NR_inotify_add_watch, fd, name, mask);
81}
82
83static inline int inotify_rm_watch (int fd, __u32 wd)
84{
85 return syscall (__NR_inotify_rm_watch, fd, wd);
86}
8d91577f 87#endif //0
357915bb 88#define HAS_INOTIFY
89#else
90static inline int inotify_init (void)
91{
92 return -1;
93}
1d483eea 94
357915bb 95static inline int inotify_add_watch (int fd, const char *name, __u32 mask)
96{
97 return 0;
98}
99
100static inline int inotify_rm_watch (int fd, __u32 wd)
101{
102 return 0;
103}
104#undef HAS_INOTIFY
105#endif
617de8e1 106
617de8e1 107struct fd_pair {
108 int channel;
109 int trace;
572db7d9
MD
110 unsigned int n_sb;
111 unsigned int max_sb_size;
1d483eea 112 void *mmap;
5ffb77aa 113 pthread_mutex_t mutex;
617de8e1 114};
115
116struct channel_trace_fd {
117 struct fd_pair *pair;
118 int num_pairs;
119};
120
357915bb 121struct inotify_watch {
122 int wd;
123 char path_channel[PATH_MAX];
124 char path_trace[PATH_MAX];
125};
126
127struct inotify_watch_array {
128 struct inotify_watch *elem;
129 int num;
130};
131
f01152ea 132static __thread int thread_pipe[2];
31482529 133
134struct channel_trace_fd fd_pairs = { NULL, 0 };
135int inotify_fd = -1;
136struct inotify_watch_array inotify_watch_array = { NULL, 0 };
137
138/* protects fd_pairs and inotify_watch_array */
139pthread_rwlock_t fd_pairs_lock = PTHREAD_RWLOCK_INITIALIZER;
140
141
89565b43 142static char *trace_name = NULL;
143static char *channel_name = NULL;
144static int daemon_mode = 0;
145static int append_mode = 0;
146static unsigned long num_threads = 1;
1d483eea 147volatile static int quit_program = 0; /* For signal handler */
89565b43 148static int dump_flight_only = 0;
149static int dump_normal_only = 0;
083518b7 150static int verbose_mode = 0;
151
152#define printf_verbose(fmt, args...) \
153 do { \
154 if (verbose_mode) \
155 printf(fmt, ##args); \
156 } while (0)
617de8e1 157
158/* Args :
159 *
160 * -t directory Directory name of the trace to write to. Will be created.
c2ffa20f 161 * -c directory Root directory of the debugfs trace channels.
617de8e1 162 * -d Run in background (daemon).
083518b7 163 * -a Trace append mode.
164 * -s Send SIGUSR1 to parent when ready for IO.
617de8e1 165 */
166void show_arguments(void)
167{
168 printf("Please use the following arguments :\n");
169 printf("\n");
170 printf("-t directory Directory name of the trace to write to.\n"
171 " It will be created.\n");
c2ffa20f 172 printf("-c directory Root directory of the debugfs trace channels.\n");
617de8e1 173 printf("-d Run in background (daemon).\n");
90ccaa9a 174 printf("-a Append to an possibly existing trace.\n");
5ffb77aa 175 printf("-N Number of threads to start.\n");
89565b43 176 printf("-f Dump only flight recorder channels.\n");
177 printf("-n Dump only normal channels.\n");
083518b7 178 printf("-v Verbose mode.\n");
617de8e1 179 printf("\n");
180}
181
182
183/* parse_arguments
184 *
185 * Parses the command line arguments.
186 *
187 * Returns 1 if the arguments were correct, but doesn't ask for program
188 * continuation. Returns -1 if the arguments are incorrect, or 0 if OK.
189 */
190int parse_arguments(int argc, char **argv)
191{
192 int ret = 0;
193 int argn = 1;
194
195 if(argc == 2) {
196 if(strcmp(argv[1], "-h") == 0) {
197 return 1;
198 }
199 }
200
90ccaa9a 201 while(argn < argc) {
617de8e1 202
203 switch(argv[argn][0]) {
204 case '-':
205 switch(argv[argn][1]) {
206 case 't':
90ccaa9a 207 if(argn+1 < argc) {
208 trace_name = argv[argn+1];
209 argn++;
210 }
617de8e1 211 break;
212 case 'c':
90ccaa9a 213 if(argn+1 < argc) {
214 channel_name = argv[argn+1];
215 argn++;
216 }
617de8e1 217 break;
218 case 'd':
219 daemon_mode = 1;
220 break;
90ccaa9a 221 case 'a':
222 append_mode = 1;
223 break;
5ffb77aa 224 case 'N':
e54e1d5d 225 if(argn+1 < argc) {
226 num_threads = strtoul(argv[argn+1], NULL, 0);
227 argn++;
228 }
229 break;
89565b43 230 case 'f':
231 dump_flight_only = 1;
232 break;
233 case 'n':
234 dump_normal_only = 1;
235 break;
083518b7 236 case 'v':
237 verbose_mode = 1;
238 break;
617de8e1 239 default:
240 printf("Invalid argument '%s'.\n", argv[argn]);
241 printf("\n");
242 ret = -1;
243 }
244 break;
245 default:
246 printf("Invalid argument '%s'.\n", argv[argn]);
247 printf("\n");
248 ret = -1;
249 }
250 argn++;
251 }
252
253 if(trace_name == NULL) {
254 printf("Please specify a trace name.\n");
255 printf("\n");
256 ret = -1;
257 }
258
259 if(channel_name == NULL) {
260 printf("Please specify a channel name.\n");
261 printf("\n");
262 ret = -1;
263 }
264
265 return ret;
266}
267
268void show_info(void)
269{
15061ecb 270 printf("Linux Trace Toolkit Trace Daemon " VERSION "\n");
617de8e1 271 printf("\n");
c2ffa20f 272 printf("Reading from debugfs directory : %s\n", channel_name);
617de8e1 273 printf("Writing to trace directory : %s\n", trace_name);
274 printf("\n");
275}
276
277
1d483eea 278/* signal handling */
279
280static void handler(int signo)
281{
282 printf("Signal %d received : exiting cleanly\n", signo);
283 quit_program = 1;
284}
285
286
357915bb 287int open_buffer_file(char *filename, char *path_channel, char *path_trace,
288 struct channel_trace_fd *fd_pairs)
289{
290 int open_ret = 0;
291 int ret = 0;
292 struct stat stat_buf;
293
294 if(strncmp(filename, "flight-", sizeof("flight-")-1) != 0) {
295 if(dump_flight_only) {
083518b7 296 printf_verbose("Skipping normal channel %s\n",
297 path_channel);
357915bb 298 return 0;
299 }
300 } else {
301 if(dump_normal_only) {
083518b7 302 printf_verbose("Skipping flight channel %s\n",
303 path_channel);
357915bb 304 return 0;
305 }
306 }
083518b7 307 printf_verbose("Opening file.\n");
357915bb 308
309 fd_pairs->pair = realloc(fd_pairs->pair,
310 ++fd_pairs->num_pairs * sizeof(struct fd_pair));
311
312 /* Open the channel in read mode */
313 fd_pairs->pair[fd_pairs->num_pairs-1].channel =
314 open(path_channel, O_RDONLY | O_NONBLOCK);
315 if(fd_pairs->pair[fd_pairs->num_pairs-1].channel == -1) {
316 perror(path_channel);
317 fd_pairs->num_pairs--;
318 return 0; /* continue */
319 }
320 /* Open the trace in write mode, only append if append_mode */
321 ret = stat(path_trace, &stat_buf);
322 if(ret == 0) {
323 if(append_mode) {
083518b7 324 printf_verbose("Appending to file %s as requested\n",
325 path_trace);
357915bb 326
327 fd_pairs->pair[fd_pairs->num_pairs-1].trace =
42e99028 328 open(path_trace, O_WRONLY,
357915bb 329 S_IRWXU|S_IRWXG|S_IRWXO);
357915bb 330 if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) {
331 perror(path_trace);
1ee8f63e
MD
332 open_ret = -1;
333 close(fd_pairs->pair[fd_pairs->num_pairs-1].channel);
334 fd_pairs->num_pairs--;
335 goto end;
357915bb 336 }
42e99028 337 ret = lseek(fd_pairs->pair[fd_pairs->num_pairs-1].trace,
338 0, SEEK_END);
339 if (ret < 0) {
340 perror(path_trace);
1ee8f63e
MD
341 open_ret = -1;
342 close(fd_pairs->pair[fd_pairs->num_pairs-1].channel);
343 close(fd_pairs->pair[fd_pairs->num_pairs-1].trace);
344 fd_pairs->num_pairs--;
345 goto end;
42e99028 346 }
357915bb 347 } else {
348 printf("File %s exists, cannot open. Try append mode.\n", path_trace);
349 open_ret = -1;
1ee8f63e
MD
350 close(fd_pairs->pair[fd_pairs->num_pairs-1].channel);
351 fd_pairs->num_pairs--;
357915bb 352 goto end;
353 }
354 } else {
355 if(errno == ENOENT) {
356 fd_pairs->pair[fd_pairs->num_pairs-1].trace =
357 open(path_trace, O_WRONLY|O_CREAT|O_EXCL,
358 S_IRWXU|S_IRWXG|S_IRWXO);
359 if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) {
360 perror(path_trace);
1ee8f63e
MD
361 open_ret = -1;
362 close(fd_pairs->pair[fd_pairs->num_pairs-1].channel);
363 fd_pairs->num_pairs--;
364 goto end;
357915bb 365 }
366 }
367 }
368end:
369 return open_ret;
370}
1d483eea 371
617de8e1 372int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name,
357915bb 373 struct channel_trace_fd *fd_pairs, int *inotify_fd,
374 struct inotify_watch_array *iwatch_array)
617de8e1 375{
376 DIR *channel_dir = opendir(subchannel_name);
377 struct dirent *entry;
378 struct stat stat_buf;
379 int ret;
380 char path_channel[PATH_MAX];
381 int path_channel_len;
382 char *path_channel_ptr;
383 char path_trace[PATH_MAX];
384 int path_trace_len;
385 char *path_trace_ptr;
002f91bb 386 int open_ret = 0;
617de8e1 387
388 if(channel_dir == NULL) {
389 perror(subchannel_name);
d304b1dd 390 open_ret = ENOENT;
002f91bb 391 goto end;
617de8e1 392 }
393
083518b7 394 printf_verbose("Creating trace subdirectory %s\n", subtrace_name);
617de8e1 395 ret = mkdir(subtrace_name, S_IRWXU|S_IRWXG|S_IRWXO);
396 if(ret == -1) {
b1e3e7c7 397 if(errno != EEXIST) {
90ccaa9a 398 perror(subtrace_name);
002f91bb 399 open_ret = -1;
d304b1dd 400 goto end;
90ccaa9a 401 }
617de8e1 402 }
403
404 strncpy(path_channel, subchannel_name, PATH_MAX-1);
405 path_channel_len = strlen(path_channel);
406 path_channel[path_channel_len] = '/';
407 path_channel_len++;
408 path_channel_ptr = path_channel + path_channel_len;
409
410 strncpy(path_trace, subtrace_name, PATH_MAX-1);
411 path_trace_len = strlen(path_trace);
412 path_trace[path_trace_len] = '/';
413 path_trace_len++;
414 path_trace_ptr = path_trace + path_trace_len;
415
357915bb 416#ifdef HAS_INOTIFY
417 iwatch_array->elem = realloc(iwatch_array->elem,
418 ++iwatch_array->num * sizeof(struct inotify_watch));
419
083518b7 420 printf_verbose("Adding inotify for channel %s\n", path_channel);
357915bb 421 iwatch_array->elem[iwatch_array->num-1].wd = inotify_add_watch(*inotify_fd, path_channel, IN_CREATE);
422 strcpy(iwatch_array->elem[iwatch_array->num-1].path_channel, path_channel);
423 strcpy(iwatch_array->elem[iwatch_array->num-1].path_trace, path_trace);
083518b7 424 printf_verbose("Added inotify for channel %s, wd %u\n",
425 iwatch_array->elem[iwatch_array->num-1].path_channel,
357915bb 426 iwatch_array->elem[iwatch_array->num-1].wd);
427#endif
428
617de8e1 429 while((entry = readdir(channel_dir)) != NULL) {
430
431 if(entry->d_name[0] == '.') continue;
432
433 strncpy(path_channel_ptr, entry->d_name, PATH_MAX - path_channel_len);
434 strncpy(path_trace_ptr, entry->d_name, PATH_MAX - path_trace_len);
435
436 ret = stat(path_channel, &stat_buf);
437 if(ret == -1) {
438 perror(path_channel);
439 continue;
440 }
441
083518b7 442 printf_verbose("Channel file : %s\n", path_channel);
617de8e1 443
444 if(S_ISDIR(stat_buf.st_mode)) {
445
083518b7 446 printf_verbose("Entering channel subdirectory...\n");
357915bb 447 ret = open_channel_trace_pairs(path_channel, path_trace, fd_pairs,
448 inotify_fd, iwatch_array);
617de8e1 449 if(ret < 0) continue;
90ccaa9a 450 } else if(S_ISREG(stat_buf.st_mode)) {
357915bb 451 open_ret = open_buffer_file(entry->d_name, path_channel, path_trace,
452 fd_pairs);
453 if(open_ret)
454 goto end;
617de8e1 455 }
617de8e1 456 }
457
d304b1dd 458end:
617de8e1 459 closedir(channel_dir);
460
d304b1dd 461 return open_ret;
617de8e1 462}
463
1d483eea 464
465int read_subbuffer(struct fd_pair *pair)
466{
572db7d9 467 unsigned int consumed_old, len;
f01152ea 468 int err;
469 long ret;
4e1c69e6 470 off_t offset;
1d483eea 471
472
572db7d9 473 err = ioctl(pair->channel, RELAY_GET_SB, &consumed_old);
083518b7 474 printf_verbose("cookie : %u\n", consumed_old);
469206ed 475 if(err != 0) {
5ffb77aa 476 ret = errno;
30478a4d 477 perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)");
469206ed 478 goto get_error;
1d483eea 479 }
f01152ea 480#if 0
469206ed 481 err = TEMP_FAILURE_RETRY(write(pair->trace,
e4bed64a 482 pair->mmap
483 + (consumed_old & ((pair->n_subbufs * pair->subbuf_size)-1)),
1d483eea 484 pair->subbuf_size));
469206ed 485
486 if(err < 0) {
5ffb77aa 487 ret = errno;
1d483eea 488 perror("Error in writing to file");
469206ed 489 goto write_error;
1d483eea 490 }
f01152ea 491#endif //0
572db7d9
MD
492 err = ioctl(pair->channel, RELAY_GET_SB_SIZE, &len);
493 if(err != 0) {
494 ret = errno;
495 perror("Getting sub-buffer len failed.");
496 goto get_error;
497 }
498
f01152ea 499 offset = 0;
500 while (len > 0) {
4e1c69e6 501 printf_verbose("splice chan to pipe offset %lu\n",
502 (unsigned long)offset);
f01152ea 503 ret = splice(pair->channel, &offset, thread_pipe[1], NULL,
4b6ff6ef 504 len, SPLICE_F_MOVE | SPLICE_F_MORE);
083518b7 505 printf_verbose("splice chan to pipe ret %ld\n", ret);
f01152ea 506 if (ret < 0) {
507 perror("Error in relay splice");
508 goto write_error;
509 }
510 ret = splice(thread_pipe[0], NULL, pair->trace, NULL,
4b6ff6ef 511 ret, SPLICE_F_MOVE | SPLICE_F_MORE);
083518b7 512 printf_verbose("splice pipe to file %ld\n", ret);
f01152ea 513 if (ret < 0) {
514 perror("Error in file splice");
515 goto write_error;
516 }
517 len -= ret;
518 }
519
a7eb8aa2 520#if 0
521 err = fsync(pair->trace);
522 if(err < 0) {
523 ret = errno;
524 perror("Error in writing to file");
525 goto write_error;
526 }
527#endif //0
469206ed 528write_error:
f01152ea 529 ret = 0;
572db7d9 530 err = ioctl(pair->channel, RELAY_PUT_SB, &consumed_old);
469206ed 531 if(err != 0) {
5ffb77aa 532 ret = errno;
30478a4d 533 if(errno == EFAULT) {
5ffb77aa 534 perror("Error in unreserving sub buffer\n");
30478a4d 535 } else if(errno == EIO) {
572db7d9
MD
536 /* Should never happen with newer LTTng versions */
537 perror("Reader has been pushed by the writer, last sub-buffer corrupted.");
4f31148b 538 }
469206ed 539 goto get_error;
1d483eea 540 }
541
469206ed 542get_error:
543 return ret;
1d483eea 544}
545
546
357915bb 547int map_channels(struct channel_trace_fd *fd_pairs,
548 int idx_begin, int idx_end)
617de8e1 549{
1d483eea 550 int i,j;
e54e1d5d 551 int ret=0;
1d483eea 552
469206ed 553 if(fd_pairs->num_pairs <= 0) {
554 printf("No channel to read\n");
555 goto end;
556 }
557
1d483eea 558 /* Get the subbuf sizes and number */
559
357915bb 560 for(i=idx_begin;i<idx_end;i++) {
1d483eea 561 struct fd_pair *pair = &fd_pairs->pair[i];
90ccaa9a 562
572db7d9 563 ret = ioctl(pair->channel, RELAY_GET_N_SB, &pair->n_sb);
1d483eea 564 if(ret != 0) {
572db7d9 565 perror("Error in getting the number of sub-buffers");
1d483eea 566 goto end;
567 }
572db7d9
MD
568 ret = ioctl(pair->channel, RELAY_GET_MAX_SB_SIZE,
569 &pair->max_sb_size);
1d483eea 570 if(ret != 0) {
572db7d9 571 perror("Error in getting the max sub-buffer size");
1d483eea 572 goto end;
573 }
5ffb77aa 574 ret = pthread_mutex_init(&pair->mutex, NULL); /* Fast mutex */
575 if(ret != 0) {
576 perror("Error in mutex init");
577 goto end;
578 }
1d483eea 579 }
580
f01152ea 581#if 0
1d483eea 582 /* Mmap each FD */
357915bb 583 for(i=idx_begin;i<idx_end;i++) {
1d483eea 584 struct fd_pair *pair = &fd_pairs->pair[i];
585
586 pair->mmap = mmap(0, pair->subbuf_size * pair->n_subbufs, PROT_READ,
587 MAP_SHARED, pair->channel, 0);
588 if(pair->mmap == MAP_FAILED) {
589 perror("Mmap error");
590 goto munmap;
591 }
592 }
593
5ffb77aa 594 goto end; /* success */
1d483eea 595
e54e1d5d 596 /* Error handling */
597 /* munmap only the successfully mmapped indexes */
598munmap:
599 /* Munmap each FD */
357915bb 600 for(j=idx_begin;j<i;j++) {
e54e1d5d 601 struct fd_pair *pair = &fd_pairs->pair[j];
602 int err_ret;
603
604 err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs);
605 if(err_ret != 0) {
606 perror("Error in munmap");
607 }
608 ret |= err_ret;
609 }
610
f01152ea 611#endif //0
e54e1d5d 612end:
613 return ret;
e54e1d5d 614}
615
e54e1d5d 616int unmap_channels(struct channel_trace_fd *fd_pairs)
617{
618 int j;
619 int ret=0;
620
621 /* Munmap each FD */
622 for(j=0;j<fd_pairs->num_pairs;j++) {
623 struct fd_pair *pair = &fd_pairs->pair[j];
624 int err_ret;
625
f01152ea 626#if 0
e54e1d5d 627 err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs);
628 if(err_ret != 0) {
629 perror("Error in munmap");
630 }
631 ret |= err_ret;
f01152ea 632#endif //0
5ffb77aa 633 err_ret = pthread_mutex_destroy(&pair->mutex);
634 if(err_ret != 0) {
635 perror("Error in mutex destroy");
636 }
637 ret |= err_ret;
e54e1d5d 638 }
639
640 return ret;
641}
642
357915bb 643#ifdef HAS_INOTIFY
644/* Inotify event arrived.
645 *
646 * Only support add file for now.
647 */
648
649int read_inotify(int inotify_fd,
650 struct channel_trace_fd *fd_pairs,
651 struct inotify_watch_array *iwatch_array)
652{
653 char buf[sizeof(struct inotify_event) + PATH_MAX];
654 char path_channel[PATH_MAX];
655 char path_trace[PATH_MAX];
656 ssize_t len;
657 struct inotify_event *ievent;
658 size_t offset;
659 unsigned int i;
660 int ret;
661 int old_num;
662
663 offset = 0;
664 len = read(inotify_fd, buf, sizeof(struct inotify_event) + PATH_MAX);
665 if(len < 0) {
31482529 666
667 if(errno == EAGAIN)
668 return 0; /* another thread got the data before us */
669
357915bb 670 printf("Error in read from inotify FD %s.\n", strerror(len));
671 return -1;
672 }
673 while(offset < len) {
674 ievent = (struct inotify_event *)&(buf[offset]);
675 for(i=0; i<iwatch_array->num; i++) {
676 if(iwatch_array->elem[i].wd == ievent->wd &&
677 ievent->mask == IN_CREATE) {
083518b7 678 printf_verbose(
679 "inotify wd %u event mask : %u for %s%s\n",
357915bb 680 ievent->wd, ievent->mask,
083518b7 681 iwatch_array->elem[i].path_channel,
682 ievent->name);
357915bb 683 old_num = fd_pairs->num_pairs;
684 strcpy(path_channel, iwatch_array->elem[i].path_channel);
685 strcat(path_channel, ievent->name);
686 strcpy(path_trace, iwatch_array->elem[i].path_trace);
687 strcat(path_trace, ievent->name);
688 if(ret = open_buffer_file(ievent->name, path_channel,
689 path_trace, fd_pairs)) {
690 printf("Error opening buffer file\n");
691 return -1;
692 }
693 if(ret = map_channels(fd_pairs, old_num, fd_pairs->num_pairs)) {
694 printf("Error mapping channel\n");
695 return -1;
696 }
697
698 }
699 }
700 offset += sizeof(*ievent) + ievent->len;
701 }
702}
703#endif //HAS_INOTIFY
e54e1d5d 704
705/* read_channels
5ffb77aa 706 *
707 * Thread worker.
e54e1d5d 708 *
c2ffa20f 709 * Read the debugfs channels and write them in the paired tracefiles.
e54e1d5d 710 *
711 * @fd_pairs : paired channels and trace files.
712 *
357915bb 713 * returns 0 on success, -1 on error.
e54e1d5d 714 *
715 * Note that the high priority polled channels are consumed first. We then poll
716 * again to see if these channels are still in priority. Only when no
717 * high priority channel is left, we start reading low priority channels.
718 *
719 * Note that a channel is considered high priority when the buffer is almost
720 * full.
721 */
722
31482529 723int read_channels(unsigned long thread_num, struct channel_trace_fd *fd_pairs,
357915bb 724 int inotify_fd, struct inotify_watch_array *iwatch_array)
e54e1d5d 725{
357915bb 726 struct pollfd *pollfd = NULL;
31482529 727 int num_pollfd;
e54e1d5d 728 int i,j;
729 int num_rdy, num_hup;
730 int high_prio;
5ffb77aa 731 int ret = 0;
357915bb 732 int inotify_fds;
733 unsigned int old_num;
e54e1d5d 734
357915bb 735#ifdef HAS_INOTIFY
736 inotify_fds = 1;
737#else
738 inotify_fds = 0;
739#endif
740
31482529 741 pthread_rwlock_rdlock(&fd_pairs_lock);
742
357915bb 743 /* Start polling the FD. Keep one fd for inotify */
744 pollfd = malloc((inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd));
745
746#ifdef HAS_INOTIFY
747 pollfd[0].fd = inotify_fd;
748 pollfd[0].events = POLLIN|POLLPRI;
749#endif
90ccaa9a 750
751 for(i=0;i<fd_pairs->num_pairs;i++) {
357915bb 752 pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel;
753 pollfd[inotify_fds+i].events = POLLIN|POLLPRI;
90ccaa9a 754 }
31482529 755 num_pollfd = inotify_fds + fd_pairs->num_pairs;
756
757
758 pthread_rwlock_unlock(&fd_pairs_lock);
759
90ccaa9a 760 while(1) {
4f45ea55 761 high_prio = 0;
1d483eea 762 num_hup = 0;
763#ifdef DEBUG
764 printf("Press a key for next poll...\n");
765 char buf[1];
766 read(STDIN_FILENO, &buf, 1);
31482529 767 printf("Next poll (polling %d fd) :\n", num_pollfd);
1d483eea 768#endif //DEBUG
357915bb 769
1d483eea 770 /* Have we received a signal ? */
771 if(quit_program) break;
772
31482529 773 num_rdy = poll(pollfd, num_pollfd, -1);
774
90ccaa9a 775 if(num_rdy == -1) {
776 perror("Poll error");
1d483eea 777 goto free_fd;
90ccaa9a 778 }
779
083518b7 780 printf_verbose("Data received\n");
357915bb 781#ifdef HAS_INOTIFY
782 switch(pollfd[0].revents) {
783 case POLLERR:
083518b7 784 printf_verbose(
785 "Error returned in polling inotify fd %d.\n",
786 pollfd[0].fd);
357915bb 787 break;
788 case POLLHUP:
083518b7 789 printf_verbose(
790 "Polling inotify fd %d tells it has hung up.\n",
791 pollfd[0].fd);
357915bb 792 break;
793 case POLLNVAL:
083518b7 794 printf_verbose(
795 "Polling inotify fd %d tells fd is not open.\n",
796 pollfd[0].fd);
357915bb 797 break;
798 case POLLPRI:
799 case POLLIN:
083518b7 800 printf_verbose(
801 "Polling inotify fd %d : data ready.\n",
802 pollfd[0].fd);
31482529 803
804 pthread_rwlock_wrlock(&fd_pairs_lock);
357915bb 805 read_inotify(inotify_fd, fd_pairs, iwatch_array);
31482529 806 pthread_rwlock_unlock(&fd_pairs_lock);
807
357915bb 808 break;
809 }
810#endif
90ccaa9a 811
31482529 812 for(i=inotify_fds;i<num_pollfd;i++) {
90ccaa9a 813 switch(pollfd[i].revents) {
814 case POLLERR:
083518b7 815 printf_verbose(
816 "Error returned in polling fd %d.\n",
817 pollfd[i].fd);
1d483eea 818 num_hup++;
90ccaa9a 819 break;
820 case POLLHUP:
083518b7 821 printf_verbose(
822 "Polling fd %d tells it has hung up.\n",
823 pollfd[i].fd);
1d483eea 824 num_hup++;
90ccaa9a 825 break;
826 case POLLNVAL:
083518b7 827 printf_verbose(
828 "Polling fd %d tells fd is not open.\n",
829 pollfd[i].fd);
1d483eea 830 num_hup++;
90ccaa9a 831 break;
832 case POLLPRI:
31482529 833 pthread_rwlock_rdlock(&fd_pairs_lock);
357915bb 834 if(pthread_mutex_trylock(&fd_pairs->pair[i-inotify_fds].mutex) == 0) {
083518b7 835 printf_verbose(
836 "Urgent read on fd %d\n",
837 pollfd[i].fd);
5ffb77aa 838 /* Take care of high priority channels first. */
839 high_prio = 1;
572db7d9 840 /* it's ok to have an unavailable sub-buffer */
357915bb 841 ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]);
30478a4d 842 if(ret == EAGAIN) ret = 0;
cdad9787 843
357915bb 844 ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex);
5ffb77aa 845 if(ret)
846 printf("Error in mutex unlock : %s\n", strerror(ret));
847 }
31482529 848 pthread_rwlock_unlock(&fd_pairs_lock);
90ccaa9a 849 break;
4f45ea55 850 }
90ccaa9a 851 }
357915bb 852 /* If every buffer FD has hung up, we end the read loop here */
31482529 853 if(num_hup == num_pollfd - inotify_fds) break;
90ccaa9a 854
4f45ea55 855 if(!high_prio) {
31482529 856 for(i=inotify_fds;i<num_pollfd;i++) {
4f45ea55 857 switch(pollfd[i].revents) {
858 case POLLIN:
31482529 859 pthread_rwlock_rdlock(&fd_pairs_lock);
357915bb 860 if(pthread_mutex_trylock(&fd_pairs->pair[i-inotify_fds].mutex) == 0) {
5ffb77aa 861 /* Take care of low priority channels. */
083518b7 862 printf_verbose(
863 "Normal read on fd %d\n",
864 pollfd[i].fd);
5ffb77aa 865 /* it's ok to have an unavailable subbuffer */
357915bb 866 ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]);
30478a4d 867 if(ret == EAGAIN) ret = 0;
cdad9787 868
357915bb 869 ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex);
5ffb77aa 870 if(ret)
871 printf("Error in mutex unlock : %s\n", strerror(ret));
872 }
31482529 873 pthread_rwlock_unlock(&fd_pairs_lock);
4f45ea55 874 break;
875 }
876 }
90ccaa9a 877 }
878
31482529 879 /* Update pollfd array if an entry was added to fd_pairs */
880 pthread_rwlock_rdlock(&fd_pairs_lock);
881 if((inotify_fds + fd_pairs->num_pairs) != num_pollfd) {
882 pollfd = realloc(pollfd,
883 (inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd));
884 for(i=num_pollfd-inotify_fds;i<fd_pairs->num_pairs;i++) {
885 pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel;
886 pollfd[inotify_fds+i].events = POLLIN|POLLPRI;
887 }
888 num_pollfd = fd_pairs->num_pairs + inotify_fds;
889 }
890 pthread_rwlock_unlock(&fd_pairs_lock);
891
892 /* NB: If the fd_pairs structure is updated by another thread from this
893 * point forward, the current thread will wait in the poll without
894 * monitoring the new channel. However, this thread will add the
895 * new channel on next poll (and this should not take too much time
896 * on a loaded system).
897 *
898 * This event is quite unlikely and can only occur if a CPU is
899 * hot-plugged while multple lttd threads are running.
900 */
90ccaa9a 901 }
902
1d483eea 903free_fd:
90ccaa9a 904 free(pollfd);
905
1d483eea 906end:
357915bb 907 return ret;
617de8e1 908}
909
910
357915bb 911void close_channel_trace_pairs(struct channel_trace_fd *fd_pairs, int inotify_fd,
912 struct inotify_watch_array *iwatch_array)
617de8e1 913{
90ccaa9a 914 int i;
915 int ret;
617de8e1 916
90ccaa9a 917 for(i=0;i<fd_pairs->num_pairs;i++) {
918 ret = close(fd_pairs->pair[i].channel);
919 if(ret == -1) perror("Close error on channel");
920 ret = close(fd_pairs->pair[i].trace);
921 if(ret == -1) perror("Close error on trace");
922 }
923 free(fd_pairs->pair);
357915bb 924 free(iwatch_array->elem);
925}
926
927/* Thread worker */
928void * thread_main(void *arg)
929{
31482529 930 long ret;
931 unsigned long thread_num = (unsigned long)arg;
932
f01152ea 933 ret = pipe(thread_pipe);
934 if (ret < 0) {
935 perror("Error creating pipe");
936 return (void*)ret;
937 }
31482529 938 ret = read_channels(thread_num, &fd_pairs, inotify_fd, &inotify_watch_array);
f01152ea 939 close(thread_pipe[0]); /* close read end */
940 close(thread_pipe[1]); /* close write end */
31482529 941 return (void*)ret;
942}
943
944
945int channels_init()
946{
357915bb 947 int ret = 0;
357915bb 948
949 inotify_fd = inotify_init();
31482529 950 fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
357915bb 951
952 if(ret = open_channel_trace_pairs(channel_name, trace_name, &fd_pairs,
953 &inotify_fd, &inotify_watch_array))
954 goto close_channel;
c928825d 955 if (fd_pairs.num_pairs == 0) {
956 printf("No channel available for reading, exiting\n");
957 ret = -ENOENT;
958 goto close_channel;
959 }
357915bb 960 if(ret = map_channels(&fd_pairs, 0, fd_pairs.num_pairs))
961 goto close_channel;
31482529 962 return 0;
357915bb 963
964close_channel:
965 close_channel_trace_pairs(&fd_pairs, inotify_fd, &inotify_watch_array);
966 if(inotify_fd >= 0)
967 close(inotify_fd);
31482529 968 return ret;
617de8e1 969}
970
31482529 971
617de8e1 972int main(int argc, char ** argv)
973{
e54e1d5d 974 int ret = 0;
1d483eea 975 struct sigaction act;
5ffb77aa 976 pthread_t *tids;
31482529 977 unsigned long i;
5ffb77aa 978 void *tret;
617de8e1 979
980 ret = parse_arguments(argc, argv);
981
982 if(ret != 0) show_arguments();
983 if(ret < 0) return EINVAL;
984 if(ret > 0) return 0;
985
986 show_info();
987
1d483eea 988 /* Connect the signal handlers */
989 act.sa_handler = handler;
990 act.sa_flags = 0;
991 sigemptyset(&(act.sa_mask));
992 sigaddset(&(act.sa_mask), SIGTERM);
993 sigaddset(&(act.sa_mask), SIGQUIT);
994 sigaddset(&(act.sa_mask), SIGINT);
995 sigaction(SIGTERM, &act, NULL);
996 sigaction(SIGQUIT, &act, NULL);
997 sigaction(SIGINT, &act, NULL);
998
31482529 999 if(ret = channels_init())
1000 return ret;
1001
06cb3ad3 1002 if(daemon_mode) {
1003 ret = daemon(0, 0);
1004
1005 if(ret == -1) {
1006 perror("An error occured while daemonizing.");
1007 exit(-1);
1008 }
1009 }
1010
5ffb77aa 1011 tids = malloc(sizeof(pthread_t) * num_threads);
1012 for(i=0; i<num_threads; i++) {
ae410d24 1013
357915bb 1014 ret = pthread_create(&tids[i], NULL, thread_main, (void*)i);
5ffb77aa 1015 if(ret) {
1016 perror("Error creating thread");
1017 break;
1018 }
1019 }
617de8e1 1020
5ffb77aa 1021 for(i=0; i<num_threads; i++) {
1022 ret = pthread_join(tids[i], &tret);
1023 if(ret) {
1024 perror("Error joining thread");
1025 break;
1026 }
31482529 1027 if((long)tret != 0) {
1028 printf("Error %s occured in thread %u\n",
1029 strerror((long)tret), i);
5ffb77aa 1030 }
1031 }
1032
1033 free(tids);
31482529 1034 ret = unmap_channels(&fd_pairs);
1035 close_channel_trace_pairs(&fd_pairs, inotify_fd, &inotify_watch_array);
1036 if(inotify_fd >= 0)
1037 close(inotify_fd);
5ffb77aa 1038
617de8e1 1039 return ret;
1040}
This page took 0.072422 seconds and 4 git commands to generate.