+/*
+ * start_kconsumerd_thread
+ *
+ * Start the thread_manage_kconsumerd. This must be done after a kconsumerd
+ * exec or it will fails.
+ */
+static int start_kconsumerd_thread(struct ltt_session *session)
+{
+ int ret;
+
+ /* Setup semaphore */
+ sem_init(&kconsumerd_sem, 0, 0);
+
+ ret = pthread_create(&kconsumerd_thread, NULL, thread_manage_kconsumerd, (void *) session);
+ if (ret != 0) {
+ perror("pthread_create kconsumerd");
+ goto error;
+ }
+
+ sem_wait(&kconsumerd_sem);
+
+ return 0;
+
+error:
+ return ret;
+}
+
+/*
+ * kernel_start_consumer
+ *
+ * Start a kernel consumer daemon (kconsumerd).
+ *
+ * Return pid if successful else -1.
+ */
+pid_t kernel_start_consumer(void)
+{
+ int ret;
+ pid_t pid;
+
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * Exec kconsumerd.
+ */
+ execlp("kconsumerd", "kconsumerd", "--daemonize", NULL);
+ if (errno != 0) {
+ perror("kernel start consumer exec");
+ }
+ exit(EXIT_FAILURE);
+ } else if (pid > 0) {
+ ret = pid;
+ goto error;
+ } else {
+ perror("kernel start consumer fork");
+ ret = -errno;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * send_kconsumerd_fds
+ *
+ * Send all stream fds of the kernel session to the consumer.
+ */
+static int send_kconsumerd_fds(int sock, struct ltt_kernel_session *session)
+{
+ int ret, i = 0;
+ /* Plus one here for the metadata fd */
+ size_t nb_fd = session->stream_count_global + 1;
+ int fds[nb_fd];
+ struct ltt_kernel_stream *stream;
+ struct ltt_kernel_channel *chan;
+ struct lttcomm_kconsumerd_header lkh;
+ struct lttcomm_kconsumerd_msg buf[nb_fd];
+
+ /* Add metadata data */
+ fds[i] = session->metadata_stream_fd;
+ buf[i].fd = fds[i];
+ buf[i].state = ACTIVE_FD;
+ buf[i].max_sb_size = session->metadata->conf->subbuf_size;
+ strncpy(buf[i].path_name, session->metadata->pathname, PATH_MAX);
+
+ cds_list_for_each_entry(chan, &session->channel_list.head, list) {
+ cds_list_for_each_entry(stream, &chan->stream_list.head, list) {
+ i++;
+ fds[i] = stream->fd;
+ buf[i].fd = stream->fd;
+ buf[i].state = stream->state;
+ buf[i].max_sb_size = chan->channel->subbuf_size;
+ strncpy(buf[i].path_name, stream->pathname, PATH_MAX);
+ }
+ }
+
+ /* Setup header */
+ lkh.payload_size = nb_fd * sizeof(struct lttcomm_kconsumerd_msg);
+ lkh.cmd_type = LTTCOMM_ADD_STREAM;
+
+ DBG("Sending kconsumerd header");
+
+ ret = lttcomm_send_unix_sock(sock, &lkh, sizeof(struct lttcomm_kconsumerd_header));
+ if (ret < 0) {
+ perror("send kconsumerd header");
+ goto error;
+ }
+
+ DBG("Sending all fds to kconsumerd");
+
+ ret = lttcomm_send_fds_unix_sock(sock, buf, fds, nb_fd, lkh.payload_size);
+ if (ret < 0) {
+ perror("send kconsumerd fds");
+ goto error;
+ }
+
+ DBG("Kconsumerd fds sent");
+
+ return 0;
+
+error:
+ return ret;
+}
+
+/*
+ * free_kernel_session
+ *
+ * Free all data structure inside a kernel session and the session pointer.
+ */
+static void free_kernel_session(struct ltt_kernel_session *session)
+{
+ struct ltt_kernel_channel *chan;
+ struct ltt_kernel_stream *stream;
+ struct ltt_kernel_event *event;
+
+ /* Clean metadata */
+ close(session->metadata_stream_fd);
+ close(session->metadata->fd);
+ free(session->metadata->conf);
+ free(session->metadata);
+
+ cds_list_for_each_entry(chan, &session->channel_list.head, list) {
+ /* Clean all event(s) */
+ cds_list_for_each_entry(event, &chan->events_list.head, list) {
+ close(event->fd);
+ free(event->event);
+ free(event);
+ }
+
+ /* Clean streams */
+ cds_list_for_each_entry(stream, &chan->stream_list.head, list) {
+ close(stream->fd);
+ free(stream->pathname);
+ free(stream);
+ }
+ /* Clean channel */
+ close(chan->fd);
+ free(chan->channel);
+ free(chan->pathname);
+ free(chan);
+ }
+
+ close(session->fd);
+ free(session);
+
+ DBG("All kernel session data structures freed");
+}
+
+/*
+ * teardown_kernel_session
+ *
+ * Complete teardown of a kernel session. This free all data structure
+ * related to a kernel session and update counter.
+ */
+static void teardown_kernel_session(struct ltt_session *session)
+{
+ if (session->kernel_session != NULL) {
+ DBG("Tearing down kernel session");
+ free_kernel_session(session->kernel_session);
+ /* Extra precaution */
+ session->kernel_session = NULL;
+ /* Decrement session count */
+ session->kern_session_count--;
+ /* Set kconsumerd pid to 0 (inactive) */
+ session->kernel_consumer = 0;
+ }
+}
+