X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-consumerd%2Flttng-consumerd.c;h=8ddd5a372005490bb37f1ef8c01bc8045dabdbde;hp=a637a904244979b5f8b0a310e458684a03162d19;hb=bd722d76b035766511f0b329f9bbaa2f4180c4ed;hpb=60922cb08cc9fb683c6148da4ff91da8c2c0c4d5 diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c index a637a9042..8ddd5a372 100644 --- a/src/bin/lttng-consumerd/lttng-consumerd.c +++ b/src/bin/lttng-consumerd/lttng-consumerd.c @@ -2,19 +2,18 @@ * Copyright (C) 2011 - Julien Desfossez * Mathieu Desnoyers * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; only version 2 - * of the License. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _GNU_SOURCE @@ -28,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,27 +39,30 @@ #include #include #include +#include #include #include -#include -#include +#include +#include +#include #include -#include #include "lttng-consumerd.h" -/* TODO : support UST (all direct kernctl accesses). */ +/* TODO : support UST (all direct kernel-ctl accesses). */ -/* the two threads (receive fd and poll) */ -static pthread_t threads[2]; +/* threads (channel handling, poll, metadata, sessiond) */ -/* to count the number of time the user pressed ctrl+c */ +static pthread_t channel_thread, data_thread, metadata_thread, sessiond_thread; +static pthread_t metadata_timer_thread; + +/* to count the number of times the user pressed ctrl+c */ static int sigintcount = 0; /* Argument variables */ -int opt_quiet; -int opt_verbose; +int lttng_opt_quiet; /* not static in error.h */ +int lttng_opt_verbose; /* not static in error.h */ static int opt_daemon; static const char *progname; static char command_sock_path[PATH_MAX]; /* Global command socket path */ @@ -79,6 +82,14 @@ static void sighandler(int sig) return; } + /* + * Ignore SIGPIPE because it should not stop the consumer whenever a + * SIGPIPE is catched through a FD operation. + */ + if (sig == SIGPIPE) { + return; + } + lttng_consumer_should_exit(ctx); } @@ -119,28 +130,28 @@ static int set_signal_handler(void) } /* - * usage function on stderr + * Usage function on stream file. */ -static void usage(void) +static void usage(FILE *fp) { - fprintf(stderr, "Usage: %s OPTIONS\n\nOptions:\n", progname); - fprintf(stderr, " -h, --help " + fprintf(fp, "Usage: %s OPTIONS\n\nOptions:\n", progname); + fprintf(fp, " -h, --help " "Display this usage.\n"); - fprintf(stderr, " -c, --consumerd-cmd-sock PATH " + fprintf(fp, " -c, --consumerd-cmd-sock PATH " "Specify path for the command socket\n"); - fprintf(stderr, " -e, --consumerd-err-sock PATH " + fprintf(fp, " -e, --consumerd-err-sock PATH " "Specify path for the error socket\n"); - fprintf(stderr, " -d, --daemonize " + fprintf(fp, " -d, --daemonize " "Start as a daemon.\n"); - fprintf(stderr, " -q, --quiet " + fprintf(fp, " -q, --quiet " "No output at all.\n"); - fprintf(stderr, " -v, --verbose " + fprintf(fp, " -v, --verbose " "Verbose mode. Activate DBG() macro.\n"); - fprintf(stderr, " -V, --version " + fprintf(fp, " -V, --version " "Show version number.\n"); - fprintf(stderr, " -k, --kernel " + fprintf(fp, " -k, --kernel " "Consumer kernel buffers (default).\n"); - fprintf(stderr, " -u, --ust " + fprintf(fp, " -u, --ust " "Consumer UST buffers.%s\n", #ifdef HAVE_LIBLTTNG_UST_CTL "" @@ -196,13 +207,13 @@ static void parse_args(int argc, char **argv) opt_daemon = 1; break; case 'h': - usage(); - exit(EXIT_FAILURE); + usage(stdout); + exit(EXIT_SUCCESS); case 'q': - opt_quiet = 1; + lttng_opt_quiet = 1; break; case 'v': - opt_verbose = 1; + lttng_opt_verbose = 1; break; case 'V': fprintf(stdout, "%s\n", VERSION); @@ -222,18 +233,36 @@ static void parse_args(int argc, char **argv) break; #endif default: - usage(); + usage(stderr); exit(EXIT_FAILURE); } } } +/* + * Set open files limit to unlimited. This daemon can open a large number of + * file descriptors in order to consumer multiple kernel traces. + */ +static void set_ulimit(void) +{ + int ret; + struct rlimit lim; + + /* The kernel does not allowed an infinite limit for open files */ + lim.rlim_cur = 65535; + lim.rlim_max = 65535; + + ret = setrlimit(RLIMIT_NOFILE, &lim); + if (ret < 0) { + PERROR("failed to set open files limit"); + } +} + /* * main */ int main(int argc, char **argv) { - int i; int ret = 0; void *status; @@ -243,14 +272,32 @@ int main(int argc, char **argv) /* Daemonize */ if (opt_daemon) { + int i; + + /* + * fork + * child: setsid, close FD 0, 1, 2, chdir / + * parent: exit (if fork is successful) + */ ret = daemon(0, 0); if (ret < 0) { - perror("daemon"); + 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. + */ + for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { + (void) close(i); + } } - if (strlen(command_sock_path) == 0) { + /* Set up max poll set size */ + lttng_poll_set_max_size(); + + if (*command_sock_path == '\0') { switch (opt_type) { case LTTNG_CONSUMER_KERNEL: snprintf(command_sock_path, PATH_MAX, DEFAULT_KCONSUMERD_CMD_SOCK_PATH, @@ -273,6 +320,11 @@ int main(int argc, char **argv) /* Init */ lttng_consumer_init(); + if (!getuid()) { + /* Set limit for open files */ + set_ulimit(); + } + /* create the consumer instance with and assign the callbacks */ ctx = lttng_consumer_create(opt_type, lttng_consumer_read_subbuffer, NULL, lttng_consumer_on_recv_stream, NULL); @@ -281,7 +333,7 @@ int main(int argc, char **argv) } lttng_consumer_set_command_sock_path(ctx, command_sock_path); - if (strlen(error_sock_path) == 0) { + if (*error_sock_path == '\0') { switch (opt_type) { case LTTNG_CONSUMER_KERNEL: snprintf(error_sock_path, PATH_MAX, DEFAULT_KCONSUMERD_ERR_SOCK_PATH, @@ -310,40 +362,116 @@ int main(int argc, char **argv) ret = lttcomm_connect_unix_sock(error_sock_path); /* not a fatal error, but all communication with lttng-sessiond will fail */ if (ret < 0) { - WARN("Cannot connect to error socket, is lttng-sessiond started ?"); + WARN("Cannot connect to error socket (is lttng-sessiond started?)"); } lttng_consumer_set_error_sock(ctx, ret); - /* Create the thread to manage the receive of fd */ - ret = pthread_create(&threads[0], NULL, lttng_consumer_thread_receive_fds, + /* + * For UST consumer, we block RT signals used for periodical metadata flush + * in main and create a dedicated thread to handle these signals. + */ + switch (opt_type) { + case LTTNG_CONSUMER32_UST: + case LTTNG_CONSUMER64_UST: + consumer_signal_init(); + break; + default: + break; + } + ctx->type = opt_type; + + /* Create thread to manage channels */ + ret = pthread_create(&channel_thread, NULL, consumer_thread_channel_poll, (void *) ctx); if (ret != 0) { perror("pthread_create"); goto error; } - /* Create thread to manage the polling/writing of traces */ - ret = pthread_create(&threads[1], NULL, lttng_consumer_thread_poll_fds, + /* Create thread to manage the polling/writing of trace metadata */ + ret = pthread_create(&metadata_thread, NULL, consumer_thread_metadata_poll, (void *) ctx); if (ret != 0) { perror("pthread_create"); - goto error; + goto metadata_error; + } + + /* Create thread to manage the polling/writing of trace data */ + ret = pthread_create(&data_thread, NULL, consumer_thread_data_poll, + (void *) ctx); + if (ret != 0) { + perror("pthread_create"); + goto data_error; } - for (i = 0; i < 2; i++) { - ret = pthread_join(threads[i], &status); + /* Create the thread to manage the receive of fd */ + ret = pthread_create(&sessiond_thread, NULL, consumer_thread_sessiond_poll, + (void *) ctx); + if (ret != 0) { + perror("pthread_create"); + goto sessiond_error; + } + + switch (opt_type) { + case LTTNG_CONSUMER32_UST: + case LTTNG_CONSUMER64_UST: + /* Create the thread to manage the metadata periodic timers */ + ret = pthread_create(&metadata_timer_thread, NULL, + consumer_timer_metadata_thread, (void *) ctx); if (ret != 0) { - perror("pthread_join"); - goto error; + perror("pthread_create"); + goto metadata_timer_error; } + + ret = pthread_detach(metadata_timer_thread); + if (ret) { + errno = ret; + perror("pthread_detach"); + } + break; + default: + break; + } + +metadata_timer_error: + ret = pthread_join(sessiond_thread, &status); + if (ret != 0) { + perror("pthread_join"); + goto error; + } + +sessiond_error: + ret = pthread_join(data_thread, &status); + if (ret != 0) { + perror("pthread_join"); + goto error; + } + +data_error: + ret = pthread_join(metadata_thread, &status); + if (ret != 0) { + perror("pthread_join"); + goto error; + } + +metadata_error: + ret = pthread_join(channel_thread, &status); + if (ret != 0) { + perror("pthread_join"); + goto error; + } + + if (!ret) { + ret = EXIT_SUCCESS; + lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_EXIT_SUCCESS); + goto end; } - ret = EXIT_SUCCESS; - lttng_consumer_send_error(ctx, CONSUMERD_EXIT_SUCCESS); - goto end; error: ret = EXIT_FAILURE; - lttng_consumer_send_error(ctx, CONSUMERD_EXIT_FAILURE); + if (ctx) { + lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_EXIT_FAILURE); + } end: lttng_consumer_destroy(ctx);