#include "health-sessiond.h"
#include "testpoint.h"
#include "ust-thread.h"
-#include "jul-thread.h"
+#include "agent-thread.h"
#include "save.h"
#include "load-session-thread.h"
+#include "syscall.h"
#define CONSUMERD_FILE "lttng-consumerd"
static pid_t ppid; /* Parent PID for --sig-parent option */
static pid_t child_ppid; /* Internal parent PID use with daemonize. */
static char *rundir;
+static int lockfile_fd = -1;
/* Set to 1 when a SIGUSR1 signal is received. */
static int recv_child_signal;
{ "verbose-consumer", 0, 0, 'Z' },
{ "no-kernel", 0, 0, 'N' },
{ "pidfile", 1, 0, 'p' },
- { "jul-tcp-port", 1, 0, 'J' },
+ { "agent-tcp-port", 1, 0, 'J' },
{ "config", 1, 0, 'f' },
{ "load", 1, 0, 'l' },
+ { "kmod-probes", 1, 0, 'P' },
+ { "extra-kmod-probes", 1, 0, 'e' },
{ NULL, 0, 0, 0 }
};
static pthread_t dispatch_thread;
static pthread_t health_thread;
static pthread_t ht_cleanup_thread;
-static pthread_t jul_reg_thread;
+static pthread_t agent_reg_thread;
static pthread_t load_session_thread;
/*
/* Application health monitoring */
struct health_app *health_sessiond;
-/* JUL TCP port for registration. Used by the JUL thread. */
-unsigned int jul_tcp_port = DEFAULT_JUL_TCP_PORT;
+/* Agent TCP port for registration. Used by the agent thread. */
+unsigned int agent_tcp_port = DEFAULT_AGENT_TCP_PORT;
/* Am I root or not. */
int is_root; /* Set to 1 if the daemon is running as root */
}
}
+/*
+ * Generate the full lock file path using the rundir.
+ *
+ * Return the snprintf() return value thus a negative value is an error.
+ */
+static int generate_lock_file_path(char *path, size_t len)
+{
+ int ret;
+
+ assert(path);
+ assert(rundir);
+
+ /* Build lockfile path from rundir. */
+ ret = snprintf(path, len, "%s/" DEFAULT_LTTNG_SESSIOND_LOCKFILE, rundir);
+ if (ret < 0) {
+ PERROR("snprintf lockfile path");
+ }
+
+ return ret;
+}
+
/*
* Cleanup the daemon
*/
(void) unlink(path);
snprintf(path, PATH_MAX, "%s/%s", rundir,
- DEFAULT_LTTNG_SESSIOND_JULPORT_FILE);
+ DEFAULT_LTTNG_SESSIOND_AGENTPORT_FILE);
DBG("Removing %s", path);
(void) unlink(path);
DBG("Removing directory %s", path);
(void) rmdir(path);
- /*
- * We do NOT rmdir rundir because there are other processes
- * using it, for instance lttng-relayd, which can start in
- * parallel with this teardown.
- */
-
- free(rundir);
-
DBG("Cleaning up all sessions");
/* Destroy session list mutex */
}
DBG("Unloading kernel modules");
modprobe_remove_lttng_all();
+ free(syscall_table);
}
close_consumer_sockets();
free(load_info);
}
+ /*
+ * Cleanup lock file by deleting it and finaly closing it which will
+ * release the file system lock.
+ */
+ if (lockfile_fd >= 0) {
+ char lockfile_path[PATH_MAX];
+
+ ret = generate_lock_file_path(lockfile_path, sizeof(lockfile_path));
+ if (ret > 0) {
+ ret = remove(lockfile_path);
+ if (ret < 0) {
+ PERROR("remove lock file");
+ }
+ ret = close(lockfile_fd);
+ if (ret < 0) {
+ PERROR("close lock file");
+ }
+ }
+ }
+
+ /*
+ * We do NOT rmdir rundir because there are other processes
+ * using it, for instance lttng-relayd, which can start in
+ * parallel with this teardown.
+ */
+
+ free(rundir);
+
/* <fun> */
DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm"
"Matthew, BEET driven development works!%c[%dm",
*/
static void *thread_manage_consumer(void *data)
{
- int sock = -1, i, ret, pollfd, err = -1;
+ int sock = -1, i, ret, pollfd, err = -1, should_quit = 0;
uint32_t revents, nb_fd;
enum lttcomm_return_code code;
struct lttng_poll_event events;
/* Infinite blocking call, waiting for transmission */
restart_poll:
while (1) {
+ health_code_update();
+
+ /* Exit the thread because the thread quit pipe has been triggered. */
+ if (should_quit) {
+ /* Not a health error. */
+ err = 0;
+ goto exit;
+ }
+
health_poll_entry();
ret = lttng_poll_wait(&events, -1);
health_poll_exit();
health_code_update();
- /* Thread quit pipe has been closed. Killing thread. */
- ret = sessiond_check_thread_quit_pipe(pollfd, revents);
- if (ret) {
- err = 0;
- goto exit;
- }
+ /*
+ * Thread quit pipe has been triggered, flag that we should stop
+ * but continue the current loop to handle potential data from
+ * consumer.
+ */
+ should_quit = sessiond_check_thread_quit_pipe(pollfd, revents);
if (pollfd == sock) {
/* Event on the consumerd socket */
ERR("Handling metadata request");
goto error;
}
- break;
- } else {
- ERR("Unknown pollfd");
- goto error;
}
+ /* No need for an else branch all FDs are tested prior. */
}
health_code_update();
}
static void *thread_dispatch_ust_registration(void *data)
{
int ret, err = -1;
- struct cds_wfq_node *node;
+ struct cds_wfcq_node *node;
struct ust_command *ust_cmd = NULL;
struct ust_reg_wait_node *wait_node = NULL, *tmp_wait_node;
struct ust_reg_wait_queue wait_queue = {
health_code_update();
/* Dequeue command for registration */
- node = cds_wfq_dequeue_blocking(&ust_cmd_queue.queue);
+ node = cds_wfcq_dequeue_blocking(&ust_cmd_queue.head, &ust_cmd_queue.tail);
if (node == NULL) {
DBG("Woken up but nothing in the UST command queue");
/* Continue thread execution */
* Lock free enqueue the registration request. The red pill
* has been taken! This apps will be part of the *system*.
*/
- cds_wfq_enqueue(&ust_cmd_queue.queue, &ust_cmd->node);
+ cds_wfcq_enqueue(&ust_cmd_queue.head, &ust_cmd_queue.tail, &ust_cmd->node);
/*
* Wake the registration queue futex. Implicit memory
- * barrier with the exchange in cds_wfq_enqueue.
+ * barrier with the exchange in cds_wfcq_enqueue.
*/
futex_nto1_wake(&ust_cmd_queue.futex);
}
dir_name = DEFAULT_KERNEL_TRACE_DIR;
break;
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
DBG3("Copying tracing session consumer output in UST session");
if (session->ust_session->consumer) {
switch (domain->type) {
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
break;
default:
case LTTNG_LIST_DOMAINS:
case LTTNG_LIST_CHANNELS:
case LTTNG_LIST_EVENTS:
+ case LTTNG_LIST_SYSCALLS:
break;
default:
/* Setup lttng message with no payload */
case LTTNG_CALIBRATE:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_TRACEPOINTS:
+ case LTTNG_LIST_SYSCALLS:
case LTTNG_LIST_TRACEPOINT_FIELDS:
case LTTNG_SAVE_SESSION:
need_tracing_session = 0;
break;
}
+ /*
+ * Commands that need a valid session but should NOT create one if none
+ * exists. Instead of creating one and destroying it when the command is
+ * handled, process that right before so we save some round trip in useless
+ * code path.
+ */
+ switch (cmd_ctx->lsm->cmd_type) {
+ case LTTNG_DISABLE_CHANNEL:
+ case LTTNG_DISABLE_EVENT:
+ switch (cmd_ctx->lsm->domain.type) {
+ case LTTNG_DOMAIN_KERNEL:
+ if (!cmd_ctx->session->kernel_session) {
+ ret = LTTNG_ERR_NO_CHANNEL;
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
+ case LTTNG_DOMAIN_UST:
+ if (!cmd_ctx->session->ust_session) {
+ ret = LTTNG_ERR_NO_CHANNEL;
+ goto error;
+ }
+ break;
+ default:
+ ret = LTTNG_ERR_UNKNOWN_DOMAIN;
+ goto error;
+ }
+ default:
+ break;
+ }
+
if (!need_domain) {
goto skip_domain;
}
break;
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
{
if (!ust_app_supported()) {
}
/* 32-bit */
+ pthread_mutex_lock(&ustconsumer32_data.pid_mutex);
if (consumerd32_bin[0] != '\0' &&
ustconsumer32_data.pid == 0 &&
cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
cmd_ctx->lsm->cmd_type == LTTNG_STOP_TRACE) {
switch (cmd_ctx->lsm->domain.type) {
case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_PYTHON:
case LTTNG_DOMAIN_UST:
if (uatomic_read(&ust_consumerd_state) != CONSUMER_STARTED) {
ret = LTTNG_ERR_NO_USTCONSUMERD;
}
case LTTNG_DISABLE_EVENT:
{
+ /* FIXME: passing packed structure to non-packed pointer */
+ /* TODO: handle filter */
ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
cmd_ctx->lsm->u.disable.channel_name,
- cmd_ctx->lsm->u.disable.name);
- break;
- }
- case LTTNG_DISABLE_ALL_EVENT:
- {
- DBG("Disabling all events");
-
- ret = cmd_disable_event_all(cmd_ctx->session, cmd_ctx->lsm->domain.type,
- cmd_ctx->lsm->u.disable.channel_name);
+ &cmd_ctx->lsm->u.disable.event);
break;
}
case LTTNG_ENABLE_CHANNEL:
kernel_poll_pipe[1]);
break;
}
- case LTTNG_ENABLE_ALL_EVENT:
- {
- DBG("Enabling all events");
-
- ret = cmd_enable_event_all(cmd_ctx->session, &cmd_ctx->lsm->domain,
- cmd_ctx->lsm->u.enable.channel_name,
- cmd_ctx->lsm->u.enable.event.type, NULL, NULL,
- kernel_poll_pipe[1]);
- break;
- }
case LTTNG_LIST_TRACEPOINTS:
{
struct lttng_event *events;
ret = LTTNG_OK;
break;
}
+ case LTTNG_LIST_SYSCALLS:
+ {
+ struct lttng_event *events;
+ ssize_t nb_events;
+
+ nb_events = cmd_list_syscalls(&events);
+ if (nb_events < 0) {
+ /* Return value is a negative lttng_error_code. */
+ ret = -nb_events;
+ goto error;
+ }
+
+ /*
+ * Setup lttng message with payload size set to the event list size in
+ * bytes and then copy list into the llm payload.
+ */
+ ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event) * nb_events);
+ if (ret < 0) {
+ free(events);
+ goto setup_error;
+ }
+
+ /* Copy event list into message payload */
+ memcpy(cmd_ctx->llm->payload, events,
+ sizeof(struct lttng_event) * nb_events);
+
+ free(events);
+
+ ret = LTTNG_OK;
+ break;
+ }
case LTTNG_SET_CONSUMER_URI:
{
size_t nb_uri, len;
case LTTNG_LIST_DOMAINS:
{
ssize_t nb_dom;
- struct lttng_domain *domains;
+ struct lttng_domain *domains = NULL;
nb_dom = cmd_list_domains(cmd_ctx->session, &domains);
if (nb_dom < 0) {
fprintf(stderr, " -p, --pidfile FILE Write a pid to FILE name overriding the default value.\n");
fprintf(stderr, " --verbose-consumer Verbose mode for consumer. Activate DBG() macro.\n");
fprintf(stderr, " --no-kernel Disable kernel tracer\n");
- fprintf(stderr, " --jul-tcp-port JUL application registration TCP port\n");
+ fprintf(stderr, " --agent-tcp-port Agent registration TCP port\n");
fprintf(stderr, " -f --config Load daemon configuration file\n");
fprintf(stderr, " -l --load PATH Load session configuration\n");
+ fprintf(stderr, " --kmod-probes Specify kernel module probes to load\n");
+ fprintf(stderr, " --extra-kmod-probes Specify extra kernel module probes to load\n");
}
/*
opt_background = 1;
break;
case 'g':
+ /*
+ * If the override option is set, the pointer points to a
+ * *non* const thus freeing it even though the variable type is
+ * set to const.
+ */
+ if (tracing_group_name_override) {
+ free((void *) tracing_group_name);
+ }
tracing_group_name = strdup(arg);
+ if (!tracing_group_name) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
+ tracing_group_name_override = 1;
break;
case 'h':
usage();
case 'v':
/* Verbose level can increase using multiple -v */
if (arg) {
+ /* Value obtained from config file */
lttng_opt_verbose = config_parse_value(arg);
} else {
- lttng_opt_verbose += 1;
+ /* -v used on command line */
+ lttng_opt_verbose++;
}
+ /* Clamp value to [0, 3] */
+ lttng_opt_verbose = lttng_opt_verbose < 0 ? 0 :
+ (lttng_opt_verbose <= 3 ? lttng_opt_verbose : 3);
break;
case 'Z':
if (arg) {
}
break;
case 'u':
+ if (consumerd32_bin_override) {
+ free((void *) consumerd32_bin);
+ }
consumerd32_bin = strdup(arg);
+ if (!consumerd32_bin) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
consumerd32_bin_override = 1;
break;
case 'U':
+ if (consumerd32_libdir_override) {
+ free((void *) consumerd32_libdir);
+ }
consumerd32_libdir = strdup(arg);
+ if (!consumerd32_libdir) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
consumerd32_libdir_override = 1;
break;
case 't':
+ if (consumerd64_bin_override) {
+ free((void *) consumerd64_bin);
+ }
consumerd64_bin = strdup(arg);
+ if (!consumerd64_bin) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
consumerd64_bin_override = 1;
break;
case 'T':
+ if (consumerd64_libdir_override) {
+ free((void *) consumerd64_libdir);
+ }
consumerd64_libdir = strdup(arg);
+ if (!consumerd64_libdir) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
consumerd64_libdir_override = 1;
break;
case 'p':
+ free(opt_pidfile);
opt_pidfile = strdup(arg);
+ if (!opt_pidfile) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
break;
- case 'J': /* JUL TCP port. */
+ case 'J': /* Agent TCP port. */
{
unsigned long v;
errno = 0;
v = strtoul(arg, NULL, 0);
if (errno != 0 || !isdigit(arg[0])) {
- ERR("Wrong value in --jul-tcp-port parameter: %s", arg);
+ ERR("Wrong value in --agent-tcp-port parameter: %s", arg);
return -1;
}
if (v == 0 || v >= 65535) {
- ERR("Port overflow in --jul-tcp-port parameter: %s", arg);
+ ERR("Port overflow in --agent-tcp-port parameter: %s", arg);
return -1;
}
- jul_tcp_port = (uint32_t) v;
- DBG3("JUL TCP port set to non default: %u", jul_tcp_port);
+ agent_tcp_port = (uint32_t) v;
+ DBG3("Agent TCP port set to non default: %u", agent_tcp_port);
break;
}
case 'l':
+ free(opt_load_session_path);
opt_load_session_path = strdup(arg);
if (!opt_load_session_path) {
perror("strdup");
ret = -ENOMEM;
}
break;
+ case 'P': /* probe modules list */
+ free(kmod_probes_list);
+ kmod_probes_list = strdup(arg);
+ if (!kmod_probes_list) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
+ break;
+ case 'e':
+ free(kmod_extra_probes_list);
+ kmod_extra_probes_list = strdup(arg);
+ if (!kmod_extra_probes_list) {
+ perror("strdup");
+ ret = -ENOMEM;
+ }
+ break;
case 'f':
/* This is handled in set_options() thus silent break. */
break;
}
/*
- * Write JUL TCP port using the rundir.
+ * Create lockfile using the rundir and return its fd.
+ */
+static int create_lockfile(void)
+{
+ int ret;
+ char lockfile_path[PATH_MAX];
+
+ ret = generate_lock_file_path(lockfile_path, sizeof(lockfile_path));
+ if (ret < 0) {
+ goto error;
+ }
+
+ ret = utils_create_lock_file(lockfile_path);
+error:
+ return ret;
+}
+
+/*
+ * Write agent TCP port using the rundir.
*/
-static void write_julport(void)
+static void write_agent_port(void)
{
int ret;
char path[PATH_MAX];
assert(rundir);
ret = snprintf(path, sizeof(path), "%s/"
- DEFAULT_LTTNG_SESSIOND_JULPORT_FILE, rundir);
+ DEFAULT_LTTNG_SESSIOND_AGENTPORT_FILE, rundir);
if (ret < 0) {
- PERROR("snprintf julport path");
+ PERROR("snprintf agent port path");
goto error;
}
/*
- * Create TCP JUL port file in rundir. Return value is of no importance.
+ * Create TCP agent port file in rundir. Return value is of no importance.
* The execution will continue even though we are not able to write the
* file.
*/
- (void) utils_create_pid_file(jul_tcp_port, path);
+ (void) utils_create_pid_file(agent_tcp_port, path);
error:
return;
}
}
+ lockfile_fd = create_lockfile();
+ if (lockfile_fd < 0) {
+ goto error;
+ }
+
/* Set consumer initial state */
kernel_consumerd_state = CONSUMER_STOPPED;
ust_consumerd_state = CONSUMER_STOPPED;
*/
ust_app_ht_alloc();
- /* Initialize JUL domain subsystem. */
- if ((ret = jul_init()) < 0) {
+ /* Initialize agent domain subsystem. */
+ if ((ret = agent_setup()) < 0) {
/* ENOMEM at this point. */
goto error;
}
/* Setup kernel tracer */
if (!opt_no_kernel) {
init_kernel_tracer();
+ if (kernel_tracer_fd >= 0) {
+ ret = syscall_init_table();
+ if (ret < 0) {
+ ERR("Unable to populate syscall table. Syscall tracing"
+ " won't work for this session daemon.");
+ }
+ }
}
/* Set ulimit for open files */
buffer_reg_init_pid_registry();
/* Init UST command queue. */
- cds_wfq_init(&ust_cmd_queue.queue);
+ cds_wfcq_init(&ust_cmd_queue.head, &ust_cmd_queue.tail);
/*
* Get session list pointer. This pointer MUST NOT be free(). This list is
}
write_pidfile();
- write_julport();
+ write_agent_port();
/* Initialize communication library */
lttcomm_init();
ret = pthread_create(&apps_notify_thread, NULL,
ust_thread_manage_notify, (void *) NULL);
if (ret != 0) {
- PERROR("pthread_create apps");
+ PERROR("pthread_create notify");
goto exit_apps_notify;
}
- /* Create JUL registration thread. */
- ret = pthread_create(&jul_reg_thread, NULL,
- jul_thread_manage_registration, (void *) NULL);
+ /* Create agent registration thread. */
+ ret = pthread_create(&agent_reg_thread, NULL,
+ agent_thread_manage_registration, (void *) NULL);
if (ret != 0) {
- PERROR("pthread_create apps");
- goto exit_jul_reg;
+ PERROR("pthread_create agent");
+ goto exit_agent_reg;
}
/* Don't start this thread if kernel tracing is not requested nor root */
}
exit_kernel:
- ret = pthread_join(jul_reg_thread, &status);
+ ret = pthread_join(agent_reg_thread, &status);
if (ret != 0) {
- PERROR("pthread_join JUL");
+ PERROR("pthread_join agent");
goto error; /* join error, exit without cleanup */
}
-exit_jul_reg:
+exit_agent_reg:
ret = pthread_join(apps_notify_thread, &status);
if (ret != 0) {
PERROR("pthread_join apps notify");