2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
11 #include <common/common.h>
12 #include <common/sessiond-comm/sessiond-comm.h>
13 #include <common/uri.h>
14 #include <common/utils.h>
16 #include <common/compat/endian.h>
19 #include "agent-thread.h"
21 #include "lttng-sessiond.h"
26 struct thread_notifiers
{
27 struct lttng_pipe
*quit_pipe
;
31 static int agent_tracing_enabled
= -1;
34 * Note that there is not port here. It's set after this URI is parsed so we
35 * can let the user define a custom one. However, localhost is ALWAYS the
36 * default listening address.
38 static const char *default_reg_uri
=
39 "tcp://" DEFAULT_NETWORK_VIEWER_BIND_ADDRESS
;
42 * Update agent application using the given socket. This is done just after
43 * registration was successful.
45 * This is a quite heavy call in terms of locking since the session list lock
46 * AND session lock are acquired.
48 static void update_agent_app(struct agent_app
*app
)
50 struct ltt_session
*session
, *stmp
;
51 struct ltt_session_list
*list
;
53 list
= session_get_list();
57 cds_list_for_each_entry_safe(session
, stmp
, &list
->head
, list
) {
58 if (!session_get(session
)) {
62 session_lock(session
);
63 if (session
->ust_session
) {
67 agt
= trace_ust_find_agent(session
->ust_session
, app
->domain
);
69 agent_update(agt
, app
->sock
->fd
);
73 session_unlock(session
);
76 session_unlock_list();
80 * Create and init socket from uri.
82 static struct lttcomm_sock
*init_tcp_socket(void)
85 struct lttng_uri
*uri
= NULL
;
86 struct lttcomm_sock
*sock
= NULL
;
88 bool bind_succeeded
= false;
91 * This should never fail since the URI is hardcoded and the port is set
92 * before this thread is launched.
94 ret
= uri_parse(default_reg_uri
, &uri
);
96 assert(config
.agent_tcp_port
.begin
> 0);
97 uri
->port
= config
.agent_tcp_port
.begin
;
99 sock
= lttcomm_alloc_sock_from_uri(uri
);
102 ERR("[agent-thread] agent allocating TCP socket");
106 ret
= lttcomm_create_sock(sock
);
111 for (port
= config
.agent_tcp_port
.begin
;
112 port
<= config
.agent_tcp_port
.end
; port
++) {
113 ret
= lttcomm_sock_set_port(sock
, (uint16_t) port
);
115 ERR("[agent-thread] Failed to set port %u on socket",
119 DBG3("[agent-thread] Trying to bind on port %u", port
);
120 ret
= sock
->ops
->bind(sock
);
122 bind_succeeded
= true;
126 if (errno
== EADDRINUSE
) {
127 DBG("Failed to bind to port %u since it is already in use",
130 PERROR("Failed to bind to port %u", port
);
135 if (!bind_succeeded
) {
136 if (config
.agent_tcp_port
.begin
== config
.agent_tcp_port
.end
) {
137 WARN("Another process is already using the agent port %i. "
138 "Agent support will be deactivated.",
139 config
.agent_tcp_port
.begin
);
142 WARN("All ports in the range [%i, %i] are already in use. "
143 "Agent support will be deactivated.",
144 config
.agent_tcp_port
.begin
,
145 config
.agent_tcp_port
.end
);
150 ret
= sock
->ops
->listen(sock
, -1);
155 DBG("[agent-thread] Listening on TCP port %u and socket %d",
162 lttcomm_destroy_sock(sock
);
168 * Close and destroy the given TCP socket.
170 static void destroy_tcp_socket(struct lttcomm_sock
*sock
)
177 ret
= lttcomm_sock_get_port(sock
, &port
);
179 ERR("[agent-thread] Failed to get port of agent TCP socket");
183 DBG3("[agent-thread] Destroy TCP socket on port %" PRIu16
,
186 /* This will return gracefully if fd is invalid. */
187 sock
->ops
->close(sock
);
188 lttcomm_destroy_sock(sock
);
192 * Handle a new agent registration using the reg socket. After that, a new
193 * agent application is added to the global hash table and attach to an UST app
194 * object. If r_app is not NULL, the created app is set to the pointer.
196 * Return the new FD created upon accept() on success or else a negative errno
199 static int handle_registration(struct lttcomm_sock
*reg_sock
,
200 struct agent_app
**r_app
)
204 uint32_t major_version
, minor_version
;
206 enum lttng_domain_type domain
;
207 struct agent_app
*app
;
208 struct agent_register_msg msg
;
209 struct lttcomm_sock
*new_sock
;
213 new_sock
= reg_sock
->ops
->accept(reg_sock
);
219 size
= new_sock
->ops
->recvmsg(new_sock
, &msg
, sizeof(msg
), 0);
220 if (size
< sizeof(msg
)) {
224 domain
= be32toh(msg
.domain
);
225 pid
= be32toh(msg
.pid
);
226 major_version
= be32toh(msg
.major_version
);
227 minor_version
= be32toh(msg
.minor_version
);
229 /* Test communication protocol version of the registring agent. */
230 if (major_version
!= AGENT_MAJOR_VERSION
) {
234 if (minor_version
!= AGENT_MINOR_VERSION
) {
239 DBG2("[agent-thread] New registration for pid %d domain %d on socket %d",
240 pid
, domain
, new_sock
->fd
);
242 app
= agent_create_app(pid
, domain
, new_sock
);
249 * Add before assigning the socket value to the UST app so it can be found
255 * We don't need to attach the agent app to the app. If we ever do so, we
256 * should consider both registration order of agent before app and app
267 new_sock
->ops
->close(new_sock
);
268 lttcomm_destroy_sock(new_sock
);
273 bool agent_tracing_is_enabled(void)
277 enabled
= uatomic_read(&agent_tracing_enabled
);
278 assert(enabled
!= -1);
283 * Write agent TCP port using the rundir.
285 static int write_agent_port(uint16_t port
)
287 return utils_create_pid_file((pid_t
) port
,
288 config
.agent_port_file_path
.value
);
292 void mark_thread_as_ready(struct thread_notifiers
*notifiers
)
294 DBG("Marking agent management thread as ready");
295 sem_post(¬ifiers
->ready
);
299 void wait_until_thread_is_ready(struct thread_notifiers
*notifiers
)
301 DBG("Waiting for agent management thread to be ready");
302 sem_wait(¬ifiers
->ready
);
303 DBG("Agent management thread is ready");
307 * This thread manage application notify communication.
309 static void *thread_agent_management(void *data
)
312 uint32_t revents
, nb_fd
;
313 struct lttng_poll_event events
;
314 struct lttcomm_sock
*reg_sock
;
315 struct thread_notifiers
*notifiers
= data
;
316 const int quit_pipe_read_fd
= lttng_pipe_get_readfd(
317 notifiers
->quit_pipe
);
319 DBG("[agent-thread] Manage agent application registration.");
321 rcu_register_thread();
324 /* Agent initialization call MUST be called before starting the thread. */
325 assert(agent_apps_ht_by_sock
);
327 /* Create pollset with size 2, quit pipe and registration socket. */
328 ret
= lttng_poll_create(&events
, 2, LTTNG_CLOEXEC
);
330 goto error_poll_create
;
333 ret
= lttng_poll_add(&events
, quit_pipe_read_fd
,
336 goto error_tcp_socket
;
339 reg_sock
= init_tcp_socket();
343 assert(lttcomm_sock_get_port(reg_sock
, &port
) == 0);
345 ret
= write_agent_port(port
);
347 ERR("[agent-thread] Failed to create agent port file: agent tracing will be unavailable");
348 /* Don't prevent the launch of the sessiond on error. */
349 mark_thread_as_ready(notifiers
);
353 /* Don't prevent the launch of the sessiond on error. */
354 mark_thread_as_ready(notifiers
);
355 goto error_tcp_socket
;
359 * Signal that the agent thread is ready. The command thread
360 * may start to query whether or not agent tracing is enabled.
362 uatomic_set(&agent_tracing_enabled
, 1);
363 mark_thread_as_ready(notifiers
);
365 /* Add TCP socket to poll set. */
366 ret
= lttng_poll_add(&events
, reg_sock
->fd
,
367 LPOLLIN
| LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
);
373 DBG3("[agent-thread] Manage agent polling");
375 /* Inifinite blocking call, waiting for transmission */
377 ret
= lttng_poll_wait(&events
, -1);
378 DBG3("[agent-thread] Manage agent return from poll on %d fds",
379 LTTNG_POLL_GETNB(&events
));
382 * Restart interrupted system call.
384 if (errno
== EINTR
) {
390 DBG3("[agent-thread] %d fd ready", nb_fd
);
392 for (i
= 0; i
< nb_fd
; i
++) {
393 /* Fetch once the poll data */
394 revents
= LTTNG_POLL_GETEV(&events
, i
);
395 pollfd
= LTTNG_POLL_GETFD(&events
, i
);
397 /* Thread quit pipe has been closed. Killing thread. */
398 if (pollfd
== quit_pipe_read_fd
) {
402 if (revents
& LPOLLIN
) {
404 struct agent_app
*app
= NULL
;
406 assert(pollfd
== reg_sock
->fd
);
407 new_fd
= handle_registration(reg_sock
, &app
);
411 /* Should not have a NULL app on success. */
415 * Since this is a command socket (write then read),
416 * only add poll error event to only detect shutdown.
418 ret
= lttng_poll_add(&events
, new_fd
,
419 LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
);
421 agent_destroy_app_by_sock(new_fd
);
425 /* Update newly registered app. */
426 update_agent_app(app
);
428 /* On failure, the poll will detect it and clean it up. */
429 ret
= agent_send_registration_done(app
);
431 /* Removing from the poll set */
432 ret
= lttng_poll_del(&events
, new_fd
);
436 agent_destroy_app_by_sock(new_fd
);
439 } else if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
440 /* Removing from the poll set */
441 ret
= lttng_poll_del(&events
, pollfd
);
445 agent_destroy_app_by_sock(pollfd
);
447 ERR("Unexpected poll events %u for sock %d", revents
, pollfd
);
454 /* Whatever happens, try to delete it and exit. */
455 (void) lttng_poll_del(&events
, reg_sock
->fd
);
457 destroy_tcp_socket(reg_sock
);
459 lttng_poll_clean(&events
);
461 uatomic_set(&agent_tracing_enabled
, 0);
462 DBG("[agent-thread] Cleaning up and stopping.");
463 rcu_thread_offline();
464 rcu_unregister_thread();
468 static bool shutdown_agent_management_thread(void *data
)
470 struct thread_notifiers
*notifiers
= data
;
471 const int write_fd
= lttng_pipe_get_writefd(notifiers
->quit_pipe
);
473 return notify_thread_pipe(write_fd
) == 1;
476 static void cleanup_agent_management_thread(void *data
)
478 struct thread_notifiers
*notifiers
= data
;
480 lttng_pipe_destroy(notifiers
->quit_pipe
);
481 sem_destroy(¬ifiers
->ready
);
485 bool launch_agent_management_thread(void)
487 struct thread_notifiers
*notifiers
;
488 struct lttng_thread
*thread
;
490 notifiers
= zmalloc(sizeof(*notifiers
));
495 sem_init(¬ifiers
->ready
, 0, 0);
496 notifiers
->quit_pipe
= lttng_pipe_open(FD_CLOEXEC
);
497 if (!notifiers
->quit_pipe
) {
500 thread
= lttng_thread_create("Agent management",
501 thread_agent_management
,
502 shutdown_agent_management_thread
,
503 cleanup_agent_management_thread
,
508 wait_until_thread_is_ready(notifiers
);
509 lttng_thread_put(thread
);
512 cleanup_agent_management_thread(notifiers
);