2 * Copyright (C) 2011 EfficiOS Inc.
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * SPDX-License-Identifier: GPL-2.0-only
10 #include "health-sessiond.hpp"
11 #include "kernel-consumer.hpp"
13 #include "manage-kernel.hpp"
14 #include "testpoint.hpp"
18 #include <common/make-unique-wrapper.hpp>
19 #include <common/pipe.hpp>
20 #include <common/pthread-lock.hpp>
21 #include <common/urcu.hpp>
22 #include <common/utils.hpp>
27 struct thread_notifiers
{
28 struct lttng_pipe
*quit_pipe
;
29 int kernel_poll_pipe_read_fd
;
34 * Update the kernel poll set of all channel fd available over all tracing
35 * session. Add the wakeup pipe at the end of the set.
37 static int update_kernel_poll(struct lttng_poll_event
*events
)
41 DBG("Updating kernel poll set");
43 const auto list_lock
= lttng::sessiond::lock_session_list();
44 const struct ltt_session_list
*session_list
= session_get_list();
46 for (auto *session
: lttng::urcu::list_iteration_adapter
<ltt_session
, <t_session::list
>(
47 session_list
->head
)) {
48 if (!session_get(session
)) {
52 session_lock(session
);
53 if (session
->kernel_session
== nullptr) {
54 session_unlock(session
);
59 for (auto *channel
: lttng::urcu::list_iteration_adapter
<ltt_kernel_channel
,
60 <t_kernel_channel::list
>(
61 session
->kernel_session
->channel_list
.head
)) {
62 /* Add channel fd to the kernel poll set */
63 ret
= lttng_poll_add(events
, channel
->fd
, LPOLLIN
| LPOLLRDNORM
);
65 session_unlock(session
);
70 DBG("Channel fd %d added to kernel set", channel
->fd
);
73 session_unlock(session
);
81 * Find the channel fd from 'fd' over all tracing session. When found, check
82 * for new channel stream and send those stream fds to the kernel consumer.
84 * Useful for CPU hotplug feature.
86 static int update_kernel_stream(int fd
)
90 DBG("Updating kernel streams for channel fd %d", fd
);
92 const auto list_lock
= lttng::sessiond::lock_session_list();
93 const struct ltt_session_list
*session_list
= session_get_list();
95 for (auto *raw_session_ptr
:
96 lttng::urcu::list_iteration_adapter
<ltt_session
, <t_session::list
>(
97 session_list
->head
)) {
98 ltt_kernel_session
*ksess
;
100 const auto session
= [raw_session_ptr
]() {
101 session_get(raw_session_ptr
);
102 raw_session_ptr
->lock();
103 return ltt_session::make_locked_ref(*raw_session_ptr
);
106 if (session
->kernel_session
== nullptr) {
110 ksess
= session
->kernel_session
;
112 for (auto *channel
: lttng::urcu::list_iteration_adapter
<ltt_kernel_channel
,
113 <t_kernel_channel::list
>(
114 ksess
->channel_list
.head
)) {
115 if (channel
->fd
!= fd
) {
118 DBG("Channel found, updating kernel streams");
119 ret
= kernel_open_channel_stream(channel
);
123 /* Update the stream global counter */
124 ksess
->stream_count_global
+= ret
;
127 * Have we already sent fds to the consumer? If yes, it
128 * means that tracing is started so it is safe to send
129 * our updated stream fds.
131 if (ksess
->consumer_fds_sent
!= 1 || ksess
->consumer
== nullptr) {
136 lttng::urcu::lfht_iteration_adapter
<consumer_socket
,
137 decltype(consumer_socket::node
),
138 &consumer_socket::node
>(
139 *ksess
->consumer
->socks
->ht
)) {
140 const lttng::pthread::lock_guard
socket_lock(*socket
->lock
);
142 ret
= kernel_consumer_send_channel_streams(
143 socket
, channel
, ksess
, session
->output_traces
? 1 : 0);
155 * This thread manage event coming from the kernel.
157 * Features supported in this thread:
160 static void *thread_kernel_management(void *data
)
162 int ret
, i
, update_poll_flag
= 1, err
= -1;
165 struct lttng_poll_event events
;
166 struct thread_notifiers
*notifiers
= (thread_notifiers
*) data
;
167 const auto thread_quit_pipe_fd
= lttng_pipe_get_readfd(notifiers
->quit_pipe
);
169 DBG("[thread] Thread manage kernel started");
171 health_register(the_health_sessiond
, HEALTH_SESSIOND_TYPE_KERNEL
);
174 * This first step of the while is to clean this structure which could free
175 * non NULL pointers so initialize it before the loop.
177 lttng_poll_init(&events
);
179 if (testpoint(sessiond_thread_manage_kernel
)) {
180 goto error_testpoint
;
183 health_code_update();
185 if (testpoint(sessiond_thread_manage_kernel_before_loop
)) {
186 goto error_testpoint
;
190 health_code_update();
192 if (update_poll_flag
== 1) {
193 /* Clean events object. We are about to populate it again. */
194 lttng_poll_clean(&events
);
196 ret
= lttng_poll_create(&events
, 2, LTTNG_CLOEXEC
);
198 goto error_poll_create
;
201 ret
= lttng_poll_add(&events
, notifiers
->kernel_poll_pipe_read_fd
, LPOLLIN
);
206 ret
= lttng_poll_add(&events
, thread_quit_pipe_fd
, LPOLLIN
);
211 /* This will add the available kernel channel if any. */
212 ret
= update_kernel_poll(&events
);
216 update_poll_flag
= 0;
219 DBG("Thread kernel polling");
221 /* Poll infinite value of time */
224 ret
= lttng_poll_wait(&events
, -1);
225 DBG("Thread kernel return from poll on %d fds", LTTNG_POLL_GETNB(&events
));
229 * Restart interrupted system call.
231 if (errno
== EINTR
) {
235 } else if (ret
== 0) {
236 /* Should not happen since timeout is infinite */
237 ERR("Return value of poll is 0 with an infinite timeout.\n"
238 "This should not have happened! Continuing...");
244 for (i
= 0; i
< nb_fd
; i
++) {
245 /* Fetch once the poll data */
246 const auto revents
= LTTNG_POLL_GETEV(&events
, i
);
247 const auto pollfd
= LTTNG_POLL_GETFD(&events
, i
);
249 health_code_update();
251 /* Activity on thread quit pipe, exiting. */
252 if (pollfd
== thread_quit_pipe_fd
) {
253 DBG("Activity on thread quit pipe");
258 /* Check for data on kernel pipe */
259 if (revents
& LPOLLIN
) {
260 if (pollfd
== notifiers
->kernel_poll_pipe_read_fd
) {
262 notifiers
->kernel_poll_pipe_read_fd
, &tmp
, 1);
264 * Ret value is useless here, if this pipe gets any actions
265 * an update is required anyway.
267 update_poll_flag
= 1;
271 * New CPU detected by the kernel. Adding kernel stream to
272 * kernel session and updating the kernel consumer
274 ret
= update_kernel_stream(pollfd
);
280 } else if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
281 update_poll_flag
= 1;
284 ERR("Unexpected poll events %u for sock %d", revents
, pollfd
);
292 lttng_poll_clean(&events
);
297 ERR("Health error occurred in %s", __func__
);
298 WARN("Kernel thread died unexpectedly. "
299 "Kernel tracing can continue but CPU hotplug is disabled.");
301 health_unregister(the_health_sessiond
);
302 DBG("Kernel thread dying");
306 static bool shutdown_kernel_management_thread(void *data
)
308 struct thread_notifiers
*notifiers
= (thread_notifiers
*) data
;
309 const int write_fd
= lttng_pipe_get_writefd(notifiers
->quit_pipe
);
311 return notify_thread_pipe(write_fd
) == 1;
314 static void cleanup_kernel_management_thread(void *data
)
316 struct thread_notifiers
*notifiers
= (thread_notifiers
*) data
;
318 lttng_pipe_destroy(notifiers
->quit_pipe
);
322 bool launch_kernel_management_thread(int kernel_poll_pipe_read_fd
)
324 struct lttng_pipe
*quit_pipe
;
325 struct thread_notifiers
*notifiers
= nullptr;
326 struct lttng_thread
*thread
;
328 notifiers
= zmalloc
<thread_notifiers
>();
332 quit_pipe
= lttng_pipe_open(FD_CLOEXEC
);
336 notifiers
->quit_pipe
= quit_pipe
;
337 notifiers
->kernel_poll_pipe_read_fd
= kernel_poll_pipe_read_fd
;
339 thread
= lttng_thread_create("Kernel management",
340 thread_kernel_management
,
341 shutdown_kernel_management_thread
,
342 cleanup_kernel_management_thread
,
347 lttng_thread_put(thread
);
350 cleanup_kernel_management_thread(notifiers
);