#include <lttng/ust-abi.h>
#include <lttng/ust.h>
#include <lttng/ust-error.h>
+#include <lttng/ust-ctl.h>
+#include <urcu/tls-compat.h>
#include <ust-comm.h>
#include <usterr-signal-safe.h>
#include <helper.h>
* Counting nesting within lttng-ust. Used to ensure that calling fork()
* from liblttng-ust does not execute the pre/post fork handlers.
*/
-static int __thread lttng_ust_nest_count;
+static DEFINE_URCU_TLS(int, lttng_ust_nest_count);
/*
* Info about socket and associated listener thread.
int constructor_sem_posted;
int allowed;
int global;
+ int thread_active;
char sock_path[PATH_MAX];
int socket;
.root_handle = -1,
.allowed = 1,
+ .thread_active = 0,
.sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK,
.socket = -1,
.global = 0,
.root_handle = -1,
.allowed = 0, /* Check setuid bit first */
+ .thread_active = 0,
.socket = -1,
};
static int wait_poll_fallback;
+static const char *cmd_name_mapping[] = {
+ [ LTTNG_UST_RELEASE ] = "Release",
+ [ LTTNG_UST_SESSION ] = "Create Session",
+ [ LTTNG_UST_TRACER_VERSION ] = "Get Tracer Version",
+
+ [ LTTNG_UST_TRACEPOINT_LIST ] = "Create Tracepoint List",
+ [ LTTNG_UST_WAIT_QUIESCENT ] = "Wait for Quiescent State",
+ [ LTTNG_UST_REGISTER_DONE ] = "Registration Done",
+ [ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List",
+
+ /* Session FD commands */
+ [ LTTNG_UST_CHANNEL ] = "Create Channel",
+ [ LTTNG_UST_SESSION_START ] = "Start Session",
+ [ LTTNG_UST_SESSION_STOP ] = "Stop Session",
+
+ /* Channel FD commands */
+ [ LTTNG_UST_STREAM ] = "Create Stream",
+ [ LTTNG_UST_EVENT ] = "Create Event",
+
+ /* Event and Channel FD commands */
+ [ LTTNG_UST_CONTEXT ] = "Create Context",
+ [ LTTNG_UST_FLUSH_BUFFER ] = "Flush Buffer",
+
+ /* Event, Channel and Session commands */
+ [ LTTNG_UST_ENABLE ] = "Enable",
+ [ LTTNG_UST_DISABLE ] = "Disable",
+
+ /* Tracepoint list commands */
+ [ LTTNG_UST_TRACEPOINT_LIST_GET ] = "List Next Tracepoint",
+ [ LTTNG_UST_TRACEPOINT_FIELD_LIST_GET ] = "List Next Tracepoint Field",
+
+ /* Event FD commands */
+ [ LTTNG_UST_FILTER ] = "Create Filter",
+};
+
extern void lttng_ring_buffer_client_overwrite_init(void);
extern void lttng_ring_buffer_client_discard_init(void);
extern void lttng_ring_buffer_metadata_client_init(void);
static
void lttng_fixup_nest_count_tls(void)
{
- asm volatile ("" : : "m" (lttng_ust_nest_count));
+ asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count)));
+}
+
+static
+void print_cmd(int cmd, int handle)
+{
+ const char *cmd_name = "Unknown";
+
+ if (cmd_name_mapping[cmd]) {
+ cmd_name = cmd_name_mapping[cmd];
+ }
+ DBG("Message Received \"%s\", Handle \"%s\" (%d)", cmd_name,
+ lttng_ust_obj_get_name(handle), handle);
}
static
int ret = 0;
const struct lttng_ust_objd_ops *ops;
struct ustcomm_ust_reply lur;
- int shm_fd, wait_fd;
union ust_args args;
ssize_t len;
memset(&lur, 0, sizeof(lur));
if (lttng_ust_comm_should_quit) {
- ret = -EPERM;
+ ret = -LTTNG_UST_ERR_EXITING;
goto end;
}
}
break;
}
+ case LTTNG_UST_CHANNEL:
+ {
+ void *chan_data;
+
+ len = ustcomm_recv_channel_from_sessiond(sock,
+ &chan_data, lum->u.channel.len);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ default:
+ if (len == lum->u.channel.len) {
+ DBG("channel data received");
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection", sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto end;
+ } else {
+ DBG("incorrect channel data message size: %zd", len);
+ ret = -EINVAL;
+ goto end;
+ }
+ }
+ args.channel.chan_data = chan_data;
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
+ case LTTNG_UST_STREAM:
+ {
+ /* Receive shm_fd, wakeup_fd */
+ ret = ustcomm_recv_stream_from_sessiond(sock,
+ &lum->u.stream.len,
+ &args.stream.shm_fd,
+ &args.stream.wakeup_fd);
+ if (ret) {
+ goto end;
+ }
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
default:
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
}
if (ret >= 0) {
switch (lum->cmd) {
- case LTTNG_UST_STREAM:
- /*
- * Special-case reply to send stream info.
- * Use lum.u output.
- */
- lur.u.stream.memory_map_size = *args.stream.memory_map_size;
- shm_fd = *args.stream.shm_fd;
- wait_fd = *args.stream.wait_fd;
- break;
- case LTTNG_UST_METADATA:
- case LTTNG_UST_CHANNEL:
- lur.u.channel.memory_map_size = *args.channel.memory_map_size;
- shm_fd = *args.channel.shm_fd;
- wait_fd = *args.channel.wait_fd;
- break;
case LTTNG_UST_TRACER_VERSION:
lur.u.version = lum->u.version;
break;
break;
}
}
+ DBG("Return value: %d", lur.ret_val);
ret = send_reply(sock, &lur);
if (ret < 0) {
DBG("error sending reply");
goto error;
}
- if ((lum->cmd == LTTNG_UST_STREAM
- || lum->cmd == LTTNG_UST_CHANNEL
- || lum->cmd == LTTNG_UST_METADATA)
- && lur.ret_code == LTTNG_UST_OK) {
- int sendret = 0;
-
- /* we also need to send the file descriptors. */
- ret = ustcomm_send_fds_unix_sock(sock,
- &shm_fd, &shm_fd,
- 1, sizeof(int));
- if (ret < 0) {
- ERR("send shm_fd");
- sendret = ret;
- }
- /*
- * The sessiond expects 2 file descriptors, even upon
- * error.
- */
- ret = ustcomm_send_fds_unix_sock(sock,
- &wait_fd, &wait_fd,
- 1, sizeof(int));
- if (ret < 0) {
- perror("send wait_fd");
- goto error;
- }
- if (sendret) {
- ret = sendret;
- goto error;
- }
- }
/*
* LTTNG_UST_TRACEPOINT_FIELD_LIST_GET needs to send the field
* after the reply.
}
}
}
- /*
- * We still have the memory map reference, and the fds have been
- * sent to the sessiond. We can therefore close those fds. Note
- * that we keep the write side of the wait_fd open, but close
- * the read side.
- */
- if (lur.ret_code == LTTNG_UST_OK) {
- switch (lum->cmd) {
- case LTTNG_UST_STREAM:
- if (shm_fd >= 0) {
- ret = close(shm_fd);
- if (ret) {
- PERROR("Error closing stream shm_fd");
- }
- *args.stream.shm_fd = -1;
- }
- if (wait_fd >= 0) {
- ret = close(wait_fd);
- if (ret) {
- PERROR("Error closing stream wait_fd");
- }
- *args.stream.wait_fd = -1;
- }
- break;
- case LTTNG_UST_METADATA:
- case LTTNG_UST_CHANNEL:
- if (shm_fd >= 0) {
- ret = close(shm_fd);
- if (ret) {
- PERROR("Error closing channel shm_fd");
- }
- *args.channel.shm_fd = -1;
- }
- if (wait_fd >= 0) {
- ret = close(wait_fd);
- if (ret) {
- PERROR("Error closing channel wait_fd");
- }
- *args.channel.wait_fd = -1;
- }
- break;
- }
- }
error:
ust_unlock();
* If the open failed because the file did not exist, try
* creating it ourself.
*/
- lttng_ust_nest_count++;
+ URCU_TLS(lttng_ust_nest_count)++;
pid = fork();
- lttng_ust_nest_count--;
+ URCU_TLS(lttng_ust_nest_count)--;
if (pid > 0) {
int status;
ust_lock();
if (lttng_ust_comm_should_quit) {
- ust_unlock();
goto quit;
}
ret = lttng_abi_create_root_handle();
if (ret < 0) {
ERR("Error creating root handle");
- ust_unlock();
goto quit;
}
sock_info->root_handle = ret;
case 0: /* orderly shutdown */
DBG("%s lttng-sessiond has performed an orderly shutdown", sock_info->name);
ust_lock();
+ if (lttng_ust_comm_should_quit) {
+ goto quit;
+ }
/*
* Either sessiond has shutdown or refused us by closing the socket.
* In either case, we don't want to delay construction execution,
ust_unlock();
goto end;
case sizeof(lum):
- DBG("message received");
+ print_cmd(lum.cmd, lum.handle);
ret = handle_message(sock_info, sock, &lum);
if (ret) {
ERR("Error handling message for %s socket", sock_info->name);
}
end:
ust_lock();
+ if (lttng_ust_comm_should_quit) {
+ goto quit;
+ }
/* Cleanup socket handles before trying to reconnect */
lttng_ust_objd_table_owner_cleanup(sock_info);
ust_unlock();
goto restart; /* try to reconnect */
+
quit:
+ sock_info->thread_active = 0;
+ ust_unlock();
return NULL;
}
* to be the dynamic linker mutex) and ust_lock, taken within
* the ust lock.
*/
- lttng_fixup_event_tls();
lttng_fixup_ringbuffer_tls();
lttng_fixup_vtid_tls();
lttng_fixup_nest_count_tls();
ERR("pthread_attr_setdetachstate: %s", strerror(ret));
}
+ ust_lock();
ret = pthread_create(&global_apps.ust_listener, &thread_attr,
ust_listener_thread, &global_apps);
if (ret) {
ERR("pthread_create global: %s", strerror(ret));
}
+ global_apps.thread_active = 1;
+ ust_unlock();
+
if (local_apps.allowed) {
+ ust_lock();
ret = pthread_create(&local_apps.ust_listener, &thread_attr,
ust_listener_thread, &local_apps);
if (ret) {
ERR("pthread_create local: %s", strerror(ret));
}
+ local_apps.thread_active = 1;
+ ust_unlock();
} else {
handle_register_done(&local_apps);
}
*/
ust_lock();
lttng_ust_comm_should_quit = 1;
- ust_unlock();
/* cancel threads */
- ret = pthread_cancel(global_apps.ust_listener);
- if (ret) {
- ERR("Error cancelling global ust listener thread: %s",
- strerror(ret));
+ if (global_apps.thread_active) {
+ ret = pthread_cancel(global_apps.ust_listener);
+ if (ret) {
+ ERR("Error cancelling global ust listener thread: %s",
+ strerror(ret));
+ } else {
+ global_apps.thread_active = 0;
+ }
}
- if (local_apps.allowed) {
+ if (local_apps.thread_active) {
ret = pthread_cancel(local_apps.ust_listener);
if (ret) {
ERR("Error cancelling local ust listener thread: %s",
strerror(ret));
+ } else {
+ local_apps.thread_active = 0;
}
}
+ ust_unlock();
+
/*
* Do NOT join threads: use of sys_futex makes it impossible to
* join the threads without using async-cancel, but async-cancel
sigset_t all_sigs;
int ret;
- if (lttng_ust_nest_count)
+ if (URCU_TLS(lttng_ust_nest_count))
return;
/* Disable signals */
sigfillset(&all_sigs);
void ust_after_fork_parent(sigset_t *restore_sigset)
{
- if (lttng_ust_nest_count)
+ if (URCU_TLS(lttng_ust_nest_count))
return;
DBG("process %d", getpid());
rcu_bp_after_fork_parent();
*/
void ust_after_fork_child(sigset_t *restore_sigset)
{
- if (lttng_ust_nest_count)
+ if (URCU_TLS(lttng_ust_nest_count))
return;
DBG("process %d", getpid());
/* Release urcu mutexes */