+ * Update the kernel pollfd set of all channel fd available over all tracing
+ * session. Add the wakeup pipe at the end of the set.
+ */
+static int update_kernel_pollfd(void)
+{
+ int i = 0;
+ /*
+ * The wakup pipe and the quit pipe are needed so the number of fds starts
+ * at 2 for those pipes.
+ */
+ unsigned int nb_fd = 2;
+ struct ltt_session *session;
+ struct ltt_kernel_channel *channel;
+
+ DBG("Updating kernel_pollfd");
+
+ /* Get the number of channel of all kernel session */
+ lock_session_list();
+ cds_list_for_each_entry(session, &session_list_ptr->head, list) {
+ lock_session(session);
+ if (session->kernel_session == NULL) {
+ unlock_session(session);
+ continue;
+ }
+ nb_fd += session->kernel_session->channel_count;
+ unlock_session(session);
+ }
+
+ DBG("Resizing kernel_pollfd to size %d", nb_fd);
+
+ kernel_pollfd = realloc(kernel_pollfd, nb_fd * sizeof(struct pollfd));
+ if (kernel_pollfd == NULL) {
+ perror("malloc kernel_pollfd");
+ goto error;
+ }
+
+ cds_list_for_each_entry(session, &session_list_ptr->head, list) {
+ lock_session(session);
+ if (session->kernel_session == NULL) {
+ unlock_session(session);
+ continue;
+ }
+ if (i >= nb_fd) {
+ ERR("To much channel for kernel_pollfd size");
+ unlock_session(session);
+ break;
+ }
+ cds_list_for_each_entry(channel, &session->kernel_session->channel_list.head, list) {
+ kernel_pollfd[i].fd = channel->fd;
+ kernel_pollfd[i].events = POLLIN | POLLRDNORM;
+ i++;
+ }
+ unlock_session(session);
+ }
+ unlock_session_list();
+
+ /* Adding wake up pipe */
+ kernel_pollfd[nb_fd - 2].fd = kernel_poll_pipe[0];
+ kernel_pollfd[nb_fd - 2].events = POLLIN;
+
+ /* Adding the quit pipe */
+ kernel_pollfd[nb_fd - 1].fd = thread_quit_pipe[0];
+
+ return nb_fd;
+
+error:
+ unlock_session_list();
+ return -1;
+}
+
+/*
+ * Find the channel fd from 'fd' over all tracing session. When found, check
+ * for new channel stream and send those stream fds to the kernel consumer.
+ *
+ * Useful for CPU hotplug feature.
+ */
+static int update_kernel_stream(int fd)
+{
+ int ret = 0;
+ struct ltt_session *session;
+ struct ltt_kernel_channel *channel;
+
+ DBG("Updating kernel streams for channel fd %d", fd);
+
+ lock_session_list();
+ cds_list_for_each_entry(session, &session_list_ptr->head, list) {
+ lock_session(session);
+ if (session->kernel_session == NULL) {
+ unlock_session(session);
+ continue;
+ }
+
+ /* This is not suppose to be 0 but this is an extra security check */
+ if (session->kernel_session->consumer_fd == 0) {
+ session->kernel_session->consumer_fd = kconsumerd_cmd_sock;
+ }
+
+ cds_list_for_each_entry(channel, &session->kernel_session->channel_list.head, list) {
+ if (channel->fd == fd) {
+ DBG("Channel found, updating kernel streams");
+ ret = kernel_open_channel_stream(channel);
+ if (ret < 0) {
+ goto end;
+ }
+
+ /*
+ * Have we already sent fds to the consumer? If yes, it means that
+ * tracing is started so it is safe to send our updated stream fds.
+ */
+ if (session->kernel_session->kconsumer_fds_sent == 1) {
+ ret = send_kconsumerd_channel_fds(session->kernel_session->consumer_fd,
+ channel);
+ if (ret < 0) {
+ goto end;
+ }
+ }
+ goto end;
+ }
+ }
+ unlock_session(session);
+ }
+
+end:
+ unlock_session_list();
+ if (session) {
+ unlock_session(session);
+ }
+ return ret;
+}
+
+/*
+ * This thread manage event coming from the kernel.