2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include <common/buffer-view.h>
10 #include <common/dynamic-buffer.h>
11 #include <common/error.h>
12 #include <common/macros.h>
13 #include <common/payload-view.h>
14 #include <common/payload.h>
16 #include <lttng/action/firing-policy-internal.h>
17 #include <lttng/action/firing-policy.h>
19 #include <sys/types.h>
21 #define IS_EVERY_N_FIRING_POLICY(policy) \
22 (lttng_firing_policy_get_type(policy) == \
23 LTTNG_FIRING_POLICY_TYPE_EVERY_N)
25 #define IS_ONCE_AFTER_N_FIRING_POLICY(policy) \
26 (lttng_firing_policy_get_type(policy) == \
27 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N)
29 typedef void (*firing_policy_destroy_cb
)(
30 struct lttng_firing_policy
*firing_policy
);
31 typedef int (*firing_policy_serialize_cb
)(
32 struct lttng_firing_policy
*firing_policy
,
33 struct lttng_payload
*payload
);
34 typedef bool (*firing_policy_equal_cb
)(const struct lttng_firing_policy
*a
,
35 const struct lttng_firing_policy
*b
);
36 typedef ssize_t (*firing_policy_create_from_payload_cb
)(
37 struct lttng_payload_view
*view
,
38 struct lttng_firing_policy
**firing_policy
);
39 typedef struct lttng_firing_policy
*(*firing_policy_copy_cb
)(
40 const struct lttng_firing_policy
*source
);
42 struct lttng_firing_policy
{
43 enum lttng_firing_policy_type type
;
44 firing_policy_serialize_cb serialize
;
45 firing_policy_equal_cb equal
;
46 firing_policy_destroy_cb destroy
;
47 firing_policy_copy_cb copy
;
50 struct lttng_firing_policy_every_n
{
51 struct lttng_firing_policy parent
;
55 struct lttng_firing_policy_once_after_n
{
56 struct lttng_firing_policy parent
;
60 struct lttng_firing_policy_comm
{
61 /* enum lttng_firing_policy_type */
62 int8_t firing_policy_type
;
65 struct lttng_firing_policy_once_after_n_comm
{
69 struct lttng_firing_policy_every_n_comm
{
73 /* Forward declaration. */
74 static void lttng_firing_policy_init(struct lttng_firing_policy
*firing_policy
,
75 enum lttng_firing_policy_type type
,
76 firing_policy_serialize_cb serialize
,
77 firing_policy_equal_cb equal
,
78 firing_policy_destroy_cb destroy
,
79 firing_policy_copy_cb copy
);
82 const char *lttng_firing_policy_type_string(
83 enum lttng_firing_policy_type firing_policy_type
)
85 switch (firing_policy_type
) {
86 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
88 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
89 return "ONCE-AFTER-N";
95 enum lttng_firing_policy_type
lttng_firing_policy_get_type(
96 const struct lttng_firing_policy
*policy
)
98 return policy
? policy
->type
: LTTNG_FIRING_POLICY_TYPE_UNKNOWN
;
102 void lttng_firing_policy_init(struct lttng_firing_policy
*firing_policy
,
103 enum lttng_firing_policy_type type
,
104 firing_policy_serialize_cb serialize
,
105 firing_policy_equal_cb equal
,
106 firing_policy_destroy_cb destroy
,
107 firing_policy_copy_cb copy
)
109 firing_policy
->type
= type
;
110 firing_policy
->serialize
= serialize
;
111 firing_policy
->equal
= equal
;
112 firing_policy
->destroy
= destroy
;
113 firing_policy
->copy
= copy
;
116 void lttng_firing_policy_destroy(struct lttng_firing_policy
*firing_policy
)
118 if (!firing_policy
) {
122 firing_policy
->destroy(firing_policy
);
126 int lttng_firing_policy_serialize(struct lttng_firing_policy
*firing_policy
,
127 struct lttng_payload
*payload
)
130 const struct lttng_firing_policy_comm firing_policy_comm
= {
131 .firing_policy_type
= (int8_t) firing_policy
->type
,
134 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &firing_policy_comm
,
135 sizeof(firing_policy_comm
));
140 ret
= firing_policy
->serialize(firing_policy
, payload
);
148 static ssize_t
lttng_firing_policy_once_after_n_create_from_payload(
149 struct lttng_payload_view
*view
,
150 struct lttng_firing_policy
**firing_policy
)
152 ssize_t consumed_len
= -1;
153 struct lttng_firing_policy
*policy
= NULL
;
154 const struct lttng_firing_policy_once_after_n_comm
*comm
;
155 const struct lttng_payload_view comm_view
=
156 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
158 if (!view
|| !firing_policy
) {
163 if (!lttng_payload_view_is_valid(&comm_view
)) {
164 /* Payload not large enough to contain the header. */
169 comm
= (const struct lttng_firing_policy_once_after_n_comm
*)
170 comm_view
.buffer
.data
;
172 policy
= lttng_firing_policy_once_after_n_create(comm
->threshold
);
173 if (policy
== NULL
) {
178 *firing_policy
= policy
;
179 consumed_len
= sizeof(*comm
);
185 static ssize_t
lttng_firing_policy_every_n_create_from_payload(
186 struct lttng_payload_view
*view
,
187 struct lttng_firing_policy
**firing_policy
)
189 ssize_t consumed_len
= -1;
190 struct lttng_firing_policy
*policy
= NULL
;
191 const struct lttng_firing_policy_every_n_comm
*comm
;
192 const struct lttng_payload_view comm_view
=
193 lttng_payload_view_from_view(view
, 0, sizeof(*comm
));
195 if (!view
|| !firing_policy
) {
200 if (!lttng_payload_view_is_valid(&comm_view
)) {
201 /* Payload not large enough to contain the header. */
206 comm
= (const struct lttng_firing_policy_every_n_comm
*)
207 comm_view
.buffer
.data
;
209 policy
= lttng_firing_policy_every_n_create(comm
->interval
);
210 if (policy
== NULL
) {
215 *firing_policy
= policy
;
216 consumed_len
= sizeof(*comm
);
223 ssize_t
lttng_firing_policy_create_from_payload(struct lttng_payload_view
*view
,
224 struct lttng_firing_policy
**firing_policy
)
226 ssize_t consumed_len
, specific_firing_policy_consumed_len
;
227 firing_policy_create_from_payload_cb create_from_payload_cb
;
228 const struct lttng_firing_policy_comm
*firing_policy_comm
;
229 const struct lttng_payload_view firing_policy_comm_view
=
230 lttng_payload_view_from_view(
231 view
, 0, sizeof(*firing_policy_comm
));
233 if (!view
|| !firing_policy
) {
238 if (!lttng_payload_view_is_valid(&firing_policy_comm_view
)) {
239 /* Payload not large enough to contain the header. */
245 (const struct lttng_firing_policy_comm
*)
246 firing_policy_comm_view
.buffer
.data
;
248 DBG("Create firing_policy from payload: firing-policy-type=%s",
249 lttng_firing_policy_type_string(
250 firing_policy_comm
->firing_policy_type
));
252 switch (firing_policy_comm
->firing_policy_type
) {
253 case LTTNG_FIRING_POLICY_TYPE_EVERY_N
:
254 create_from_payload_cb
=
255 lttng_firing_policy_every_n_create_from_payload
;
257 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
:
258 create_from_payload_cb
=
259 lttng_firing_policy_once_after_n_create_from_payload
;
262 ERR("Failed to create firing-policy from payload, unhandled firing-policy type: firing-policy-type=%u (%s)",
263 firing_policy_comm
->firing_policy_type
,
264 lttng_firing_policy_type_string(firing_policy_comm
->firing_policy_type
));
271 * Create buffer view for the firing_policy-type-specific data.
273 struct lttng_payload_view specific_firing_policy_view
=
274 lttng_payload_view_from_view(view
,
275 sizeof(struct lttng_firing_policy_comm
),
278 specific_firing_policy_consumed_len
= create_from_payload_cb(
279 &specific_firing_policy_view
, firing_policy
);
282 if (specific_firing_policy_consumed_len
< 0) {
283 ERR("Failed to create specific firing_policy from buffer");
288 assert(*firing_policy
);
290 consumed_len
= sizeof(struct lttng_firing_policy_comm
) +
291 specific_firing_policy_consumed_len
;
298 bool lttng_firing_policy_is_equal(const struct lttng_firing_policy
*a
,
299 const struct lttng_firing_policy
*b
)
301 bool is_equal
= false;
307 if (a
->type
!= b
->type
) {
317 is_equal
= a
->equal(a
, b
);
323 static const struct lttng_firing_policy_every_n
*
324 firing_policy_every_n_from_firing_policy_const(
325 const struct lttng_firing_policy
*policy
)
329 return container_of(policy
, const struct lttng_firing_policy_every_n
,
333 static int lttng_firing_policy_every_n_serialize(
334 struct lttng_firing_policy
*policy
,
335 struct lttng_payload
*payload
)
338 const struct lttng_firing_policy_every_n
*every_n_policy
;
339 struct lttng_firing_policy_every_n_comm comm
= {};
344 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
345 comm
.interval
= every_n_policy
->interval
;
347 ret
= lttng_dynamic_buffer_append(
348 &payload
->buffer
, &comm
, sizeof(comm
));
352 static bool lttng_firing_policy_every_n_is_equal(
353 const struct lttng_firing_policy
*_a
,
354 const struct lttng_firing_policy
*_b
)
356 bool is_equal
= false;
357 const struct lttng_firing_policy_every_n
*a
, *b
;
359 a
= firing_policy_every_n_from_firing_policy_const(_a
);
360 b
= firing_policy_every_n_from_firing_policy_const(_b
);
362 if (a
->interval
!= b
->interval
) {
372 static void lttng_firing_policy_every_n_destroy(
373 struct lttng_firing_policy
*policy
)
375 /* Nothing type-specific to release. */
379 static struct lttng_firing_policy
*lttng_firing_policy_every_n_copy(
380 const struct lttng_firing_policy
*source
)
382 struct lttng_firing_policy
*copy
= NULL
;
383 const struct lttng_firing_policy_every_n
*every_n_policy
;
389 every_n_policy
= firing_policy_every_n_from_firing_policy_const(source
);
390 copy
= lttng_firing_policy_every_n_create(
391 every_n_policy
->interval
);
398 struct lttng_firing_policy
*lttng_firing_policy_every_n_create(
401 struct lttng_firing_policy_every_n
*policy
= NULL
;
403 policy
= zmalloc(sizeof(struct lttng_firing_policy_every_n
));
408 lttng_firing_policy_init(&policy
->parent
,
409 LTTNG_FIRING_POLICY_TYPE_EVERY_N
,
410 lttng_firing_policy_every_n_serialize
,
411 lttng_firing_policy_every_n_is_equal
,
412 lttng_firing_policy_every_n_destroy
,
413 lttng_firing_policy_every_n_copy
);
415 policy
->interval
= interval
;
418 return policy
? &policy
->parent
: NULL
;
422 enum lttng_firing_policy_status
lttng_firing_policy_every_n_get_interval(
423 const struct lttng_firing_policy
*policy
, uint64_t *interval
)
425 const struct lttng_firing_policy_every_n
*every_n_policy
;
426 enum lttng_firing_policy_status status
;
428 if (!policy
|| !IS_EVERY_N_FIRING_POLICY(policy
) || !interval
) {
429 status
= LTTNG_FIRING_POLICY_STATUS_INVALID
;
433 every_n_policy
= firing_policy_every_n_from_firing_policy_const(policy
);
434 *interval
= every_n_policy
->interval
;
435 status
= LTTNG_FIRING_POLICY_STATUS_OK
;
443 static const struct lttng_firing_policy_once_after_n
*
444 firing_policy_once_after_n_from_firing_policy_const(
445 const struct lttng_firing_policy
*policy
)
449 return container_of(policy
, struct lttng_firing_policy_once_after_n
,
453 static int lttng_firing_policy_once_after_n_serialize(
454 struct lttng_firing_policy
*policy
,
455 struct lttng_payload
*payload
)
458 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
459 struct lttng_firing_policy_once_after_n_comm comm
= {};
464 once_after_n_policy
=
465 firing_policy_once_after_n_from_firing_policy_const(
467 comm
.threshold
= once_after_n_policy
->threshold
;
469 ret
= lttng_dynamic_buffer_append(
470 &payload
->buffer
, &comm
, sizeof(comm
));
474 static bool lttng_firing_policy_once_after_n_is_equal(
475 const struct lttng_firing_policy
*_a
,
476 const struct lttng_firing_policy
*_b
)
478 bool is_equal
= false;
479 const struct lttng_firing_policy_once_after_n
*a
, *b
;
481 a
= firing_policy_once_after_n_from_firing_policy_const(_a
);
482 b
= firing_policy_once_after_n_from_firing_policy_const(_b
);
484 if (a
->threshold
!= b
->threshold
) {
494 static void lttng_firing_policy_once_after_n_destroy(
495 struct lttng_firing_policy
*policy
)
497 /* Nothing type specific to release. */
501 static struct lttng_firing_policy
*lttng_firing_policy_once_after_n_copy(
502 const struct lttng_firing_policy
*source
)
504 struct lttng_firing_policy
*copy
= NULL
;
505 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
511 once_after_n_policy
=
512 firing_policy_once_after_n_from_firing_policy_const(
514 copy
= lttng_firing_policy_once_after_n_create(
515 once_after_n_policy
->threshold
);
522 struct lttng_firing_policy
*lttng_firing_policy_once_after_n_create(
525 struct lttng_firing_policy_once_after_n
*policy
= NULL
;
527 policy
= zmalloc(sizeof(struct lttng_firing_policy_once_after_n
));
532 lttng_firing_policy_init(&policy
->parent
,
533 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N
,
534 lttng_firing_policy_once_after_n_serialize
,
535 lttng_firing_policy_once_after_n_is_equal
,
536 lttng_firing_policy_once_after_n_destroy
,
537 lttng_firing_policy_once_after_n_copy
);
539 policy
->threshold
= threshold
;
542 return policy
? &policy
->parent
: NULL
;
546 enum lttng_firing_policy_status
lttng_firing_policy_once_after_n_get_threshold(
547 const struct lttng_firing_policy
*policy
, uint64_t *threshold
)
549 const struct lttng_firing_policy_once_after_n
*once_after_n_policy
;
550 enum lttng_firing_policy_status status
;
552 if (!policy
|| !IS_ONCE_AFTER_N_FIRING_POLICY(policy
) || !threshold
) {
553 status
= LTTNG_FIRING_POLICY_STATUS_INVALID
;
557 once_after_n_policy
=
558 firing_policy_once_after_n_from_firing_policy_const(
560 *threshold
= once_after_n_policy
->threshold
;
561 status
= LTTNG_FIRING_POLICY_STATUS_OK
;
568 struct lttng_firing_policy
*lttng_firing_policy_copy(
569 const struct lttng_firing_policy
*source
)
571 assert(source
->copy
);
572 return source
->copy(source
);