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