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 "lttng-sessiond.h"
10 #include "health-sessiond.h"
11 #include <common/macros.h>
12 #include <common/error.h>
13 #include <common/utils.h>
14 #include <common/pipe.h>
20 struct thread_notifiers
{
21 struct lttng_pipe
*quit_pipe
;
26 void mark_thread_as_ready(struct thread_notifiers
*notifiers
)
28 DBG("Marking health management thread as ready");
29 sem_post(¬ifiers
->ready
);
33 void wait_until_thread_is_ready(struct thread_notifiers
*notifiers
)
35 DBG("Waiting for health management thread to be ready");
36 sem_wait(¬ifiers
->ready
);
37 DBG("Health management thread is ready");
40 static void cleanup_health_management_thread(void *data
)
42 struct thread_notifiers
*notifiers
= data
;
44 lttng_pipe_destroy(notifiers
->quit_pipe
);
45 sem_destroy(¬ifiers
->ready
);
50 * Thread managing health check socket.
52 static void *thread_manage_health(void *data
)
54 const bool is_root
= (getuid() == 0);
55 int sock
= -1, new_sock
= -1, ret
, i
, pollfd
, err
= -1;
56 uint32_t revents
, nb_fd
;
57 struct lttng_poll_event events
;
58 struct health_comm_msg msg
;
59 struct health_comm_reply reply
;
60 /* Thread-specific quit pipe. */
61 struct thread_notifiers
*notifiers
= data
;
62 const int quit_pipe_read_fd
= lttng_pipe_get_readfd(
63 notifiers
->quit_pipe
);
65 DBG("[thread] Manage health check started");
67 rcu_register_thread();
70 * Created with a size of two for:
74 ret
= lttng_poll_create(&events
, 2, LTTNG_CLOEXEC
);
79 /* Create unix socket */
80 sock
= lttcomm_create_unix_sock(config
.health_unix_sock_path
.value
);
82 ERR("Unable to create health check Unix socket");
87 /* lttng health client socket path permissions */
90 ret
= utils_get_group_id(config
.tracing_group_name
.value
, true, &gid
);
92 /* Default to root group. */
96 ret
= chown(config
.health_unix_sock_path
.value
, 0, gid
);
98 ERR("Unable to set group on %s", config
.health_unix_sock_path
.value
);
103 ret
= chmod(config
.health_unix_sock_path
.value
,
104 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
106 ERR("Unable to set permissions on %s", config
.health_unix_sock_path
.value
);
113 * Set the CLOEXEC flag. Return code is useless because either way, the
116 (void) utils_set_fd_cloexec(sock
);
118 ret
= lttcomm_listen_unix_sock(sock
);
123 ret
= lttng_poll_add(&events
, quit_pipe_read_fd
, LPOLLIN
| LPOLLERR
);
128 /* Add the application registration socket */
129 ret
= lttng_poll_add(&events
, sock
, LPOLLIN
| LPOLLPRI
);
134 mark_thread_as_ready(notifiers
);
136 DBG("Health check ready");
138 /* Infinite blocking call, waiting for transmission */
140 ret
= lttng_poll_wait(&events
, -1);
143 * Restart interrupted system call.
145 if (errno
== EINTR
) {
153 for (i
= 0; i
< nb_fd
; i
++) {
154 /* Fetch once the poll data */
155 revents
= LTTNG_POLL_GETEV(&events
, i
);
156 pollfd
= LTTNG_POLL_GETFD(&events
, i
);
158 /* Event on the registration socket */
159 if (pollfd
== sock
) {
160 if (revents
& LPOLLIN
) {
162 } else if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
163 ERR("Health socket poll error");
166 ERR("Unexpected poll events %u for sock %d", revents
, pollfd
);
170 /* Event on the thread's quit pipe. */
176 new_sock
= lttcomm_accept_unix_sock(sock
);
182 * Set the CLOEXEC flag. Return code is useless because either way, the
185 (void) utils_set_fd_cloexec(new_sock
);
187 DBG("Receiving data from client for health...");
188 ret
= lttcomm_recv_unix_sock(new_sock
, (void *)&msg
, sizeof(msg
));
190 DBG("Nothing recv() from client... continuing");
191 ret
= close(new_sock
);
200 memset(&reply
, 0, sizeof(reply
));
201 for (i
= 0; i
< NR_HEALTH_SESSIOND_TYPES
; i
++) {
203 * health_check_state returns 0 if health is
206 if (!health_check_state(health_sessiond
, i
)) {
207 reply
.ret_code
|= 1ULL << i
;
211 DBG2("Health check return value %" PRIx64
, reply
.ret_code
);
213 ret
= lttcomm_send_unix_sock(new_sock
, (void *) &reply
,
216 ERR("Failed to send health data back to client");
219 /* End of transmission */
220 ret
= close(new_sock
);
229 ERR("Health error occurred in %s", __func__
);
231 DBG("Health check thread dying");
232 unlink(config
.health_unix_sock_path
.value
);
240 lttng_poll_clean(&events
);
241 rcu_unregister_thread();
245 static bool shutdown_health_management_thread(void *data
)
247 struct thread_notifiers
*notifiers
= data
;
248 const int write_fd
= lttng_pipe_get_writefd(notifiers
->quit_pipe
);
250 return notify_thread_pipe(write_fd
) == 1;
253 bool launch_health_management_thread(void)
255 struct thread_notifiers
*notifiers
;
256 struct lttng_thread
*thread
;
258 notifiers
= zmalloc(sizeof(*notifiers
));
263 sem_init(¬ifiers
->ready
, 0, 0);
264 notifiers
->quit_pipe
= lttng_pipe_open(FD_CLOEXEC
);
265 if (!notifiers
->quit_pipe
) {
268 thread
= lttng_thread_create("Health management",
269 thread_manage_health
,
270 shutdown_health_management_thread
,
271 cleanup_health_management_thread
,
277 wait_until_thread_is_ready(notifiers
);
278 lttng_thread_put(thread
);
281 cleanup_health_management_thread(notifiers
);