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;
//};
}
}
-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)
return (void *)1;
}
- inform_consumer_daemon();
+ inform_consumer_daemon(trace_name);
result = ltt_trace_start(trace_name);
if(result < 0) {
break;
}
}
+
+ buffers_to_export--;
}
else if(nth_token_is(recvbuf, "get_n_subbufs", 0) == 1) {
struct ltt_trace_struct *trace;
return;
}
+ inform_consumer_daemon(trace_name);
+
result = ltt_trace_start(trace_name);
if(result < 0) {
ERR("ltt_trace_start failed");
return;
}
- inform_consumer_daemon();
}
#if 0
static void __attribute__((destructor)) fini()
{
- int result;
+// int result;
/* if trace running, finish it */
- DBG("destructor stopping traces");
+// DBG("destructor stopping traces");
- result = ltt_trace_stop("auto");
- if(result == -1) {
- ERR("ltt_trace_stop error");
- }
-
- result = ltt_trace_destroy("auto");
- if(result == -1) {
- ERR("ltt_trace_destroy error");
- }
-
- destroy_socket();
+// result = ltt_trace_stop("auto");
+// if(result == -1) {
+// ERR("ltt_trace_stop error");
+// }
+//
+// result = ltt_trace_destroy("auto");
+// if(result == -1) {
+// ERR("ltt_trace_destroy error");
+// }
+//
+// destroy_socket();
}
#endif
-#if 0
static int trace_recording(void)
{
int retval = 0;
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);
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...");
+ }
}
-#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
init_socket();
have_listener = 0;
create_listener();
- ustcomm_request_consumer(getpid(), "metadata");
- ustcomm_request_consumer(getpid(), "ust");
+ inform_consumer_daemon("auto");
}