liblttd cleanup and error handling fixes
[ltt-control.git] / liblttd / liblttd.c
CommitLineData
8ba26eae 1/* liblttd
008e2515
MSL
2 *
3 * Linux Trace Toolkit Daemon
4 *
5 * This is a simple daemon that reads a few relay+debugfs channels and save
6 * them in a trace.
7 *
8 * CPU hot-plugging is supported using inotify.
9 *
10 * Copyright 2005 -
11 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
d9cbca27
MSL
12 * Copyright 2010 -
13 * Michael Sills-Lavoie <michael.sills-lavoie@polymtl.ca>
14 * Oumarou Dicko <oumarou.dicko@polymtl.ca>
8ba26eae
MD
15 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
008e2515
MSL
29 */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include "liblttd.h"
36
37#define _REENTRANT
38#define _GNU_SOURCE
39#include <features.h>
40#include <stdio.h>
41#include <unistd.h>
42#include <errno.h>
43#include <sys/types.h>
44#include <stdlib.h>
45#include <dirent.h>
46#include <string.h>
47#include <fcntl.h>
48#include <sys/stat.h>
49#include <sys/poll.h>
50#include <sys/mman.h>
51#include <sys/syscall.h>
52#include <unistd.h>
53#include <asm/ioctls.h>
54
55#include <linux/version.h>
56
57/* Relayfs IOCTL */
58#include <asm/ioctl.h>
59#include <asm/types.h>
60
61/* Get the next sub buffer that can be read. */
62#define RELAY_GET_SB _IOR(0xF5, 0x00,__u32)
63/* Release the oldest reserved (by "get") sub buffer. */
64#define RELAY_PUT_SB _IOW(0xF5, 0x01,__u32)
65/* returns the number of sub buffers in the per cpu channel. */
66#define RELAY_GET_N_SB _IOR(0xF5, 0x02,__u32)
67/* returns the size of the current sub buffer. */
68#define RELAY_GET_SB_SIZE _IOR(0xF5, 0x03, __u32)
69/* returns the size of data to consume in the current sub-buffer. */
70#define RELAY_GET_MAX_SB_SIZE _IOR(0xF5, 0x04, __u32)
71
72
73#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
74#include <sys/inotify.h>
75
76#define HAS_INOTIFY
77#else
78static inline int inotify_init (void)
79{
80 return -1;
81}
82
83static inline int inotify_add_watch (int fd, const char *name, __u32 mask)
84{
85 return 0;
86}
87
88static inline int inotify_rm_watch (int fd, __u32 wd)
89{
90 return 0;
91}
92#undef HAS_INOTIFY
93#endif
94
d6d516b7
MSL
95struct liblttd_thread_data {
96 int thread_num;
97 struct liblttd_instance *instance;
98};
008e2515
MSL
99
100#define printf_verbose(fmt, args...) \
101 do { \
d6d516b7 102 if (instance->verbose_mode) \
008e2515
MSL
103 printf(fmt, ##args); \
104 } while (0)
105
106
d6d516b7
MSL
107int open_buffer_file(struct liblttd_instance *instance, char *filename,
108 char *path_channel, char *base_path_channel)
008e2515
MSL
109{
110 int open_ret = 0;
111 int ret = 0;
112
8ba26eae
MD
113 if (strncmp(filename, "flight-", sizeof("flight-")-1) != 0) {
114 if (instance->dump_flight_only) {
008e2515
MSL
115 printf_verbose("Skipping normal channel %s\n",
116 path_channel);
117 return 0;
118 }
119 } else {
8ba26eae 120 if (instance->dump_normal_only) {
008e2515
MSL
121 printf_verbose("Skipping flight channel %s\n",
122 path_channel);
123 return 0;
124 }
125 }
126 printf_verbose("Opening file.\n");
127
d6d516b7
MSL
128 instance->fd_pairs.pair = realloc(instance->fd_pairs.pair,
129 ++instance->fd_pairs.num_pairs * sizeof(struct fd_pair));
008e2515
MSL
130
131 /* Open the channel in read mode */
d6d516b7 132 instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1].channel =
008e2515 133 open(path_channel, O_RDONLY | O_NONBLOCK);
8ba26eae 134 if (instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1].channel == -1) {
008e2515 135 perror(path_channel);
d6d516b7 136 instance->fd_pairs.num_pairs--;
008e2515
MSL
137 return 0; /* continue */
138 }
139
8ba26eae 140 if (instance->callbacks->on_open_channel) ret = instance->callbacks->on_open_channel(
d6d516b7 141 instance->callbacks, &instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1],
008e2515
MSL
142 base_path_channel);
143
8ba26eae 144 if (ret != 0) {
008e2515 145 open_ret = -1;
d6d516b7
MSL
146 close(instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1].channel);
147 instance->fd_pairs.num_pairs--;
008e2515
MSL
148 goto end;
149 }
150
151end:
152 return open_ret;
153}
154
d6d516b7
MSL
155int open_channel_trace_pairs(struct liblttd_instance *instance,
156 char *subchannel_name, char *base_subchannel_name)
008e2515
MSL
157{
158 DIR *channel_dir = opendir(subchannel_name);
159 struct dirent *entry;
160 struct stat stat_buf;
161 int ret;
162 char path_channel[PATH_MAX];
163 int path_channel_len;
164 char *path_channel_ptr;
165 char *base_subchannel_ptr;
166
167 int open_ret = 0;
168
8ba26eae 169 if (channel_dir == NULL) {
008e2515
MSL
170 perror(subchannel_name);
171 open_ret = ENOENT;
172 goto end;
173 }
174
d9cbca27 175 printf_verbose("Calling : on new channels folder\n");
8ba26eae 176 if (instance->callbacks->on_new_channels_folder) ret = instance->callbacks->
d6d516b7 177 on_new_channels_folder(instance->callbacks,
008e2515 178 base_subchannel_name);
8ba26eae 179 if (ret == -1) {
008e2515
MSL
180 open_ret = -1;
181 goto end;
182 }
183
184 strncpy(path_channel, subchannel_name, PATH_MAX-1);
185 path_channel_len = strlen(path_channel);
186 path_channel[path_channel_len] = '/';
187 path_channel_len++;
188 path_channel_ptr = path_channel + path_channel_len;
189 base_subchannel_ptr = path_channel +
190 (base_subchannel_name - subchannel_name);
191
192#ifdef HAS_INOTIFY
d6d516b7
MSL
193 instance->inotify_watch_array.elem = realloc(instance->inotify_watch_array.elem,
194 ++instance->inotify_watch_array.num * sizeof(struct inotify_watch));
008e2515
MSL
195
196 printf_verbose("Adding inotify for channel %s\n", path_channel);
d6d516b7
MSL
197 instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].wd = inotify_add_watch(instance->inotify_fd, path_channel, IN_CREATE);
198 strcpy(instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].path_channel, path_channel);
199 instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].base_path_channel =
200 instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].path_channel +
008e2515
MSL
201 (base_subchannel_name - subchannel_name);
202 printf_verbose("Added inotify for channel %s, wd %u\n",
d6d516b7
MSL
203 instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].path_channel,
204 instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].wd);
008e2515
MSL
205#endif
206
207 while((entry = readdir(channel_dir)) != NULL) {
208
8ba26eae 209 if (entry->d_name[0] == '.') continue;
008e2515
MSL
210
211 strncpy(path_channel_ptr, entry->d_name, PATH_MAX - path_channel_len);
212
213 ret = stat(path_channel, &stat_buf);
8ba26eae 214 if (ret == -1) {
008e2515
MSL
215 perror(path_channel);
216 continue;
217 }
218
219 printf_verbose("Channel file : %s\n", path_channel);
220
8ba26eae 221 if (S_ISDIR(stat_buf.st_mode)) {
008e2515
MSL
222
223 printf_verbose("Entering channel subdirectory...\n");
d6d516b7 224 ret = open_channel_trace_pairs(instance, path_channel, base_subchannel_ptr);
8ba26eae
MD
225 if (ret < 0) continue;
226 } else if (S_ISREG(stat_buf.st_mode)) {
d6d516b7
MSL
227 open_ret = open_buffer_file(instance, entry->d_name,
228 path_channel, base_subchannel_ptr);
8ba26eae 229 if (open_ret)
008e2515
MSL
230 goto end;
231 }
232 }
233
234end:
235 closedir(channel_dir);
236
237 return open_ret;
238}
239
240
d6d516b7 241int read_subbuffer(struct liblttd_instance *instance, struct fd_pair *pair)
008e2515
MSL
242{
243 unsigned int consumed_old, len;
244 int err;
245 long ret;
246 off_t offset;
247
008e2515
MSL
248 err = ioctl(pair->channel, RELAY_GET_SB, &consumed_old);
249 printf_verbose("cookie : %u\n", consumed_old);
8ba26eae 250 if (err != 0) {
008e2515
MSL
251 ret = errno;
252 perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)");
253 goto get_error;
254 }
255
256 err = ioctl(pair->channel, RELAY_GET_SB_SIZE, &len);
8ba26eae 257 if (err != 0) {
008e2515
MSL
258 ret = errno;
259 perror("Getting sub-buffer len failed.");
260 goto get_error;
261 }
262
8ba26eae
MD
263 if (instance->callbacks->on_read_subbuffer)
264 ret = instance->callbacks->on_read_subbuffer(
265 instance->callbacks, pair, len);
008e2515
MSL
266
267write_error:
268 ret = 0;
269 err = ioctl(pair->channel, RELAY_PUT_SB, &consumed_old);
8ba26eae 270 if (err != 0) {
008e2515 271 ret = errno;
8ba26eae 272 if (errno == EFAULT) {
008e2515 273 perror("Error in unreserving sub buffer\n");
8ba26eae 274 } else if (errno == EIO) {
008e2515
MSL
275 /* Should never happen with newer LTTng versions */
276 perror("Reader has been pushed by the writer, last sub-buffer corrupted.");
277 }
278 goto get_error;
279 }
280
281get_error:
282 return ret;
283}
284
285
d6d516b7 286int map_channels(struct liblttd_instance *instance, int idx_begin, int idx_end)
008e2515
MSL
287{
288 int i,j;
289 int ret=0;
290
8ba26eae 291 if (instance->fd_pairs.num_pairs <= 0) {
008e2515
MSL
292 printf("No channel to read\n");
293 goto end;
294 }
295
296 /* Get the subbuf sizes and number */
297
298 for(i=idx_begin;i<idx_end;i++) {
d6d516b7 299 struct fd_pair *pair = &instance->fd_pairs.pair[i];
008e2515
MSL
300
301 ret = ioctl(pair->channel, RELAY_GET_N_SB, &pair->n_sb);
8ba26eae 302 if (ret != 0) {
008e2515
MSL
303 perror("Error in getting the number of sub-buffers");
304 goto end;
305 }
306 ret = ioctl(pair->channel, RELAY_GET_MAX_SB_SIZE,
307 &pair->max_sb_size);
8ba26eae 308 if (ret != 0) {
008e2515
MSL
309 perror("Error in getting the max sub-buffer size");
310 goto end;
311 }
312 ret = pthread_mutex_init(&pair->mutex, NULL); /* Fast mutex */
8ba26eae 313 if (ret != 0) {
008e2515
MSL
314 perror("Error in mutex init");
315 goto end;
316 }
317 }
318
319end:
320 return ret;
321}
322
d6d516b7 323int unmap_channels(struct liblttd_instance *instance)
008e2515
MSL
324{
325 int j;
326 int ret=0;
327
328 /* Munmap each FD */
d6d516b7
MSL
329 for(j=0;j<instance->fd_pairs.num_pairs;j++) {
330 struct fd_pair *pair = &instance->fd_pairs.pair[j];
008e2515
MSL
331 int err_ret;
332
333 err_ret = pthread_mutex_destroy(&pair->mutex);
8ba26eae 334 if (err_ret != 0) {
008e2515
MSL
335 perror("Error in mutex destroy");
336 }
337 ret |= err_ret;
338 }
339
340 return ret;
341}
342
343#ifdef HAS_INOTIFY
344/* Inotify event arrived.
345 *
346 * Only support add file for now.
347 */
d6d516b7 348int read_inotify(struct liblttd_instance *instance)
008e2515
MSL
349{
350 char buf[sizeof(struct inotify_event) + PATH_MAX];
351 char path_channel[PATH_MAX];
352 ssize_t len;
353 struct inotify_event *ievent;
354 size_t offset;
355 unsigned int i;
356 int ret;
357 int old_num;
358
359 offset = 0;
d6d516b7 360 len = read(instance->inotify_fd, buf, sizeof(struct inotify_event) + PATH_MAX);
8ba26eae 361 if (len < 0) {
008e2515 362
8ba26eae 363 if (errno == EAGAIN)
008e2515
MSL
364 return 0; /* another thread got the data before us */
365
366 printf("Error in read from inotify FD %s.\n", strerror(len));
367 return -1;
368 }
369 while(offset < len) {
370 ievent = (struct inotify_event *)&(buf[offset]);
d6d516b7 371 for(i=0; i<instance->inotify_watch_array.num; i++) {
8ba26eae 372 if (instance->inotify_watch_array.elem[i].wd == ievent->wd &&
008e2515
MSL
373 ievent->mask == IN_CREATE) {
374 printf_verbose(
375 "inotify wd %u event mask : %u for %s%s\n",
376 ievent->wd, ievent->mask,
d6d516b7 377 instance->inotify_watch_array.elem[i].path_channel,
008e2515 378 ievent->name);
d6d516b7
MSL
379 old_num = instance->fd_pairs.num_pairs;
380 strcpy(path_channel, instance->inotify_watch_array.elem[i].path_channel);
008e2515 381 strcat(path_channel, ievent->name);
8ba26eae 382 if (ret = open_buffer_file(instance, ievent->name, path_channel,
d6d516b7
MSL
383 path_channel + (instance->inotify_watch_array.elem[i].base_path_channel -
384 instance->inotify_watch_array.elem[i].path_channel))) {
008e2515
MSL
385 printf("Error opening buffer file\n");
386 return -1;
387 }
8ba26eae 388 if (ret = map_channels(instance, old_num, instance->fd_pairs.num_pairs)) {
008e2515
MSL
389 printf("Error mapping channel\n");
390 return -1;
391 }
392
393 }
394 }
395 offset += sizeof(*ievent) + ievent->len;
396 }
397}
398#endif //HAS_INOTIFY
399
8ba26eae
MD
400/*
401 * read_channels
008e2515
MSL
402 *
403 * Thread worker.
404 *
405 * Read the debugfs channels and write them in the paired tracefiles.
406 *
407 * @fd_pairs : paired channels and trace files.
408 *
409 * returns 0 on success, -1 on error.
410 *
411 * Note that the high priority polled channels are consumed first. We then poll
412 * again to see if these channels are still in priority. Only when no
413 * high priority channel is left, we start reading low priority channels.
414 *
415 * Note that a channel is considered high priority when the buffer is almost
416 * full.
417 */
418
d6d516b7 419int read_channels(struct liblttd_instance *instance, unsigned long thread_num)
008e2515
MSL
420{
421 struct pollfd *pollfd = NULL;
422 int num_pollfd;
423 int i,j;
424 int num_rdy, num_hup;
425 int high_prio;
426 int ret = 0;
427 int inotify_fds;
428 unsigned int old_num;
429
430#ifdef HAS_INOTIFY
431 inotify_fds = 1;
432#else
433 inotify_fds = 0;
434#endif
435
d6d516b7 436 pthread_rwlock_rdlock(&instance->fd_pairs_lock);
008e2515
MSL
437
438 /* Start polling the FD. Keep one fd for inotify */
d6d516b7 439 pollfd = malloc((inotify_fds + instance->fd_pairs.num_pairs) * sizeof(struct pollfd));
008e2515
MSL
440
441#ifdef HAS_INOTIFY
d6d516b7 442 pollfd[0].fd = instance->inotify_fd;
008e2515
MSL
443 pollfd[0].events = POLLIN|POLLPRI;
444#endif
445
d6d516b7
MSL
446 for(i=0;i<instance->fd_pairs.num_pairs;i++) {
447 pollfd[inotify_fds+i].fd = instance->fd_pairs.pair[i].channel;
008e2515
MSL
448 pollfd[inotify_fds+i].events = POLLIN|POLLPRI;
449 }
d6d516b7 450 num_pollfd = inotify_fds + instance->fd_pairs.num_pairs;
008e2515
MSL
451
452
d6d516b7 453 pthread_rwlock_unlock(&instance->fd_pairs_lock);
008e2515
MSL
454
455 while(1) {
456 high_prio = 0;
457 num_hup = 0;
458#ifdef DEBUG
459 printf("Press a key for next poll...\n");
460 char buf[1];
461 read(STDIN_FILENO, &buf, 1);
462 printf("Next poll (polling %d fd) :\n", num_pollfd);
463#endif //DEBUG
464
465 /* Have we received a signal ? */
8ba26eae 466 if (instance->quit_program) break;
008e2515
MSL
467
468 num_rdy = poll(pollfd, num_pollfd, -1);
469
8ba26eae 470 if (num_rdy == -1) {
008e2515
MSL
471 perror("Poll error");
472 goto free_fd;
473 }
474
475 printf_verbose("Data received\n");
476#ifdef HAS_INOTIFY
477 switch(pollfd[0].revents) {
478 case POLLERR:
479 printf_verbose(
480 "Error returned in polling inotify fd %d.\n",
481 pollfd[0].fd);
482 break;
483 case POLLHUP:
484 printf_verbose(
485 "Polling inotify fd %d tells it has hung up.\n",
486 pollfd[0].fd);
487 break;
488 case POLLNVAL:
489 printf_verbose(
490 "Polling inotify fd %d tells fd is not open.\n",
491 pollfd[0].fd);
492 break;
493 case POLLPRI:
494 case POLLIN:
495 printf_verbose(
496 "Polling inotify fd %d : data ready.\n",
497 pollfd[0].fd);
498
d6d516b7
MSL
499 pthread_rwlock_wrlock(&instance->fd_pairs_lock);
500 read_inotify(instance);
501 pthread_rwlock_unlock(&instance->fd_pairs_lock);
008e2515
MSL
502
503 break;
504 }
505#endif
506
507 for(i=inotify_fds;i<num_pollfd;i++) {
508 switch(pollfd[i].revents) {
509 case POLLERR:
510 printf_verbose(
511 "Error returned in polling fd %d.\n",
512 pollfd[i].fd);
513 num_hup++;
514 break;
515 case POLLHUP:
516 printf_verbose(
517 "Polling fd %d tells it has hung up.\n",
518 pollfd[i].fd);
519 num_hup++;
520 break;
521 case POLLNVAL:
522 printf_verbose(
523 "Polling fd %d tells fd is not open.\n",
524 pollfd[i].fd);
525 num_hup++;
526 break;
527 case POLLPRI:
d6d516b7 528 pthread_rwlock_rdlock(&instance->fd_pairs_lock);
8ba26eae 529 if (pthread_mutex_trylock(&instance->fd_pairs.pair[i-inotify_fds].mutex) == 0) {
008e2515
MSL
530 printf_verbose(
531 "Urgent read on fd %d\n",
532 pollfd[i].fd);
533 /* Take care of high priority channels first. */
534 high_prio = 1;
535 /* it's ok to have an unavailable sub-buffer */
d6d516b7 536 ret = read_subbuffer(instance, &instance->fd_pairs.pair[i-inotify_fds]);
8ba26eae 537 if (ret == EAGAIN) ret = 0;
008e2515 538
d6d516b7 539 ret = pthread_mutex_unlock(&instance->fd_pairs.pair[i-inotify_fds].mutex);
8ba26eae 540 if (ret)
008e2515
MSL
541 printf("Error in mutex unlock : %s\n", strerror(ret));
542 }
d6d516b7 543 pthread_rwlock_unlock(&instance->fd_pairs_lock);
008e2515
MSL
544 break;
545 }
546 }
547 /* If every buffer FD has hung up, we end the read loop here */
8ba26eae 548 if (num_hup == num_pollfd - inotify_fds) break;
008e2515 549
8ba26eae 550 if (!high_prio) {
008e2515
MSL
551 for(i=inotify_fds;i<num_pollfd;i++) {
552 switch(pollfd[i].revents) {
553 case POLLIN:
d6d516b7 554 pthread_rwlock_rdlock(&instance->fd_pairs_lock);
8ba26eae 555 if (pthread_mutex_trylock(&instance->fd_pairs.pair[i-inotify_fds].mutex) == 0) {
008e2515
MSL
556 /* Take care of low priority channels. */
557 printf_verbose(
558 "Normal read on fd %d\n",
559 pollfd[i].fd);
560 /* it's ok to have an unavailable subbuffer */
d6d516b7 561 ret = read_subbuffer(instance, &instance->fd_pairs.pair[i-inotify_fds]);
8ba26eae 562 if (ret == EAGAIN) ret = 0;
008e2515 563
d6d516b7 564 ret = pthread_mutex_unlock(&instance->fd_pairs.pair[i-inotify_fds].mutex);
8ba26eae 565 if (ret)
008e2515
MSL
566 printf("Error in mutex unlock : %s\n", strerror(ret));
567 }
d6d516b7 568 pthread_rwlock_unlock(&instance->fd_pairs_lock);
008e2515
MSL
569 break;
570 }
571 }
572 }
573
574 /* Update pollfd array if an entry was added to fd_pairs */
d6d516b7 575 pthread_rwlock_rdlock(&instance->fd_pairs_lock);
8ba26eae 576 if ((inotify_fds + instance->fd_pairs.num_pairs) != num_pollfd) {
008e2515 577 pollfd = realloc(pollfd,
d6d516b7
MSL
578 (inotify_fds + instance->fd_pairs.num_pairs) * sizeof(struct pollfd));
579 for(i=num_pollfd-inotify_fds;i<instance->fd_pairs.num_pairs;i++) {
580 pollfd[inotify_fds+i].fd = instance->fd_pairs.pair[i].channel;
008e2515
MSL
581 pollfd[inotify_fds+i].events = POLLIN|POLLPRI;
582 }
d6d516b7 583 num_pollfd = instance->fd_pairs.num_pairs + inotify_fds;
008e2515 584 }
d6d516b7 585 pthread_rwlock_unlock(&instance->fd_pairs_lock);
008e2515
MSL
586
587 /* NB: If the fd_pairs structure is updated by another thread from this
588 * point forward, the current thread will wait in the poll without
589 * monitoring the new channel. However, this thread will add the
590 * new channel on next poll (and this should not take too much time
591 * on a loaded system).
592 *
593 * This event is quite unlikely and can only occur if a CPU is
594 * hot-plugged while multple lttd threads are running.
595 */
596 }
597
598free_fd:
599 free(pollfd);
600
601end:
602 return ret;
603}
604
605
d6d516b7 606void close_channel_trace_pairs(struct liblttd_instance *instance)
008e2515
MSL
607{
608 int i;
609 int ret;
610
d6d516b7
MSL
611 for(i=0;i<instance->fd_pairs.num_pairs;i++) {
612 ret = close(instance->fd_pairs.pair[i].channel);
8ba26eae
MD
613 if (ret == -1) perror("Close error on channel");
614 if (instance->callbacks->on_close_channel) {
d6d516b7
MSL
615 ret = instance->callbacks->on_close_channel(
616 instance->callbacks, &instance->fd_pairs.pair[i]);
8ba26eae 617 if (ret != 0) perror("Error on close channel callback");
008e2515
MSL
618 }
619 }
d6d516b7
MSL
620 free(instance->fd_pairs.pair);
621 free(instance->inotify_watch_array.elem);
008e2515
MSL
622}
623
624/* Thread worker */
625void * thread_main(void *arg)
626{
627 long ret = 0;
d6d516b7 628 struct liblttd_thread_data *thread_data = (struct liblttd_thread_data*) arg;
008e2515 629
8ba26eae 630 if (thread_data->instance->callbacks->on_new_thread)
d6d516b7
MSL
631 ret = thread_data->instance->callbacks->on_new_thread(
632 thread_data->instance->callbacks, thread_data->thread_num);
008e2515
MSL
633
634 if (ret < 0) {
635 return (void*)ret;
636 }
d6d516b7
MSL
637 ret = read_channels(thread_data->instance, thread_data->thread_num);
638
8ba26eae 639 if (thread_data->instance->callbacks->on_close_thread)
d6d516b7
MSL
640 thread_data->instance->callbacks->on_close_thread(
641 thread_data->instance->callbacks, thread_data->thread_num);
008e2515 642
d6d516b7 643 free(thread_data);
008e2515
MSL
644
645 return (void*)ret;
646}
647
d6d516b7 648int channels_init(struct liblttd_instance *instance)
008e2515
MSL
649{
650 int ret = 0;
651
d6d516b7
MSL
652 instance->inotify_fd = inotify_init();
653 fcntl(instance->inotify_fd, F_SETFL, O_NONBLOCK);
008e2515 654
8ba26eae 655 if (ret = open_channel_trace_pairs(instance, instance->channel_name,
d6d516b7
MSL
656 instance->channel_name +
657 strlen(instance->channel_name)))
008e2515 658 goto close_channel;
d6d516b7 659 if (instance->fd_pairs.num_pairs == 0) {
008e2515
MSL
660 printf("No channel available for reading, exiting\n");
661 ret = -ENOENT;
662 goto close_channel;
663 }
d6d516b7 664
8ba26eae 665 if (ret = map_channels(instance, 0, instance->fd_pairs.num_pairs))
008e2515
MSL
666 goto close_channel;
667 return 0;
668
669close_channel:
d6d516b7 670 close_channel_trace_pairs(instance);
8ba26eae 671 if (instance->inotify_fd >= 0)
d6d516b7 672 close(instance->inotify_fd);
008e2515
MSL
673 return ret;
674}
675
d6d516b7
MSL
676int delete_instance(struct liblttd_instance *instance)
677{
678 pthread_rwlock_destroy(&instance->fd_pairs_lock);
679 free(instance);
680 return 0;
681}
682
683int liblttd_start_instance(struct liblttd_instance *instance)
684{
008e2515
MSL
685 int ret = 0;
686 pthread_t *tids;
687 unsigned long i;
688 void *tret;
689
8ba26eae 690 if (!instance)
d6d516b7 691 return -EINVAL;
008e2515 692
8ba26eae 693 if (ret = channels_init(instance))
008e2515
MSL
694 return ret;
695
d6d516b7
MSL
696 tids = malloc(sizeof(pthread_t) * instance->num_threads);
697 for(i=0; i<instance->num_threads; i++) {
698 struct liblttd_thread_data *thread_data =
699 malloc(sizeof(struct liblttd_thread_data));
700 thread_data->thread_num = i;
701 thread_data->instance = instance;
008e2515 702
d6d516b7 703 ret = pthread_create(&tids[i], NULL, thread_main, thread_data);
8ba26eae 704 if (ret) {
008e2515
MSL
705 perror("Error creating thread");
706 break;
707 }
708 }
709
d6d516b7 710 for(i=0; i<instance->num_threads; i++) {
008e2515 711 ret = pthread_join(tids[i], &tret);
8ba26eae 712 if (ret) {
008e2515
MSL
713 perror("Error joining thread");
714 break;
715 }
8ba26eae 716 if ((long)tret != 0) {
008e2515
MSL
717 printf("Error %s occured in thread %ld\n",
718 strerror((long)tret), i);
719 }
720 }
721
722 free(tids);
d6d516b7
MSL
723 ret = unmap_channels(instance);
724 close_channel_trace_pairs(instance);
8ba26eae 725 if (instance->inotify_fd >= 0)
d6d516b7 726 close(instance->inotify_fd);
008e2515 727
8ba26eae 728 if (instance->callbacks->on_trace_end)
d9cbca27 729 instance->callbacks->on_trace_end(instance);
d6d516b7
MSL
730
731 delete_instance(instance);
008e2515
MSL
732
733 return ret;
734}
735
d6d516b7
MSL
736struct liblttd_instance * liblttd_new_instance(
737 struct liblttd_callbacks *callbacks, char *channel_path,
738 unsigned long n_threads, int flight_only, int normal_only, int verbose)
739{
740 struct liblttd_instance * instance;
8ba26eae
MD
741
742 if (!channel_path || !callbacks)
743 return NULL;
744 if (n_threads == 0)
745 n_threads = 1;
746 if (flight_only && normal_only)
747 return NULL;
d6d516b7
MSL
748
749 instance = malloc(sizeof(struct liblttd_instance));
8ba26eae
MD
750 if (!instance)
751 return NULL;
d6d516b7
MSL
752
753 instance->callbacks = callbacks;
754
755 instance->inotify_fd = -1;
756
757 instance->fd_pairs.pair = NULL;
758 instance->fd_pairs.num_pairs = 0;
759
760 instance->inotify_watch_array.elem = NULL;
761 instance->inotify_watch_array.num = 0;
762
763 pthread_rwlock_init(&instance->fd_pairs_lock, NULL);
764
765 strncpy(instance->channel_name, channel_path, PATH_MAX -1);
766 instance->num_threads = n_threads;
767 instance->dump_flight_only = flight_only;
768 instance->dump_normal_only = normal_only;
769 instance->verbose_mode = verbose;
f51abe5f 770 instance->quit_program = 0;
d6d516b7
MSL
771
772 return instance;
773}
774
775int liblttd_stop_instance(struct liblttd_instance *instance)
776{
777 instance->quit_program = 1;
008e2515
MSL
778 return 0;
779}
780
This page took 0.056236 seconds and 4 git commands to generate.