#include <ust/marker.h>
#include <ust/tracepoint.h>
#include <ust/tracectl.h>
+#include <ust/clock.h>
#include "tracer.h"
#include "usterr.h"
#include "ustcomm.h"
static char send_buffer[USTCOMM_BUFFER_SIZE];
static int epoll_fd;
+
+/*
+ * Listener thread data vs fork() protection mechanism. Ensures that no listener
+ * thread mutexes and data structures are being concurrently modified or held by
+ * other threads when fork() is executed.
+ */
+static pthread_mutex_t listener_thread_data_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Mutex protecting listen_sock. Nests inside listener_thread_data_mutex. */
+static pthread_mutex_t listen_sock_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct ustcomm_sock *listen_sock;
extern struct chan_info_struct chan_infos[];
/* volatile because shared between the listener and the main thread */
int buffers_to_export = 0;
+int ust_clock_source;
+
static long long make_pidunique(void)
{
s64 retval;
while (iter.marker) {
fprintf(fp, "marker: %s/%s %d \"%s\" %p\n",
- iter.marker->channel,
- iter.marker->name,
- (int)imv_read(iter.marker->state),
- iter.marker->format,
- iter.marker->location);
+ (*iter.marker)->channel,
+ (*iter.marker)->name,
+ (int)imv_read((*iter.marker)->state),
+ (*iter.marker)->format,
+ (*iter.marker)->location);
marker_iter_next(&iter);
}
unlock_markers();
trace_event_iter_start(&iter);
while (iter.trace_event) {
- fprintf(fp, "trace_event: %s\n", iter.trace_event->name);
+ fprintf(fp, "trace_event: %s\n", (*iter.trace_event)->name);
trace_event_iter_next(&iter);
}
unlock_trace_events();
}
-static int connect_ustd(void)
+static int connect_ustconsumer(void)
{
int result, fd;
- char default_daemon_path[] = SOCK_DIR "/ustd";
+ char default_daemon_path[] = SOCK_DIR "/ustconsumer";
char *explicit_daemon_path, *daemon_path;
explicit_daemon_path = getenv("UST_DAEMON_SOCKET");
result = ustcomm_connect_path(daemon_path, &fd);
if (result < 0) {
- WARN("connect_ustd failed, daemon_path: %s",
+ WARN("connect_ustconsumer failed, daemon_path: %s",
daemon_path);
return result;
}
struct ust_trace *trace;
const char *ch_name;
- sock = connect_ustd();
+ sock = connect_ustconsumer();
if (sock < 0) {
return;
}
- DBG("Connected to ustd");
+ DBG("Connected to ustconsumer");
ltt_lock_traces();
}
channel->subbuf_size = power;
- DBG("the set_subbuf_size for the requested channel is %u", channel->subbuf_size);
+ DBG("the set_subbuf_size for the requested channel is %zu", channel->subbuf_size);
unlock_traces:
ltt_unlock_traces();
}
channel->subbuf_cnt = num;
- DBG("the set_subbuf_cnt for the requested channel is %zd", channel->subbuf_cnt);
+ DBG("the set_subbuf_cnt for the requested channel is %u", channel->subbuf_cnt);
unlock_traces:
ltt_unlock_traces();
return retval;
}
+static void release_listener_mutex(void *ptr)
+{
+ pthread_mutex_unlock(&listener_thread_data_mutex);
+}
+
static void listener_cleanup(void *ptr)
{
- ustcomm_del_named_sock(listen_sock, 0);
+ pthread_mutex_lock(&listen_sock_mutex);
+ if (listen_sock) {
+ ustcomm_del_named_sock(listen_sock, 0);
+ listen_sock = NULL;
+ }
+ pthread_mutex_unlock(&listen_sock_mutex);
}
static void force_subbuf_switch()
/* Simple commands are those which need only respond with a return value. */
static int process_simple_client_cmd(int command, char *recv_buf)
{
+ int result;
+
switch(command) {
case SET_SOCK_PATH:
{
- struct ustcomm_sock_path *sock_msg;
- sock_msg = (struct ustcomm_sock_path *)recv_buf;
- sock_msg->sock_path =
- ustcomm_restore_ptr(sock_msg->sock_path,
- sock_msg->data,
- sizeof(sock_msg->data));
- if (!sock_msg->sock_path) {
-
- return -EINVAL;
+ struct ustcomm_single_field *sock_msg;
+ sock_msg = (struct ustcomm_single_field *)recv_buf;
+ result = ustcomm_unpack_single_field(sock_msg);
+ if (result < 0) {
+ return result;
}
- return setenv("UST_DAEMON_SOCKET", sock_msg->sock_path, 1);
+ return setenv("UST_DAEMON_SOCKET", sock_msg->field, 1);
}
case FORCE_SUBBUF_SWITCH:
{
struct ustcomm_header _reply_header;
struct ustcomm_header *reply_header = &_reply_header;
- int result;
+ int result = 0;
memset(reply_header, 0, sizeof(*reply_header));
print_markers(fp);
fclose(fp);
- reply_header->size = size;
+ reply_header->size = size + 1; /* Include final \0 */
result = ustcomm_send(sock, reply_header, ptr);
print_trace_events(fp);
fclose(fp);
- reply_header->size = size;
+ reply_header->size = size + 1; /* Include final \0 */
result = ustcomm_send(sock, reply_header, ptr);
}
case GET_SOCK_PATH:
{
- struct ustcomm_sock_path *sock_msg;
+ struct ustcomm_single_field *sock_msg;
char *sock_path_env;
- sock_msg = (struct ustcomm_sock_path *)send_buf;
+ sock_msg = (struct ustcomm_single_field *)send_buf;
sock_path_env = getenv("UST_DAEMON_SOCKET");
if (!sock_path_env) {
- result = ustcomm_pack_sock_path(reply_header,
- sock_msg,
- SOCK_DIR "/ustd");
+ result = ustcomm_pack_single_field(reply_header,
+ sock_msg,
+ SOCK_DIR "/ustconsumer");
} else {
- result = ustcomm_pack_sock_path(reply_header,
- sock_msg,
- sock_path_env);
+ result = ustcomm_pack_single_field(reply_header,
+ sock_msg,
+ sock_path_env);
}
reply_header->result = result;
case STOP_TRACE:
case DESTROY_TRACE:
{
- struct ustcomm_trace_info *trace_inf =
- (struct ustcomm_trace_info *)recv_buf;
+ struct ustcomm_single_field *trace_inf =
+ (struct ustcomm_single_field *)recv_buf;
- result = ustcomm_unpack_trace_info(trace_inf);
+ result = ustcomm_unpack_single_field(trace_inf);
if (result < 0) {
ERR("couldn't unpack trace info");
reply_header->result = -EINVAL;
reply_header->result =
process_trace_cmd(recv_header->command,
- trace_inf->trace);
+ trace_inf->field);
goto send_response;
}
}
for (i = 0; i < nfds; i++) {
+ pthread_mutex_lock(&listener_thread_data_mutex);
+ pthread_cleanup_push(release_listener_mutex, NULL);
epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
if (epoll_sock == listen_sock) {
addr_size = sizeof(struct sockaddr);
epoll_sock->fd);
}
}
+ pthread_cleanup_pop(1); /* release listener mutex */
}
}
static void __attribute__((constructor)) init()
{
+ struct timespec ts;
int result;
char* autoprobe_val = NULL;
char* subbuffer_size_val = NULL;
create_listener();
+ /* Get clock the clock source type */
+
+ /* Default clock source */
+ ust_clock_source = CLOCK_TRACE;
+ if (clock_gettime(ust_clock_source, &ts) != 0) {
+ ust_clock_source = CLOCK_MONOTONIC;
+ DBG("UST traces will not be synchronized with LTTng traces");
+ }
+
autoprobe_val = getenv("UST_AUTOPROBE");
if (autoprobe_val) {
struct marker_iter iter;
DBG("now iterating on markers already registered");
while (iter.marker) {
- DBG("now iterating on marker %s", iter.marker->name);
- auto_probe_connect(iter.marker);
+ DBG("now iterating on marker %s", (*iter.marker)->name);
+ auto_probe_connect(*iter.marker);
marker_iter_next(&iter);
}
}
}
/* This destructor keeps the process alive for a few seconds in order
- * to leave time to ustd to connect to its buffers. This is necessary
+ * 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.
{
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 */
/* Get the pid of the new process */
processpid = getpid();
- /* break lock if necessary */
- ltt_unlock_traces();
+ /*
+ * 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);
+ }
- ltt_trace_stop("auto");
- ltt_trace_destroy("auto", 1);
/* 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) {
- result = close(buf->data_ready_fd_read);
- if (result == -1) {
- PERROR("close");
- }
- result = close(buf->data_ready_fd_write);
- if (result == -1) {
- PERROR("close");
- }
cds_list_del(&buf->open_buffers_list);
}
- /* Clean up the listener socket and epoll, keeping the scoket file */
- ustcomm_del_named_sock(listen_sock, 1);
+ /*
+ * 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 */
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 */
{
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) {
void ust_after_fork_parent(ust_fork_info_t *fork_info)
{
- /* Reenable signals */
+ 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)
{
- /* First sanitize the child */
+ /* Release urcu mutexes */
+ rcu_bp_after_fork_child();
+
+ /* Sanitize the child */
ust_fork();
- /* Then reenable interrupts */
+ /* Then release mutexes and reenable signals */
ust_after_fork_common(fork_info);
}