2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <lttng/trigger/trigger.h>
20 #include <lttng/notification/channel-internal.h>
21 #include <lttng/notification/notification-internal.h>
22 #include <lttng/condition/condition-internal.h>
23 #include <lttng/condition/buffer-usage-internal.h>
24 #include <common/error.h>
25 #include <common/config/session-config.h>
26 #include <common/defaults.h>
27 #include <common/utils.h>
28 #include <common/align.h>
29 #include <common/time.h>
30 #include <sys/eventfd.h>
35 #include "notification-thread.h"
36 #include "notification-thread-events.h"
37 #include "notification-thread-commands.h"
38 #include "lttng-sessiond.h"
39 #include "health-sessiond.h"
42 #include <urcu/list.h>
43 #include <urcu/rculfhash.h>
46 * This thread maintains an internal state associating clients and triggers.
48 * In order to speed-up and simplify queries, hash tables providing the
49 * following associations are maintained:
51 * - client_socket_ht: associate a client's socket (fd) to its "struct client"
52 * This hash table owns the "struct client" which must thus be
53 * disposed-of on removal from the hash table.
55 * - channel_triggers_ht:
56 * associates a channel key to a list of
57 * struct lttng_trigger_list_nodes. The triggers in this list are
58 * those that have conditions that apply to this channel.
59 * This hash table owns the list, but not the triggers themselves.
62 * associates a pair (channel key, channel domain) to its last
63 * sampled state received from the consumer daemon
64 * (struct channel_state).
65 * This previous sample is kept to implement edge-triggered
66 * conditions as we need to detect the state transitions.
67 * This hash table owns the channel state.
69 * - notification_trigger_clients_ht:
70 * associates notification-emitting triggers to clients
71 * (struct notification_client_ht_node) subscribed to those
73 * The condition's hash and match functions are used directly since
74 * all triggers in this hash table have the "notify" action.
75 * This hash table holds no ownership.
78 * associates a channel_key to a struct channel_info. The hash table
79 * holds the ownership of the struct channel_info.
82 * associated a condition to a struct lttng_trigger_ht_element.
83 * The hash table holds the ownership of the
84 * lttng_trigger_ht_elements along with the triggers themselves.
86 * The thread reacts to the following internal events:
87 * 1) creation of a tracing channel,
88 * 2) destruction of a tracing channel,
89 * 3) registration of a trigger,
90 * 4) unregistration of a trigger,
91 * 5) reception of a channel monitor sample from the consumer daemon.
93 * Events specific to notification-emitting triggers:
94 * 6) connection of a notification client,
95 * 7) disconnection of a notification client,
96 * 8) subscription of a client to a conditions' notifications,
97 * 9) unsubscription of a client from a conditions' notifications,
100 * 1) Creation of a tracing channel
101 * - notification_trigger_clients_ht is traversed to identify
102 * triggers which apply to this new channel,
103 * - triggers identified are added to the channel_triggers_ht.
104 * - add channel to channels_ht
106 * 2) Destruction of a tracing channel
107 * - remove entry from channel_triggers_ht, releasing the list wrapper and
109 * - remove entry from the channel_state_ht.
110 * - remove channel from channels_ht
112 * 3) Registration of a trigger
113 * - if the trigger's action is of type "notify",
114 * - traverse the list of conditions of every client to build a list of
115 * clients which have to be notified when this trigger's condition is met,
116 * - add list of clients (even if it is empty) to the
117 * notification_trigger_clients_ht,
118 * - add trigger to channel_triggers_ht (if applicable),
119 * - add trigger to triggers_ht
121 * 4) Unregistration of a trigger
122 * - if the trigger's action is of type "notify",
123 * - remove the trigger from the notification_trigger_clients_ht,
124 * - remove trigger from channel_triggers_ht (if applicable),
125 * - remove trigger from triggers_ht
127 * 5) Reception of a channel monitor sample from the consumer daemon
128 * - evaluate the conditions associated with the triggers found in
129 * the channel_triggers_ht,
130 * - if a condition evaluates to "true" and the condition is of type
131 * "notify", query the notification_trigger_clients_ht and send
132 * a notification to the clients.
134 * 6) Connection of a client
135 * - add client socket to the client_socket_ht.
137 * 7) Disconnection of a client
138 * - remove client socket from the client_socket_ht,
139 * - traverse all conditions to which the client is subscribed and remove
140 * the client from the notification_trigger_clients_ht.
142 * 8) Subscription of a client to a condition's notifications
143 * - Add the condition to the client's list of subscribed conditions,
144 * - Look-up notification_trigger_clients_ht and add the client to
147 * 9) Unsubscription of a client to a condition's notifications
148 * - Remove the condition from the client's list of subscribed conditions,
149 * - Look-up notification_trigger_clients_ht and remove the client
150 * from the list of clients.
154 * Destroy the thread data previously created by the init function.
156 void notification_thread_handle_destroy(
157 struct notification_thread_handle
*handle
)
165 if (handle
->cmd_queue
.event_fd
< 0) {
168 ret
= close(handle
->cmd_queue
.event_fd
);
170 PERROR("close notification command queue event_fd");
173 assert(cds_list_empty(&handle
->cmd_queue
.list
));
174 pthread_mutex_destroy(&handle
->cmd_queue
.lock
);
176 if (handle
->channel_monitoring_pipes
.ust32_consumer
>= 0) {
177 ret
= close(handle
->channel_monitoring_pipes
.ust32_consumer
);
179 PERROR("close 32-bit consumer channel monitoring pipe");
182 if (handle
->channel_monitoring_pipes
.ust64_consumer
>= 0) {
183 ret
= close(handle
->channel_monitoring_pipes
.ust64_consumer
);
185 PERROR("close 64-bit consumer channel monitoring pipe");
188 if (handle
->channel_monitoring_pipes
.kernel_consumer
>= 0) {
189 ret
= close(handle
->channel_monitoring_pipes
.kernel_consumer
);
191 PERROR("close kernel consumer channel monitoring pipe");
198 struct notification_thread_handle
*notification_thread_handle_create(
199 struct lttng_pipe
*ust32_channel_monitor_pipe
,
200 struct lttng_pipe
*ust64_channel_monitor_pipe
,
201 struct lttng_pipe
*kernel_channel_monitor_pipe
)
204 struct notification_thread_handle
*handle
;
206 handle
= zmalloc(sizeof(*handle
));
211 /* FIXME Replace eventfd by a pipe to support older kernels. */
212 handle
->cmd_queue
.event_fd
= eventfd(0, EFD_CLOEXEC
);
213 if (handle
->cmd_queue
.event_fd
< 0) {
214 PERROR("eventfd notification command queue");
217 CDS_INIT_LIST_HEAD(&handle
->cmd_queue
.list
);
218 ret
= pthread_mutex_init(&handle
->cmd_queue
.lock
, NULL
);
223 if (ust32_channel_monitor_pipe
) {
224 handle
->channel_monitoring_pipes
.ust32_consumer
=
225 lttng_pipe_release_readfd(
226 ust32_channel_monitor_pipe
);
227 if (handle
->channel_monitoring_pipes
.ust32_consumer
< 0) {
231 handle
->channel_monitoring_pipes
.ust32_consumer
= -1;
233 if (ust64_channel_monitor_pipe
) {
234 handle
->channel_monitoring_pipes
.ust64_consumer
=
235 lttng_pipe_release_readfd(
236 ust64_channel_monitor_pipe
);
237 if (handle
->channel_monitoring_pipes
.ust64_consumer
< 0) {
241 handle
->channel_monitoring_pipes
.ust64_consumer
= -1;
243 if (kernel_channel_monitor_pipe
) {
244 handle
->channel_monitoring_pipes
.kernel_consumer
=
245 lttng_pipe_release_readfd(
246 kernel_channel_monitor_pipe
);
247 if (handle
->channel_monitoring_pipes
.kernel_consumer
< 0) {
251 handle
->channel_monitoring_pipes
.kernel_consumer
= -1;
256 notification_thread_handle_destroy(handle
);
261 char *get_notification_channel_sock_path(void)
264 bool is_root
= !getuid();
267 sock_path
= zmalloc(LTTNG_PATH_MAX
);
273 ret
= snprintf(sock_path
, LTTNG_PATH_MAX
,
274 DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK
);
279 char *home_path
= utils_get_home_dir();
282 ERR("Can't get HOME directory for socket creation");
286 ret
= snprintf(sock_path
, LTTNG_PATH_MAX
,
287 DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK
,
301 void notification_channel_socket_destroy(int fd
)
304 char *sock_path
= get_notification_channel_sock_path();
306 DBG("[notification-thread] Destroying notification channel socket");
309 ret
= unlink(sock_path
);
312 PERROR("unlink notification channel socket");
318 PERROR("close notification channel socket");
323 int notification_channel_socket_create(void)
326 char *sock_path
= get_notification_channel_sock_path();
328 DBG("[notification-thread] Creating notification channel UNIX socket at %s",
331 ret
= lttcomm_create_unix_sock(sock_path
);
333 ERR("[notification-thread] Failed to create notification socket");
338 ret
= chmod(sock_path
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
340 ERR("Set file permissions failed: %s", sock_path
);
341 PERROR("chmod notification channel socket");
346 ret
= chown(sock_path
, 0,
347 utils_get_group_id(tracing_group_name
));
349 ERR("Failed to set the notification channel socket's group");
355 DBG("[notification-thread] Notification channel UNIX socket created (fd = %i)",
360 if (fd
>= 0 && close(fd
) < 0) {
361 PERROR("close notification channel socket");
368 int init_poll_set(struct lttng_poll_event
*poll_set
,
369 struct notification_thread_handle
*handle
,
370 int notification_channel_socket
)
375 * Create pollset with size 5:
376 * - notification channel socket (listen for new connections),
377 * - command queue event fd (internal sessiond commands),
378 * - consumerd (32-bit user space) channel monitor pipe,
379 * - consumerd (64-bit user space) channel monitor pipe,
380 * - consumerd (kernel) channel monitor pipe.
382 ret
= lttng_poll_create(poll_set
, 5, LTTNG_CLOEXEC
);
387 ret
= lttng_poll_add(poll_set
, notification_channel_socket
,
388 LPOLLIN
| LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
);
390 ERR("[notification-thread] Failed to add notification channel socket to pollset");
393 ret
= lttng_poll_add(poll_set
, handle
->cmd_queue
.event_fd
,
396 ERR("[notification-thread] Failed to add notification command queue event fd to pollset");
399 ret
= lttng_poll_add(poll_set
,
400 handle
->channel_monitoring_pipes
.ust32_consumer
,
403 ERR("[notification-thread] Failed to add ust-32 channel monitoring pipe fd to pollset");
406 ret
= lttng_poll_add(poll_set
,
407 handle
->channel_monitoring_pipes
.ust64_consumer
,
410 ERR("[notification-thread] Failed to add ust-64 channel monitoring pipe fd to pollset");
413 if (handle
->channel_monitoring_pipes
.kernel_consumer
< 0) {
416 ret
= lttng_poll_add(poll_set
,
417 handle
->channel_monitoring_pipes
.kernel_consumer
,
420 ERR("[notification-thread] Failed to add kernel channel monitoring pipe fd to pollset");
426 lttng_poll_clean(poll_set
);
431 void fini_thread_state(struct notification_thread_state
*state
)
435 if (state
->client_socket_ht
) {
436 ret
= handle_notification_thread_client_disconnect_all(state
);
438 ret
= cds_lfht_destroy(state
->client_socket_ht
, NULL
);
441 if (state
->triggers_ht
) {
442 ret
= handle_notification_thread_trigger_unregister_all(state
);
444 ret
= cds_lfht_destroy(state
->triggers_ht
, NULL
);
447 if (state
->channel_triggers_ht
) {
448 ret
= cds_lfht_destroy(state
->channel_triggers_ht
, NULL
);
451 if (state
->channel_state_ht
) {
452 ret
= cds_lfht_destroy(state
->channel_state_ht
, NULL
);
455 if (state
->notification_trigger_clients_ht
) {
456 ret
= cds_lfht_destroy(state
->notification_trigger_clients_ht
,
460 if (state
->channels_ht
) {
461 ret
= cds_lfht_destroy(state
->channels_ht
,
466 if (state
->notification_channel_socket
>= 0) {
467 notification_channel_socket_destroy(
468 state
->notification_channel_socket
);
470 lttng_poll_clean(&state
->events
);
474 int init_thread_state(struct notification_thread_handle
*handle
,
475 struct notification_thread_state
*state
)
479 memset(state
, 0, sizeof(*state
));
480 state
->notification_channel_socket
= -1;
481 lttng_poll_init(&state
->events
);
483 ret
= notification_channel_socket_create();
487 state
->notification_channel_socket
= ret
;
489 ret
= init_poll_set(&state
->events
, handle
,
490 state
->notification_channel_socket
);
495 DBG("[notification-thread] Listening on notification channel socket");
496 ret
= lttcomm_listen_unix_sock(state
->notification_channel_socket
);
498 ERR("[notification-thread] Listen failed on notification channel socket");
502 state
->client_socket_ht
= cds_lfht_new(DEFAULT_HT_SIZE
, 1, 0,
503 CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
504 if (!state
->client_socket_ht
) {
508 state
->channel_triggers_ht
= cds_lfht_new(DEFAULT_HT_SIZE
, 1, 0,
509 CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
510 if (!state
->channel_triggers_ht
) {
514 state
->channel_state_ht
= cds_lfht_new(DEFAULT_HT_SIZE
, 1, 0,
515 CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
516 if (!state
->channel_state_ht
) {
520 state
->notification_trigger_clients_ht
= cds_lfht_new(DEFAULT_HT_SIZE
,
521 1, 0, CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
522 if (!state
->notification_trigger_clients_ht
) {
526 state
->channels_ht
= cds_lfht_new(DEFAULT_HT_SIZE
,
527 1, 0, CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
528 if (!state
->channels_ht
) {
532 state
->triggers_ht
= cds_lfht_new(DEFAULT_HT_SIZE
,
533 1, 0, CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
534 if (!state
->triggers_ht
) {
540 fini_thread_state(state
);
545 int handle_channel_monitoring_pipe(int fd
, uint32_t revents
,
546 struct notification_thread_handle
*handle
,
547 struct notification_thread_state
*state
)
550 enum lttng_domain_type domain
;
552 if (fd
== handle
->channel_monitoring_pipes
.ust32_consumer
||
553 fd
== handle
->channel_monitoring_pipes
.ust64_consumer
) {
554 domain
= LTTNG_DOMAIN_UST
;
555 } else if (fd
== handle
->channel_monitoring_pipes
.kernel_consumer
) {
556 domain
= LTTNG_DOMAIN_KERNEL
;
561 if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
562 ret
= lttng_poll_del(&state
->events
, fd
);
564 ERR("[notification-thread] Failed to remove consumer monitoring pipe from poll set");
569 ret
= handle_notification_thread_channel_sample(
572 ERR("[notification-thread] Consumer sample handling error occured");
581 * This thread services notification channel clients and commands received
582 * from various lttng-sessiond components over a command queue.
584 void *thread_notification(void *data
)
587 struct notification_thread_handle
*handle
= data
;
588 struct notification_thread_state state
;
590 DBG("[notification-thread] Started notification thread");
593 ERR("[notification-thread] Invalid thread context provided");
597 rcu_register_thread();
600 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_NOTIFICATION
);
601 health_code_update();
603 ret
= init_thread_state(handle
, &state
);
608 /* Ready to handle client connections. */
609 sessiond_notify_ready();
615 DBG("[notification-thread] Entering poll wait");
616 ret
= lttng_poll_wait(&state
.events
, -1);
617 DBG("[notification-thread] Poll wait returned (%i)", ret
);
621 * Restart interrupted system call.
623 if (errno
== EINTR
) {
626 ERR("[notification-thread] Error encountered during lttng_poll_wait (%i)", ret
);
631 for (i
= 0; i
< fd_count
; i
++) {
632 int fd
= LTTNG_POLL_GETFD(&state
.events
, i
);
633 uint32_t revents
= LTTNG_POLL_GETEV(&state
.events
, i
);
638 DBG("[notification-thread] Handling fd (%i) activity (%u)", fd
, revents
);
640 if (fd
== state
.notification_channel_socket
) {
641 if (revents
& LPOLLIN
) {
642 ret
= handle_notification_thread_client_connect(
648 (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
649 ERR("[notification-thread] Notification socket poll error");
652 ERR("[notification-thread] Unexpected poll events %u for notification socket %i", revents
, fd
);
655 } else if (fd
== handle
->cmd_queue
.event_fd
) {
656 ret
= handle_notification_thread_command(handle
,
659 DBG("[notification-thread] Error encountered while servicing command queue");
661 } else if (ret
> 0) {
664 } else if (fd
== handle
->channel_monitoring_pipes
.ust32_consumer
||
665 fd
== handle
->channel_monitoring_pipes
.ust64_consumer
||
666 fd
== handle
->channel_monitoring_pipes
.kernel_consumer
) {
667 ret
= handle_channel_monitoring_pipe(fd
,
668 revents
, handle
, &state
);
673 /* Activity on a client's socket. */
674 if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
676 * It doesn't matter if a command was
677 * pending on the client socket at this
678 * point since it now has no way to
679 * receive the notifications to which
680 * it was subscribing or unsubscribing.
682 ret
= handle_notification_thread_client_disconnect(
688 if (revents
& LPOLLIN
) {
689 ret
= handle_notification_thread_client_in(
696 if (revents
& LPOLLOUT
) {
697 ret
= handle_notification_thread_client_out(
709 fini_thread_state(&state
);
710 health_unregister(health_sessiond
);
711 rcu_thread_offline();
712 rcu_unregister_thread();