X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=libust%2Ftracectl.c;h=faa471461c71c901b9399682ac019f0cb8fe1c13;hb=1ba7c17b4f8dac4f73ab47b6d983b1fe18b24d12;hp=533cc6599639bb5750d4f4437600c2b407a2e0f3;hpb=5de74e51f06139ba97ad5f6291417768ba3b82ca;p=ust.git diff --git a/libust/tracectl.c b/libust/tracectl.c index 533cc65..faa4714 100644 --- a/libust/tracectl.c +++ b/libust/tracectl.c @@ -46,6 +46,11 @@ char consumer_stack[10000]; +/* This should only be accessed by the constructor, before the creation + * of the listener, and then only by the listener. + */ +s64 pidunique = -1LL; + struct list_head blocked_consumers = LIST_HEAD_INIT(blocked_consumers); static struct ustcomm_app ustcomm_app; @@ -55,6 +60,9 @@ struct tracecmd { /* no padding */ uint16_t command; }; +/* volatile because shared between the listener and the main thread */ +volatile sig_atomic_t buffers_to_export = 0; + //struct listener_arg { // int pipe_fd; //}; @@ -90,6 +98,20 @@ struct blocked_consumer { struct list_head list; }; +static long long make_pidunique(void) +{ + s64 retval; + struct timeval tv; + + gettimeofday(&tv, NULL); + + retval = tv.tv_sec; + retval <<= 32; + retval |= tv.tv_usec; + + return retval; +} + static void print_markers(FILE *fp) { struct marker_iter iter; @@ -99,7 +121,7 @@ static void print_markers(FILE *fp) marker_iter_start(&iter); while(iter.marker) { - fprintf(fp, "marker: %s_%s %d \"%s\"\n", iter.marker->channel, iter.marker->name, (int)imv_read(iter.marker->state), iter.marker->format); + fprintf(fp, "marker: %s/%s %d \"%s\"\n", iter.marker->channel, iter.marker->name, (int)imv_read(iter.marker->state), iter.marker->format); marker_iter_next(&iter); } unlock_markers(); @@ -138,10 +160,39 @@ void notif_cb(void) } } -static void inform_consumer_daemon(void) +/* Ask the daemon to collect a trace called trace_name and being + * produced by this pid. + * + * The trace must be at least allocated. (It can also be started.) + * This is because _ltt_trace_find is used. + */ + +static void inform_consumer_daemon(const char *trace_name) { - ustcomm_request_consumer(getpid(), "metadata"); - ustcomm_request_consumer(getpid(), "ust"); + int i; + struct ltt_trace_struct *trace; + pid_t pid = getpid(); + int result; + + ltt_lock_traces(); + + trace = _ltt_trace_find(trace_name); + if(trace == NULL) { + WARN("inform_consumer_daemon: could not find trace \"%s\"; it is probably already destroyed", trace_name); + goto finish; + } + + for(i=0; i < trace->nr_channels; i++) { + result = ustcomm_request_consumer(pid, trace->channels[i].channel_name); + if(result == -1) { + WARN("Failed to request collection for channel %s. Is the daemon available?", trace->channels[i].channel_name); + /* continue even if fail */ + } + buffers_to_export++; + } + + finish: + ltt_unlock_traces(); } void process_blocked_consumers(void) @@ -253,7 +304,7 @@ void *listener_main(void *p) continue; } - DBG("received a message! it's: %s\n", recvbuf); + DBG("received a message! it's: %s", recvbuf); len = strlen(recvbuf); if(!strcmp(recvbuf, "print_markers")) { @@ -292,7 +343,7 @@ void *listener_main(void *p) return (void *)1; } - inform_consumer_daemon(); + inform_consumer_daemon(trace_name); result = ltt_trace_start(trace_name); if(result < 0) { @@ -398,6 +449,8 @@ void *listener_main(void *p) break; } } + + buffers_to_export--; } else if(nth_token_is(recvbuf, "get_n_subbufs", 0) == 1) { struct ltt_trace_struct *trace; @@ -648,6 +701,19 @@ void *listener_main(void *p) WARN("could not disable marker; channel=%s, name=%s", channel_name, marker_name); } } + else if(nth_token_is(recvbuf, "get_pidunique", 0) == 1) { + char *reply; + + asprintf(&reply, "%lld", pidunique); + + result = ustcomm_send_reply(&ustcomm_app.server, reply, &src); + if(result) { + ERR("listener: get_pidunique: ustcomm_send_reply failed"); + goto next_cmd; + } + + free(reply); + } // else if(nth_token_is(recvbuf, "get_notifications", 0) == 1) { // struct ltt_trace_struct *trace; // char trace_name[] = "auto"; @@ -706,7 +772,7 @@ void *listener_main(void *p) } } -int have_listener = 0; +volatile sig_atomic_t have_listener = 0; void create_listener(void) { @@ -738,12 +804,10 @@ void create_listener(void) void sighandler(int sig) { - static char have_listener = 0; DBG("sighandler"); if(!have_listener) { create_listener(); - have_listener = 1; } } @@ -759,23 +823,6 @@ static int init_socket(void) return ustcomm_init_app(getpid(), &ustcomm_app); } -/* FIXME: reenable this to delete socket file. */ - -#if 0 -static void destroy_socket(void) -{ - int result; - - if(mysocketfile[0] == '\0') - return; - - result = unlink(mysocketfile); - if(result == -1) { - PERROR("unlink"); - } -} -#endif - static int init_signal_handler(void) { /* Attempt to handler SIGIO. If the main program wants to @@ -850,6 +897,11 @@ static void __attribute__((constructor(1000))) init() int result; char* autoprobe_val = NULL; + /* Assign the pidunique, to be able to differentiate the processes with same + * pid, (before and after an exec). + */ + pidunique = make_pidunique(); + /* Initialize RCU in case the constructor order is not good. */ urcu_init(); @@ -875,7 +927,7 @@ static void __attribute__((constructor(1000))) init() if(autoprobe_val) { struct marker_iter iter; - DBG("Autoprobe enabled.\n"); + DBG("Autoprobe enabled."); /* Ensure markers are initialized */ //init_markers(); @@ -910,9 +962,9 @@ static void __attribute__((constructor(1000))) init() marker_iter_reset(&iter); marker_iter_start(&iter); - DBG("now iterating on markers already registered\n"); + DBG("now iterating on markers already registered"); while(iter.marker) { - DBG("now iterating on marker %s\n", iter.marker->name); + DBG("now iterating on marker %s", iter.marker->name); auto_probe_connect(iter.marker); marker_iter_next(&iter); } @@ -959,7 +1011,10 @@ static void __attribute__((constructor(1000))) init() ERR("ltt_trace_start failed"); return; } - inform_consumer_daemon(); + + /* Do this after the trace is started in order to avoid creating confusion + * if the trace fails to start. */ + inform_consumer_daemon(trace_name); } @@ -970,11 +1025,17 @@ static void __attribute__((constructor(1000))) init() } /* This is only called if we terminate normally, not with an unhandled signal, - * so we cannot rely on it. */ + * so we cannot rely on it. However, for now, LTTV requires that the header of + * the last sub-buffer contain a valid end time for the trace. This is done + * automatically only when the trace is properly stopped. + * + * If the traced program crashed, it is always possible to manually add the + * right value in the header, or to open the trace in text mode. + * + * FIXME: Fix LTTV so it doesn't need this. + */ -/* This destructor probably isn't needed, because ustd can do crash recovery. */ -#if 0 -static void __attribute__((destructor)) fini() +static void destroy_traces(void) { int result; @@ -991,12 +1052,8 @@ static void __attribute__((destructor)) fini() if(result == -1) { ERR("ltt_trace_destroy error"); } - - destroy_socket(); } -#endif -#if 0 static int trace_recording(void) { int retval = 0; @@ -1016,22 +1073,20 @@ static int trace_recording(void) return retval; } +#if 0 static int have_consumer(void) { return !list_empty(&blocked_consumers); } +#endif -/* This destructor keeps the process alive for a few seconds in order - * to leave time to ustd to consume its buffers. - */ - -int restarting_sleep(int secs) +int restarting_usleep(useconds_t usecs) { struct timespec tv; int result; - tv.tv_sec = secs; - tv.tv_nsec = 0; + tv.tv_sec = 0; + tv.tv_nsec = usecs * 1000; do { result = nanosleep(&tv, &tv); @@ -1040,50 +1095,45 @@ int restarting_sleep(int secs) return result; } +/* 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 + * 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() { -// struct ustcomm_ustd ustd; -// int result; -// sigset_t sigset; -// -// result = sigemptyset(&sigset); -// if(result == -1) { -// perror("sigemptyset"); -// return; -// } -// result = sigaddset(&sigset, SIGIO); -// if(result == -1) { -// perror("sigaddset"); -// return; -// } -// result = sigprocmask(SIG_BLOCK, &sigset, NULL); -// if(result == -1) { -// perror("sigprocmask"); -// return; -// } -// -// if(trace_recording()) { -// if(!have_consumer()) { -// /* Request listener creation. We've blocked SIGIO's in -// * order to not interrupt sleep(), so we will miss the -// * one sent by the daemon and therefore won't create -// * the listener automatically. -// */ -// create_listener(); -// - printf("Keeping process alive for consumer daemon...\n"); - restarting_sleep(3); - printf("Finally dying...\n"); -// } -// } -// -// result = sigprocmask(SIG_UNBLOCK, &sigset, NULL); -// if(result == -1) { -// perror("sigprocmask"); -// return; -// } + if(trace_recording() && buffers_to_export) { + int total = 0; + DBG("Keeping process alive for consumer daemon..."); + while(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(); + + ustcomm_fini_app(&ustcomm_app); +} + +void ust_potential_exec(void) +{ + trace_mark(ust, potential_exec, MARK_NOARGS); + + keepalive(); } -#endif /* 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 @@ -1093,15 +1143,37 @@ static void __attribute__((destructor)) keepalive() void ust_fork(void) { + struct blocked_consumer *bc; + struct blocked_consumer *deletable_bc = NULL; + int result; + DBG("ust: forking"); ltt_trace_stop("auto"); ltt_trace_destroy("auto"); - ltt_trace_alloc("auto"); - ltt_trace_start("auto"); - init_socket(); + /* Delete all active connections */ + ustcomm_close_all_connections(&ustcomm_app.server); + + /* Delete all blocked consumers */ + list_for_each_entry(bc, &blocked_consumers, list) { + close(bc->fd_producer); + close(bc->fd_consumer); + free(deletable_bc); + deletable_bc = bc; + list_del(&bc->list); + } + have_listener = 0; create_listener(); - ustcomm_request_consumer(getpid(), "metadata"); - ustcomm_request_consumer(getpid(), "ust"); + init_socket(); + 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"); }