+}
+
+static int trace_recording(void)
+{
+ int retval = 0;
+ struct ust_trace *trace;
+
+ ltt_lock_traces();
+
+ cds_list_for_each_entry(trace, <t_traces.head, list) {
+ if (trace->active) {
+ retval = 1;
+ break;
+ }
+ }
+
+ ltt_unlock_traces();
+
+ return retval;
+}
+
+int restarting_usleep(useconds_t usecs)
+{
+ struct timespec tv;
+ int result;
+
+ tv.tv_sec = 0;
+ tv.tv_nsec = usecs * 1000;
+
+ do {
+ result = nanosleep(&tv, &tv);
+ } while (result == -1 && errno == EINTR);
+
+ return result;
+}
+
+static void stop_listener(void)
+{
+ int result;
+
+ if (!have_listener)
+ return;
+
+ result = pthread_cancel(listener_thread);
+ if (result != 0) {
+ ERR("pthread_cancel: %s", strerror(result));
+ }
+ result = pthread_join(listener_thread, NULL);
+ if (result != 0) {
+ ERR("pthread_join: %s", strerror(result));
+ }
+}
+
+/* This destructor keeps the process alive for a few seconds in order
+ * to leave time for ustconsumer to connect to its buffers. This is necessary
+ * for programs whose execution is very short. It is also useful in all
+ * programs when tracing is started close to the end of the program
+ * execution.
+ *
+ * FIXME: For now, this only works for the first trace created in a
+ * process.
+ */
+
+static void __attribute__((destructor)) keepalive()
+{
+ if (processpid != getpid()) {
+ return;
+ }
+
+ if (trace_recording() && CMM_LOAD_SHARED(buffers_to_export)) {
+ int total = 0;
+ DBG("Keeping process alive for consumer daemon...");
+ while (CMM_LOAD_SHARED(buffers_to_export)) {
+ const int interv = 200000;
+ restarting_usleep(interv);
+ total += interv;
+
+ if (total >= 3000000) {
+ WARN("non-consumed buffers remaining after wait limit; not waiting anymore");
+ break;
+ }
+ }
+ DBG("Finally dying...");
+ }
+
+ destroy_traces();
+
+ /* Ask the listener to stop and clean up. */
+ stop_listener();
+}
+
+void ust_potential_exec(void)
+{
+ trace_mark(ust, potential_exec, MARK_NOARGS);
+
+ DBG("test");
+
+ keepalive();
+}
+
+/* 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);
+ }