bce7268e5bac05ccf695f5415d06447f2df1ee41
[lttng-tools.git] / src / bin / lttng-sessiond / action-executor.c
1 /*
2 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "action-executor.h"
9 #include "cmd.h"
10 #include "health-sessiond.h"
11 #include "lttng-sessiond.h"
12 #include "notification-thread-internal.h"
13 #include "session.h"
14 #include "thread.h"
15 #include <common/macros.h>
16 #include <common/optional.h>
17 #include <lttng/action/action-internal.h>
18 #include <lttng/action/group.h>
19 #include <lttng/action/notify-internal.h>
20 #include <lttng/action/notify.h>
21 #include <lttng/action/rotate-session.h>
22 #include <lttng/action/snapshot-session.h>
23 #include <lttng/action/start-session.h>
24 #include <lttng/action/stop-session.h>
25 #include <lttng/condition/evaluation.h>
26 #include <lttng/condition/on-event-internal.h>
27 #include <lttng/lttng-error.h>
28 #include <lttng/trigger/trigger-internal.h>
29 #include <pthread.h>
30 #include <stdbool.h>
31 #include <stddef.h>
32 #include <urcu/list.h>
33
34 #define THREAD_NAME "Action Executor"
35 #define MAX_QUEUED_WORK_COUNT 8192
36
37 struct action_work_item {
38 uint64_t id;
39 struct lttng_trigger *trigger;
40 struct lttng_evaluation *evaluation;
41 struct notification_client_list *client_list;
42 LTTNG_OPTIONAL(struct lttng_credentials) object_creds;
43 struct cds_list_head list_node;
44 };
45
46 struct action_executor {
47 struct lttng_thread *thread;
48 struct notification_thread_handle *notification_thread_handle;
49 struct {
50 uint64_t pending_count;
51 struct cds_list_head list;
52 pthread_cond_t cond;
53 pthread_mutex_t lock;
54 } work;
55 bool should_quit;
56 uint64_t next_work_item_id;
57 };
58
59 /*
60 * Only return non-zero on a fatal error that should shut down the action
61 * executor.
62 */
63 typedef int (*action_executor_handler)(struct action_executor *executor,
64 const struct action_work_item *,
65 const struct lttng_action *action);
66
67 static int action_executor_notify_handler(struct action_executor *executor,
68 const struct action_work_item *,
69 const struct lttng_action *);
70 static int action_executor_start_session_handler(struct action_executor *executor,
71 const struct action_work_item *,
72 const struct lttng_action *);
73 static int action_executor_stop_session_handler(struct action_executor *executor,
74 const struct action_work_item *,
75 const struct lttng_action *);
76 static int action_executor_rotate_session_handler(struct action_executor *executor,
77 const struct action_work_item *,
78 const struct lttng_action *);
79 static int action_executor_snapshot_session_handler(struct action_executor *executor,
80 const struct action_work_item *,
81 const struct lttng_action *);
82 static int action_executor_group_handler(struct action_executor *executor,
83 const struct action_work_item *,
84 const struct lttng_action *);
85 static int action_executor_generic_handler(struct action_executor *executor,
86 const struct action_work_item *,
87 const struct lttng_action *);
88
89 static const action_executor_handler action_executors[] = {
90 [LTTNG_ACTION_TYPE_NOTIFY] = action_executor_notify_handler,
91 [LTTNG_ACTION_TYPE_START_SESSION] = action_executor_start_session_handler,
92 [LTTNG_ACTION_TYPE_STOP_SESSION] = action_executor_stop_session_handler,
93 [LTTNG_ACTION_TYPE_ROTATE_SESSION] = action_executor_rotate_session_handler,
94 [LTTNG_ACTION_TYPE_SNAPSHOT_SESSION] = action_executor_snapshot_session_handler,
95 [LTTNG_ACTION_TYPE_GROUP] = action_executor_group_handler,
96 };
97
98 static const char *get_action_name(const struct lttng_action *action)
99 {
100 const enum lttng_action_type action_type = lttng_action_get_type(action);
101
102 assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
103
104 return lttng_action_type_string(action_type);
105 }
106
107 /* Check if this trigger allowed to interect with a given session. */
108 static bool is_trigger_allowed_for_session(const struct lttng_trigger *trigger,
109 struct ltt_session *session)
110 {
111 bool is_allowed = false;
112 const struct lttng_credentials session_creds = {
113 .uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
114 .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
115 };
116 /* Can never be NULL. */
117 const struct lttng_credentials *trigger_creds =
118 lttng_trigger_get_credentials(trigger);
119
120 is_allowed = (lttng_credentials_is_equal_uid(trigger_creds, &session_creds)) ||
121 (lttng_credentials_get_uid(trigger_creds) == 0);
122 if (!is_allowed) {
123 WARN("Trigger is not allowed to interact with session `%s`: session uid = %ld, session gid = %ld, trigger uid = %ld",
124 session->name,
125 (long int) session->uid,
126 (long int) session->gid,
127 (long int) lttng_credentials_get_uid(trigger_creds));
128 }
129
130 return is_allowed;
131 }
132
133 static const char *get_trigger_name(const struct lttng_trigger *trigger)
134 {
135 const char *trigger_name;
136 enum lttng_trigger_status trigger_status;
137
138 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
139 assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
140
141 return trigger_name;
142 }
143
144 static int client_handle_transmission_status(
145 struct notification_client *client,
146 enum client_transmission_status status,
147 void *user_data)
148 {
149 int ret = 0;
150 struct action_executor *executor = user_data;
151 bool update_communication = true;
152
153 switch (status) {
154 case CLIENT_TRANSMISSION_STATUS_COMPLETE:
155 DBG("Successfully sent full notification to client, client_id = %" PRIu64,
156 client->id);
157 update_communication = false;
158 break;
159 case CLIENT_TRANSMISSION_STATUS_QUEUED:
160 DBG("Queued notification in client outgoing buffer, client_id = %" PRIu64,
161 client->id);
162 break;
163 case CLIENT_TRANSMISSION_STATUS_FAIL:
164 DBG("Communication error occurred while sending notification to client, client_id = %" PRIu64,
165 client->id);
166 break;
167 default:
168 ERR("Fatal error encoutered while sending notification to client, client_id = %" PRIu64,
169 client->id);
170 ret = -1;
171 goto end;
172 }
173
174 if (!update_communication) {
175 goto end;
176 }
177
178 /* Safe to read client's id without locking as it is immutable. */
179 ret = notification_thread_client_communication_update(
180 executor->notification_thread_handle, client->id,
181 status);
182 end:
183 return ret;
184 }
185
186 static int action_executor_notify_handler(struct action_executor *executor,
187 const struct action_work_item *work_item,
188 const struct lttng_action *action)
189 {
190 return notification_client_list_send_evaluation(work_item->client_list,
191 work_item->trigger,
192 work_item->evaluation,
193 work_item->object_creds.is_set ?
194 &(work_item->object_creds.value) :
195 NULL,
196 client_handle_transmission_status, executor);
197 }
198
199 static int action_executor_start_session_handler(struct action_executor *executor,
200 const struct action_work_item *work_item,
201 const struct lttng_action *action)
202 {
203 int ret = 0;
204 const char *session_name;
205 enum lttng_action_status action_status;
206 struct ltt_session *session;
207 enum lttng_error_code cmd_ret;
208
209 action_status = lttng_action_start_session_get_session_name(
210 action, &session_name);
211 if (action_status != LTTNG_ACTION_STATUS_OK) {
212 ERR("Failed to get session name from `%s` action",
213 get_action_name(action));
214 ret = -1;
215 goto end;
216 }
217
218 session_lock_list();
219 session = session_find_by_name(session_name);
220 if (!session) {
221 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
222 session_name, get_action_name(action),
223 get_trigger_name(work_item->trigger));
224 goto error_unlock_list;
225 }
226
227 session_lock(session);
228 if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
229 goto error_dispose_session;
230 }
231
232 cmd_ret = cmd_start_trace(session);
233 switch (cmd_ret) {
234 case LTTNG_OK:
235 DBG("Successfully started session `%s` on behalf of trigger `%s`",
236 session_name, get_trigger_name(work_item->trigger));
237 break;
238 case LTTNG_ERR_TRACE_ALREADY_STARTED:
239 DBG("Attempted to start session `%s` on behalf of trigger `%s` but it was already started",
240 session_name, get_trigger_name(work_item->trigger));
241 break;
242 default:
243 WARN("Failed to start session `%s` on behalf of trigger `%s`: %s",
244 session_name, get_trigger_name(work_item->trigger),
245 lttng_strerror(-cmd_ret));
246 break;
247 }
248
249 error_dispose_session:
250 session_unlock(session);
251 session_put(session);
252 error_unlock_list:
253 session_unlock_list();
254 end:
255 return ret;
256 }
257
258 static int action_executor_stop_session_handler(struct action_executor *executor,
259 const struct action_work_item *work_item,
260 const struct lttng_action *action)
261 {
262 int ret = 0;
263 const char *session_name;
264 enum lttng_action_status action_status;
265 struct ltt_session *session;
266 enum lttng_error_code cmd_ret;
267
268 action_status = lttng_action_stop_session_get_session_name(
269 action, &session_name);
270 if (action_status != LTTNG_ACTION_STATUS_OK) {
271 ERR("Failed to get session name from `%s` action",
272 get_action_name(action));
273 ret = -1;
274 goto end;
275 }
276
277 session_lock_list();
278 session = session_find_by_name(session_name);
279 if (!session) {
280 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
281 session_name, get_action_name(action),
282 get_trigger_name(work_item->trigger));
283 goto error_unlock_list;
284 }
285
286 session_lock(session);
287 if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
288 goto error_dispose_session;
289 }
290
291 cmd_ret = cmd_stop_trace(session);
292 switch (cmd_ret) {
293 case LTTNG_OK:
294 DBG("Successfully stopped session `%s` on behalf of trigger `%s`",
295 session_name, get_trigger_name(work_item->trigger));
296 break;
297 case LTTNG_ERR_TRACE_ALREADY_STOPPED:
298 DBG("Attempted to stop session `%s` on behalf of trigger `%s` but it was already stopped",
299 session_name, get_trigger_name(work_item->trigger));
300 break;
301 default:
302 WARN("Failed to stop session `%s` on behalf of trigger `%s`: %s",
303 session_name, get_trigger_name(work_item->trigger),
304 lttng_strerror(-cmd_ret));
305 break;
306 }
307
308 error_dispose_session:
309 session_unlock(session);
310 session_put(session);
311 error_unlock_list:
312 session_unlock_list();
313 end:
314 return ret;
315 }
316
317 static int action_executor_rotate_session_handler(struct action_executor *executor,
318 const struct action_work_item *work_item,
319 const struct lttng_action *action)
320 {
321 int ret = 0;
322 const char *session_name;
323 enum lttng_action_status action_status;
324 struct ltt_session *session;
325 enum lttng_error_code cmd_ret;
326
327 action_status = lttng_action_rotate_session_get_session_name(
328 action, &session_name);
329 if (action_status != LTTNG_ACTION_STATUS_OK) {
330 ERR("Failed to get session name from `%s` action",
331 get_action_name(action));
332 ret = -1;
333 goto end;
334 }
335
336 session_lock_list();
337 session = session_find_by_name(session_name);
338 if (!session) {
339 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
340 session_name, get_action_name(action),
341 get_trigger_name(work_item->trigger));
342 goto error_unlock_list;
343 }
344
345 session_lock(session);
346 if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
347 goto error_dispose_session;
348 }
349
350 cmd_ret = cmd_rotate_session(session, NULL, false,
351 LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED);
352 switch (cmd_ret) {
353 case LTTNG_OK:
354 DBG("Successfully started rotation of session `%s` on behalf of trigger `%s`",
355 session_name, get_trigger_name(work_item->trigger));
356 break;
357 case LTTNG_ERR_ROTATION_PENDING:
358 DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation is already ongoing",
359 session_name, get_trigger_name(work_item->trigger));
360 break;
361 case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP:
362 case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR:
363 DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation has already been completed since the last stop or clear",
364 session_name, get_trigger_name(work_item->trigger));
365 break;
366 default:
367 WARN("Failed to start a rotation of session `%s` on behalf of trigger `%s`: %s",
368 session_name, get_trigger_name(work_item->trigger),
369 lttng_strerror(-cmd_ret));
370 break;
371 }
372
373 error_dispose_session:
374 session_unlock(session);
375 session_put(session);
376 error_unlock_list:
377 session_unlock_list();
378 end:
379 return ret;
380 }
381
382 static int action_executor_snapshot_session_handler(struct action_executor *executor,
383 const struct action_work_item *work_item,
384 const struct lttng_action *action)
385 {
386 int ret = 0;
387 const char *session_name;
388 enum lttng_action_status action_status;
389 struct ltt_session *session;
390 const struct lttng_snapshot_output default_snapshot_output = {
391 .max_size = UINT64_MAX,
392 };
393 const struct lttng_snapshot_output *snapshot_output =
394 &default_snapshot_output;
395 enum lttng_error_code cmd_ret;
396
397 action_status = lttng_action_snapshot_session_get_session_name(
398 action, &session_name);
399 if (action_status != LTTNG_ACTION_STATUS_OK) {
400 ERR("Failed to get session name from `%s` action",
401 get_action_name(action));
402 ret = -1;
403 goto end;
404 }
405
406 action_status = lttng_action_snapshot_session_get_output(
407 action, &snapshot_output);
408 if (action_status != LTTNG_ACTION_STATUS_OK &&
409 action_status != LTTNG_ACTION_STATUS_UNSET) {
410 ERR("Failed to get output from `%s` action",
411 get_action_name(action));
412 ret = -1;
413 goto end;
414 }
415
416 session_lock_list();
417 session = session_find_by_name(session_name);
418 if (!session) {
419 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
420 session_name, get_action_name(action),
421 get_trigger_name(work_item->trigger));
422 goto error_unlock_list;
423 }
424
425
426 session_lock(session);
427 if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
428 goto error_dispose_session;
429 }
430
431 cmd_ret = cmd_snapshot_record(session, snapshot_output, 0);
432 switch (cmd_ret) {
433 case LTTNG_OK:
434 DBG("Successfully recorded snapshot of session `%s` on behalf of trigger `%s`",
435 session_name, get_trigger_name(work_item->trigger));
436 break;
437 default:
438 WARN("Failed to record snapshot of session `%s` on behalf of trigger `%s`: %s",
439 session_name, get_trigger_name(work_item->trigger),
440 lttng_strerror(-cmd_ret));
441 break;
442 }
443
444 error_dispose_session:
445 session_unlock(session);
446 session_put(session);
447 error_unlock_list:
448 session_unlock_list();
449 end:
450 return ret;
451 }
452
453 static int action_executor_group_handler(struct action_executor *executor,
454 const struct action_work_item *work_item,
455 const struct lttng_action *action_group)
456 {
457 int ret = 0;
458 unsigned int i, count;
459 enum lttng_action_status action_status;
460
461 action_status = lttng_action_group_get_count(action_group, &count);
462 if (action_status != LTTNG_ACTION_STATUS_OK) {
463 /* Fatal error. */
464 ERR("Failed to get count of action in action group");
465 ret = -1;
466 goto end;
467 }
468
469 DBG("Action group has %u action%s", count, count != 1 ? "s" : "");
470 for (i = 0; i < count; i++) {
471 const struct lttng_action *action =
472 lttng_action_group_get_at_index(
473 action_group, i);
474
475 ret = action_executor_generic_handler(
476 executor, work_item, action);
477 if (ret) {
478 ERR("Stopping the execution of the action group of trigger `%s` following a fatal error",
479 get_trigger_name(work_item->trigger));
480 goto end;
481 }
482 }
483 end:
484 return ret;
485 }
486
487 static int action_executor_generic_handler(struct action_executor *executor,
488 const struct action_work_item *work_item,
489 const struct lttng_action *action)
490 {
491 const enum lttng_action_type action_type = lttng_action_get_type(action);
492
493 assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
494
495 DBG("Executing action `%s` of trigger `%s` action work item %" PRIu64,
496 get_action_name(action),
497 get_trigger_name(work_item->trigger),
498 work_item->id);
499
500 return action_executors[action_type](
501 executor, work_item, action);
502 }
503
504 static int action_work_item_execute(struct action_executor *executor,
505 struct action_work_item *work_item)
506 {
507 int ret;
508 const struct lttng_action *action =
509 lttng_trigger_get_const_action(work_item->trigger);
510
511 DBG("Starting execution of action work item %" PRIu64 " of trigger `%s`",
512 work_item->id, get_trigger_name(work_item->trigger));
513 ret = action_executor_generic_handler(executor, work_item, action);
514 DBG("Completed execution of action work item %" PRIu64 " of trigger `%s`",
515 work_item->id, get_trigger_name(work_item->trigger));
516 return ret;
517 }
518
519 static void action_work_item_destroy(struct action_work_item *work_item)
520 {
521 lttng_trigger_put(work_item->trigger);
522 lttng_evaluation_destroy(work_item->evaluation);
523 notification_client_list_put(work_item->client_list);
524 free(work_item);
525 }
526
527 static void *action_executor_thread(void *_data)
528 {
529 struct action_executor *executor = _data;
530
531 assert(executor);
532
533 health_register(the_health_sessiond,
534 HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR);
535
536 rcu_register_thread();
537 rcu_thread_online();
538
539 DBG("Entering work execution loop");
540 pthread_mutex_lock(&executor->work.lock);
541 while (!executor->should_quit) {
542 int ret;
543 struct action_work_item *work_item;
544
545 health_code_update();
546 if (executor->work.pending_count == 0) {
547 health_poll_entry();
548 DBG("No work items enqueued, entering wait");
549 pthread_cond_wait(&executor->work.cond,
550 &executor->work.lock);
551 DBG("Woke-up from wait");
552 health_poll_exit();
553 continue;
554 }
555
556 /* Pop item from front of the list with work lock held. */
557 work_item = cds_list_first_entry(&executor->work.list,
558 struct action_work_item, list_node);
559 cds_list_del(&work_item->list_node);
560 executor->work.pending_count--;
561
562 /*
563 * Work can be performed without holding the work lock,
564 * allowing new items to be queued.
565 */
566 pthread_mutex_unlock(&executor->work.lock);
567 ret = action_work_item_execute(executor, work_item);
568 action_work_item_destroy(work_item);
569 if (ret) {
570 /* Fatal error. */
571 break;
572 }
573
574 health_code_update();
575 pthread_mutex_lock(&executor->work.lock);
576 }
577
578 if (executor->should_quit) {
579 pthread_mutex_unlock(&executor->work.lock);
580 }
581 DBG("Left work execution loop");
582
583 health_code_update();
584
585 rcu_thread_offline();
586 rcu_unregister_thread();
587 health_unregister(the_health_sessiond);
588
589 return NULL;
590 }
591
592 static bool shutdown_action_executor_thread(void *_data)
593 {
594 struct action_executor *executor = _data;
595
596 pthread_mutex_lock(&executor->work.lock);
597 executor->should_quit = true;
598 pthread_cond_signal(&executor->work.cond);
599 pthread_mutex_unlock(&executor->work.lock);
600 return true;
601 }
602
603 static void clean_up_action_executor_thread(void *_data)
604 {
605 struct action_executor *executor = _data;
606
607 assert(cds_list_empty(&executor->work.list));
608
609 pthread_mutex_destroy(&executor->work.lock);
610 pthread_cond_destroy(&executor->work.cond);
611 free(executor);
612 }
613
614 struct action_executor *action_executor_create(
615 struct notification_thread_handle *handle)
616 {
617 struct action_executor *executor = zmalloc(sizeof(*executor));
618
619 if (!executor) {
620 goto end;
621 }
622
623 CDS_INIT_LIST_HEAD(&executor->work.list);
624 pthread_cond_init(&executor->work.cond, NULL);
625 pthread_mutex_init(&executor->work.lock, NULL);
626 executor->notification_thread_handle = handle;
627
628 executor->thread = lttng_thread_create(THREAD_NAME,
629 action_executor_thread, shutdown_action_executor_thread,
630 clean_up_action_executor_thread, executor);
631 end:
632 return executor;
633 }
634
635 void action_executor_destroy(struct action_executor *executor)
636 {
637 struct action_work_item *work_item, *tmp;
638
639 /* TODO Wait for work list to drain? */
640 lttng_thread_shutdown(executor->thread);
641 pthread_mutex_lock(&executor->work.lock);
642 if (executor->work.pending_count != 0) {
643 WARN("%" PRIu64
644 " trigger action%s still queued for execution and will be discarded",
645 executor->work.pending_count,
646 executor->work.pending_count == 1 ? " is" :
647 "s are");
648 }
649
650 cds_list_for_each_entry_safe (
651 work_item, tmp, &executor->work.list, list_node) {
652 WARN("Discarding action work item %" PRIu64
653 " associated to trigger `%s`",
654 work_item->id, get_trigger_name(work_item->trigger));
655 cds_list_del(&work_item->list_node);
656 action_work_item_destroy(work_item);
657 }
658 pthread_mutex_unlock(&executor->work.lock);
659 lttng_thread_put(executor->thread);
660 }
661
662 /* RCU read-lock must be held by the caller. */
663 enum action_executor_status action_executor_enqueue(
664 struct action_executor *executor,
665 struct lttng_trigger *trigger,
666 struct lttng_evaluation *evaluation,
667 const struct lttng_credentials *object_creds,
668 struct notification_client_list *client_list)
669 {
670 enum action_executor_status executor_status = ACTION_EXECUTOR_STATUS_OK;
671 const uint64_t work_item_id = executor->next_work_item_id++;
672 struct action_work_item *work_item;
673 bool signal = false;
674
675 pthread_mutex_lock(&executor->work.lock);
676 /* Check for queue overflow. */
677 if (executor->work.pending_count >= MAX_QUEUED_WORK_COUNT) {
678 /* Most likely spammy, remove if it is the case. */
679 DBG("Refusing to enqueue action for trigger `%s` as work item %" PRIu64
680 " (overflow)", get_trigger_name(trigger), work_item_id);
681 executor_status = ACTION_EXECUTOR_STATUS_OVERFLOW;
682 goto error_unlock;
683 }
684
685 work_item = zmalloc(sizeof(*work_item));
686 if (!work_item) {
687 PERROR("Failed to allocate action executor work item on behalf of trigger `%s`",
688 get_trigger_name(trigger));
689 executor_status = ACTION_EXECUTOR_STATUS_ERROR;
690 goto error_unlock;
691 }
692
693 lttng_trigger_get(trigger);
694 if (client_list) {
695 const bool reference_acquired =
696 notification_client_list_get(client_list);
697
698 assert(reference_acquired);
699 }
700
701 *work_item = (typeof(*work_item)){
702 .id = work_item_id,
703 .trigger = trigger,
704 /* Ownership transferred to the work item. */
705 .evaluation = evaluation,
706 .object_creds = {
707 .is_set = !!object_creds,
708 .value = object_creds ? *object_creds :
709 (typeof(work_item->object_creds.value)) {},
710 },
711 .client_list = client_list,
712 .list_node = CDS_LIST_HEAD_INIT(work_item->list_node),
713 };
714
715 evaluation = NULL;
716 cds_list_add_tail(&work_item->list_node, &executor->work.list);
717 executor->work.pending_count++;
718 DBG("Enqueued action for trigger `%s` as work item #%" PRIu64,
719 get_trigger_name(trigger), work_item_id);
720 signal = true;
721
722 error_unlock:
723 if (signal) {
724 pthread_cond_signal(&executor->work.cond);
725 }
726 pthread_mutex_unlock(&executor->work.lock);
727
728 lttng_evaluation_destroy(evaluation);
729 return executor_status;
730 }
This page took 0.042135 seconds and 3 git commands to generate.