X-Git-Url: http://git.lttng.org/?p=ust.git;a=blobdiff_plain;f=libust%2Ftracectl.c;h=410b1c72e75cb52a2fd24a2898c590f31c011455;hp=3d09cc2a136ea5e49e48ba19d6d1c40b443a79cb;hb=HEAD;hpb=72098143aa5d995802b411e152b89ad252dd37ca diff --git a/libust/tracectl.c b/libust/tracectl.c index 3d09cc2..410b1c7 100644 --- a/libust/tracectl.c +++ b/libust/tracectl.c @@ -21,6 +21,7 @@ */ #define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -33,14 +34,16 @@ #include #include #include -#include +#include #include #include #include +#include #include +#include #include "tracer.h" -#include "usterr.h" +#include "usterr_signal_safe.h" #include "ustcomm.h" #include "buffers.h" #include "marker-control.h" @@ -50,23 +53,39 @@ */ s64 pidunique = -1LL; +/* The process pid is used to detect a non-traceable fork + * and allow the non-traceable fork to be ignored + * by destructor sequences in libust + */ +static pid_t processpid = 0; + static struct ustcomm_header _receive_header; static struct ustcomm_header *receive_header = &_receive_header; static char receive_buffer[USTCOMM_BUFFER_SIZE]; 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[]; -static struct list_head open_buffers_list = LIST_HEAD_INIT(open_buffers_list); - -static struct list_head ust_socks = LIST_HEAD_INIT(ust_socks); +static struct cds_list_head ust_socks = CDS_LIST_HEAD_INIT(ust_socks); /* 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; @@ -81,45 +100,46 @@ static long long make_pidunique(void) return retval; } -static void print_markers(FILE *fp) +static void print_ust_marker(FILE *fp) { - struct marker_iter iter; - - lock_markers(); - marker_iter_reset(&iter); - marker_iter_start(&iter); - - 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); - marker_iter_next(&iter); - } - unlock_markers(); + struct ust_marker_iter iter; + + ust_marker_iter_reset(&iter); + ust_marker_iter_start(&iter); + + while (iter.ust_marker) { + fprintf(fp, "ust_marker: %s/%s %d \"%s\" %p\n", + (*iter.ust_marker)->channel, + (*iter.ust_marker)->name, + (int)(*iter.ust_marker)->state, + (*iter.ust_marker)->format, + NULL); /* + * location is null for now, will be added + * to a different table. + */ + ust_marker_iter_next(&iter); + } + ust_marker_iter_stop(&iter); } static void print_trace_events(FILE *fp) { struct trace_event_iter iter; - lock_trace_events(); trace_event_iter_reset(&iter); 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(); + trace_event_iter_stop(&iter); } -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"); @@ -133,7 +153,7 @@ static int connect_ustd(void) 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; } @@ -143,8 +163,9 @@ static int connect_ustd(void) static void request_buffer_consumer(int sock, - const char *channel, - int cpu) + const char *trace, + const char *channel, + int cpu) { struct ustcomm_header send_header, recv_header; struct ustcomm_buffer_info buf_inf; @@ -152,6 +173,7 @@ static void request_buffer_consumer(int sock, result = ustcomm_pack_buffer_info(&send_header, &buf_inf, + trace, channel, cpu); @@ -186,12 +208,12 @@ static void inform_consumer_daemon(const char *trace_name) 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(); @@ -206,9 +228,10 @@ static void inform_consumer_daemon(const char *trace_name) /* iterate on all cpus */ for (j=0; jchannels[i].n_cpus; j++) { ch_name = trace->channels[i].channel_name; - request_buffer_consumer(sock, ch_name, j); - STORE_SHARED(buffers_to_export, - LOAD_SHARED(buffers_to_export)+1); + request_buffer_consumer(sock, trace_name, + ch_name, j); + CMM_STORE_SHARED(buffers_to_export, + CMM_LOAD_SHARED(buffers_to_export)+1); } } } @@ -343,7 +366,7 @@ static int set_subbuf_size(const char *trace_name, const char *ch_name, } 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(); @@ -381,7 +404,7 @@ static int set_subbuf_num(const char *trace_name, const char *ch_name, } 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(); @@ -464,14 +487,9 @@ static int notify_buffer_mapped(const char *trace_name, */ if (uatomic_read(&buf->consumed) == 0) { DBG("decrementing buffers_to_export"); - STORE_SHARED(buffers_to_export, LOAD_SHARED(buffers_to_export)-1); + CMM_STORE_SHARED(buffers_to_export, CMM_LOAD_SHARED(buffers_to_export)-1); } - /* The buffer has been exported, ergo, we can add it to the - * list of open buffers - */ - list_add(&buf->open_buffers_list, &open_buffers_list); - unlock_traces: ltt_unlock_traces(); @@ -521,43 +539,53 @@ 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() +static int force_subbuf_switch(const char *trace_name) { - struct ust_buffer *buf; + struct ust_trace *trace; + int i, j, retval = 0; - list_for_each_entry(buf, &open_buffers_list, - open_buffers_list) { - ltt_force_switch(buf, FORCE_FLUSH); + ltt_lock_traces(); + trace = _ltt_trace_find(trace_name); + if (!trace) { + retval = -ENODATA; + DBG("Cannot find trace. It was likely destroyed by the user."); + goto unlock_traces; + } + + for (i = 0; i < trace->nr_channels; i++) { + for (j = 0; j < trace->channels[i].n_cpus; j++) { + ltt_force_switch(trace->channels[i].buf[j], + FORCE_FLUSH); + } } + +unlock_traces: + ltt_unlock_traces(); + + return retval; } -/* Simple commands are those which need only respond with a return value. */ -static int process_simple_client_cmd(int command, char *recv_buf) +static int process_trace_cmd(int command, char *trace_name) { int result; char trace_type[] = "ustrelay"; - char trace_name[] = "auto"; 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; - } - return setenv("UST_DAEMON_SOCKET", sock_msg->sock_path, 1); - } case START: /* start is an operation that setups the trace, allocates it and starts it */ result = ltt_trace_setup(trace_name); @@ -670,18 +698,20 @@ static int process_simple_client_cmd(int command, char *recv_buf) } return 0; case FORCE_SUBBUF_SWITCH: - /* FIXME: return codes? */ - force_subbuf_switch(); + DBG("force switch"); - break; - - default: - return -EINVAL; + result = force_subbuf_switch(trace_name); + if (result < 0) { + ERR("force_subbuf_switch failed"); + return result; + } + return 0; } return 0; } + static void process_channel_cmd(int sock, int command, struct ustcomm_channel_info *ch_inf) { @@ -689,14 +719,13 @@ static void process_channel_cmd(int sock, int command, struct ustcomm_header *reply_header = &_reply_header; struct ustcomm_channel_info *reply_msg = (struct ustcomm_channel_info *)send_buffer; - char trace_name[] = "auto"; int result, offset = 0, num, size; memset(reply_header, 0, sizeof(*reply_header)); switch (command) { case GET_SUBBUF_NUM_SIZE: - result = get_subbuf_num_size(trace_name, + result = get_subbuf_num_size(ch_inf->trace, ch_inf->channel, &num, &size); if (result < 0) { @@ -713,13 +742,13 @@ static void process_channel_cmd(int sock, int command, break; case SET_SUBBUF_NUM: - reply_header->result = set_subbuf_num(trace_name, + reply_header->result = set_subbuf_num(ch_inf->trace, ch_inf->channel, ch_inf->subbuf_num); break; case SET_SUBBUF_SIZE: - reply_header->result = set_subbuf_size(trace_name, + reply_header->result = set_subbuf_size(ch_inf->trace, ch_inf->channel, ch_inf->subbuf_size); @@ -738,7 +767,6 @@ static void process_buffer_cmd(int sock, int command, struct ustcomm_header *reply_header = &_reply_header; struct ustcomm_buffer_info *reply_msg = (struct ustcomm_buffer_info *)send_buffer; - char trace_name[] = "auto"; int result, offset = 0, buf_shmid, buf_struct_shmid, buf_pipe_fd; long consumed_old; @@ -746,7 +774,8 @@ static void process_buffer_cmd(int sock, int command, switch (command) { case GET_BUF_SHMID_PIPE_FD: - result = get_buffer_shmid_pipe_fd(trace_name, buf_inf->channel, + result = get_buffer_shmid_pipe_fd(buf_inf->trace, + buf_inf->channel, buf_inf->ch_cpu, &buf_shmid, &buf_struct_shmid, @@ -771,12 +800,12 @@ static void process_buffer_cmd(int sock, int command, case NOTIFY_BUF_MAPPED: reply_header->result = - notify_buffer_mapped(trace_name, + notify_buffer_mapped(buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu); break; case GET_SUBBUFFER: - result = get_subbuffer(trace_name, buf_inf->channel, + result = get_subbuffer(buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu, &consumed_old); if (result < 0) { reply_header->result = result; @@ -790,7 +819,7 @@ static void process_buffer_cmd(int sock, int command, break; case PUT_SUBBUFFER: - result = put_subbuffer(trace_name, buf_inf->channel, + result = put_subbuffer(buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu, buf_inf->consumed_old); reply_header->result = result; @@ -804,38 +833,38 @@ static void process_buffer_cmd(int sock, int command, } -static void process_marker_cmd(int sock, int command, - struct ustcomm_marker_info *marker_inf) +static void process_ust_marker_cmd(int sock, int command, + struct ustcomm_ust_marker_info *ust_marker_inf) { struct ustcomm_header _reply_header; struct ustcomm_header *reply_header = &_reply_header; - int result; + int result = 0; memset(reply_header, 0, sizeof(*reply_header)); switch(command) { case ENABLE_MARKER: - result = ltt_marker_connect(marker_inf->channel, - marker_inf->marker, + result = ltt_ust_marker_connect(ust_marker_inf->channel, + ust_marker_inf->ust_marker, "default"); if (result < 0) { - WARN("could not enable marker; channel=%s," + WARN("could not enable ust_marker; channel=%s," " name=%s", - marker_inf->channel, - marker_inf->marker); + ust_marker_inf->channel, + ust_marker_inf->ust_marker); } break; case DISABLE_MARKER: - result = ltt_marker_disconnect(marker_inf->channel, - marker_inf->marker, + result = ltt_ust_marker_disconnect(ust_marker_inf->channel, + ust_marker_inf->ust_marker, "default"); if (result < 0) { - WARN("could not disable marker; channel=%s," + WARN("could not disable ust_marker; channel=%s," " name=%s", - marker_inf->channel, - marker_inf->marker); + ust_marker_inf->channel, + ust_marker_inf->ust_marker); } break; } @@ -893,15 +922,15 @@ static void process_client_cmd(struct ustcomm_header *recv_header, case ENABLE_MARKER: case DISABLE_MARKER: { - struct ustcomm_marker_info *marker_inf; - marker_inf = (struct ustcomm_marker_info *)recv_buf; - result = ustcomm_unpack_marker_info(marker_inf); + struct ustcomm_ust_marker_info *ust_marker_inf; + ust_marker_inf = (struct ustcomm_ust_marker_info *)recv_buf; + result = ustcomm_unpack_ust_marker_info(ust_marker_inf); if (result < 0) { - ERR("couldn't unpack marker info"); + ERR("couldn't unpack ust_marker info"); reply_header->result = -EINVAL; goto send_response; } - process_marker_cmd(sock, recv_header->command, marker_inf); + process_ust_marker_cmd(sock, recv_header->command, ust_marker_inf); return; } case LIST_MARKERS: @@ -915,17 +944,17 @@ static void process_client_cmd(struct ustcomm_header *recv_header, ERR("opening memstream failed"); return; } - print_markers(fp); + print_ust_marker(fp); fclose(fp); - reply_header->size = size; + reply_header->size = size + 1; /* Include final \0 */ result = ustcomm_send(sock, reply_header, ptr); free(ptr); if (result < 0) { - PERROR("failed to send markers list"); + PERROR("failed to send ust_marker list"); } break; @@ -944,7 +973,7 @@ static void process_client_cmd(struct ustcomm_header *recv_header, 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); @@ -981,34 +1010,72 @@ static void process_client_cmd(struct ustcomm_header *recv_header, } 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; goto send_response; } - default: + case SET_SOCK_PATH: + { + struct ustcomm_single_field *sock_msg; + sock_msg = (struct ustcomm_single_field *)recv_buf; + result = ustcomm_unpack_single_field(sock_msg); + if (result < 0) { + reply_header->result = -EINVAL; + goto send_response; + } + + reply_header->result = setenv("UST_DAEMON_SOCKET", + sock_msg->field, 1); + + goto send_response; + } + case START: + case SETUP_TRACE: + case ALLOC_TRACE: + case CREATE_TRACE: + case START_TRACE: + case STOP_TRACE: + case DESTROY_TRACE: + case FORCE_SUBBUF_SWITCH: + { + struct ustcomm_single_field *trace_inf = + (struct ustcomm_single_field *)recv_buf; + + result = ustcomm_unpack_single_field(trace_inf); + if (result < 0) { + ERR("couldn't unpack trace info"); + reply_header->result = -EINVAL; + goto send_response; + } + reply_header->result = - process_simple_client_cmd(recv_header->command, - recv_buf); + process_trace_cmd(recv_header->command, + trace_inf->field); goto send_response; } + default: + reply_header->result = -EINVAL; + + goto send_response; + } return; @@ -1037,6 +1104,8 @@ void *listener_main(void *p) } 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); @@ -1065,6 +1134,7 @@ void *listener_main(void *p) epoll_sock->fd); } } + pthread_cleanup_pop(1); /* release listener mutex */ } } @@ -1121,7 +1191,7 @@ void create_listener(void) static int autoprobe_method = AUTOPROBE_DISABLED; static regex_t autoprobe_regex; -static void auto_probe_connect(struct marker *m) +static void auto_probe_connect(struct ust_marker *m) { int result; @@ -1133,7 +1203,7 @@ static void auto_probe_connect(struct marker *m) } else if (autoprobe_method == AUTOPROBE_ENABLE_REGEX) { result = asprintf(&concat_name, "%s/%s", m->channel, m->name); if (result == -1) { - ERR("auto_probe_connect: asprintf failed (marker %s/%s)", + ERR("auto_probe_connect: asprintf failed (ust_marker %s/%s)", m->channel, m->name); return; } @@ -1144,51 +1214,63 @@ static void auto_probe_connect(struct marker *m) free(concat_name); } - result = ltt_marker_connect(m->channel, m->name, probe_name); + result = ltt_ust_marker_connect(m->channel, m->name, probe_name); if (result && result != -EEXIST) - ERR("ltt_marker_connect (marker = %s/%s, errno = %d)", m->channel, m->name, -result); + ERR("ltt_ust_marker_connect (ust_marker = %s/%s, errno = %d)", m->channel, m->name, -result); - DBG("auto connected marker %s (addr: %p) %s to probe default", m->channel, m, m->name); + DBG("auto connected ust_marker %s (addr: %p) %s to probe default", m->channel, m, m->name); } static struct ustcomm_sock * init_app_socket(int epoll_fd) { - char *name; + char *dir_name, *sock_name; int result; - struct ustcomm_sock *sock; + struct ustcomm_sock *sock = NULL; + time_t mtime; + + dir_name = ustcomm_user_sock_dir(); + if (!dir_name) + return NULL; - result = asprintf(&name, "%s/%d", SOCK_DIR, (int)getpid()); + mtime = ustcomm_pid_st_mtime(getpid()); + if (!mtime) { + goto free_dir_name; + } + + result = asprintf(&sock_name, "%s/%d.%ld", dir_name, + (int) getpid(), (long) mtime); if (result < 0) { ERR("string overflow allocating socket name, " "UST thread bailing"); - return NULL; + goto free_dir_name; } - result = ensure_dir_exists(SOCK_DIR); + result = ensure_dir_exists(dir_name, S_IRWXU); if (result == -1) { ERR("Unable to create socket directory %s, UST thread bailing", - SOCK_DIR); - goto free_name; + dir_name); + goto free_sock_name; } - sock = ustcomm_init_named_socket(name, epoll_fd); + sock = ustcomm_init_named_socket(sock_name, epoll_fd); if (!sock) { ERR("Error initializing named socket (%s). Check that directory" - "exists and that it is writable. UST thread bailing", name); - goto free_name; + "exists and that it is writable. UST thread bailing", sock_name); + goto free_sock_name; } - free(name); - return sock; +free_sock_name: + free(sock_name); +free_dir_name: + free(dir_name); -free_name: - free(name); - return NULL; + return sock; } static void __attribute__((constructor)) init() { + struct timespec ts; int result; char* autoprobe_val = NULL; char* subbuffer_size_val = NULL; @@ -1201,6 +1283,7 @@ static void __attribute__((constructor)) init() * pid, (before and after an exec). */ pidunique = make_pidunique(); + processpid = getpid(); DBG("Tracectl constructor"); @@ -1221,20 +1304,28 @@ static void __attribute__((constructor)) init() 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"); + } + + if (getenv("UST_TRACE") || getenv("UST_AUTOPROBE")) { + /* Ensure ust_marker control is initialized */ + init_ust_marker_control(); + } + autoprobe_val = getenv("UST_AUTOPROBE"); if (autoprobe_val) { - struct marker_iter iter; + struct ust_marker_iter iter; DBG("Autoprobe enabled."); - /* Ensure markers are initialized */ - //init_markers(); - - /* Ensure marker control is initialized, for the probe */ - init_marker_control(); - /* first, set the callback that will connect the - * probe on new markers + * probe on new ust_marker */ if (autoprobe_val[0] == '/') { result = regcomp(&autoprobe_regex, autoprobe_val+1, 0); @@ -1252,24 +1343,25 @@ static void __attribute__((constructor)) init() autoprobe_method = AUTOPROBE_ENABLE_ALL; } - marker_set_new_marker_cb(auto_probe_connect); + ust_marker_set_new_ust_marker_cb(auto_probe_connect); /* Now, connect the probes that were already registered. */ - marker_iter_reset(&iter); - marker_iter_start(&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); - marker_iter_next(&iter); + ust_marker_iter_reset(&iter); + ust_marker_iter_start(&iter); + + DBG("now iterating on ust_marker already registered"); + while (iter.ust_marker) { + DBG("now iterating on ust_marker %s", (*iter.ust_marker)->name); + auto_probe_connect(*iter.ust_marker); + ust_marker_iter_next(&iter); } + ust_marker_iter_stop(&iter); } if (getenv("UST_OVERWRITE")) { int val = atoi(getenv("UST_OVERWRITE")); if (val == 0 || val == 1) { - STORE_SHARED(ust_channels_overwrite_by_default, val); + CMM_STORE_SHARED(ust_channels_overwrite_by_default, val); } else { WARN("invalid value for UST_OVERWRITE"); } @@ -1278,7 +1370,7 @@ static void __attribute__((constructor)) init() if (getenv("UST_AUTOCOLLECT")) { int val = atoi(getenv("UST_AUTOCOLLECT")); if (val == 0 || val == 1) { - STORE_SHARED(ust_channels_request_collection_by_default, val); + CMM_STORE_SHARED(ust_channels_request_collection_by_default, val); } else { WARN("invalid value for UST_AUTOCOLLECT"); } @@ -1307,19 +1399,13 @@ static void __attribute__((constructor)) init() DBG("starting early tracing"); - /* Ensure marker control is initialized */ - init_marker_control(); - - /* Ensure markers are initialized */ - init_markers(); - /* Ensure buffers are initialized, for the transport to be available. * We are about to set a trace type and it will fail without this. */ init_ustrelay_transport(); /* FIXME: When starting early tracing (here), depending on the - * order of constructors, it is very well possible some marker + * order of constructors, it is very well possible some ust_marker * sections are not yet registered. Because of this, some * channels may not be registered. Yet, we are about to ask the * daemon to collect the channels. Channels which are not yet @@ -1410,7 +1496,7 @@ static int trace_recording(void) ltt_lock_traces(); - list_for_each_entry(trace, <t_traces.head, list) { + cds_list_for_each_entry(trace, <t_traces.head, list) { if (trace->active) { retval = 1; break; @@ -1455,7 +1541,7 @@ static void stop_listener(void) } /* 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. @@ -1466,10 +1552,14 @@ static void stop_listener(void) static void __attribute__((destructor)) keepalive() { - if (trace_recording() && LOAD_SHARED(buffers_to_export)) { + if (processpid != getpid()) { + return; + } + + if (trace_recording() && CMM_LOAD_SHARED(buffers_to_export)) { int total = 0; DBG("Keeping process alive for consumer daemon..."); - while (LOAD_SHARED(buffers_to_export)) { + while (CMM_LOAD_SHARED(buffers_to_export)) { const int interv = 200000; restarting_usleep(interv); total += interv; @@ -1490,7 +1580,7 @@ static void __attribute__((destructor)) keepalive() void ust_potential_exec(void) { - trace_mark(ust, potential_exec, MARK_NOARGS); + ust_marker(potential_exec, UST_MARKER_NOARGS); DBG("test"); @@ -1509,43 +1599,46 @@ void ust_potential_exec(void) 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"); - /* break lock if necessary */ - ltt_unlock_traces(); + /* 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); + } - ltt_trace_stop("auto"); - ltt_trace_destroy("auto", 1); /* Delete all active connections, but leave them in the epoll set */ - list_for_each_entry_safe(sock, sock_tmp, &ust_socks, list) { + cds_list_for_each_entry_safe(sock, sock_tmp, &ust_socks, list) { ustcomm_del_sock(sock, 1); } - /* Delete all blocked consumers */ - 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"); - } - 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 scoket file */ - ustcomm_del_named_sock(listen_sock, 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 */ - STORE_SHARED(buffers_to_export, 0); + CMM_STORE_SHARED(buffers_to_export, 0); have_listener = 0; /* Set up epoll */ @@ -1596,6 +1689,17 @@ void ust_before_fork(ust_fork_info_t *fork_info) 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 */ @@ -1603,6 +1707,8 @@ 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) { @@ -1613,16 +1719,20 @@ static void ust_after_fork_common(ust_fork_info_t *fork_info) 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 */ + /* Release mutexes and reenable signals */ ust_after_fork_common(fork_info); }