Remove lttng_ust_synchronize_trace public symbol
[lttng-ust.git] / liblttng-ust / lttng-context.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * LTTng UST trace/channel/event context management.
7 */
8
9 #define _LGPL_SOURCE
10 #include <lttng/ust-events.h>
11 #include <lttng/ust-tracer.h>
12 #include <ust-context-provider.h>
13 #include <lttng/urcu/pointer.h>
14 #include <lttng/urcu/urcu-ust.h>
15 #include <usterr-signal-safe.h>
16 #include <ust-helper.h>
17 #include <stddef.h>
18 #include <string.h>
19 #include <assert.h>
20 #include "tracepoint-internal.h"
21
22 #include "context-internal.h"
23
24 /*
25 * The filter implementation requires that two consecutive "get" for the
26 * same context performed by the same thread return the same result.
27 */
28
29 int lttng_find_context(struct lttng_ctx *ctx, const char *name)
30 {
31 unsigned int i;
32 const char *subname;
33
34 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
35 subname = name + strlen("$ctx.");
36 } else {
37 subname = name;
38 }
39 for (i = 0; i < ctx->nr_fields; i++) {
40 /* Skip allocated (but non-initialized) contexts */
41 if (!ctx->fields[i].event_field.name)
42 continue;
43 if (!strcmp(ctx->fields[i].event_field.name, subname))
44 return 1;
45 }
46 return 0;
47 }
48
49 int lttng_get_context_index(struct lttng_ctx *ctx, const char *name)
50 {
51 unsigned int i;
52 const char *subname;
53
54 if (!ctx)
55 return -1;
56 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
57 subname = name + strlen("$ctx.");
58 } else {
59 subname = name;
60 }
61 for (i = 0; i < ctx->nr_fields; i++) {
62 /* Skip allocated (but non-initialized) contexts */
63 if (!ctx->fields[i].event_field.name)
64 continue;
65 if (!strcmp(ctx->fields[i].event_field.name, subname))
66 return i;
67 }
68 return -1;
69 }
70
71 static int lttng_find_context_provider(struct lttng_ctx *ctx, const char *name)
72 {
73 unsigned int i;
74
75 for (i = 0; i < ctx->nr_fields; i++) {
76 /* Skip allocated (but non-initialized) contexts */
77 if (!ctx->fields[i].event_field.name)
78 continue;
79 if (!strncmp(ctx->fields[i].event_field.name, name,
80 strlen(name)))
81 return 1;
82 }
83 return 0;
84 }
85
86 /*
87 * Note: as we append context information, the pointer location may change.
88 */
89 struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p)
90 {
91 struct lttng_ctx_field *field;
92 struct lttng_ctx *ctx;
93
94 if (!*ctx_p) {
95 *ctx_p = zmalloc(sizeof(struct lttng_ctx));
96 if (!*ctx_p)
97 return NULL;
98 (*ctx_p)->largest_align = 1;
99 }
100 ctx = *ctx_p;
101 if (ctx->nr_fields + 1 > ctx->allocated_fields) {
102 struct lttng_ctx_field *new_fields;
103
104 ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
105 new_fields = zmalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field));
106 if (!new_fields)
107 return NULL;
108 if (ctx->fields)
109 memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
110 free(ctx->fields);
111 ctx->fields = new_fields;
112 }
113 field = &ctx->fields[ctx->nr_fields];
114 ctx->nr_fields++;
115 return field;
116 }
117
118 int lttng_context_add_rcu(struct lttng_ctx **ctx_p,
119 const struct lttng_ctx_field *f)
120 {
121 struct lttng_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
122 struct lttng_ctx_field *new_fields = NULL;
123 struct lttng_ctx_field *nf;
124
125 if (old_ctx) {
126 new_ctx = zmalloc(sizeof(struct lttng_ctx));
127 if (!new_ctx)
128 return -ENOMEM;
129 *new_ctx = *old_ctx;
130 new_fields = zmalloc(new_ctx->allocated_fields
131 * sizeof(struct lttng_ctx_field));
132 if (!new_fields) {
133 free(new_ctx);
134 return -ENOMEM;
135 }
136 memcpy(new_fields, old_ctx->fields,
137 sizeof(*old_ctx->fields) * old_ctx->nr_fields);
138 new_ctx->fields = new_fields;
139 }
140 nf = lttng_append_context(&new_ctx);
141 if (!nf) {
142 free(new_fields);
143 free(new_ctx);
144 return -ENOMEM;
145 }
146 *nf = *f;
147 lttng_context_update(new_ctx);
148 lttng_ust_rcu_assign_pointer(*ctx_p, new_ctx);
149 lttng_ust_urcu_synchronize_rcu();
150 if (old_ctx) {
151 free(old_ctx->fields);
152 free(old_ctx);
153 }
154 return 0;
155 }
156
157 /*
158 * lttng_context_update() should be called at least once between context
159 * modification and trace start.
160 */
161 void lttng_context_update(struct lttng_ctx *ctx)
162 {
163 int i;
164 size_t largest_align = 8; /* in bits */
165
166 for (i = 0; i < ctx->nr_fields; i++) {
167 struct lttng_type *type;
168 size_t field_align = 8;
169
170 type = &ctx->fields[i].event_field.type;
171 switch (type->atype) {
172 case atype_integer:
173 field_align = type->u.integer.alignment;
174 break;
175 case atype_array:
176 {
177 struct lttng_basic_type *btype;
178
179 btype = &type->u.legacy.array.elem_type;
180 switch (btype->atype) {
181 case atype_integer:
182 field_align = btype->u.basic.integer.alignment;
183 break;
184 case atype_string:
185 break;
186
187 case atype_array:
188 case atype_array_nestable:
189 case atype_sequence:
190 case atype_sequence_nestable:
191 default:
192 WARN_ON_ONCE(1);
193 break;
194 }
195 break;
196 }
197 case atype_array_nestable:
198 {
199 const struct lttng_type *nested_type;
200
201 nested_type = type->u.array_nestable.elem_type;
202 switch (nested_type->atype) {
203 case atype_integer:
204 field_align = nested_type->u.integer.alignment;
205 break;
206 case atype_string:
207 break;
208
209 case atype_array:
210 case atype_array_nestable:
211 case atype_sequence:
212 case atype_sequence_nestable:
213 default:
214 WARN_ON_ONCE(1);
215 break;
216 }
217 field_align = max_t(size_t, field_align,
218 type->u.array_nestable.alignment);
219 break;
220 }
221 case atype_sequence:
222 {
223 struct lttng_basic_type *btype;
224
225 btype = &type->u.legacy.sequence.length_type;
226 switch (btype->atype) {
227 case atype_integer:
228 field_align = btype->u.basic.integer.alignment;
229 break;
230
231 case atype_string:
232 case atype_array:
233 case atype_array_nestable:
234 case atype_sequence:
235 case atype_sequence_nestable:
236 default:
237 WARN_ON_ONCE(1);
238 break;
239 }
240
241 btype = &type->u.legacy.sequence.elem_type;
242 switch (btype->atype) {
243 case atype_integer:
244 field_align = max_t(size_t,
245 field_align,
246 btype->u.basic.integer.alignment);
247 break;
248
249 case atype_string:
250 break;
251
252 case atype_array:
253 case atype_array_nestable:
254 case atype_sequence:
255 case atype_sequence_nestable:
256 default:
257 WARN_ON_ONCE(1);
258 break;
259 }
260 break;
261 }
262 case atype_sequence_nestable:
263 {
264 const struct lttng_type *nested_type;
265
266 nested_type = type->u.sequence_nestable.elem_type;
267 switch (nested_type->atype) {
268 case atype_integer:
269 field_align = nested_type->u.integer.alignment;
270 break;
271
272 case atype_string:
273 break;
274
275 case atype_array:
276 case atype_array_nestable:
277 case atype_sequence:
278 case atype_sequence_nestable:
279 default:
280 WARN_ON_ONCE(1);
281 break;
282 }
283 field_align = max_t(size_t, field_align,
284 type->u.sequence_nestable.alignment);
285 break;
286 }
287 case atype_string:
288 break;
289 case atype_dynamic:
290 break;
291 case atype_enum:
292 case atype_enum_nestable:
293 default:
294 WARN_ON_ONCE(1);
295 break;
296 }
297 largest_align = max_t(size_t, largest_align, field_align);
298 }
299 ctx->largest_align = largest_align >> 3; /* bits to bytes */
300 }
301
302 /*
303 * Remove last context field.
304 */
305 void lttng_remove_context_field(struct lttng_ctx **ctx_p,
306 struct lttng_ctx_field *field)
307 {
308 struct lttng_ctx *ctx;
309
310 ctx = *ctx_p;
311 ctx->nr_fields--;
312 assert(&ctx->fields[ctx->nr_fields] == field);
313 assert(field->field_name == NULL);
314 memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
315 }
316
317 void lttng_destroy_context(struct lttng_ctx *ctx)
318 {
319 int i;
320
321 if (!ctx)
322 return;
323 for (i = 0; i < ctx->nr_fields; i++) {
324 if (ctx->fields[i].destroy)
325 ctx->fields[i].destroy(&ctx->fields[i]);
326 free(ctx->fields[i].field_name);
327 }
328 free(ctx->fields);
329 free(ctx);
330 }
331
332 /*
333 * Can be safely performed concurrently with tracing using the struct
334 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
335 * contexts.
336 *
337 * This does not allow adding, removing, or changing typing of the
338 * contexts, since this needs to stay invariant for metadata. However,
339 * it allows updating the handlers associated with all contexts matching
340 * a provider (by name) while tracing is using it, in a way that ensures
341 * a single RCU read-side critical section see either all old, or all
342 * new handlers.
343 */
344 int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
345 const char *name,
346 size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
347 void (*record)(struct lttng_ctx_field *field,
348 struct lttng_ust_lib_ring_buffer_ctx *ctx,
349 struct lttng_channel *chan),
350 void (*get_value)(struct lttng_ctx_field *field,
351 struct lttng_ctx_value *value))
352 {
353 int i, ret;
354 struct lttng_ctx *ctx = *_ctx, *new_ctx;
355 struct lttng_ctx_field *new_fields;
356
357 if (!ctx || !lttng_find_context_provider(ctx, name))
358 return 0;
359 /*
360 * We have at least one instance of context for the provider.
361 */
362 new_ctx = zmalloc(sizeof(*new_ctx));
363 if (!new_ctx)
364 return -ENOMEM;
365 *new_ctx = *ctx;
366 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
367 if (!new_fields) {
368 ret = -ENOMEM;
369 goto field_error;
370 }
371 memcpy(new_fields, ctx->fields,
372 sizeof(*new_fields) * ctx->allocated_fields);
373 for (i = 0; i < ctx->nr_fields; i++) {
374 if (strncmp(new_fields[i].event_field.name,
375 name, strlen(name)) != 0)
376 continue;
377 new_fields[i].get_size = get_size;
378 new_fields[i].record = record;
379 new_fields[i].get_value = get_value;
380 }
381 new_ctx->fields = new_fields;
382 lttng_ust_rcu_assign_pointer(*_ctx, new_ctx);
383 lttng_ust_urcu_synchronize_rcu();
384 free(ctx->fields);
385 free(ctx);
386 return 0;
387
388 field_error:
389 free(new_ctx);
390 return ret;
391 }
392
393 int lttng_context_init_all(struct lttng_ctx **ctx)
394 {
395 int ret;
396
397 ret = lttng_add_pthread_id_to_ctx(ctx);
398 if (ret) {
399 WARN("Cannot add context lttng_add_pthread_id_to_ctx");
400 goto error;
401 }
402 ret = lttng_add_vtid_to_ctx(ctx);
403 if (ret) {
404 WARN("Cannot add context lttng_add_vtid_to_ctx");
405 goto error;
406 }
407 ret = lttng_add_vpid_to_ctx(ctx);
408 if (ret) {
409 WARN("Cannot add context lttng_add_vpid_to_ctx");
410 goto error;
411 }
412 ret = lttng_add_procname_to_ctx(ctx);
413 if (ret) {
414 WARN("Cannot add context lttng_add_procname_to_ctx");
415 goto error;
416 }
417 ret = lttng_add_cpu_id_to_ctx(ctx);
418 if (ret) {
419 WARN("Cannot add context lttng_add_cpu_id_to_ctx");
420 goto error;
421 }
422 ret = lttng_add_cgroup_ns_to_ctx(ctx);
423 if (ret) {
424 WARN("Cannot add context lttng_add_cgroup_ns_to_ctx");
425 goto error;
426 }
427 ret = lttng_add_ipc_ns_to_ctx(ctx);
428 if (ret) {
429 WARN("Cannot add context lttng_add_ipc_ns_to_ctx");
430 goto error;
431 }
432 ret = lttng_add_mnt_ns_to_ctx(ctx);
433 if (ret) {
434 WARN("Cannot add context lttng_add_mnt_ns_to_ctx");
435 goto error;
436 }
437 ret = lttng_add_net_ns_to_ctx(ctx);
438 if (ret) {
439 WARN("Cannot add context lttng_add_net_ns_to_ctx");
440 goto error;
441 }
442 ret = lttng_add_pid_ns_to_ctx(ctx);
443 if (ret) {
444 WARN("Cannot add context lttng_add_pid_ns_to_ctx");
445 goto error;
446 }
447 ret = lttng_add_time_ns_to_ctx(ctx);
448 if (ret) {
449 WARN("Cannot add context lttng_add_time_ns_to_ctx");
450 goto error;
451 }
452 ret = lttng_add_user_ns_to_ctx(ctx);
453 if (ret) {
454 WARN("Cannot add context lttng_add_user_ns_to_ctx");
455 goto error;
456 }
457 ret = lttng_add_uts_ns_to_ctx(ctx);
458 if (ret) {
459 WARN("Cannot add context lttng_add_uts_ns_to_ctx");
460 goto error;
461 }
462 ret = lttng_add_vuid_to_ctx(ctx);
463 if (ret) {
464 WARN("Cannot add context lttng_add_vuid_to_ctx");
465 goto error;
466 }
467 ret = lttng_add_veuid_to_ctx(ctx);
468 if (ret) {
469 WARN("Cannot add context lttng_add_veuid_to_ctx");
470 goto error;
471 }
472 ret = lttng_add_vsuid_to_ctx(ctx);
473 if (ret) {
474 WARN("Cannot add context lttng_add_vsuid_to_ctx");
475 goto error;
476 }
477 ret = lttng_add_vgid_to_ctx(ctx);
478 if (ret) {
479 WARN("Cannot add context lttng_add_vgid_to_ctx");
480 goto error;
481 }
482 ret = lttng_add_vegid_to_ctx(ctx);
483 if (ret) {
484 WARN("Cannot add context lttng_add_vegid_to_ctx");
485 goto error;
486 }
487 ret = lttng_add_vsgid_to_ctx(ctx);
488 if (ret) {
489 WARN("Cannot add context lttng_add_vsgid_to_ctx");
490 goto error;
491 }
492 lttng_context_update(*ctx);
493 return 0;
494
495 error:
496 lttng_destroy_context(*ctx);
497 return ret;
498 }
This page took 0.049931 seconds and 5 git commands to generate.