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