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