#undef HAS_INOTIFY
#endif
-struct liblttd_callbacks *callbacks;
-
struct channel_trace_fd {
struct fd_pair *pair;
int num_pairs;
int num;
};
-struct channel_trace_fd fd_pairs = { NULL, 0 };
-int inotify_fd = -1;
-struct inotify_watch_array inotify_watch_array = { NULL, 0 };
+struct liblttd_instance {
+ struct liblttd_callbacks *callbacks;
+
+ int inotify_fd;
+ struct channel_trace_fd fd_pairs;
+ struct inotify_watch_array inotify_watch_array;
-/* protects fd_pairs and inotify_watch_array */
-pthread_rwlock_t fd_pairs_lock = PTHREAD_RWLOCK_INITIALIZER;
+ /* protects fd_pairs and inotify_watch_array */
+ pthread_rwlock_t fd_pairs_lock;
-static char *channel_name = NULL;
-static unsigned long num_threads = 1;
-volatile static int quit_program = 0; /* For signal handler */
-static int dump_flight_only = 0;
-static int dump_normal_only = 0;
-static int verbose_mode = 0;
+ char channel_name[PATH_MAX];
+ unsigned long num_threads;
+ int quit_program; /* For signal handler */
+ int dump_flight_only;
+ int dump_normal_only;
+ int verbose_mode;
+};
+
+struct liblttd_thread_data {
+ int thread_num;
+ struct liblttd_instance *instance;
+};
#define printf_verbose(fmt, args...) \
do { \
- if (verbose_mode) \
+ if (instance->verbose_mode) \
printf(fmt, ##args); \
} while (0)
-int open_buffer_file(char *filename, char *path_channel,
- char *base_path_channel, struct channel_trace_fd *fd_pairs)
+int open_buffer_file(struct liblttd_instance *instance, char *filename,
+ char *path_channel, char *base_path_channel)
{
int open_ret = 0;
int ret = 0;
if(strncmp(filename, "flight-", sizeof("flight-")-1) != 0) {
- if(dump_flight_only) {
+ if(instance->dump_flight_only) {
printf_verbose("Skipping normal channel %s\n",
path_channel);
return 0;
}
} else {
- if(dump_normal_only) {
+ if(instance->dump_normal_only) {
printf_verbose("Skipping flight channel %s\n",
path_channel);
return 0;
}
printf_verbose("Opening file.\n");
- fd_pairs->pair = realloc(fd_pairs->pair,
- ++fd_pairs->num_pairs * sizeof(struct fd_pair));
+ instance->fd_pairs.pair = realloc(instance->fd_pairs.pair,
+ ++instance->fd_pairs.num_pairs * sizeof(struct fd_pair));
/* Open the channel in read mode */
- fd_pairs->pair[fd_pairs->num_pairs-1].channel =
+ instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1].channel =
open(path_channel, O_RDONLY | O_NONBLOCK);
- if(fd_pairs->pair[fd_pairs->num_pairs-1].channel == -1) {
+ if(instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1].channel == -1) {
perror(path_channel);
- fd_pairs->num_pairs--;
+ instance->fd_pairs.num_pairs--;
return 0; /* continue */
}
- if(callbacks->on_open_channel) ret = callbacks->on_open_channel(
- callbacks, &fd_pairs->pair[fd_pairs->num_pairs-1],
+ if(instance->callbacks->on_open_channel) ret = instance->callbacks->on_open_channel(
+ instance->callbacks, &instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1],
base_path_channel);
if(ret != 0) {
open_ret = -1;
- close(fd_pairs->pair[fd_pairs->num_pairs-1].channel);
- fd_pairs->num_pairs--;
+ close(instance->fd_pairs.pair[instance->fd_pairs.num_pairs-1].channel);
+ instance->fd_pairs.num_pairs--;
goto end;
}
return open_ret;
}
-int open_channel_trace_pairs(char *subchannel_name,
- char *base_subchannel_name,
- struct channel_trace_fd *fd_pairs, int *inotify_fd,
- struct inotify_watch_array *iwatch_array)
+int open_channel_trace_pairs(struct liblttd_instance *instance,
+ char *subchannel_name, char *base_subchannel_name)
{
DIR *channel_dir = opendir(subchannel_name);
struct dirent *entry;
goto end;
}
- printf_verbose("Calling on new channels folder");
- if(callbacks->on_new_channels_folder) ret = callbacks->
- on_new_channels_folder(callbacks,
+ printf_verbose("Calling on new channels folder\n");
+ if(instance->callbacks->on_new_channels_folder) ret = instance->callbacks->
+ on_new_channels_folder(instance->callbacks,
base_subchannel_name);
if(ret == -1) {
open_ret = -1;
(base_subchannel_name - subchannel_name);
#ifdef HAS_INOTIFY
- iwatch_array->elem = realloc(iwatch_array->elem,
- ++iwatch_array->num * sizeof(struct inotify_watch));
+ instance->inotify_watch_array.elem = realloc(instance->inotify_watch_array.elem,
+ ++instance->inotify_watch_array.num * sizeof(struct inotify_watch));
printf_verbose("Adding inotify for channel %s\n", path_channel);
- iwatch_array->elem[iwatch_array->num-1].wd = inotify_add_watch(*inotify_fd, path_channel, IN_CREATE);
- strcpy(iwatch_array->elem[iwatch_array->num-1].path_channel, path_channel);
- iwatch_array->elem[iwatch_array->num-1].base_path_channel =
- iwatch_array->elem[iwatch_array->num-1].path_channel +
+ instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].wd = inotify_add_watch(instance->inotify_fd, path_channel, IN_CREATE);
+ strcpy(instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].path_channel, path_channel);
+ instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].base_path_channel =
+ instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].path_channel +
(base_subchannel_name - subchannel_name);
printf_verbose("Added inotify for channel %s, wd %u\n",
- iwatch_array->elem[iwatch_array->num-1].path_channel,
- iwatch_array->elem[iwatch_array->num-1].wd);
+ instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].path_channel,
+ instance->inotify_watch_array.elem[instance->inotify_watch_array.num-1].wd);
#endif
while((entry = readdir(channel_dir)) != NULL) {
if(S_ISDIR(stat_buf.st_mode)) {
printf_verbose("Entering channel subdirectory...\n");
- ret = open_channel_trace_pairs(path_channel, base_subchannel_ptr, fd_pairs,
- inotify_fd, iwatch_array);
+ ret = open_channel_trace_pairs(instance, path_channel, base_subchannel_ptr);
if(ret < 0) continue;
} else if(S_ISREG(stat_buf.st_mode)) {
- open_ret = open_buffer_file(entry->d_name, path_channel, base_subchannel_ptr,
- fd_pairs);
+ open_ret = open_buffer_file(instance, entry->d_name,
+ path_channel, base_subchannel_ptr);
if(open_ret)
goto end;
}
}
-int read_subbuffer(struct fd_pair *pair)
+int read_subbuffer(struct liblttd_instance *instance, struct fd_pair *pair)
{
unsigned int consumed_old, len;
int err;
goto get_error;
}
- if(callbacks->on_read_subbuffer) ret = callbacks->on_read_subbuffer(
- callbacks, pair, len);
+ if(instance->callbacks->on_read_subbuffer) ret = instance->callbacks->on_read_subbuffer(
+ instance->callbacks, pair, len);
write_error:
ret = 0;
}
-int map_channels(struct channel_trace_fd *fd_pairs,
- int idx_begin, int idx_end)
+int map_channels(struct liblttd_instance *instance, int idx_begin, int idx_end)
{
int i,j;
int ret=0;
- if(fd_pairs->num_pairs <= 0) {
+ if(instance->fd_pairs.num_pairs <= 0) {
printf("No channel to read\n");
goto end;
}
/* Get the subbuf sizes and number */
for(i=idx_begin;i<idx_end;i++) {
- struct fd_pair *pair = &fd_pairs->pair[i];
+ struct fd_pair *pair = &instance->fd_pairs.pair[i];
ret = ioctl(pair->channel, RELAY_GET_N_SB, &pair->n_sb);
if(ret != 0) {
return ret;
}
-int unmap_channels(struct channel_trace_fd *fd_pairs)
+int unmap_channels(struct liblttd_instance *instance)
{
int j;
int ret=0;
/* Munmap each FD */
- for(j=0;j<fd_pairs->num_pairs;j++) {
- struct fd_pair *pair = &fd_pairs->pair[j];
+ for(j=0;j<instance->fd_pairs.num_pairs;j++) {
+ struct fd_pair *pair = &instance->fd_pairs.pair[j];
int err_ret;
err_ret = pthread_mutex_destroy(&pair->mutex);
*
* Only support add file for now.
*/
-
-int read_inotify(int inotify_fd,
- struct channel_trace_fd *fd_pairs,
- struct inotify_watch_array *iwatch_array)
+int read_inotify(struct liblttd_instance *instance)
{
char buf[sizeof(struct inotify_event) + PATH_MAX];
char path_channel[PATH_MAX];
int old_num;
offset = 0;
- len = read(inotify_fd, buf, sizeof(struct inotify_event) + PATH_MAX);
+ len = read(instance->inotify_fd, buf, sizeof(struct inotify_event) + PATH_MAX);
if(len < 0) {
if(errno == EAGAIN)
}
while(offset < len) {
ievent = (struct inotify_event *)&(buf[offset]);
- for(i=0; i<iwatch_array->num; i++) {
- if(iwatch_array->elem[i].wd == ievent->wd &&
+ for(i=0; i<instance->inotify_watch_array.num; i++) {
+ if(instance->inotify_watch_array.elem[i].wd == ievent->wd &&
ievent->mask == IN_CREATE) {
printf_verbose(
"inotify wd %u event mask : %u for %s%s\n",
ievent->wd, ievent->mask,
- iwatch_array->elem[i].path_channel,
+ instance->inotify_watch_array.elem[i].path_channel,
ievent->name);
- old_num = fd_pairs->num_pairs;
- strcpy(path_channel, iwatch_array->elem[i].path_channel);
+ old_num = instance->fd_pairs.num_pairs;
+ strcpy(path_channel, instance->inotify_watch_array.elem[i].path_channel);
strcat(path_channel, ievent->name);
- if(ret = open_buffer_file(ievent->name, path_channel,
- path_channel + (iwatch_array->elem[i].base_path_channel -
- iwatch_array->elem[i].path_channel), fd_pairs)) {
+ if(ret = open_buffer_file(instance, ievent->name, path_channel,
+ path_channel + (instance->inotify_watch_array.elem[i].base_path_channel -
+ instance->inotify_watch_array.elem[i].path_channel))) {
printf("Error opening buffer file\n");
return -1;
}
- if(ret = map_channels(fd_pairs, old_num, fd_pairs->num_pairs)) {
+ if(ret = map_channels(instance, old_num, instance->fd_pairs.num_pairs)) {
printf("Error mapping channel\n");
return -1;
}
* full.
*/
-int read_channels(unsigned long thread_num, struct channel_trace_fd *fd_pairs,
- int inotify_fd, struct inotify_watch_array *iwatch_array)
+int read_channels(struct liblttd_instance *instance, unsigned long thread_num)
{
struct pollfd *pollfd = NULL;
int num_pollfd;
inotify_fds = 0;
#endif
- pthread_rwlock_rdlock(&fd_pairs_lock);
+ pthread_rwlock_rdlock(&instance->fd_pairs_lock);
/* Start polling the FD. Keep one fd for inotify */
- pollfd = malloc((inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd));
+ pollfd = malloc((inotify_fds + instance->fd_pairs.num_pairs) * sizeof(struct pollfd));
#ifdef HAS_INOTIFY
- pollfd[0].fd = inotify_fd;
+ pollfd[0].fd = instance->inotify_fd;
pollfd[0].events = POLLIN|POLLPRI;
#endif
- for(i=0;i<fd_pairs->num_pairs;i++) {
- pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel;
+ for(i=0;i<instance->fd_pairs.num_pairs;i++) {
+ pollfd[inotify_fds+i].fd = instance->fd_pairs.pair[i].channel;
pollfd[inotify_fds+i].events = POLLIN|POLLPRI;
}
- num_pollfd = inotify_fds + fd_pairs->num_pairs;
+ num_pollfd = inotify_fds + instance->fd_pairs.num_pairs;
- pthread_rwlock_unlock(&fd_pairs_lock);
+ pthread_rwlock_unlock(&instance->fd_pairs_lock);
while(1) {
high_prio = 0;
#endif //DEBUG
/* Have we received a signal ? */
- if(quit_program) break;
+ if(instance->quit_program) break;
num_rdy = poll(pollfd, num_pollfd, -1);
"Polling inotify fd %d : data ready.\n",
pollfd[0].fd);
- pthread_rwlock_wrlock(&fd_pairs_lock);
- read_inotify(inotify_fd, fd_pairs, iwatch_array);
- pthread_rwlock_unlock(&fd_pairs_lock);
+ pthread_rwlock_wrlock(&instance->fd_pairs_lock);
+ read_inotify(instance);
+ pthread_rwlock_unlock(&instance->fd_pairs_lock);
break;
}
num_hup++;
break;
case POLLPRI:
- pthread_rwlock_rdlock(&fd_pairs_lock);
- if(pthread_mutex_trylock(&fd_pairs->pair[i-inotify_fds].mutex) == 0) {
+ pthread_rwlock_rdlock(&instance->fd_pairs_lock);
+ if(pthread_mutex_trylock(&instance->fd_pairs.pair[i-inotify_fds].mutex) == 0) {
printf_verbose(
"Urgent read on fd %d\n",
pollfd[i].fd);
/* Take care of high priority channels first. */
high_prio = 1;
/* it's ok to have an unavailable sub-buffer */
- ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]);
+ ret = read_subbuffer(instance, &instance->fd_pairs.pair[i-inotify_fds]);
if(ret == EAGAIN) ret = 0;
- ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex);
+ ret = pthread_mutex_unlock(&instance->fd_pairs.pair[i-inotify_fds].mutex);
if(ret)
printf("Error in mutex unlock : %s\n", strerror(ret));
}
- pthread_rwlock_unlock(&fd_pairs_lock);
+ pthread_rwlock_unlock(&instance->fd_pairs_lock);
break;
}
}
for(i=inotify_fds;i<num_pollfd;i++) {
switch(pollfd[i].revents) {
case POLLIN:
- pthread_rwlock_rdlock(&fd_pairs_lock);
- if(pthread_mutex_trylock(&fd_pairs->pair[i-inotify_fds].mutex) == 0) {
+ pthread_rwlock_rdlock(&instance->fd_pairs_lock);
+ if(pthread_mutex_trylock(&instance->fd_pairs.pair[i-inotify_fds].mutex) == 0) {
/* Take care of low priority channels. */
printf_verbose(
"Normal read on fd %d\n",
pollfd[i].fd);
/* it's ok to have an unavailable subbuffer */
- ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]);
+ ret = read_subbuffer(instance, &instance->fd_pairs.pair[i-inotify_fds]);
if(ret == EAGAIN) ret = 0;
- ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex);
+ ret = pthread_mutex_unlock(&instance->fd_pairs.pair[i-inotify_fds].mutex);
if(ret)
printf("Error in mutex unlock : %s\n", strerror(ret));
}
- pthread_rwlock_unlock(&fd_pairs_lock);
+ pthread_rwlock_unlock(&instance->fd_pairs_lock);
break;
}
}
}
/* Update pollfd array if an entry was added to fd_pairs */
- pthread_rwlock_rdlock(&fd_pairs_lock);
- if((inotify_fds + fd_pairs->num_pairs) != num_pollfd) {
+ pthread_rwlock_rdlock(&instance->fd_pairs_lock);
+ if((inotify_fds + instance->fd_pairs.num_pairs) != num_pollfd) {
pollfd = realloc(pollfd,
- (inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd));
- for(i=num_pollfd-inotify_fds;i<fd_pairs->num_pairs;i++) {
- pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel;
+ (inotify_fds + instance->fd_pairs.num_pairs) * sizeof(struct pollfd));
+ for(i=num_pollfd-inotify_fds;i<instance->fd_pairs.num_pairs;i++) {
+ pollfd[inotify_fds+i].fd = instance->fd_pairs.pair[i].channel;
pollfd[inotify_fds+i].events = POLLIN|POLLPRI;
}
- num_pollfd = fd_pairs->num_pairs + inotify_fds;
+ num_pollfd = instance->fd_pairs.num_pairs + inotify_fds;
}
- pthread_rwlock_unlock(&fd_pairs_lock);
+ pthread_rwlock_unlock(&instance->fd_pairs_lock);
/* NB: If the fd_pairs structure is updated by another thread from this
* point forward, the current thread will wait in the poll without
}
-void close_channel_trace_pairs(struct channel_trace_fd *fd_pairs, int inotify_fd,
- struct inotify_watch_array *iwatch_array)
+void close_channel_trace_pairs(struct liblttd_instance *instance)
{
int i;
int ret;
- for(i=0;i<fd_pairs->num_pairs;i++) {
- ret = close(fd_pairs->pair[i].channel);
+ for(i=0;i<instance->fd_pairs.num_pairs;i++) {
+ ret = close(instance->fd_pairs.pair[i].channel);
if(ret == -1) perror("Close error on channel");
- if(callbacks->on_close_channel) {
- ret = callbacks->on_close_channel(
- callbacks, &fd_pairs->pair[i]);
+ if(instance->callbacks->on_close_channel) {
+ ret = instance->callbacks->on_close_channel(
+ instance->callbacks, &instance->fd_pairs.pair[i]);
if(ret != 0) perror("Error on close channel callback");
}
}
- free(fd_pairs->pair);
- free(iwatch_array->elem);
+ free(instance->fd_pairs.pair);
+ free(instance->inotify_watch_array.elem);
}
/* Thread worker */
void * thread_main(void *arg)
{
long ret = 0;
- unsigned long thread_num = (unsigned long)arg;
+ struct liblttd_thread_data *thread_data = (struct liblttd_thread_data*) arg;
- if(callbacks->on_new_thread)
- ret = callbacks->on_new_thread(callbacks, thread_num);
+ if(thread_data->instance->callbacks->on_new_thread)
+ ret = thread_data->instance->callbacks->on_new_thread(
+ thread_data->instance->callbacks, thread_data->thread_num);
if (ret < 0) {
return (void*)ret;
}
- ret = read_channels(thread_num, &fd_pairs, inotify_fd, &inotify_watch_array);
+ ret = read_channels(thread_data->instance, thread_data->thread_num);
+
+ if(thread_data->instance->callbacks->on_close_thread)
+ thread_data->instance->callbacks->on_close_thread(
+ thread_data->instance->callbacks, thread_data->thread_num);
- if(callbacks->on_close_thread)
- callbacks->on_close_thread(callbacks, thread_num);
+ free(thread_data);
return (void*)ret;
}
-/*on_close_thread has to be reentrant, it'll be called by many threads*/
-int(*on_close_thread)(struct liblttd_callbacks *data, unsigned long thread_num);
-
-int channels_init()
+int channels_init(struct liblttd_instance *instance)
{
int ret = 0;
- inotify_fd = inotify_init();
- fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
+ instance->inotify_fd = inotify_init();
+ fcntl(instance->inotify_fd, F_SETFL, O_NONBLOCK);
- if(ret = open_channel_trace_pairs(channel_name,
- channel_name + strlen(channel_name), &fd_pairs,
- &inotify_fd, &inotify_watch_array))
+ if(ret = open_channel_trace_pairs(instance, instance->channel_name,
+ instance->channel_name +
+ strlen(instance->channel_name)))
goto close_channel;
- if (fd_pairs.num_pairs == 0) {
+ if (instance->fd_pairs.num_pairs == 0) {
printf("No channel available for reading, exiting\n");
ret = -ENOENT;
goto close_channel;
}
- if(ret = map_channels(&fd_pairs, 0, fd_pairs.num_pairs))
+
+ if(ret = map_channels(instance, 0, instance->fd_pairs.num_pairs))
goto close_channel;
return 0;
close_channel:
- close_channel_trace_pairs(&fd_pairs, inotify_fd, &inotify_watch_array);
- if(inotify_fd >= 0)
- close(inotify_fd);
+ close_channel_trace_pairs(instance);
+ if(instance->inotify_fd >= 0)
+ close(instance->inotify_fd);
return ret;
}
-int liblttd_start(char *channel_path, unsigned long n_threads,
- int flight_only, int normal_only, int verbose,
- struct liblttd_callbacks *user_data){
+int delete_instance(struct liblttd_instance *instance)
+{
+ pthread_rwlock_destroy(&instance->fd_pairs_lock);
+ free(instance);
+ return 0;
+}
+
+int liblttd_start_instance(struct liblttd_instance *instance)
+{
int ret = 0;
pthread_t *tids;
unsigned long i;
void *tret;
- channel_name = channel_path;
- num_threads = n_threads;
- dump_flight_only = flight_only;
- dump_normal_only = normal_only;
- verbose_mode = verbose;
- callbacks = user_data;
+ if(!instance)
+ return -EINVAL;
- if(ret = channels_init())
+ if(ret = channels_init(instance))
return ret;
- tids = malloc(sizeof(pthread_t) * num_threads);
- for(i=0; i<num_threads; i++) {
+ tids = malloc(sizeof(pthread_t) * instance->num_threads);
+ for(i=0; i<instance->num_threads; i++) {
+ struct liblttd_thread_data *thread_data =
+ malloc(sizeof(struct liblttd_thread_data));
+ thread_data->thread_num = i;
+ thread_data->instance = instance;
- ret = pthread_create(&tids[i], NULL, thread_main, (void*)i);
+ ret = pthread_create(&tids[i], NULL, thread_main, thread_data);
if(ret) {
perror("Error creating thread");
break;
}
}
- for(i=0; i<num_threads; i++) {
+ for(i=0; i<instance->num_threads; i++) {
ret = pthread_join(tids[i], &tret);
if(ret) {
perror("Error joining thread");
}
free(tids);
- ret = unmap_channels(&fd_pairs);
- close_channel_trace_pairs(&fd_pairs, inotify_fd, &inotify_watch_array);
- if(inotify_fd >= 0)
- close(inotify_fd);
+ ret = unmap_channels(instance);
+ close_channel_trace_pairs(instance);
+ if(instance->inotify_fd >= 0)
+ close(instance->inotify_fd);
- if(callbacks->on_trace_end) callbacks->on_trace_end(callbacks);
+ if(instance->callbacks->on_trace_end)
+ instance->callbacks->on_trace_end(instance->callbacks);
+
+ delete_instance(instance);
return ret;
}
-int liblttd_stop() {
- quit_program = 1;
+struct liblttd_instance * liblttd_new_instance(
+ struct liblttd_callbacks *callbacks, char *channel_path,
+ unsigned long n_threads, int flight_only, int normal_only, int verbose)
+{
+ struct liblttd_instance * instance;
+ if(!channel_path || !callbacks) return NULL;
+ if(n_threads == 0) n_threads = 1;
+ if(flight_only && normal_only) return NULL;
+
+ instance = malloc(sizeof(struct liblttd_instance));
+ if(!instance) return NULL;
+
+ instance->callbacks = callbacks;
+
+ instance->inotify_fd = -1;
+
+ instance->fd_pairs.pair = NULL;
+ instance->fd_pairs.num_pairs = 0;
+
+ instance->inotify_watch_array.elem = NULL;
+ instance->inotify_watch_array.num = 0;
+
+ pthread_rwlock_init(&instance->fd_pairs_lock, NULL);
+
+ strncpy(instance->channel_name, channel_path, PATH_MAX -1);
+ instance->num_threads = n_threads;
+ instance->dump_flight_only = flight_only;
+ instance->dump_normal_only = normal_only;
+ instance->verbose_mode = verbose;
+
+ return instance;
+}
+
+int liblttd_stop_instance(struct liblttd_instance *instance)
+{
+ instance->quit_program = 1;
return 0;
}
#include <pthread.h>
/**
-* This structure contains the data associated with the channel file descriptor.
-* The lib user can use user_data to store the data associated to the specified
-* channel. The lib user can read but MUST NOT change the other attributes.
-*/
+ * struct fd_pair - Contains the data associated with the channel file
+ * descriptor. The lib user can use user_data to store the data associated to
+ * the specified channel. The lib user can read but MUST NOT change the other
+ * attributes.
+ * @channel: channel file descriptor
+ * @n_sb: the number of subbuffer for this channel
+ * @max_sb_size: the subbuffer size for this channel
+ * @mmap: Not used anymore.
+ * @mutex: a mutex for internal library usage
+ * @user_data: library user data
+ */
struct fd_pair {
- /**
- * This is the channel file descriptor.
- */
int channel;
-
- /**
- * This is the number of subbuffer for this channel.
- */
unsigned int n_sb;
-
- /**
- * This is the subbuffer size for this channel.
- */
unsigned int max_sb_size;
-
- /**
- * Not used anymore.
- */
void *mmap;
-
- /**
- * This is a mutex for internal library usage.
- */
pthread_mutex_t mutex;
-
- /**
- * Library user data.
- */
void *user_data;
};
+struct liblttd_instance;
+
/**
-* This structure contains the necessary callbacks for a tracing session. The
-* user can set the unnecessary functions to NULL if he does not need them.
+* struct liblttd_callbacks - Contains the necessary callbacks for a tracing
+* session. The user can set the unnecessary functions to NULL if he does not
+* need them.
*/
struct liblttd_callbacks {
/**
- * This callback is called after a channel file is open.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- * @args pair This structure contains the data associated with the
- * channel file descriptor. The lib user can use user_data to
- * store the data associated to the specified channel.
- * @args relative_channel_path This argument represents a relative path
- * to the channel file. This path is relative to the root
- * folder of the trace channels.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_open_channel - Is called after a channel file is open.
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ * @pair: structure that contains the data associated with the
+ * channel file descriptor. The lib user can use user_data to
+ * store the data associated to the specified channel.
+ * @relative_channel_path: represents a relative path to the channel
+ * file. This path is relative to the root folder of the trace channels.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ */
int(*on_open_channel)(struct liblttd_callbacks *data,
struct fd_pair *pair, char *relative_channel_path);
/**
- * This callback is called after a channel file is closed.
- *
- * @remarks After a channel file has been closed, it will never be read
- * again.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- * @args pair This structure contains the data associated with the
- * channel file descriptor. The lib user should clean
- * user_data at this time.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_close_channel - Is called after a channel file is closed.
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ * @pair: structure that contains the data associated with the channel
+ * file descriptor. The lib user should clean user_data at this time.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ *
+ * After a channel file has been closed, it will never be read again.
+ */
int(*on_close_channel)(struct liblttd_callbacks *data,
struct fd_pair *pair);
-
/**
- * This callback is called when the library enter in a new subfolder
- * while it is scanning the trace channel tree. It can be used to create
- * the output file structure of the trace.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- * @args relative_folder_path This argument represents a relative path
- * to the channel folder. This path is relative to the root
- * folder of the trace channels.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_new_channels_folder - Is called when the library enter in a new
+ * subfolder while it is scanning the trace channel tree. It can be used
+ * to create the output file structure of the trace.
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ * @relative_folder_path: represents a relative path
+ * to the channel folder. This path is relative to the root
+ * folder of the trace channels.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ */
int(*on_new_channels_folder)(struct liblttd_callbacks *data,
char *relative_folder_path);
/**
- * This callback is called after a subbuffer is a reserved.
- *
- * @attention It has to be thread safe, it'll be called by many threads.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- * @args pair This structure contains the data associated with the
- * channel file descriptor. The lib user should clean
- * user_data at this time.
- * @args len This argument represents the length the data that has to be
- * read.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_read_subbuffer - Is called after a subbuffer is a reserved.
+ *
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ * @pair: structure that contains the data associated with the
+ * channel file descriptor.
+ * @len: represents the length the data that has to be read.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ *
+ * It has to be thread safe, it'll be called by many threads.
+ */
int(*on_read_subbuffer)(struct liblttd_callbacks *data,
struct fd_pair *pair, unsigned int len);
/**
- * This callback is called at the very end of the tracing session. At
- * this time, all the channels have been closed and the threads have been
- * destroyed.
- *
- * @remarks After this callback is called, no other callback will be
- * called again.
- *
- * @attention It has to be thread safe, it'll be called by many threads.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_trace_en - Is called at the very end of the tracing session. At
+ * this time, all the channels have been closed and the threads have
+ * been destroyed.
+ *
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ *
+ * It has to be thread safe, it'll be called by many threads.
+ * After this callback is called, no other callback will be called
+ * again and the tracing instance will be deleted automatically by
+ * liblttd. After this call, the user must not use the liblttd instance.
+ */
int(*on_trace_end)(struct liblttd_callbacks *data);
/**
- * This callback is called after a new thread has been created.
- *
- * @attention It has to be thread safe, it'll be called by many threads.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- * @args thread_num This argument represents the id of the thread.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_new_thread - Is called after a new thread has been created.
+ *
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ * @thread_num: represents the id of the thread.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ *
+ * It has to be thread safe, it'll be called by many threads.
+ */
int(*on_new_thread)(struct liblttd_callbacks *data,
unsigned long thread_num);
/**
- * This callback is called just before a thread is destroyed.
- *
- * @attention It has to be thread safe, it'll be called by many threads.
- *
- * @args data This argument is a pointeur to the callbacks struct that
- * has been passed to the lib.
- * @args thread_num This argument represents the number of the thread.
- *
- * @return Should return 0 if the callback succeeds else not 0.
- */
+ * on_close_thread - Is Called just before a thread is destroyed.
+ *
+ * @data: pointeur to the callbacks struct that has been passed to the
+ * lib.
+ * @thread_num: represents the number of the thread.
+ *
+ * Returns 0 if the callback succeeds else not 0.
+ *
+ * It has to be thread safe, it'll be called by many threads.
+ */
int(*on_close_thread)(struct liblttd_callbacks *data,
unsigned long thread_num);
/**
- * This is where the user can put the library's data.
- */
+ * The library's data.
+ */
void *user_data;
};
/**
-* This function is called to start a new tracing session.
-*
-* @attention It has to be thread safe, it'll be called by many threads.
-*
-* @args channel_path This argument is a path to the root folder of the trace's
-* channels.
-* @args n_threads This argument represents the number of threads that will be
-* used by the library.
-* @args flight_only If this argument to set to 1, only the channel that are in
-* flight recorder mode will be recorded.
-* @args normal_only If this argument to set to 1, only the channel that are in
-* normal mode will be recorded.
-* @args verbose If this argument to set to 1, more informations will be printed.
-* @args user_data This argument is a pointeur to the callbacks struct that
-* contains the user's functions.
-*
-* @return Return 0 if the function succeeds else not 0.
-*/
-int liblttd_start(char *channel_path, unsigned long n_threads,
- int flight_only, int normal_only, int verbose,
- struct liblttd_callbacks *user_data);
+ * liblttd_new_instance - Is called to create a new tracing session.
+ *
+ * @callbacks: Pointer to a callbacks struct that contain the user callbacks and
+ * data.
+ * @channel_path: This argument is a path to the root folder of the trace's
+ * channels.
+ * @n_threads: This argument represents the number of threads that will be
+ * used by the library.
+ * @flight_only: If this argument to set to 1, only the channel that are in
+ * flight recorder mode will be recorded.
+ * @normal_only: If this argument to set to 1, only the channel that are in
+ * normal mode will be recorded.
+ * @verbose: If this argument to set to 1, more informations will be printed.
+ *
+ * Returns the instance if the function succeeds else NULL.
+ */
+struct liblttd_instance * liblttd_new_instance(
+ struct liblttd_callbacks *callbacks, char *channel_path,
+ unsigned long n_threads, int flight_only, int normal_only, int verbose);
/**
-* This function is called to stop a tracing session.
-*
-* @return Return 0 if the function succeeds.
-*/
-int liblttd_stop();
+ * liblttd_start - Is called to start a new tracing session.
+ *
+ * @instance: The tracing session instance that needs to be starded.
+ *
+ * Returns 0 if the function succeeds.
+ *
+ * This is a blocking function. The caller will be bloked on it until the
+ * tracing session is stoped by the user usign liblttd_stop_instance or until
+ * the trace is stoped by LTTng directly.
+ */
+int liblttd_start_instance(struct liblttd_instance *instance);
+
+/**
+ * liblttd_stop - Is called to stop a tracing session.
+ *
+ * @instance: The tracing session instance that needs to be stoped.
+ *
+ * Returns 0 if the function succeeds.
+ *
+ * This function return immediately, it only tells liblttd to stop the instance.
+ * The on_trace_end callback will be called when the tracing session will really
+ * be stoped (after every thread will be done). The instance is deleted
+ * automatically by liblttd after on_trace_end is called.
+ */
+int liblttd_stop_instance(struct liblttd_instance *instance);
#endif /*_LIBLTTD_H */