X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=bbbc75588c6f044a159f05a9588579f639037ec4;hp=028f5f9d233a0933ddd9199e9171bf620065fbba;hb=de2fad4824768bbd5d1ed4f630caae1ee1f842fd;hpb=b9dfb1671626365019a72318fb131eb321244245 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 028f5f9d2..bbbc75588 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include "health-sessiond.h" #include "testpoint.h" #include "ust-thread.h" +#include "jul-thread.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -75,8 +77,12 @@ static int opt_daemon; static int opt_no_kernel; static int is_root; /* Set to 1 if the daemon is running as root */ static pid_t ppid; /* Parent PID for --sig-parent option */ +static pid_t child_ppid; /* Internal parent PID use with daemonize. */ static char *rundir; +/* Set to 1 when a SIGUSR1 signal is received. */ +static int recv_child_signal; + /* * Consumer daemon specific control data. Every value not initialized here is * set to 0 by the static definition. @@ -156,6 +162,7 @@ static pthread_t kernel_thread; static pthread_t dispatch_thread; static pthread_t health_thread; static pthread_t ht_cleanup_thread; +static pthread_t jul_reg_thread; /* * UST registration command queue. This queue is tied with a futex and uses a N @@ -233,6 +240,9 @@ long page_size; /* 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; + static void setup_consumerd_path(void) { @@ -450,6 +460,11 @@ static void cleanup(void) DBG("Removing %s", path); (void) unlink(path); + snprintf(path, PATH_MAX, "%s/%s", rundir, + DEFAULT_LTTNG_SESSIOND_JULPORT_FILE); + DBG("Removing %s", path); + (void) unlink(path); + /* kconsumerd */ snprintf(path, PATH_MAX, DEFAULT_KCONSUMERD_ERR_SOCK_PATH, @@ -489,6 +504,12 @@ static void cleanup(void) 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"); @@ -855,9 +876,8 @@ static void *thread_manage_kernel(void *data) /* Check for data on kernel pipe */ if (pollfd == kernel_poll_pipe[0] && (revents & LPOLLIN)) { - do { - ret = read(kernel_poll_pipe[0], &tmp, 1); - } while (ret < 0 && errno == EINTR); + (void) lttng_read(kernel_poll_pipe[0], + &tmp, 1); /* * Ret value is useless here, if this pipe gets any actions an * update is required anyway. @@ -1229,6 +1249,7 @@ error_poll: static void *thread_manage_apps(void *data) { int i, ret, pollfd, err = -1; + ssize_t size_ret; uint32_t revents, nb_fd; struct lttng_poll_event events; @@ -1304,10 +1325,8 @@ static void *thread_manage_apps(void *data) int sock; /* Empty pipe */ - do { - ret = read(apps_cmd_pipe[0], &sock, sizeof(sock)); - } while (ret < 0 && errno == EINTR); - if (ret < 0 || ret < sizeof(sock)) { + size_ret = lttng_read(apps_cmd_pipe[0], &sock, sizeof(sock)); + if (size_ret < sizeof(sock)) { PERROR("read apps cmd pipe"); goto error; } @@ -1390,7 +1409,7 @@ error_testpoint: */ static int send_socket_to_thread(int fd, int sock) { - int ret; + ssize_t ret; /* * It's possible that the FD is set as invalid with -1 concurrently just @@ -1401,10 +1420,8 @@ static int send_socket_to_thread(int fd, int sock) goto error; } - do { - ret = write(fd, &sock, sizeof(sock)); - } while (ret < 0 && errno == EINTR); - if (ret < 0 || ret != sizeof(sock)) { + ret = lttng_write(fd, &sock, sizeof(sock)); + if (ret < sizeof(sock)) { PERROR("write apps pipe %d", fd); if (ret < 0) { ret = -errno; @@ -1415,7 +1432,7 @@ static int send_socket_to_thread(int fd, int sock) /* All good. Don't send back the write positive ret value. */ ret = 0; error: - return ret; + return (int) ret; } /* @@ -1568,7 +1585,7 @@ static void *thread_dispatch_ust_registration(void *data) if (ret < 0) { PERROR("close ust sock dispatch %d", ust_cmd->sock); } - lttng_fd_put(1, LTTNG_FD_APPS); + lttng_fd_put(LTTNG_FD_APPS, 1); free(ust_cmd); goto error; } @@ -1582,7 +1599,7 @@ static void *thread_dispatch_ust_registration(void *data) if (ret < 0) { PERROR("close ust sock dispatch %d", ust_cmd->sock); } - lttng_fd_put(1, LTTNG_FD_APPS); + lttng_fd_put(LTTNG_FD_APPS, 1); free(wait_node); free(ust_cmd); continue; @@ -1630,7 +1647,7 @@ static void *thread_dispatch_ust_registration(void *data) if (ret < 0) { PERROR("close ust sock dispatch %d", ust_cmd->sock); } - lttng_fd_put(1, LTTNG_FD_APPS); + lttng_fd_put(LTTNG_FD_APPS, 1); } free(ust_cmd); } @@ -2410,6 +2427,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session) consumer = session->kernel_session->consumer; dir_name = DEFAULT_KERNEL_TRACE_DIR; break; + case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_UST: DBG3("Copying tracing session consumer output in UST session"); if (session->ust_session->consumer) { @@ -2453,6 +2471,7 @@ static int create_ust_session(struct ltt_session *session, assert(session->consumer); switch (domain->type) { + case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_UST: break; default: @@ -2745,10 +2764,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, break; case LTTNG_DOMAIN_JUL: - { - ret = LTTNG_ERR_UNKNOWN_DOMAIN; - goto error; - } case LTTNG_DOMAIN_UST: { if (!ust_app_supported()) { @@ -2921,10 +2936,74 @@ skip_domain: break; } case LTTNG_ENABLE_EVENT: + case LTTNG_ENABLE_EVENT_WITH_EXCLUSION: + case LTTNG_ENABLE_EVENT_WITH_FILTER: { - ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, - cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]); + struct lttng_event_exclusion *exclusion = NULL; + struct lttng_filter_bytecode *bytecode = NULL; + + if (cmd_ctx->lsm->cmd_type == LTTNG_ENABLE_EVENT || + (cmd_ctx->lsm->u.enable.exclusion_count == 0 && cmd_ctx->lsm->u.enable.bytecode_len == 0)) { + ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, + cmd_ctx->lsm->u.enable.channel_name, + &cmd_ctx->lsm->u.enable.event, NULL, NULL, kernel_poll_pipe[1]); + } else { + if (cmd_ctx->lsm->u.enable.exclusion_count != 0) { + exclusion = zmalloc(sizeof(struct lttng_event_exclusion) + + cmd_ctx->lsm->u.enable.exclusion_count * LTTNG_SYMBOL_NAME_LEN); + if (!exclusion) { + ret = LTTNG_ERR_EXCLUSION_NOMEM; + goto error; + } + DBG("Receiving var len data from client ..."); + exclusion->count = cmd_ctx->lsm->u.enable.exclusion_count; + ret = lttcomm_recv_unix_sock(sock, exclusion->names, + cmd_ctx->lsm->u.enable.exclusion_count * LTTNG_SYMBOL_NAME_LEN); + if (ret <= 0) { + DBG("Nothing recv() from client var len data... continuing"); + *sock_error = 1; + ret = LTTNG_ERR_EXCLUSION_INVAL; + goto error; + } + } + if (cmd_ctx->lsm->u.enable.bytecode_len != 0) { + bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len); + if (!bytecode) { + if (!exclusion) + free(exclusion); + ret = LTTNG_ERR_FILTER_NOMEM; + goto error; + } + /* Receive var. len. data */ + DBG("Receiving var len data from client ..."); + ret = lttcomm_recv_unix_sock(sock, bytecode, + cmd_ctx->lsm->u.enable.bytecode_len); + if (ret <= 0) { + DBG("Nothing recv() from client car len data... continuing"); + *sock_error = 1; + if (!exclusion) + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + + if (bytecode->len + sizeof(*bytecode) + != cmd_ctx->lsm->u.enable.bytecode_len) { + free(bytecode); + if (!exclusion) + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + } + + ret = cmd_enable_event(cmd_ctx->session, + &cmd_ctx->lsm->domain, + cmd_ctx->lsm->u.enable.channel_name, + &cmd_ctx->lsm->u.enable.event, bytecode, + exclusion, + kernel_poll_pipe[1]); + } break; } case LTTNG_ENABLE_ALL_EVENT: @@ -3248,46 +3327,6 @@ skip_domain: cmd_ctx->lsm->u.reg.path, cdata); break; } - case LTTNG_ENABLE_EVENT_WITH_FILTER: - { - struct lttng_filter_bytecode *bytecode; - - if (cmd_ctx->lsm->u.enable.bytecode_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - if (cmd_ctx->lsm->u.enable.bytecode_len == 0) { - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len); - if (!bytecode) { - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; - } - /* Receive var. len. data */ - DBG("Receiving var len data from client ..."); - ret = lttcomm_recv_unix_sock(sock, bytecode, - cmd_ctx->lsm->u.enable.bytecode_len); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - if (bytecode->len + sizeof(*bytecode) - != cmd_ctx->lsm->u.enable.bytecode_len) { - free(bytecode); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, - cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, bytecode, kernel_poll_pipe[1]); - break; - } case LTTNG_DATA_PENDING: { ret = cmd_data_pending(cmd_ctx->session); @@ -3686,11 +3725,17 @@ static void *thread_manage_clients(void *data) /* * Notify parent pid that we are ready to accept command for client side. + * This ppid is the one from the external process that spawned us. */ if (opt_sig_parent) { kill(ppid, SIGUSR1); } + /* Notify the parent of the fork() process that we are ready. */ + if (opt_daemon) { + kill(child_ppid, SIGUSR1); + } + if (testpoint(thread_manage_clients_before_loop)) { goto error; } @@ -3911,12 +3956,13 @@ static void usage(void) fprintf(stderr, " -d, --daemonize Start as a daemon.\n"); fprintf(stderr, " -g, --group NAME Specify the tracing group name. (default: tracing)\n"); fprintf(stderr, " -V, --version Show version number.\n"); - fprintf(stderr, " -S, --sig-parent Send SIGCHLD to parent pid to notify readiness.\n"); + fprintf(stderr, " -S, --sig-parent Send SIGUSR1 to parent pid to notify readiness.\n"); fprintf(stderr, " -q, --quiet No output at all.\n"); fprintf(stderr, " -v, --verbose Verbose mode. Activate DBG() macro.\n"); 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"); } /* @@ -3949,12 +3995,13 @@ static int parse_args(int argc, char **argv) { "verbose-consumer", 0, 0, 'Z' }, { "no-kernel", 0, 0, 'N' }, { "pidfile", 1, 0, 'p' }, + { "jul-tcp-port", 1, 0, 'J' }, { NULL, 0, 0, 0 } }; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:", + c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:", long_options, &option_index); if (c == -1) { break; @@ -4034,6 +4081,24 @@ static int parse_args(int argc, char **argv) case 'p': opt_pidfile = optarg; break; + case 'J': /* JUL TCP port. */ + { + unsigned long v; + + errno = 0; + v = strtoul(optarg, NULL, 0); + if (errno != 0 || !isdigit(optarg[0])) { + ERR("Wrong value in --jul-tcp-port parameter: %s", optarg); + return -1; + } + if (v == 0 || v >= 65535) { + ERR("Port overflow in --jul-tcp-port parameter: %s", optarg); + return -1; + } + jul_tcp_port = (uint32_t) v; + DBG3("JUL TCP port set to non default: %u", jul_tcp_port); + break; + } default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -4312,6 +4377,9 @@ static void sighandler(int sig) DBG("SIGTERM caught"); stop_threads(); break; + case SIGUSR1: + CMM_STORE_SHARED(recv_child_signal, 1); + break; default: break; } @@ -4350,7 +4418,12 @@ static int set_signal_handler(void) return ret; } - DBG("Signal handler set for SIGTERM, SIGPIPE and SIGINT"); + if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + DBG("Signal handler set for SIGTERM, SIGUSR1, SIGPIPE and SIGINT"); return ret; } @@ -4406,6 +4479,123 @@ error: return; } +/* + * Write JUL TCP port using the rundir. + */ +static void write_julport(void) +{ + int ret; + char path[PATH_MAX]; + + assert(rundir); + + ret = snprintf(path, sizeof(path), "%s/" + DEFAULT_LTTNG_SESSIOND_JULPORT_FILE, rundir); + if (ret < 0) { + PERROR("snprintf julport path"); + goto error; + } + + /* + * Create TCP JUL 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); + +error: + return; +} + +/* + * Daemonize this process by forking and making the parent wait for the child + * to signal it indicating readiness. Once received, the parent successfully + * quits. + * + * The child process undergoes the same action that daemon(3) does meaning + * setsid, chdir, and dup /dev/null into 0, 1 and 2. + * + * Return 0 on success else -1 on error. + */ +static int daemonize(void) +{ + int ret; + pid_t pid; + + /* Get parent pid of this process. */ + child_ppid = getppid(); + + pid = fork(); + if (pid < 0) { + PERROR("fork"); + goto error; + } else if (pid == 0) { + int fd; + pid_t sid; + + /* Child */ + + /* + * Get the newly created parent pid so we can signal that process when + * we are ready to operate. + */ + child_ppid = getppid(); + + sid = setsid(); + if (sid < 0) { + PERROR("setsid"); + goto error; + } + + /* Try to change directory to /. If we can't well at least notify. */ + ret = chdir("/"); + if (ret < 0) { + PERROR("chdir"); + } + + fd = open(_PATH_DEVNULL, O_RDWR, 0); + if (fd < 0) { + PERROR("open %s", _PATH_DEVNULL); + /* Let 0, 1 and 2 open since we can't bind them to /dev/null. */ + } else { + (void) dup2(fd, STDIN_FILENO); + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + if (fd > 2) { + ret = close(fd); + if (ret < 0) { + PERROR("close"); + } + } + } + goto end; + } else { + /* Parent */ + + /* + * Waiting for child to notify this parent that it can exit. Note that + * sleep() is interrupted before the 1 second delay as soon as the + * signal is received, so it will not cause visible delay for the + * user. + */ + while (!CMM_LOAD_SHARED(recv_child_signal)) { + sleep(1); + } + + /* + * From this point on, the parent can exit and the child is now an + * operationnal session daemon ready to serve clients and applications. + */ + exit(EXIT_SUCCESS); + } + +end: + return 0; + +error: + return -1; +} + /* * main */ @@ -4419,6 +4609,10 @@ int main(int argc, char **argv) rcu_register_thread(); + if ((ret = set_signal_handler()) < 0) { + goto error; + } + setup_consumerd_path(); page_size = sysconf(_SC_PAGESIZE); @@ -4438,20 +4632,15 @@ int main(int argc, char **argv) if (opt_daemon) { int i; - /* - * fork - * child: setsid, close FD 0, 1, 2, chdir / - * parent: exit (if fork is successful) - */ - ret = daemon(0, 0); + ret = daemonize(); if (ret < 0) { - PERROR("daemon"); goto error; } + /* - * We are in the child. Make sure all other file - * descriptors are closed, in case we are called with - * more opened file descriptors than the standard ones. + * We are in the child. Make sure all other file descriptors are + * closed, in case we are called with more opened file descriptors than + * the standard ones. */ for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { (void) close(i); @@ -4603,6 +4792,12 @@ int main(int argc, char **argv) */ ust_app_ht_alloc(); + /* Initialize JUL domain subsystem. */ + if ((ret = jul_init()) < 0) { + /* ENOMEM at this point. */ + goto error; + } + /* After this point, we can safely call cleanup() with "goto exit" */ /* @@ -4638,10 +4833,6 @@ int main(int argc, char **argv) goto exit; } - if ((ret = set_signal_handler()) < 0) { - goto exit; - } - /* Setup the needed unix socket */ if ((ret = init_daemon_socket()) < 0) { goto exit; @@ -4706,6 +4897,7 @@ int main(int argc, char **argv) } write_pidfile(); + write_julport(); /* Initialize communication library */ lttcomm_init(); @@ -4722,7 +4914,7 @@ int main(int argc, char **argv) goto exit_health_sessiond_cleanup; } - /* Create thread to manage the client socket */ + /* Create thread to clean up RCU hash tables */ ret = pthread_create(&ht_cleanup_thread, NULL, thread_ht_cleanup, (void *) NULL); if (ret != 0) { @@ -4730,7 +4922,7 @@ int main(int argc, char **argv) goto exit_ht_cleanup; } - /* Create thread to manage the client socket */ + /* Create health-check thread */ ret = pthread_create(&health_thread, NULL, thread_manage_health, (void *) NULL); if (ret != 0) { @@ -4778,6 +4970,14 @@ int main(int argc, char **argv) goto exit_apps_notify; } + /* Create JUL registration thread. */ + ret = pthread_create(&jul_reg_thread, NULL, + jul_thread_manage_registration, (void *) NULL); + if (ret != 0) { + PERROR("pthread_create apps"); + goto exit_jul_reg; + } + /* Don't start this thread if kernel tracing is not requested nor root */ if (is_root && !opt_no_kernel) { /* Create kernel thread to manage kernel event */ @@ -4796,6 +4996,13 @@ int main(int argc, char **argv) } exit_kernel: + ret = pthread_join(jul_reg_thread, &status); + if (ret != 0) { + PERROR("pthread_join JUL"); + goto error; /* join error, exit without cleanup */ + } + +exit_jul_reg: ret = pthread_join(apps_notify_thread, &status); if (ret != 0) { PERROR("pthread_join apps notify");