From: Jérémie Galarneau Date: Thu, 2 Mar 2017 22:21:36 +0000 (-0500) Subject: Add notification thread skeleton X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=commitdiff_plain;h=de27ada252d776daa12245b504ff772f72c7d37f Add notification thread skeleton Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index 423866139..a62d7f499 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -30,7 +30,8 @@ lttng_sessiond_SOURCES = utils.c utils.h \ agent.c agent.h \ save.h save.c \ load-session-thread.h load-session-thread.c \ - syscall.h syscall.c + syscall.h syscall.c \ + notification-thread.h notification-thread.c if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \ diff --git a/src/bin/lttng-sessiond/health-sessiond.h b/src/bin/lttng-sessiond/health-sessiond.h index 22ea1bb3e..5d94cc639 100644 --- a/src/bin/lttng-sessiond/health-sessiond.h +++ b/src/bin/lttng-sessiond/health-sessiond.h @@ -29,6 +29,7 @@ enum health_type_sessiond { HEALTH_SESSIOND_TYPE_HT_CLEANUP = 5, HEALTH_SESSIOND_TYPE_APP_MANAGE_NOTIFY = 6, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH = 7, + HEALTH_SESSIOND_TYPE_NOTIFICATION = 8, NR_HEALTH_SESSIOND_TYPES, }; diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index af4a76608..dcfa34379 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -71,6 +71,7 @@ #include "agent-thread.h" #include "save.h" #include "load-session-thread.h" +#include "notification-thread.h" #include "syscall.h" #include "agent.h" #include "ht-cleanup.h" @@ -211,6 +212,7 @@ static pthread_t health_thread; static pthread_t ht_cleanup_thread; static pthread_t agent_reg_thread; static pthread_t load_session_thread; +static pthread_t notification_thread; /* * UST registration command queue. This queue is tied with a futex and uses a N @@ -305,6 +307,9 @@ const char * const config_section_name = "sessiond"; /* Load session thread information to operate. */ struct load_session_thread_data *load_info; +/* Notification thread command queue. */ +struct notification_thread_data *notification_thread_data; + /* Global hash tables */ struct lttng_ht *agent_apps_ht_by_sock = NULL; @@ -697,6 +702,10 @@ static void sessiond_cleanup(void) free(load_info); } + if (notification_thread_data) { + notification_destroy_data(notification_thread_data); + } + /* * Cleanup lock file by deleting it and finaly closing it which will * release the file system lock. @@ -5990,6 +5999,23 @@ int main(int argc, char **argv) goto exit_health; } + notification_thread_data = notification_init_data(); + if (!notification_thread_data) { + retval = -1; + ERR("Failed to initialize notification thread shared data"); + goto exit_notification; + } + + /* Create notification thread. */ + ret = pthread_create(¬ification_thread, default_pthread_attr(), + thread_notification, notification_thread_data); + if (ret) { + errno = ret; + PERROR("pthread_create notification"); + retval = -1; + goto exit_notification; + } + /* Create thread to manage the client socket */ ret = pthread_create(&client_thread, default_pthread_attr(), thread_manage_clients, (void *) NULL); @@ -6146,16 +6172,24 @@ exit_dispatch: PERROR("pthread_join"); retval = -1; } + exit_client: + ret = pthread_join(notification_thread, &status); + if (ret) { + errno = ret; + PERROR("pthread_join notification thread"); + retval = -1; + } +exit_notification: ret = pthread_join(health_thread, &status); if (ret) { errno = ret; PERROR("pthread_join health thread"); retval = -1; } -exit_health: +exit_health: exit_init_data: /* * Wait for all pending call_rcu work to complete before tearing diff --git a/src/bin/lttng-sessiond/notification-thread.c b/src/bin/lttng-sessiond/notification-thread.c new file mode 100644 index 000000000..5ec27b614 --- /dev/null +++ b/src/bin/lttng-sessiond/notification-thread.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2017 - Jérémie Galarneau + * + * 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., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "notification-thread.h" +#include "lttng-sessiond.h" +#include "health-sessiond.h" + +/* + * Destroy the thread data previously created by the init function. + */ +void notification_destroy_data(struct notification_thread_data *data) +{ + int ret; + + if (!data) { + goto end; + } + + if (data->cmd_queue.event_fd < 0) { + goto end; + } + ret = close(data->cmd_queue.event_fd); + if (ret < 0) { + PERROR("close notification command queue event_fd"); + } + + /* TODO: purge queue and mark commands as cancelled. */ +end: + free(data); +} + +/* + * Initialize the thread's data. This MUST be called before the notification + * thread is started. + */ +struct notification_thread_data *notification_init_data(void) +{ + struct notification_thread_data *data; + + data = zmalloc(sizeof(*data)); + if (!data) { + goto end; + } + + data->cmd_queue.event_fd = eventfd(0, EFD_CLOEXEC); + if (data->cmd_queue.event_fd < 0) { + PERROR("eventfd notification command queue"); + goto error; + } + cds_wfcq_init(&data->cmd_queue.head, &data->cmd_queue.tail); +end: + return data; +error: + notification_destroy_data(data); + return NULL; +} + +static +char *get_notification_channel_sock_path(void) +{ + int ret; + bool is_root = !getuid(); + char *sock_path; + + sock_path = zmalloc(LTTNG_PATH_MAX); + if (!sock_path) { + goto error; + } + + if (is_root) { + ret = snprintf(sock_path, LTTNG_PATH_MAX, + DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK); + if (ret < 0) { + goto error; + } + } else { + char *home_path = utils_get_home_dir(); + + if (!home_path) { + ERR("Can't get HOME directory for socket creation"); + goto error; + } + puts(home_path); + + ret = snprintf(sock_path, LTTNG_PATH_MAX, + DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK, + home_path); + if (ret < 0) { + goto error; + } + } + + return sock_path; +error: + free(sock_path); + return NULL; +} + +static +void notification_channel_socket_destroy(int fd) +{ + int ret; + char *sock_path = get_notification_channel_sock_path(); + + DBG("[notification-thread] Destroying notification channel socket"); + + if (sock_path) { + ret = unlink(sock_path); + free(sock_path); + if (ret < 0) { + PERROR("unlink notification channel socket"); + } + } + + ret = close(fd); + if (ret) { + PERROR("close notification channel socket"); + } +} + +static +int notification_channel_socket_create(void) +{ + int fd = -1, ret; + char *sock_path = get_notification_channel_sock_path(); + + DBG("[notification-thread] Creating notification channel UNIX socket at %s", + sock_path); + + ret = lttcomm_create_unix_sock(sock_path); + if (ret < 0) { + ERR("[notification-thread] Failed to create notification socket"); + goto error; + } + fd = ret; + + ret = chmod(sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (ret < 0) { + ERR("Set file permissions failed: %s", sock_path); + PERROR("chmod notification channel socket"); + goto error; + } + + DBG("[notification-thread] Notification channel UNIX socket created (fd = %i)", + fd); + free(sock_path); + return fd; +error: + if (fd >= 0 && close(fd) < 0) { + PERROR("close notification channel socket"); + } + free(sock_path); + return ret; +} + +/* + * This thread services notification channel clients and received notifications + * from various lttng-sessiond components over a command queue. + */ +void *thread_notification(void *data) +{ + int ret; + struct lttng_poll_event events; + int notification_channel_socket; + struct notification_thread_data *ctx = data; + + DBG("[notification-thread] Started notification thread"); + + if (!ctx) { + ERR("[notification-thread] Invalid thread context provided"); + goto end; + } + + rcu_register_thread(); + rcu_thread_online(); + + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_NOTIFICATION); + health_code_update(); + + notification_channel_socket = notification_channel_socket_create(); + + /* + * Create pollset with size 2, quit pipe and notification channel + * socket, and the command queue event fd. + */ + ret = sessiond_set_thread_pollset(&events, 3); + if (ret < 0) { + goto error_poll_create; + } + + /* Add notification channel socket to poll set. */ + ret = lttng_poll_add(&events, notification_channel_socket, + LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP); + if (ret < 0) { + ERR("[notification-thread] Failed to add notification channel socket to pollset"); + goto error; + } + + ret = lttng_poll_add(&events, ctx->cmd_queue.event_fd, + LPOLLIN | LPOLLERR); + if (ret < 0) { + ERR("[notification-thread] Failed to add notification command queue event fd to pollset"); + goto error; + } + + DBG("[notification-thread] Listening on notification channel socket"); + ret = lttcomm_listen_unix_sock(notification_channel_socket); + if (ret < 0) { + ERR("[notification-thread] Listen failed on notification channel socket"); + goto error; + } + + while (true) { + int fd_count, i; + + health_poll_entry(); + DBG("[notification-thread] Entering poll wait"); + ret = lttng_poll_wait(&events, -1); + DBG("[notification-thread] Poll wait returned (%i)", ret); + health_poll_exit(); + if (ret < 0) { + /* + * Restart interrupted system call. + */ + if (errno == EINTR) { + continue; + } + ERR("[notification-thread] Error encountered during lttng_poll_wait (%i)", ret); + goto error; + } + + fd_count = ret; + for (i = 0; i < fd_count; i++) { + int fd = LTTNG_POLL_GETFD(&events, i); + uint32_t revents = LTTNG_POLL_GETEV(&events, i); + + /* Thread quit pipe has been closed. Killing thread. */ + if (sessiond_check_thread_quit_pipe(fd, revents)) { + DBG("[notification-thread] Quit pipe signaled, exiting."); + goto exit; + } + } + } +exit: + +error: + lttng_poll_clean(&events); +error_poll_create: + notification_channel_socket_destroy(notification_channel_socket); + health_unregister(health_sessiond); + rcu_thread_offline(); + rcu_unregister_thread(); +end: + return NULL; +} diff --git a/src/bin/lttng-sessiond/notification-thread.h b/src/bin/lttng-sessiond/notification-thread.h new file mode 100644 index 000000000..7f797e28e --- /dev/null +++ b/src/bin/lttng-sessiond/notification-thread.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 - Jérémie Galarneau + * + * 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., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef NOTIFICATION_THREAD_H +#define NOTIFICATION_THREAD_H + +#include +#include + +enum notification_command_type { + NOTIFICATION_COMMAND_TYPE_NEW_TRIGGER, +}; + +struct notification_command { + /* Futex on which to wait for command reply. */ + int32_t futex; + enum lttng_error_code result; + enum notification_command_type type; +}; + +struct notification_new_trigger_command { + struct notification_command parent; + /* Set to NULL if ownership was transfered. */ + struct lttng_trigger *trigger; +}; + +/* Data passed to the thread on initialization. */ +struct notification_thread_data { + /* + * Queue of struct notification command. + * event_fd must be WRITE(2) to signal that a new command + * has been enqueued. + */ + struct notification_cmd_queue { + int event_fd; + struct cds_wfcq_head head; + struct cds_wfcq_tail tail; + } cmd_queue; +}; + +struct notification_command *notification_new_trigger_command_create( + struct lttng_trigger *trigger); +struct notification_command *notification_new_trigger_command_destroy( + struct lttng_trigger *trigger); + +void *thread_notification(void *data); + +int notification_thread_init_data(struct notification_thread_data **data); +void notification_thread_destroy_data(struct notification_thread_data *data); + +#endif /* NOTIFICATION_THREAD_H */ diff --git a/src/common/defaults.h b/src/common/defaults.h index 37d222a78..4b27fb320 100644 --- a/src/common/defaults.h +++ b/src/common/defaults.h @@ -106,10 +106,12 @@ #define DEFAULT_LTTNG_EXTRA_KMOD_PROBES "LTTNG_EXTRA_KMOD_PROBES" /* Default unix socket path */ -#define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/client-lttng-sessiond" -#define DEFAULT_HOME_CLIENT_UNIX_SOCK DEFAULT_LTTNG_HOME_RUNDIR "/client-lttng-sessiond" -#define DEFAULT_GLOBAL_HEALTH_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/sessiond-health" -#define DEFAULT_HOME_HEALTH_UNIX_SOCK DEFAULT_LTTNG_HOME_RUNDIR "/sessiond-health" +#define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/client-lttng-sessiond" +#define DEFAULT_HOME_CLIENT_UNIX_SOCK DEFAULT_LTTNG_HOME_RUNDIR "/client-lttng-sessiond" +#define DEFAULT_GLOBAL_HEALTH_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/sessiond-health" +#define DEFAULT_HOME_HEALTH_UNIX_SOCK DEFAULT_LTTNG_HOME_RUNDIR "/sessiond-health" +#define DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/sessiond-notification" +#define DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK DEFAULT_LTTNG_HOME_RUNDIR "/sessiond-notification" /* Default consumer health unix socket path */ #define DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK DEFAULT_LTTNG_RUNDIR "/ustconsumerd32/health"