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