* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/* This file contains the implementation of the UST listener thread, which
+ * receives trace control commands. It also coordinates the initialization of
+ * libust.
+ */
+
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MSG_NOTIF 1
#define MSG_REGISTER_NOTIF 2
-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;
+extern struct chan_info_struct chan_infos[];
+
struct list_head blocked_consumers = LIST_HEAD_INIT(blocked_consumers);
static struct ustcomm_app ustcomm_app;
};
/* volatile because shared between the listener and the main thread */
-volatile sig_atomic_t buffers_to_export = 0;
+int buffers_to_export = 0;
struct trctl_msg {
/* size: the size of all the fields except size itself */
static int init_socket(void);
-int fd_notif = -1;
-void notif_cb(void)
-{
- int result;
- struct trctl_msg msg;
-
- /* FIXME: fd_notif should probably be protected by a spinlock */
-
- if(fd_notif == -1)
- return;
-
- msg.type = MSG_NOTIF;
- msg.size = sizeof(msg.type);
-
- /* FIXME: don't block here */
- result = write(fd_notif, &msg, msg.size+sizeof(msg.size));
- if(result == -1) {
- PERROR("write");
- return;
- }
-}
-
/* Ask the daemon to collect a trace called trace_name and being
* produced by this pid.
*
}
for(i=0; i < trace->nr_channels; i++) {
- /* iterate on all cpus */
- for(j=0; j<trace->channels[i].n_cpus; j++) {
- char *buf;
- asprintf(&buf, "%s_%d", trace->channels[i].channel_name, j);
- result = ustcomm_request_consumer(pid, buf);
- if(result == -1) {
- WARN("Failed to request collection for channel %s. Is the daemon available?", trace->channels[i].channel_name);
- /* continue even if fail */
+ if(trace->channels[i].request_collection) {
+ /* iterate on all cpus */
+ for(j=0; j<trace->channels[i].n_cpus; j++) {
+ char *buf;
+ asprintf(&buf, "%s_%d", trace->channels[i].channel_name, j);
+ result = ustcomm_request_consumer(pid, buf);
+ if(result == -1) {
+ WARN("Failed to request collection for channel %s. Is the daemon available?", trace->channels[i].channel_name);
+ /* continue even if fail */
+ }
+ free(buf);
+ STORE_SHARED(buffers_to_export, LOAD_SHARED(buffers_to_export)+1);
}
- free(buf);
- buffers_to_export++;
}
}
return retval;
}
-static unsigned int poweroftwo(unsigned int x)
-{
- unsigned int power2 = 1;
- unsigned int hardcoded = 2147483648; /* FIX max 2^31 */
+/* Return the power of two which is equal or higher to v */
- if (x < 2)
- return 2;
-
- while (power2 < x && power2 < hardcoded)
- power2 *= 2;
-
- return power2;
+static unsigned int pow2_higher_or_eq(unsigned int v)
+{
+ int hb = fls(v);
+ int hbm1 = hb-1;
+ int retval = 1<<(hb-1);
+
+ if(v-retval == 0)
+ return retval;
+ else
+ return retval<<1;
}
static int do_cmd_set_subbuf_size(const char *recvbuf, struct ustcomm_source *src)
goto end;
}
- power = poweroftwo(size);
+ power = pow2_higher_or_eq(size);
+ power = max_t(unsigned int, 2u, power);
if (power != size)
- WARN("using the next 2^n = %u\n", power);
+ WARN("using the next power of two for buffer size = %u\n", power);
ltt_lock_traces();
trace = _ltt_trace_find_setup(trace_name);
*/
if(uatomic_read(&buf->consumed) == 0) {
DBG("decrementing buffers_to_export");
- buffers_to_export--;
+ STORE_SHARED(buffers_to_export, LOAD_SHARED(buffers_to_export)-1);
}
break;
DBG("put_subbuf");
- channel_and_cpu = strdup_malloc(nth_token(recvbuf, 1));
+ channel_and_cpu = strdup(nth_token(recvbuf, 1));
if(channel_and_cpu == NULL) {
ERR("cannot parse channel");
retval = -1;
goto end;
}
- consumed_old_str = strdup_malloc(nth_token(recvbuf, 2));
+ consumed_old_str = strdup(nth_token(recvbuf, 2));
if(consumed_old_str == NULL) {
ERR("cannot parse consumed_old");
retval = -1;
void create_listener(void)
{
int result;
+ sigset_t sig_all_blocked;
+ sigset_t orig_parent_mask;
if(have_listener) {
WARN("not creating listener because we already had one");
return;
}
+ /* A new thread created by pthread_create inherits the signal mask
+ * from the parent. To avoid any signal being received by the
+ * listener thread, we block all signals temporarily in the parent,
+ * while we create the listener thread.
+ */
+
+ sigfillset(&sig_all_blocked);
+
+ result = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_parent_mask);
+ if(result) {
+ PERROR("pthread_sigmask: %s", strerror(result));
+ }
+
result = pthread_create(&listener_thread, NULL, listener_main, NULL);
if(result == -1) {
PERROR("pthread_create");
}
+ /* Restore original signal mask in parent */
+ result = pthread_sigmask(SIG_SETMASK, &orig_parent_mask, NULL);
+ if(result) {
+ PERROR("pthread_sigmask: %s", strerror(result));
+ }
+
have_listener = 1;
}
{
int result;
char* autoprobe_val = NULL;
+ char* subbuffer_size_val = NULL;
+ char* subbuffer_count_val = NULL;
+ unsigned int subbuffer_size;
+ unsigned int subbuffer_count;
+ unsigned int power;
/* Assign the pidunique, to be able to differentiate the processes with same
* pid, (before and after an exec).
}
}
+ if(getenv("UST_OVERWRITE")) {
+ int val = atoi(getenv("UST_OVERWRITE"));
+ if(val == 0 || val == 1) {
+ STORE_SHARED(ust_channels_overwrite_by_default, val);
+ }
+ else {
+ WARN("invalid value for UST_OVERWRITE");
+ }
+ }
+
+ if(getenv("UST_AUTOCOLLECT")) {
+ int val = atoi(getenv("UST_AUTOCOLLECT"));
+ if(val == 0 || val == 1) {
+ STORE_SHARED(ust_channels_request_collection_by_default, val);
+ }
+ else {
+ WARN("invalid value for UST_AUTOCOLLECT");
+ }
+ }
+
+ subbuffer_size_val = getenv("UST_SUBBUF_SIZE");
+ if(subbuffer_size_val) {
+ sscanf(subbuffer_size_val, "%u", &subbuffer_size);
+ power = pow2_higher_or_eq(subbuffer_size);
+ if(power != subbuffer_size)
+ WARN("using the next power of two for buffer size = %u\n", power);
+ chan_infos[LTT_CHANNEL_UST].def_subbufsize = power;
+ }
+
+ subbuffer_count_val = getenv("UST_SUBBUF_NUM");
+ if(subbuffer_count_val) {
+ sscanf(subbuffer_count_val, "%u", &subbuffer_count);
+ if(subbuffer_count < 2)
+ subbuffer_count = 2;
+ chan_infos[LTT_CHANNEL_UST].def_subbufcount = subbuffer_count;
+ }
+
if(getenv("UST_TRACE")) {
char trace_name[] = "auto";
char trace_type[] = "ustrelay";
inform_consumer_daemon(trace_name);
}
-
return;
/* should decrementally destroy stuff if error */
int result;
result = pthread_cancel(listener_thread);
- if(result == -1) {
- PERROR("pthread_cancel");
+ if(result != 0) {
+ ERR("pthread_cancel: %s", strerror(result));
}
result = pthread_join(listener_thread, NULL);
- if(result == -1) {
- PERROR("pthread_join");
+ if(result != 0) {
+ ERR("pthread_join: %s", strerror(result));
}
}
static void __attribute__((destructor)) keepalive()
{
- if(trace_recording() && buffers_to_export) {
+ if(trace_recording() && LOAD_SHARED(buffers_to_export)) {
int total = 0;
DBG("Keeping process alive for consumer daemon...");
- while(buffers_to_export) {
+ while(LOAD_SHARED(buffers_to_export)) {
const int interv = 200000;
restarting_usleep(interv);
total += interv;
/* free app, keeping socket file */
ustcomm_fini_app(&ustcomm_app, 1);
- buffers_to_export = 0;
+ STORE_SHARED(buffers_to_export, 0);
have_listener = 0;
init_socket();
create_listener();