Add notification thread skeleton
[lttng-tools.git] / src / bin / lttng-sessiond / notification-thread.c
CommitLineData
de27ada2
JG
1/*
2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _LGPL_SOURCE
19#include <lttng/trigger/trigger.h>
20#include <common/error.h>
21#include <common/config/session-config.h>
22#include <common/defaults.h>
23#include <common/utils.h>
24#include <sys/eventfd.h>
25#include <sys/stat.h>
26
27#include "notification-thread.h"
28#include "lttng-sessiond.h"
29#include "health-sessiond.h"
30
31/*
32 * Destroy the thread data previously created by the init function.
33 */
34void notification_destroy_data(struct notification_thread_data *data)
35{
36 int ret;
37
38 if (!data) {
39 goto end;
40 }
41
42 if (data->cmd_queue.event_fd < 0) {
43 goto end;
44 }
45 ret = close(data->cmd_queue.event_fd);
46 if (ret < 0) {
47 PERROR("close notification command queue event_fd");
48 }
49
50 /* TODO: purge queue and mark commands as cancelled. */
51end:
52 free(data);
53}
54
55/*
56 * Initialize the thread's data. This MUST be called before the notification
57 * thread is started.
58 */
59struct notification_thread_data *notification_init_data(void)
60{
61 struct notification_thread_data *data;
62
63 data = zmalloc(sizeof(*data));
64 if (!data) {
65 goto end;
66 }
67
68 data->cmd_queue.event_fd = eventfd(0, EFD_CLOEXEC);
69 if (data->cmd_queue.event_fd < 0) {
70 PERROR("eventfd notification command queue");
71 goto error;
72 }
73 cds_wfcq_init(&data->cmd_queue.head, &data->cmd_queue.tail);
74end:
75 return data;
76error:
77 notification_destroy_data(data);
78 return NULL;
79}
80
81static
82char *get_notification_channel_sock_path(void)
83{
84 int ret;
85 bool is_root = !getuid();
86 char *sock_path;
87
88 sock_path = zmalloc(LTTNG_PATH_MAX);
89 if (!sock_path) {
90 goto error;
91 }
92
93 if (is_root) {
94 ret = snprintf(sock_path, LTTNG_PATH_MAX,
95 DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK);
96 if (ret < 0) {
97 goto error;
98 }
99 } else {
100 char *home_path = utils_get_home_dir();
101
102 if (!home_path) {
103 ERR("Can't get HOME directory for socket creation");
104 goto error;
105 }
106 puts(home_path);
107
108 ret = snprintf(sock_path, LTTNG_PATH_MAX,
109 DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK,
110 home_path);
111 if (ret < 0) {
112 goto error;
113 }
114 }
115
116 return sock_path;
117error:
118 free(sock_path);
119 return NULL;
120}
121
122static
123void notification_channel_socket_destroy(int fd)
124{
125 int ret;
126 char *sock_path = get_notification_channel_sock_path();
127
128 DBG("[notification-thread] Destroying notification channel socket");
129
130 if (sock_path) {
131 ret = unlink(sock_path);
132 free(sock_path);
133 if (ret < 0) {
134 PERROR("unlink notification channel socket");
135 }
136 }
137
138 ret = close(fd);
139 if (ret) {
140 PERROR("close notification channel socket");
141 }
142}
143
144static
145int notification_channel_socket_create(void)
146{
147 int fd = -1, ret;
148 char *sock_path = get_notification_channel_sock_path();
149
150 DBG("[notification-thread] Creating notification channel UNIX socket at %s",
151 sock_path);
152
153 ret = lttcomm_create_unix_sock(sock_path);
154 if (ret < 0) {
155 ERR("[notification-thread] Failed to create notification socket");
156 goto error;
157 }
158 fd = ret;
159
160 ret = chmod(sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
161 if (ret < 0) {
162 ERR("Set file permissions failed: %s", sock_path);
163 PERROR("chmod notification channel socket");
164 goto error;
165 }
166
167 DBG("[notification-thread] Notification channel UNIX socket created (fd = %i)",
168 fd);
169 free(sock_path);
170 return fd;
171error:
172 if (fd >= 0 && close(fd) < 0) {
173 PERROR("close notification channel socket");
174 }
175 free(sock_path);
176 return ret;
177}
178
179/*
180 * This thread services notification channel clients and received notifications
181 * from various lttng-sessiond components over a command queue.
182 */
183void *thread_notification(void *data)
184{
185 int ret;
186 struct lttng_poll_event events;
187 int notification_channel_socket;
188 struct notification_thread_data *ctx = data;
189
190 DBG("[notification-thread] Started notification thread");
191
192 if (!ctx) {
193 ERR("[notification-thread] Invalid thread context provided");
194 goto end;
195 }
196
197 rcu_register_thread();
198 rcu_thread_online();
199
200 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_NOTIFICATION);
201 health_code_update();
202
203 notification_channel_socket = notification_channel_socket_create();
204
205 /*
206 * Create pollset with size 2, quit pipe and notification channel
207 * socket, and the command queue event fd.
208 */
209 ret = sessiond_set_thread_pollset(&events, 3);
210 if (ret < 0) {
211 goto error_poll_create;
212 }
213
214 /* Add notification channel socket to poll set. */
215 ret = lttng_poll_add(&events, notification_channel_socket,
216 LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP);
217 if (ret < 0) {
218 ERR("[notification-thread] Failed to add notification channel socket to pollset");
219 goto error;
220 }
221
222 ret = lttng_poll_add(&events, ctx->cmd_queue.event_fd,
223 LPOLLIN | LPOLLERR);
224 if (ret < 0) {
225 ERR("[notification-thread] Failed to add notification command queue event fd to pollset");
226 goto error;
227 }
228
229 DBG("[notification-thread] Listening on notification channel socket");
230 ret = lttcomm_listen_unix_sock(notification_channel_socket);
231 if (ret < 0) {
232 ERR("[notification-thread] Listen failed on notification channel socket");
233 goto error;
234 }
235
236 while (true) {
237 int fd_count, i;
238
239 health_poll_entry();
240 DBG("[notification-thread] Entering poll wait");
241 ret = lttng_poll_wait(&events, -1);
242 DBG("[notification-thread] Poll wait returned (%i)", ret);
243 health_poll_exit();
244 if (ret < 0) {
245 /*
246 * Restart interrupted system call.
247 */
248 if (errno == EINTR) {
249 continue;
250 }
251 ERR("[notification-thread] Error encountered during lttng_poll_wait (%i)", ret);
252 goto error;
253 }
254
255 fd_count = ret;
256 for (i = 0; i < fd_count; i++) {
257 int fd = LTTNG_POLL_GETFD(&events, i);
258 uint32_t revents = LTTNG_POLL_GETEV(&events, i);
259
260 /* Thread quit pipe has been closed. Killing thread. */
261 if (sessiond_check_thread_quit_pipe(fd, revents)) {
262 DBG("[notification-thread] Quit pipe signaled, exiting.");
263 goto exit;
264 }
265 }
266 }
267exit:
268
269error:
270 lttng_poll_clean(&events);
271error_poll_create:
272 notification_channel_socket_destroy(notification_channel_socket);
273 health_unregister(health_sessiond);
274 rcu_thread_offline();
275 rcu_unregister_thread();
276end:
277 return NULL;
278}
This page took 0.034053 seconds and 5 git commands to generate.