Launch the notification thread using lttng_thread
[lttng-tools.git] / src / bin / lttng-sessiond / health.c
1 /*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
3 * Copyright (C) 2018 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "lttng-sessiond.h"
20 #include "health-sessiond.h"
21 #include <common/macros.h>
22 #include <common/error.h>
23 #include <common/utils.h>
24 #include <common/pipe.h>
25 #include <inttypes.h>
26 #include <sys/stat.h>
27 #include "utils.h"
28 #include "thread.h"
29
30 static void cleanup_health_management_thread(void *thread_data)
31 {
32 struct lttng_pipe *quit_pipe = thread_data;
33
34 lttng_pipe_destroy(quit_pipe);
35 }
36
37 /*
38 * Thread managing health check socket.
39 */
40 static void *thread_manage_health(void *thread_data)
41 {
42 const bool is_root = (getuid() == 0);
43 int sock = -1, new_sock = -1, ret, i, pollfd, err = -1;
44 uint32_t revents, nb_fd;
45 struct lttng_poll_event events;
46 struct health_comm_msg msg;
47 struct health_comm_reply reply;
48 /* Thread-specific quit pipe. */
49 struct lttng_pipe *quit_pipe = thread_data;
50 const int quit_pipe_read_fd = lttng_pipe_get_readfd(quit_pipe);
51
52 DBG("[thread] Manage health check started");
53
54 rcu_register_thread();
55
56 /*
57 * Created with a size of two for:
58 * - client socket
59 * - thread quit pipe
60 */
61 ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
62 if (ret < 0) {
63 goto error;
64 }
65
66 /* Create unix socket */
67 sock = lttcomm_create_unix_sock(config.health_unix_sock_path.value);
68 if (sock < 0) {
69 ERR("Unable to create health check Unix socket");
70 goto error;
71 }
72
73 if (is_root) {
74 /* lttng health client socket path permissions */
75 ret = chown(config.health_unix_sock_path.value, 0,
76 utils_get_group_id(config.tracing_group_name.value));
77 if (ret < 0) {
78 ERR("Unable to set group on %s", config.health_unix_sock_path.value);
79 PERROR("chown");
80 goto error;
81 }
82
83 ret = chmod(config.health_unix_sock_path.value,
84 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
85 if (ret < 0) {
86 ERR("Unable to set permissions on %s", config.health_unix_sock_path.value);
87 PERROR("chmod");
88 goto error;
89 }
90 }
91
92 /*
93 * Set the CLOEXEC flag. Return code is useless because either way, the
94 * show must go on.
95 */
96 (void) utils_set_fd_cloexec(sock);
97
98 ret = lttcomm_listen_unix_sock(sock);
99 if (ret < 0) {
100 goto error;
101 }
102
103 ret = lttng_poll_add(&events, quit_pipe_read_fd, LPOLLIN | LPOLLERR);
104 if (ret < 0) {
105 goto error;
106 }
107
108 /* Add the application registration socket */
109 ret = lttng_poll_add(&events, sock, LPOLLIN | LPOLLPRI);
110 if (ret < 0) {
111 goto error;
112 }
113
114 sessiond_notify_ready();
115
116 while (1) {
117 DBG("Health check ready");
118
119 /* Infinite blocking call, waiting for transmission */
120 restart:
121 ret = lttng_poll_wait(&events, -1);
122 if (ret < 0) {
123 /*
124 * Restart interrupted system call.
125 */
126 if (errno == EINTR) {
127 goto restart;
128 }
129 goto error;
130 }
131
132 nb_fd = ret;
133
134 for (i = 0; i < nb_fd; i++) {
135 /* Fetch once the poll data */
136 revents = LTTNG_POLL_GETEV(&events, i);
137 pollfd = LTTNG_POLL_GETFD(&events, i);
138
139 if (!revents) {
140 /* No activity for this FD (poll implementation). */
141 continue;
142 }
143
144 /* Event on the registration socket */
145 if (pollfd == sock) {
146 if (revents & LPOLLIN) {
147 continue;
148 } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
149 ERR("Health socket poll error");
150 goto error;
151 } else {
152 ERR("Unexpected poll events %u for sock %d", revents, pollfd);
153 goto error;
154 }
155 } else {
156 /* Event on the thread's quit pipe. */
157 err = 0;
158 goto exit;
159 }
160 }
161
162 new_sock = lttcomm_accept_unix_sock(sock);
163 if (new_sock < 0) {
164 goto error;
165 }
166
167 /*
168 * Set the CLOEXEC flag. Return code is useless because either way, the
169 * show must go on.
170 */
171 (void) utils_set_fd_cloexec(new_sock);
172
173 DBG("Receiving data from client for health...");
174 ret = lttcomm_recv_unix_sock(new_sock, (void *)&msg, sizeof(msg));
175 if (ret <= 0) {
176 DBG("Nothing recv() from client... continuing");
177 ret = close(new_sock);
178 if (ret) {
179 PERROR("close");
180 }
181 continue;
182 }
183
184 rcu_thread_online();
185
186 memset(&reply, 0, sizeof(reply));
187 for (i = 0; i < NR_HEALTH_SESSIOND_TYPES; i++) {
188 /*
189 * health_check_state returns 0 if health is
190 * bad.
191 */
192 if (!health_check_state(health_sessiond, i)) {
193 reply.ret_code |= 1ULL << i;
194 }
195 }
196
197 DBG2("Health check return value %" PRIx64, reply.ret_code);
198
199 ret = lttcomm_send_unix_sock(new_sock, (void *) &reply,
200 sizeof(reply));
201 if (ret < 0) {
202 ERR("Failed to send health data back to client");
203 }
204
205 /* End of transmission */
206 ret = close(new_sock);
207 if (ret) {
208 PERROR("close");
209 }
210 }
211
212 exit:
213 error:
214 if (err) {
215 ERR("Health error occurred in %s", __func__);
216 }
217 DBG("Health check thread dying");
218 unlink(config.health_unix_sock_path.value);
219 if (sock >= 0) {
220 ret = close(sock);
221 if (ret) {
222 PERROR("close");
223 }
224 }
225
226 lttng_poll_clean(&events);
227 rcu_unregister_thread();
228 return NULL;
229 }
230
231 static bool shutdown_health_management_thread(void *thread_data)
232 {
233 int ret;
234 int pipe_write_fd;
235 struct lttng_pipe *health_quit_pipe = thread_data;
236
237 pipe_write_fd = lttng_pipe_get_writefd(health_quit_pipe);
238 ret = notify_thread_pipe(pipe_write_fd);
239 if (ret < 0) {
240 ERR("Failed to notify Health management thread's quit pipe");
241 goto error;
242 }
243 return true;
244 error:
245 return false;
246 }
247
248 bool launch_health_management_thread(void)
249 {
250 struct lttng_thread *thread;
251 struct lttng_pipe *health_quit_pipe = NULL;
252
253 health_quit_pipe = lttng_pipe_open(FD_CLOEXEC);
254 if (!health_quit_pipe) {
255 goto error;
256 }
257
258 thread = lttng_thread_create("Health management",
259 thread_manage_health,
260 shutdown_health_management_thread,
261 cleanup_health_management_thread,
262 health_quit_pipe);
263 if (!thread) {
264 goto error;
265 }
266 lttng_thread_put(thread);
267 return true;
268 error:
269 cleanup_health_management_thread(health_quit_pipe);
270 return false;
271 }
This page took 0.037338 seconds and 5 git commands to generate.