+
+/* Notify ust that there was a fork. This needs to be called inside
+ * the new process, anytime a process whose memory is not shared with
+ * the parent is created. If this function is not called, the events
+ * of the new process will not be collected.
+ *
+ * Signals should be disabled before the fork and reenabled only after
+ * this call in order to guarantee tracing is not started before ust_fork()
+ * sanitizes the new process.
+ */
+
+static void ust_fork(void)
+{
+ struct ust_buffer *buf, *buf_tmp;
+ struct ustcomm_sock *sock, *sock_tmp;
+ struct ust_trace *trace, *trace_tmp;
+ int result;
+
+ /* FIXME: technically, the locks could have been taken before the fork */
+ DBG("ust: forking");
+
+ /* Get the pid of the new process */
+ processpid = getpid();
+
+ /*
+ * FIXME: This could be prettier, we loop over the list twice and
+ * following good locking practice should lock around the loop
+ */
+ cds_list_for_each_entry_safe(trace, trace_tmp, <t_traces.head, list) {
+ ltt_trace_stop(trace->trace_name);
+ }
+
+ /* Delete all active connections, but leave them in the epoll set */
+ cds_list_for_each_entry_safe(sock, sock_tmp, &ust_socks, list) {
+ ustcomm_del_sock(sock, 1);
+ }
+
+ /* Delete all blocked consumers */
+ cds_list_for_each_entry_safe(buf, buf_tmp, &open_buffers_list,
+ open_buffers_list) {
+ cds_list_del(&buf->open_buffers_list);
+ }
+
+ /*
+ * FIXME: This could be prettier, we loop over the list twice and
+ * following good locking practice should lock around the loop
+ */
+ cds_list_for_each_entry_safe(trace, trace_tmp, <t_traces.head, list) {
+ ltt_trace_destroy(trace->trace_name, 1);
+ }
+
+ /* Clean up the listener socket and epoll, keeping the socket file */
+ if (listen_sock) {
+ ustcomm_del_named_sock(listen_sock, 1);
+ listen_sock = NULL;
+ }
+ close(epoll_fd);
+
+ /* Re-start the launch sequence */
+ CMM_STORE_SHARED(buffers_to_export, 0);
+ have_listener = 0;
+
+ /* Set up epoll */
+ epoll_fd = epoll_create(MAX_EVENTS);
+ if (epoll_fd == -1) {
+ ERR("epoll_create failed, tracing shutting down");
+ return;
+ }
+
+ /* Create the socket */
+ listen_sock = init_app_socket(epoll_fd);
+ if (!listen_sock) {
+ ERR("failed to create application socket,"
+ " tracing shutting down");
+ return;
+ }
+ create_listener();
+ ltt_trace_setup("auto");
+ result = ltt_trace_set_type("auto", "ustrelay");
+ if (result < 0) {
+ ERR("ltt_trace_set_type failed");
+ return;
+ }
+
+ ltt_trace_alloc("auto");
+ ltt_trace_start("auto");
+ inform_consumer_daemon("auto");
+}
+
+void ust_before_fork(ust_fork_info_t *fork_info)
+{
+ /* Disable signals. This is to avoid that the child
+ * intervenes before it is properly setup for tracing. It is
+ * safer to disable all signals, because then we know we are not
+ * breaking anything by restoring the original mask.
+ */
+ sigset_t all_sigs;
+ int result;
+
+ /* FIXME:
+ - only do this if tracing is active
+ */
+
+ /* Disable signals */
+ sigfillset(&all_sigs);
+ result = sigprocmask(SIG_BLOCK, &all_sigs, &fork_info->orig_sigs);
+ if (result == -1) {
+ PERROR("sigprocmask");
+ return;
+ }
+
+ /*
+ * Take the fork lock to make sure we are not in the middle of
+ * something in the listener thread.
+ */
+ pthread_mutex_lock(&listener_thread_data_mutex);
+ /*
+ * Hold listen_sock_mutex to protect from listen_sock teardown.
+ */
+ pthread_mutex_lock(&listen_sock_mutex);
+ rcu_bp_before_fork();
+}
+
+/* Don't call this function directly in a traced program */
+static void ust_after_fork_common(ust_fork_info_t *fork_info)
+{
+ int result;
+
+ pthread_mutex_unlock(&listen_sock_mutex);
+ pthread_mutex_unlock(&listener_thread_data_mutex);
+
+ /* Restore signals */
+ result = sigprocmask(SIG_SETMASK, &fork_info->orig_sigs, NULL);
+ if (result == -1) {
+ PERROR("sigprocmask");
+ return;
+ }
+}
+
+void ust_after_fork_parent(ust_fork_info_t *fork_info)
+{
+ rcu_bp_after_fork_parent();
+ /* Release mutexes and reenable signals */
+ ust_after_fork_common(fork_info);
+}
+
+void ust_after_fork_child(ust_fork_info_t *fork_info)
+{
+ /* Release urcu mutexes */
+ rcu_bp_after_fork_child();
+
+ /* Sanitize the child */
+ ust_fork();
+
+ /* Then release mutexes and reenable signals */
+ ust_after_fork_common(fork_info);
+}
+