trigger: introduce refcounting
[lttng-tools.git] / src / common / trigger.c
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <lttng/trigger/trigger-internal.h>
9 #include <lttng/condition/condition-internal.h>
10 #include <lttng/action/action-internal.h>
11 #include <common/credentials.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <common/error.h>
15 #include <common/optional.h>
16 #include <assert.h>
17
18 LTTNG_HIDDEN
19 bool lttng_trigger_validate(struct lttng_trigger *trigger)
20 {
21 bool valid;
22
23 if (!trigger) {
24 valid = false;
25 goto end;
26 }
27
28 valid = lttng_condition_validate(trigger->condition) &&
29 lttng_action_validate(trigger->action);
30 end:
31 return valid;
32 }
33
34 struct lttng_trigger *lttng_trigger_create(
35 struct lttng_condition *condition,
36 struct lttng_action *action)
37 {
38 struct lttng_trigger *trigger = NULL;
39
40 if (!condition || !action) {
41 goto end;
42 }
43
44 trigger = zmalloc(sizeof(struct lttng_trigger));
45 if (!trigger) {
46 goto end;
47 }
48
49 urcu_ref_init(&trigger->ref);
50
51 lttng_condition_get(condition);
52 trigger->condition = condition;
53
54 lttng_action_get(action);
55 trigger->action = action;
56
57 end:
58 return trigger;
59 }
60
61 /*
62 * Note: the lack of reference counting 'get' on the condition object is normal.
63 * This API was exposed as such in 2.11. The client is not expected to call
64 * lttng_condition_destroy on the returned object.
65 */
66 struct lttng_condition *lttng_trigger_get_condition(
67 struct lttng_trigger *trigger)
68 {
69 return trigger ? trigger->condition : NULL;
70 }
71
72 LTTNG_HIDDEN
73 const struct lttng_condition *lttng_trigger_get_const_condition(
74 const struct lttng_trigger *trigger)
75 {
76 return trigger->condition;
77 }
78
79
80 /*
81 * Note: the lack of reference counting 'get' on the action object is normal.
82 * This API was exposed as such in 2.11. The client is not expected to call
83 * lttng_action_destroy on the returned object.
84 */
85 struct lttng_action *lttng_trigger_get_action(
86 struct lttng_trigger *trigger)
87 {
88 return trigger ? trigger->action : NULL;
89 }
90
91 LTTNG_HIDDEN
92 const struct lttng_action *lttng_trigger_get_const_action(
93 const struct lttng_trigger *trigger)
94 {
95 return trigger->action;
96 }
97
98 static void trigger_destroy_ref(struct urcu_ref *ref)
99 {
100 struct lttng_trigger *trigger =
101 container_of(ref, struct lttng_trigger, ref);
102 struct lttng_action *action = lttng_trigger_get_action(trigger);
103 struct lttng_condition *condition =
104 lttng_trigger_get_condition(trigger);
105
106 assert(action);
107 assert(condition);
108
109 /* Release ownership. */
110 lttng_action_put(action);
111 lttng_condition_put(condition);
112
113 free(trigger);
114 }
115
116 void lttng_trigger_destroy(struct lttng_trigger *trigger)
117 {
118 lttng_trigger_put(trigger);
119 }
120
121 LTTNG_HIDDEN
122 ssize_t lttng_trigger_create_from_payload(
123 struct lttng_payload_view *src_view,
124 struct lttng_trigger **trigger)
125 {
126 ssize_t ret, offset = 0, condition_size, action_size;
127 struct lttng_condition *condition = NULL;
128 struct lttng_action *action = NULL;
129 const struct lttng_trigger_comm *trigger_comm;
130
131 if (!src_view || !trigger) {
132 ret = -1;
133 goto end;
134 }
135
136 /* lttng_trigger_comm header */
137 trigger_comm = (typeof(trigger_comm)) src_view->buffer.data;
138 offset += sizeof(*trigger_comm);
139 {
140 /* struct lttng_condition */
141 struct lttng_payload_view condition_view =
142 lttng_payload_view_from_view(
143 src_view, offset, -1);
144
145 condition_size = lttng_condition_create_from_payload(&condition_view,
146 &condition);
147 }
148
149 if (condition_size < 0) {
150 ret = condition_size;
151 goto end;
152 }
153
154 offset += condition_size;
155 {
156 /* struct lttng_action */
157 struct lttng_payload_view action_view =
158 lttng_payload_view_from_view(
159 src_view, offset, -1);
160
161 action_size = lttng_action_create_from_payload(&action_view, &action);
162 }
163
164 if (action_size < 0) {
165 ret = action_size;
166 goto end;
167 }
168 offset += action_size;
169
170 /* Unexpected size of inner-elements; the buffer is corrupted. */
171 if ((ssize_t) trigger_comm->length != condition_size + action_size) {
172 ret = -1;
173 goto error;
174 }
175
176 *trigger = lttng_trigger_create(condition, action);
177 if (!*trigger) {
178 ret = -1;
179 goto error;
180 }
181
182 /*
183 * The trigger object owns references to the action and condition
184 * objects.
185 */
186 lttng_condition_put(condition);
187 condition = NULL;
188
189 lttng_action_put(action);
190 action = NULL;
191
192 ret = offset;
193
194 error:
195 lttng_condition_destroy(condition);
196 lttng_action_destroy(action);
197 end:
198 return ret;
199 }
200
201 /*
202 * Both elements are stored contiguously, see their "*_comm" structure
203 * for the detailed format.
204 */
205 LTTNG_HIDDEN
206 int lttng_trigger_serialize(struct lttng_trigger *trigger,
207 struct lttng_payload *payload)
208 {
209 int ret;
210 size_t header_offset, size_before_payload;
211 struct lttng_trigger_comm trigger_comm = {};
212 struct lttng_trigger_comm *header;
213
214 header_offset = payload->buffer.size;
215 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
216 sizeof(trigger_comm));
217 if (ret) {
218 goto end;
219 }
220
221 size_before_payload = payload->buffer.size;
222 ret = lttng_condition_serialize(trigger->condition, payload);
223 if (ret) {
224 goto end;
225 }
226
227 ret = lttng_action_serialize(trigger->action, payload);
228 if (ret) {
229 goto end;
230 }
231
232 /* Update payload size. */
233 header = (typeof(header)) (payload->buffer.data + header_offset);
234 header->length = payload->buffer.size - size_before_payload;
235 end:
236 return ret;
237 }
238
239 LTTNG_HIDDEN
240 void lttng_trigger_get(struct lttng_trigger *trigger)
241 {
242 urcu_ref_get(&trigger->ref);
243 }
244
245 LTTNG_HIDDEN
246 void lttng_trigger_put(struct lttng_trigger *trigger)
247 {
248 if (!trigger) {
249 return;
250 }
251
252 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
253 }
254
255 LTTNG_HIDDEN
256 const struct lttng_credentials *lttng_trigger_get_credentials(
257 const struct lttng_trigger *trigger)
258 {
259 return LTTNG_OPTIONAL_GET_PTR(trigger->creds);
260 }
261
262 LTTNG_HIDDEN
263 void lttng_trigger_set_credentials(
264 struct lttng_trigger *trigger,
265 const struct lttng_credentials *creds)
266 {
267 assert(creds);
268 LTTNG_OPTIONAL_SET(&trigger->creds, *creds);
269 }
This page took 0.0492 seconds and 4 git commands to generate.