2 * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
3 * Copyright (C) 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * SPDX-License-Identifier: GPL-2.0-only
9 #include "health-sessiond.hpp"
10 #include "lttng-sessiond.hpp"
14 #include <common/error.hpp>
15 #include <common/macros.hpp>
16 #include <common/pipe.hpp>
17 #include <common/utils.hpp>
23 struct thread_notifiers
{
24 struct lttng_pipe
*quit_pipe
;
29 static void mark_thread_as_ready(struct thread_notifiers
*notifiers
)
31 DBG("Marking health management thread as ready");
32 sem_post(¬ifiers
->ready
);
35 static void wait_until_thread_is_ready(struct thread_notifiers
*notifiers
)
37 DBG("Waiting for health management thread to be ready");
38 sem_wait(¬ifiers
->ready
);
39 DBG("Health management thread is ready");
42 static void cleanup_health_management_thread(void *data
)
44 struct thread_notifiers
*notifiers
= (thread_notifiers
*) data
;
46 lttng_pipe_destroy(notifiers
->quit_pipe
);
47 sem_destroy(¬ifiers
->ready
);
52 * Thread managing health check socket.
54 static void *thread_manage_health(void *data
)
56 const bool is_root
= (getuid() == 0);
57 int sock
= -1, new_sock
= -1, ret
, i
, err
= -1;
59 struct lttng_poll_event events
;
60 struct health_comm_msg msg
;
61 struct health_comm_reply reply
;
62 /* Thread-specific quit pipe. */
63 struct thread_notifiers
*notifiers
= (thread_notifiers
*) data
;
64 const auto thread_quit_pipe_fd
= lttng_pipe_get_readfd(notifiers
->quit_pipe
);
66 DBG("[thread] Manage health check started");
68 rcu_register_thread();
71 * Created with a size of two for:
72 * - health client socket
75 ret
= lttng_poll_create(&events
, 2, LTTNG_CLOEXEC
);
80 /* Create unix socket */
81 sock
= lttcomm_create_unix_sock(the_config
.health_unix_sock_path
.value
);
83 ERR("Unable to create health check Unix socket");
88 /* lttng health client socket path permissions */
91 ret
= utils_get_group_id(the_config
.tracing_group_name
.value
, true, &gid
);
93 /* Default to root group. */
97 ret
= chown(the_config
.health_unix_sock_path
.value
, 0, gid
);
99 ERR("Unable to set group on %s", the_config
.health_unix_sock_path
.value
);
104 ret
= chmod(the_config
.health_unix_sock_path
.value
,
105 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
107 ERR("Unable to set permissions on %s",
108 the_config
.health_unix_sock_path
.value
);
115 * Set the CLOEXEC flag. Return code is useless because either way, the
118 (void) utils_set_fd_cloexec(sock
);
120 ret
= lttcomm_listen_unix_sock(sock
);
125 ret
= lttng_poll_add(&events
, thread_quit_pipe_fd
, LPOLLIN
);
130 /* Add the health client socket. */
131 ret
= lttng_poll_add(&events
, sock
, LPOLLIN
| LPOLLPRI
);
136 mark_thread_as_ready(notifiers
);
138 DBG("Health check ready");
140 /* Infinite blocking call, waiting for transmission */
142 ret
= lttng_poll_wait(&events
, -1);
145 * Restart interrupted system call.
147 if (errno
== EINTR
) {
155 for (i
= 0; i
< nb_fd
; i
++) {
156 /* Fetch once the poll data */
157 const auto revents
= LTTNG_POLL_GETEV(&events
, i
);
158 const auto pollfd
= LTTNG_POLL_GETFD(&events
, i
);
160 /* Activity on thread quit pipe, exiting. */
161 if (pollfd
== thread_quit_pipe_fd
) {
162 DBG("Activity on thread quit pipe");
167 /* Event on the health client socket. */
168 if (revents
& LPOLLIN
) {
170 } else if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
171 ERR("Health socket poll error");
174 ERR("Unexpected poll events %u for sock %d", revents
, pollfd
);
179 new_sock
= lttcomm_accept_unix_sock(sock
);
185 * Set the CLOEXEC flag. Return code is useless because either way, the
188 (void) utils_set_fd_cloexec(new_sock
);
190 DBG("Receiving data from client for health...");
191 ret
= lttcomm_recv_unix_sock(new_sock
, (void *) &msg
, sizeof(msg
));
193 DBG("Nothing recv() from client... continuing");
194 ret
= close(new_sock
);
203 memset(&reply
, 0, sizeof(reply
));
204 for (i
= 0; i
< NR_HEALTH_SESSIOND_TYPES
; i
++) {
206 * health_check_state returns 0 if health is
209 if (!health_check_state(the_health_sessiond
, i
)) {
210 reply
.ret_code
|= 1ULL << i
;
214 DBG2("Health check return value %" PRIx64
, reply
.ret_code
);
216 ret
= lttcomm_send_unix_sock(new_sock
, (void *) &reply
, sizeof(reply
));
218 ERR("Failed to send health data back to client");
221 /* End of transmission */
222 ret
= close(new_sock
);
231 ERR("Health error occurred in %s", __func__
);
233 DBG("Health check thread dying");
234 unlink(the_config
.health_unix_sock_path
.value
);
242 lttng_poll_clean(&events
);
243 rcu_unregister_thread();
247 static bool shutdown_health_management_thread(void *data
)
249 struct thread_notifiers
*notifiers
= (thread_notifiers
*) data
;
250 const int write_fd
= lttng_pipe_get_writefd(notifiers
->quit_pipe
);
252 return notify_thread_pipe(write_fd
) == 1;
255 bool launch_health_management_thread()
257 struct thread_notifiers
*notifiers
;
258 struct lttng_thread
*thread
;
260 notifiers
= zmalloc
<thread_notifiers
>();
265 sem_init(¬ifiers
->ready
, 0, 0);
266 notifiers
->quit_pipe
= lttng_pipe_open(FD_CLOEXEC
);
267 if (!notifiers
->quit_pipe
) {
270 thread
= lttng_thread_create("Health management",
271 thread_manage_health
,
272 shutdown_health_management_thread
,
273 cleanup_health_management_thread
,
279 wait_until_thread_is_ready(notifiers
);
280 lttng_thread_put(thread
);
283 cleanup_health_management_thread(notifiers
);