Cleanup: reuse `lttng_action_type_string()` to print action names
[lttng-tools.git] / src / bin / lttng-sessiond / action-executor.c
CommitLineData
f2b3ef9f
JG
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>
2af3b9c9 19#include <lttng/action/notify-internal.h>
f2b3ef9f
JG
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>
e393070a 26#include <lttng/condition/on-event-internal.h>
f2b3ef9f
JG
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
37struct 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
46struct 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 */
63typedef int (*action_executor_handler)(struct action_executor *executor,
64 const struct action_work_item *,
65 const struct lttng_action *action);
66
67static int action_executor_notify_handler(struct action_executor *executor,
68 const struct action_work_item *,
69 const struct lttng_action *);
70static int action_executor_start_session_handler(struct action_executor *executor,
71 const struct action_work_item *,
72 const struct lttng_action *);
73static int action_executor_stop_session_handler(struct action_executor *executor,
74 const struct action_work_item *,
75 const struct lttng_action *);
76static int action_executor_rotate_session_handler(struct action_executor *executor,
77 const struct action_work_item *,
78 const struct lttng_action *);
79static int action_executor_snapshot_session_handler(struct action_executor *executor,
80 const struct action_work_item *,
81 const struct lttng_action *);
82static int action_executor_group_handler(struct action_executor *executor,
83 const struct action_work_item *,
84 const struct lttng_action *);
85static int action_executor_generic_handler(struct action_executor *executor,
86 const struct action_work_item *,
87 const struct lttng_action *);
88
89static 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
f2b3ef9f
JG
98static const char *get_action_name(const struct lttng_action *action)
99{
0e43bcbf
JG
100 const enum lttng_action_type action_type = lttng_action_get_type(action);
101
102 assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
103
c0e2990d 104 return lttng_action_type_string(action_type);
f2b3ef9f
JG
105}
106
107/* Check if this trigger allowed to interect with a given session. */
108static 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 = {
ff588497
JR
113 .uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
114 .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
f2b3ef9f
JG
115 };
116 /* Can never be NULL. */
117 const struct lttng_credentials *trigger_creds =
118 lttng_trigger_get_credentials(trigger);
119
ff588497
JR
120 is_allowed = (lttng_credentials_is_equal_uid(trigger_creds, &session_creds)) ||
121 (lttng_credentials_get_uid(trigger_creds) == 0);
f2b3ef9f 122 if (!is_allowed) {
ff588497 123 WARN("Trigger is not allowed to interact with session `%s`: session uid = %ld, session gid = %ld, trigger uid = %ld",
f2b3ef9f
JG
124 session->name,
125 (long int) session->uid,
126 (long int) session->gid,
ff588497 127 (long int) lttng_credentials_get_uid(trigger_creds));
f2b3ef9f
JG
128 }
129
130 return is_allowed;
131}
132
34f87583
JR
133static 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
f2b3ef9f
JG
144static 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
f2b3ef9f
JG
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);
f2b3ef9f
JG
166 break;
167 default:
168 ERR("Fatal error encoutered while sending notification to client, client_id = %" PRIu64,
169 client->id);
f2b3ef9f
JG
170 ret = -1;
171 goto end;
172 }
173
174 if (!update_communication) {
175 goto end;
176 }
177
6c24d3fd 178 /* Safe to read client's id without locking as it is immutable. */
f2b3ef9f
JG
179 ret = notification_thread_client_communication_update(
180 executor->notification_thread_handle, client->id,
181 status);
182end:
183 return ret;
184}
185
186static 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,
52d55cf9 191 work_item->trigger,
f2b3ef9f 192 work_item->evaluation,
c203f058
JR
193 work_item->object_creds.is_set ?
194 &(work_item->object_creds.value) :
195 NULL,
64eafdf6 196 client_handle_transmission_status, executor);
f2b3ef9f
JG
197}
198
199static 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) {
34f87583 221 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
f2b3ef9f 222 session_name, get_action_name(action),
34f87583 223 get_trigger_name(work_item->trigger));
f2b3ef9f
JG
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:
34f87583
JR
235 DBG("Successfully started session `%s` on behalf of trigger `%s`",
236 session_name, get_trigger_name(work_item->trigger));
f2b3ef9f
JG
237 break;
238 case LTTNG_ERR_TRACE_ALREADY_STARTED:
34f87583
JR
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));
f2b3ef9f
JG
241 break;
242 default:
34f87583
JR
243 WARN("Failed to start session `%s` on behalf of trigger `%s`: %s",
244 session_name, get_trigger_name(work_item->trigger),
f2b3ef9f
JG
245 lttng_strerror(-cmd_ret));
246 break;
247 }
248
249error_dispose_session:
250 session_unlock(session);
251 session_put(session);
252error_unlock_list:
253 session_unlock_list();
254end:
255 return ret;
256}
257
258static 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) {
34f87583 280 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
f2b3ef9f 281 session_name, get_action_name(action),
34f87583 282 get_trigger_name(work_item->trigger));
f2b3ef9f
JG
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:
34f87583
JR
294 DBG("Successfully stopped session `%s` on behalf of trigger `%s`",
295 session_name, get_trigger_name(work_item->trigger));
f2b3ef9f
JG
296 break;
297 case LTTNG_ERR_TRACE_ALREADY_STOPPED:
34f87583
JR
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));
f2b3ef9f
JG
300 break;
301 default:
34f87583
JR
302 WARN("Failed to stop session `%s` on behalf of trigger `%s`: %s",
303 session_name, get_trigger_name(work_item->trigger),
f2b3ef9f
JG
304 lttng_strerror(-cmd_ret));
305 break;
306 }
307
308error_dispose_session:
309 session_unlock(session);
310 session_put(session);
311error_unlock_list:
312 session_unlock_list();
313end:
314 return ret;
315}
316
317static 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) {
34f87583 339 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
f2b3ef9f 340 session_name, get_action_name(action),
34f87583 341 get_trigger_name(work_item->trigger));
f2b3ef9f
JG
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:
34f87583
JR
354 DBG("Successfully started rotation of session `%s` on behalf of trigger `%s`",
355 session_name, get_trigger_name(work_item->trigger));
f2b3ef9f
JG
356 break;
357 case LTTNG_ERR_ROTATION_PENDING:
34f87583
JR
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));
f2b3ef9f
JG
360 break;
361 case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP:
362 case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR:
34f87583
JR
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));
f2b3ef9f
JG
365 break;
366 default:
34f87583
JR
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),
f2b3ef9f
JG
369 lttng_strerror(-cmd_ret));
370 break;
371 }
372
373error_dispose_session:
374 session_unlock(session);
375 session_put(session);
376error_unlock_list:
377 session_unlock_list();
378end:
379 return ret;
380}
381
382static 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) {
ca46af4e 419 DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
f2b3ef9f 420 session_name, get_action_name(action),
ca46af4e 421 get_trigger_name(work_item->trigger));
f2b3ef9f
JG
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:
34f87583
JR
434 DBG("Successfully recorded snapshot of session `%s` on behalf of trigger `%s`",
435 session_name, get_trigger_name(work_item->trigger));
f2b3ef9f
JG
436 break;
437 default:
34f87583
JR
438 WARN("Failed to record snapshot of session `%s` on behalf of trigger `%s`: %s",
439 session_name, get_trigger_name(work_item->trigger),
f2b3ef9f
JG
440 lttng_strerror(-cmd_ret));
441 break;
442 }
443
444error_dispose_session:
445 session_unlock(session);
446 session_put(session);
447error_unlock_list:
448 session_unlock_list();
449end:
450 return ret;
451}
452
453static 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) {
34f87583
JR
478 ERR("Stopping the execution of the action group of trigger `%s` following a fatal error",
479 get_trigger_name(work_item->trigger));
f2b3ef9f
JG
480 goto end;
481 }
482 }
483end:
484 return ret;
485}
486
487static int action_executor_generic_handler(struct action_executor *executor,
488 const struct action_work_item *work_item,
489 const struct lttng_action *action)
490{
0e43bcbf
JG
491 const enum lttng_action_type action_type = lttng_action_get_type(action);
492
493 assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
494
2516f2d8 495 DBG("Executing action `%s` of trigger `%s` action work item %" PRIu64,
f2b3ef9f 496 get_action_name(action),
34f87583 497 get_trigger_name(work_item->trigger),
f2b3ef9f
JG
498 work_item->id);
499
0e43bcbf 500 return action_executors[action_type](
f2b3ef9f
JG
501 executor, work_item, action);
502}
503
504static 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
34f87583
JR
511 DBG("Starting execution of action work item %" PRIu64 " of trigger `%s`",
512 work_item->id, get_trigger_name(work_item->trigger));
f2b3ef9f 513 ret = action_executor_generic_handler(executor, work_item, action);
34f87583
JR
514 DBG("Completed execution of action work item %" PRIu64 " of trigger `%s`",
515 work_item->id, get_trigger_name(work_item->trigger));
f2b3ef9f
JG
516 return ret;
517}
518
519static 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
527static void *action_executor_thread(void *_data)
528{
529 struct action_executor *executor = _data;
530
531 assert(executor);
532
412d7227
SM
533 health_register(the_health_sessiond,
534 HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR);
f2b3ef9f
JG
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
0db0f8e0 556 /* Pop item from front of the list with work lock held. */
f2b3ef9f
JG
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
f5f5c54d
JG
578 if (executor->should_quit) {
579 pthread_mutex_unlock(&executor->work.lock);
580 }
f2b3ef9f
JG
581 DBG("Left work execution loop");
582
583 health_code_update();
584
585 rcu_thread_offline();
586 rcu_unregister_thread();
412d7227 587 health_unregister(the_health_sessiond);
f2b3ef9f
JG
588
589 return NULL;
590}
591
592static bool shutdown_action_executor_thread(void *_data)
593{
594 struct action_executor *executor = _data;
595
8db3acaf 596 pthread_mutex_lock(&executor->work.lock);
f2b3ef9f
JG
597 executor->should_quit = true;
598 pthread_cond_signal(&executor->work.cond);
8db3acaf 599 pthread_mutex_unlock(&executor->work.lock);
f2b3ef9f
JG
600 return true;
601}
602
603static 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
614struct 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);
631end:
632 return executor;
633}
634
635void 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
34f87583
JR
653 " associated to trigger `%s`",
654 work_item->id, get_trigger_name(work_item->trigger));
f2b3ef9f
JG
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. */
663enum 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. */
34f87583
JR
679 DBG("Refusing to enqueue action for trigger `%s` as work item %" PRIu64
680 " (overflow)", get_trigger_name(trigger), work_item_id);
f2b3ef9f
JG
681 executor_status = ACTION_EXECUTOR_STATUS_OVERFLOW;
682 goto error_unlock;
683 }
684
685 work_item = zmalloc(sizeof(*work_item));
686 if (!work_item) {
2516f2d8 687 PERROR("Failed to allocate action executor work item on behalf of trigger `%s`",
34f87583 688 get_trigger_name(trigger));
f2b3ef9f
JG
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++;
2516f2d8 718 DBG("Enqueued action for trigger `%s` as work item #%" PRIu64,
34f87583 719 get_trigger_name(trigger), work_item_id);
f2b3ef9f
JG
720 signal = true;
721
722error_unlock:
f2b3ef9f
JG
723 if (signal) {
724 pthread_cond_signal(&executor->work.cond);
725 }
8db3acaf 726 pthread_mutex_unlock(&executor->work.lock);
f2b3ef9f
JG
727
728 lttng_evaluation_destroy(evaluation);
729 return executor_status;
730}
This page took 0.0875010000000001 seconds and 4 git commands to generate.