Fix: futex wait: handle spurious futex wakeups
[lttng-tools.git] / src / common / actions / stop-session.cpp
1 /*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <common/error.hpp>
9 #include <common/macros.hpp>
10 #include <common/mi-lttng.hpp>
11 #include <lttng/action/action-internal.hpp>
12 #include <lttng/action/rate-policy-internal.hpp>
13 #include <lttng/action/rate-policy.h>
14 #include <lttng/action/stop-session-internal.hpp>
15 #include <lttng/action/stop-session.h>
16
17 #define IS_STOP_SESSION_ACTION(action) \
18 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_STOP_SESSION)
19
20 namespace {
21 struct lttng_action_stop_session {
22 struct lttng_action parent;
23
24 /* Owned by this. */
25 char *session_name;
26 struct lttng_rate_policy *policy;
27 };
28
29 struct lttng_action_stop_session_comm {
30 /* Includes the trailing \0. */
31 uint32_t session_name_len;
32
33 /*
34 * Variable data:
35 *
36 * - session name (null terminated)
37 * - policy
38 */
39 char data[];
40 } LTTNG_PACKED;
41 } /* namespace */
42
43 static const struct lttng_rate_policy *
44 lttng_action_stop_session_internal_get_rate_policy(
45 const struct lttng_action *action);
46
47 static struct lttng_action_stop_session *action_stop_session_from_action(
48 struct lttng_action *action)
49 {
50 LTTNG_ASSERT(action);
51
52 return lttng::utils::container_of(action, &lttng_action_stop_session::parent);
53 }
54
55 static const struct lttng_action_stop_session *
56 action_stop_session_from_action_const(const struct lttng_action *action)
57 {
58 LTTNG_ASSERT(action);
59
60 return lttng::utils::container_of(action, &lttng_action_stop_session::parent);
61 }
62
63 static bool lttng_action_stop_session_validate(struct lttng_action *action)
64 {
65 bool valid;
66 struct lttng_action_stop_session *action_stop_session;
67
68 if (!action) {
69 valid = false;
70 goto end;
71 }
72
73 action_stop_session = action_stop_session_from_action(action);
74
75 /* A non-empty session name is mandatory. */
76 if (!action_stop_session->session_name ||
77 strlen(action_stop_session->session_name) == 0) {
78 valid = false;
79 goto end;
80 }
81
82 valid = true;
83 end:
84 return valid;
85 }
86
87 static bool lttng_action_stop_session_is_equal(
88 const struct lttng_action *_a, const struct lttng_action *_b)
89 {
90 bool is_equal = false;
91 const struct lttng_action_stop_session *a, *b;
92
93 a = action_stop_session_from_action_const(_a);
94 b = action_stop_session_from_action_const(_b);
95
96 /* Action is not valid if this is not true. */
97 LTTNG_ASSERT(a->session_name);
98 LTTNG_ASSERT(b->session_name);
99 if (strcmp(a->session_name, b->session_name)) {
100 goto end;
101 }
102
103 is_equal = lttng_rate_policy_is_equal(a->policy, b->policy);
104 end:
105 return is_equal;
106 }
107
108 static int lttng_action_stop_session_serialize(
109 struct lttng_action *action, struct lttng_payload *payload)
110 {
111 struct lttng_action_stop_session *action_stop_session;
112 struct lttng_action_stop_session_comm comm;
113 size_t session_name_len;
114 int ret;
115
116 LTTNG_ASSERT(action);
117 LTTNG_ASSERT(payload);
118
119 action_stop_session = action_stop_session_from_action(action);
120
121 LTTNG_ASSERT(action_stop_session->session_name);
122
123 DBG("Serializing stop session action: session-name: %s",
124 action_stop_session->session_name);
125
126 session_name_len = strlen(action_stop_session->session_name) + 1;
127 comm.session_name_len = session_name_len;
128
129 ret = lttng_dynamic_buffer_append(
130 &payload->buffer, &comm, sizeof(comm));
131 if (ret) {
132 ret = -1;
133 goto end;
134 }
135
136 ret = lttng_dynamic_buffer_append(&payload->buffer,
137 action_stop_session->session_name, session_name_len);
138 if (ret) {
139 ret = -1;
140 goto end;
141 }
142
143 ret = lttng_rate_policy_serialize(action_stop_session->policy, payload);
144 if (ret) {
145 ret = -1;
146 goto end;
147 }
148
149 ret = 0;
150 end:
151 return ret;
152 }
153
154 static void lttng_action_stop_session_destroy(struct lttng_action *action)
155 {
156 struct lttng_action_stop_session *action_stop_session;
157
158 if (!action) {
159 goto end;
160 }
161
162 action_stop_session = action_stop_session_from_action(action);
163
164 lttng_rate_policy_destroy(action_stop_session->policy);
165 free(action_stop_session->session_name);
166 free(action_stop_session);
167
168 end:
169 return;
170 }
171
172 ssize_t lttng_action_stop_session_create_from_payload(
173 struct lttng_payload_view *view,
174 struct lttng_action **p_action)
175 {
176 ssize_t consumed_len, ret;
177 const struct lttng_action_stop_session_comm *comm;
178 const char *session_name;
179 struct lttng_action *action = NULL;
180 enum lttng_action_status status;
181 struct lttng_rate_policy *policy = NULL;
182
183 comm = (typeof(comm)) view->buffer.data;
184 session_name = (const char *) &comm->data;
185
186 /* Session name. */
187 if (!lttng_buffer_view_contains_string(
188 &view->buffer, session_name, comm->session_name_len)) {
189 consumed_len = -1;
190 goto end;
191 }
192 consumed_len = sizeof(*comm) + comm->session_name_len;
193
194 /* Rate policy. */
195 {
196 struct lttng_payload_view policy_view =
197 lttng_payload_view_from_view(
198 view, consumed_len, -1);
199 ret = lttng_rate_policy_create_from_payload(
200 &policy_view, &policy);
201 if (ret < 0) {
202 consumed_len = -1;
203 goto end;
204 }
205 consumed_len += ret;
206 }
207
208 action = lttng_action_stop_session_create();
209 if (!action) {
210 consumed_len = -1;
211 goto end;
212 }
213
214 status = lttng_action_stop_session_set_session_name(
215 action, session_name);
216 if (status != LTTNG_ACTION_STATUS_OK) {
217 consumed_len = -1;
218 goto end;
219 }
220
221 LTTNG_ASSERT(policy);
222 status = lttng_action_stop_session_set_rate_policy(action, policy);
223 if (status != LTTNG_ACTION_STATUS_OK) {
224 consumed_len = -1;
225 goto end;
226 }
227
228 *p_action = action;
229 action = NULL;
230
231 end:
232 lttng_rate_policy_destroy(policy);
233 lttng_action_stop_session_destroy(action);
234
235 return consumed_len;
236 }
237
238 static enum lttng_error_code lttng_action_stop_session_mi_serialize(
239 const struct lttng_action *action, struct mi_writer *writer)
240 {
241 int ret;
242 enum lttng_error_code ret_code;
243 enum lttng_action_status status;
244 const char *session_name = NULL;
245 const struct lttng_rate_policy *policy = NULL;
246
247 LTTNG_ASSERT(action);
248 LTTNG_ASSERT(IS_STOP_SESSION_ACTION(action));
249
250 status = lttng_action_stop_session_get_session_name(
251 action, &session_name);
252 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
253 LTTNG_ASSERT(session_name != NULL);
254
255 status = lttng_action_stop_session_get_rate_policy(action, &policy);
256 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
257 LTTNG_ASSERT(policy != NULL);
258
259 /* Open action stop session. */
260 ret = mi_lttng_writer_open_element(
261 writer, mi_lttng_element_action_start_session);
262 if (ret) {
263 goto mi_error;
264 }
265
266 /* Session name. */
267 ret = mi_lttng_writer_write_element_string(
268 writer, mi_lttng_element_session_name, session_name);
269 if (ret) {
270 goto mi_error;
271 }
272
273 /* Rate policy. */
274 ret_code = lttng_rate_policy_mi_serialize(policy, writer);
275 if (ret_code != LTTNG_OK) {
276 goto end;
277 }
278
279 /* Close action stop session element. */
280 ret = mi_lttng_writer_close_element(writer);
281 if (ret) {
282 goto mi_error;
283 }
284
285 ret_code = LTTNG_OK;
286 goto end;
287
288 mi_error:
289 ret_code = LTTNG_ERR_MI_IO_FAIL;
290 end:
291 return ret_code;
292 }
293
294 struct lttng_action *lttng_action_stop_session_create(void)
295 {
296 struct lttng_action_stop_session *action_stop = NULL;
297 struct lttng_rate_policy *policy = NULL;
298 enum lttng_action_status status;
299
300 /* Create a every N = 1 rate policy. */
301 policy = lttng_rate_policy_every_n_create(1);
302 if (!policy) {
303 goto end;
304 }
305
306 action_stop = zmalloc<lttng_action_stop_session>();
307 if (!action_stop) {
308 goto end;
309 }
310
311 lttng_action_init(&action_stop->parent, LTTNG_ACTION_TYPE_STOP_SESSION,
312 lttng_action_stop_session_validate,
313 lttng_action_stop_session_serialize,
314 lttng_action_stop_session_is_equal,
315 lttng_action_stop_session_destroy,
316 lttng_action_stop_session_internal_get_rate_policy,
317 lttng_action_generic_add_error_query_results,
318 lttng_action_stop_session_mi_serialize);
319
320 status = lttng_action_stop_session_set_rate_policy(
321 &action_stop->parent, policy);
322 if (status != LTTNG_ACTION_STATUS_OK) {
323 lttng_action_destroy(&action_stop->parent);
324 action_stop = NULL;
325 goto end;
326 }
327
328 end:
329 lttng_rate_policy_destroy(policy);
330 return &action_stop->parent;
331 }
332
333 enum lttng_action_status lttng_action_stop_session_set_session_name(
334 struct lttng_action *action, const char *session_name)
335 {
336 struct lttng_action_stop_session *action_stop_session;
337 enum lttng_action_status status;
338
339 if (!action || !IS_STOP_SESSION_ACTION(action) || !session_name ||
340 strlen(session_name) == 0) {
341 status = LTTNG_ACTION_STATUS_INVALID;
342 goto end;
343 }
344
345 action_stop_session = action_stop_session_from_action(action);
346
347 free(action_stop_session->session_name);
348
349 action_stop_session->session_name = strdup(session_name);
350 if (!action_stop_session->session_name) {
351 status = LTTNG_ACTION_STATUS_ERROR;
352 goto end;
353 }
354
355 status = LTTNG_ACTION_STATUS_OK;
356 end:
357 return status;
358 }
359
360 enum lttng_action_status lttng_action_stop_session_get_session_name(
361 const struct lttng_action *action, const char **session_name)
362 {
363 const struct lttng_action_stop_session *action_stop_session;
364 enum lttng_action_status status;
365
366 if (!action || !IS_STOP_SESSION_ACTION(action) || !session_name) {
367 status = LTTNG_ACTION_STATUS_INVALID;
368 goto end;
369 }
370
371 action_stop_session = action_stop_session_from_action_const(action);
372
373 *session_name = action_stop_session->session_name;
374
375 status = LTTNG_ACTION_STATUS_OK;
376 end:
377 return status;
378 }
379
380 enum lttng_action_status lttng_action_stop_session_set_rate_policy(
381 struct lttng_action *action,
382 const struct lttng_rate_policy *policy)
383 {
384 enum lttng_action_status status;
385 struct lttng_action_stop_session *stop_session_action;
386 struct lttng_rate_policy *copy = NULL;
387
388 if (!action || !policy || !IS_STOP_SESSION_ACTION(action)) {
389 status = LTTNG_ACTION_STATUS_INVALID;
390 goto end;
391 }
392
393 copy = lttng_rate_policy_copy(policy);
394 if (!copy) {
395 status = LTTNG_ACTION_STATUS_ERROR;
396 goto end;
397 }
398 stop_session_action = action_stop_session_from_action(action);
399
400 /* Free the previous rate policy .*/
401 lttng_rate_policy_destroy(stop_session_action->policy);
402
403 stop_session_action->policy = copy;
404 status = LTTNG_ACTION_STATUS_OK;
405 copy = NULL;
406
407 end:
408 lttng_rate_policy_destroy(copy);
409 return status;
410 }
411
412 enum lttng_action_status lttng_action_stop_session_get_rate_policy(
413 const struct lttng_action *action,
414 const struct lttng_rate_policy **policy)
415 {
416 enum lttng_action_status status;
417 const struct lttng_action_stop_session *stop_session_action;
418
419 if (!action || !policy || !IS_STOP_SESSION_ACTION(action)) {
420 status = LTTNG_ACTION_STATUS_INVALID;
421 goto end;
422 }
423
424 stop_session_action = action_stop_session_from_action_const(action);
425
426 *policy = stop_session_action->policy;
427 status = LTTNG_ACTION_STATUS_OK;
428 end:
429 return status;
430 }
431
432 static const struct lttng_rate_policy *
433 lttng_action_stop_session_internal_get_rate_policy(
434 const struct lttng_action *action)
435 {
436 const struct lttng_action_stop_session *_action;
437 _action = action_stop_session_from_action_const(action);
438
439 return _action->policy;
440 }
This page took 0.038077 seconds and 4 git commands to generate.