8df560e0fb1b69d07753db639e15b8ab38413dac
[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/event-rule-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 *action_type_names[] = {
99 [LTTNG_ACTION_TYPE_NOTIFY] = "Notify",
100 [LTTNG_ACTION_TYPE_START_SESSION] = "Start session",
101 [LTTNG_ACTION_TYPE_STOP_SESSION] = "Stop session",
102 [LTTNG_ACTION_TYPE_ROTATE_SESSION] = "Rotate session",
103 [LTTNG_ACTION_TYPE_SNAPSHOT_SESSION] = "Snapshot session",
104 [LTTNG_ACTION_TYPE_GROUP] = "Group",
105 };
106
107 static const char *get_action_name(const struct lttng_action *action)
108 {
109 return action_type_names[lttng_action_get_type(action)];
110 }
111
112 /* Check if this trigger allowed to interect with a given session. */
113 static bool is_trigger_allowed_for_session(const struct lttng_trigger *trigger,
114 struct ltt_session *session)
115 {
116 bool is_allowed = false;
117 const struct lttng_credentials session_creds = {
118 .uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
119 .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
120 };
121 /* Can never be NULL. */
122 const struct lttng_credentials *trigger_creds =
123 lttng_trigger_get_credentials(trigger);
124
125 is_allowed = (lttng_credentials_is_equal_uid(trigger_creds, &session_creds)) ||
126 (lttng_credentials_get_uid(trigger_creds) == 0);
127 if (!is_allowed) {
128 WARN("Trigger is not allowed to interact with session `%s`: session uid = %ld, session gid = %ld, trigger uid = %ld",
129 session->name,
130 (long int) session->uid,
131 (long int) session->gid,
132 (long int) lttng_credentials_get_uid(trigger_creds));
133 }
134
135 return is_allowed;
136 }
137
138 static const char *get_trigger_name(const struct lttng_trigger *trigger)
139 {
140 const char *trigger_name;
141 enum lttng_trigger_status trigger_status;
142
143 trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
144 assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
145
146 return trigger_name;
147 }
148
149 static int client_handle_transmission_status(
150 struct notification_client *client,
151 enum client_transmission_status status,
152 void *user_data)
153 {
154 int ret = 0;
155 struct action_executor *executor = user_data;
156 bool update_communication = true;
157
158 switch (status) {
159 case CLIENT_TRANSMISSION_STATUS_COMPLETE:
160 DBG("Successfully sent full notification to client, client_id = %" PRIu64,
161 client->id);
162 update_communication = false;
163 break;
164 case CLIENT_TRANSMISSION_STATUS_QUEUED:
165 DBG("Queued notification in client outgoing buffer, client_id = %" PRIu64,
166 client->id);
167 break;
168 case CLIENT_TRANSMISSION_STATUS_FAIL:
169 DBG("Communication error occurred while sending notification to client, client_id = %" PRIu64,
170 client->id);
171 break;
172 default:
173 ERR("Fatal error encoutered while sending notification to client, client_id = %" PRIu64,
174 client->id);
175 ret = -1;
176 goto end;
177 }
178
179 if (!update_communication) {
180 goto end;
181 }
182
183 /* Safe to read client's id without locking as it is immutable. */
184 ret = notification_thread_client_communication_update(
185 executor->notification_thread_handle, client->id,
186 status);
187 end:
188 return ret;
189 }
190
191 static int action_executor_notify_handler(struct action_executor *executor,
192 const struct action_work_item *work_item,
193 const struct lttng_action *action)
194 {
195 return notification_client_list_send_evaluation(work_item->client_list,
196 lttng_trigger_get_const_condition(work_item->trigger),
197 work_item->evaluation,
198 lttng_trigger_get_credentials(work_item->trigger),
199 work_item->object_creds.is_set ?
200 &(work_item->object_creds.value) :
201 NULL,
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 DBG("Executing action `%s` of trigger `%s` action work item %" PRIu64,
498 get_action_name(action),
499 get_trigger_name(work_item->trigger),
500 work_item->id);
501
502 return action_executors[lttng_action_get_type(action)](
503 executor, work_item, action);
504 }
505
506 static int action_work_item_execute(struct action_executor *executor,
507 struct action_work_item *work_item)
508 {
509 int ret;
510 const struct lttng_action *action =
511 lttng_trigger_get_const_action(work_item->trigger);
512
513 DBG("Starting execution of action work item %" PRIu64 " of trigger `%s`",
514 work_item->id, get_trigger_name(work_item->trigger));
515 ret = action_executor_generic_handler(executor, work_item, action);
516 DBG("Completed execution of action work item %" PRIu64 " of trigger `%s`",
517 work_item->id, get_trigger_name(work_item->trigger));
518 return ret;
519 }
520
521 static void action_work_item_destroy(struct action_work_item *work_item)
522 {
523 lttng_trigger_put(work_item->trigger);
524 lttng_evaluation_destroy(work_item->evaluation);
525 notification_client_list_put(work_item->client_list);
526 free(work_item);
527 }
528
529 static void *action_executor_thread(void *_data)
530 {
531 struct action_executor *executor = _data;
532
533 assert(executor);
534
535 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR);
536
537 rcu_register_thread();
538 rcu_thread_online();
539
540 DBG("Entering work execution loop");
541 pthread_mutex_lock(&executor->work.lock);
542 while (!executor->should_quit) {
543 int ret;
544 struct action_work_item *work_item;
545
546 health_code_update();
547 if (executor->work.pending_count == 0) {
548 health_poll_entry();
549 DBG("No work items enqueued, entering wait");
550 pthread_cond_wait(&executor->work.cond,
551 &executor->work.lock);
552 DBG("Woke-up from wait");
553 health_poll_exit();
554 continue;
555 }
556
557 /* Pop item from front of the list with work lock held. */
558 work_item = cds_list_first_entry(&executor->work.list,
559 struct action_work_item, list_node);
560 cds_list_del(&work_item->list_node);
561 executor->work.pending_count--;
562
563 /*
564 * Work can be performed without holding the work lock,
565 * allowing new items to be queued.
566 */
567 pthread_mutex_unlock(&executor->work.lock);
568 ret = action_work_item_execute(executor, work_item);
569 action_work_item_destroy(work_item);
570 if (ret) {
571 /* Fatal error. */
572 break;
573 }
574
575 health_code_update();
576 pthread_mutex_lock(&executor->work.lock);
577 }
578
579 if (executor->should_quit) {
580 pthread_mutex_unlock(&executor->work.lock);
581 }
582 DBG("Left work execution loop");
583
584 health_code_update();
585
586 rcu_thread_offline();
587 rcu_unregister_thread();
588 health_unregister(health_sessiond);
589
590 return NULL;
591 }
592
593 static bool shutdown_action_executor_thread(void *_data)
594 {
595 struct action_executor *executor = _data;
596
597 executor->should_quit = true;
598 pthread_cond_signal(&executor->work.cond);
599 return true;
600 }
601
602 static void clean_up_action_executor_thread(void *_data)
603 {
604 struct action_executor *executor = _data;
605
606 assert(cds_list_empty(&executor->work.list));
607
608 pthread_mutex_destroy(&executor->work.lock);
609 pthread_cond_destroy(&executor->work.cond);
610 free(executor);
611 }
612
613 struct action_executor *action_executor_create(
614 struct notification_thread_handle *handle)
615 {
616 struct action_executor *executor = zmalloc(sizeof(*executor));
617
618 if (!executor) {
619 goto end;
620 }
621
622 CDS_INIT_LIST_HEAD(&executor->work.list);
623 pthread_cond_init(&executor->work.cond, NULL);
624 pthread_mutex_init(&executor->work.lock, NULL);
625 executor->notification_thread_handle = handle;
626
627 executor->thread = lttng_thread_create(THREAD_NAME,
628 action_executor_thread, shutdown_action_executor_thread,
629 clean_up_action_executor_thread, executor);
630 end:
631 return executor;
632 }
633
634 void action_executor_destroy(struct action_executor *executor)
635 {
636 struct action_work_item *work_item, *tmp;
637
638 /* TODO Wait for work list to drain? */
639 lttng_thread_shutdown(executor->thread);
640 pthread_mutex_lock(&executor->work.lock);
641 if (executor->work.pending_count != 0) {
642 WARN("%" PRIu64
643 " trigger action%s still queued for execution and will be discarded",
644 executor->work.pending_count,
645 executor->work.pending_count == 1 ? " is" :
646 "s are");
647 }
648
649 cds_list_for_each_entry_safe (
650 work_item, tmp, &executor->work.list, list_node) {
651 WARN("Discarding action work item %" PRIu64
652 " associated to trigger `%s`",
653 work_item->id, get_trigger_name(work_item->trigger));
654 cds_list_del(&work_item->list_node);
655 action_work_item_destroy(work_item);
656 }
657 pthread_mutex_unlock(&executor->work.lock);
658 lttng_thread_put(executor->thread);
659 }
660
661 /* RCU read-lock must be held by the caller. */
662 enum action_executor_status action_executor_enqueue(
663 struct action_executor *executor,
664 struct lttng_trigger *trigger,
665 struct lttng_evaluation *evaluation,
666 const struct lttng_credentials *object_creds,
667 struct notification_client_list *client_list)
668 {
669 enum action_executor_status executor_status = ACTION_EXECUTOR_STATUS_OK;
670 const uint64_t work_item_id = executor->next_work_item_id++;
671 struct action_work_item *work_item;
672 bool signal = false;
673
674 pthread_mutex_lock(&executor->work.lock);
675 /* Check for queue overflow. */
676 if (executor->work.pending_count >= MAX_QUEUED_WORK_COUNT) {
677 /* Most likely spammy, remove if it is the case. */
678 DBG("Refusing to enqueue action for trigger `%s` as work item %" PRIu64
679 " (overflow)",
680 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 `%p`",
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 `%p` as work item %" PRIu64,
719 get_trigger_name(trigger), work_item_id);
720 signal = true;
721
722 error_unlock:
723 pthread_mutex_unlock(&executor->work.lock);
724 if (signal) {
725 pthread_cond_signal(&executor->work.cond);
726 }
727
728 lttng_evaluation_destroy(evaluation);
729 return executor_status;
730 }
This page took 0.074331 seconds and 5 git commands to generate.