Namespace ust-fork symbols
[lttng-ust.git] / liblttng-ust / lttng-context.c
... / ...
CommitLineData
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 <limits.h>
21#include "tracepoint-internal.h"
22
23#include "context-internal.h"
24
25/*
26 * The filter implementation requires that two consecutive "get" for the
27 * same context performed by the same thread return the same result.
28 */
29
30int lttng_find_context(struct lttng_ust_ctx *ctx, const char *name)
31{
32 unsigned int i;
33 const char *subname;
34
35 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
36 subname = name + strlen("$ctx.");
37 } else {
38 subname = name;
39 }
40 for (i = 0; i < ctx->nr_fields; i++) {
41 /* Skip allocated (but non-initialized) contexts */
42 if (!ctx->fields[i]->event_field->name)
43 continue;
44 if (!strcmp(ctx->fields[i]->event_field->name, subname))
45 return 1;
46 }
47 return 0;
48}
49
50int lttng_get_context_index(struct lttng_ust_ctx *ctx, const char *name)
51{
52 unsigned int i;
53 const char *subname;
54
55 if (!ctx)
56 return -1;
57 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
58 subname = name + strlen("$ctx.");
59 } else {
60 subname = name;
61 }
62 for (i = 0; i < ctx->nr_fields; i++) {
63 /* Skip allocated (but non-initialized) contexts */
64 if (!ctx->fields[i]->event_field->name)
65 continue;
66 if (!strcmp(ctx->fields[i]->event_field->name, subname))
67 return i;
68 }
69 return -1;
70}
71
72static int lttng_find_context_provider(struct lttng_ust_ctx *ctx, const char *name)
73{
74 unsigned int i;
75
76 for (i = 0; i < ctx->nr_fields; i++) {
77 /* Skip allocated (but non-initialized) contexts */
78 if (!ctx->fields[i]->event_field->name)
79 continue;
80 if (!strncmp(ctx->fields[i]->event_field->name, name,
81 strlen(name)))
82 return 1;
83 }
84 return 0;
85}
86
87/*
88 * Note: as we append context information, the pointer location may change.
89 * lttng_add_context leaves the new last context initialized to NULL.
90 */
91static
92int lttng_add_context(struct lttng_ust_ctx **ctx_p)
93{
94 struct lttng_ust_ctx *ctx;
95
96 if (!*ctx_p) {
97 *ctx_p = zmalloc(sizeof(struct lttng_ust_ctx));
98 if (!*ctx_p)
99 return -ENOMEM;
100 (*ctx_p)->struct_size = sizeof(struct lttng_ust_ctx);
101 (*ctx_p)->largest_align = 1;
102 }
103 ctx = *ctx_p;
104 if (ctx->nr_fields + 1 > ctx->allocated_fields) {
105 struct lttng_ust_ctx_field **new_fields;
106
107 ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
108 new_fields = zmalloc(ctx->allocated_fields * sizeof(*new_fields));
109 if (!new_fields)
110 return -ENOMEM;
111 /* Copy pointers */
112 if (ctx->fields)
113 memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
114 free(ctx->fields);
115 ctx->fields = new_fields;
116 }
117 ctx->nr_fields++;
118 return 0;
119}
120
121struct lttng_ust_ctx_field *lttng_append_context(struct lttng_ust_ctx **ctx_p)
122{
123 struct lttng_ust_ctx_field *field;
124 int ret;
125
126 field = zmalloc(sizeof(struct lttng_ust_ctx_field));
127 if (!field)
128 goto error_alloc_field;
129 field->struct_size = sizeof(struct lttng_ust_ctx_field);
130 field->event_field = zmalloc(sizeof(struct lttng_ust_event_field));
131 if (!field->event_field)
132 goto error_alloc_event_field;
133 field->event_field->struct_size = sizeof(struct lttng_ust_event_field);
134
135 ret = lttng_add_context(ctx_p);
136 if (ret)
137 goto error_add_context;
138 (*ctx_p)->fields[(*ctx_p)->nr_fields - 1] = field;
139 return field;
140
141error_add_context:
142 free(field->event_field);
143error_alloc_event_field:
144 free(field);
145error_alloc_field:
146 return NULL;
147}
148
149/*
150 * Takes ownership of @f on success.
151 */
152int lttng_context_add_rcu(struct lttng_ust_ctx **ctx_p,
153 struct lttng_ust_ctx_field *f)
154{
155 struct lttng_ust_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
156 struct lttng_ust_ctx_field **new_fields = NULL;
157 int ret;
158
159 if (old_ctx) {
160 new_ctx = zmalloc(sizeof(struct lttng_ust_ctx));
161 if (!new_ctx)
162 return -ENOMEM;
163 new_ctx->struct_size = sizeof(struct lttng_ust_ctx);
164 *new_ctx = *old_ctx;
165 new_fields = zmalloc(new_ctx->allocated_fields * sizeof(*new_fields));
166 if (!new_fields) {
167 free(new_ctx);
168 return -ENOMEM;
169 }
170 /* Copy pointers */
171 memcpy(new_fields, old_ctx->fields,
172 sizeof(*old_ctx->fields) * old_ctx->nr_fields);
173 new_ctx->fields = new_fields;
174 }
175 ret = lttng_add_context(&new_ctx);
176 if (ret) {
177 free(new_fields);
178 free(new_ctx);
179 return ret;
180 }
181 /* Taking ownership of f. */
182 (*ctx_p)->fields[(*ctx_p)->nr_fields - 1] = f;
183 lttng_context_update(new_ctx);
184 lttng_ust_rcu_assign_pointer(*ctx_p, new_ctx);
185 lttng_ust_urcu_synchronize_rcu();
186 if (old_ctx) {
187 free(old_ctx->fields);
188 free(old_ctx);
189 }
190 return 0;
191}
192
193static size_t get_type_max_align(struct lttng_ust_type_common *type)
194{
195 switch (type->type) {
196 case lttng_ust_type_integer:
197 return lttng_ust_get_type_integer(type)->alignment;
198 case lttng_ust_type_string:
199 return CHAR_BIT;
200 case lttng_ust_type_dynamic:
201 return 0;
202 case lttng_ust_type_enum:
203 return get_type_max_align(lttng_ust_get_type_enum(type)->container_type);
204 case lttng_ust_type_array:
205 return max_t(size_t, get_type_max_align(lttng_ust_get_type_array(type)->elem_type),
206 lttng_ust_get_type_array(type)->alignment);
207 case lttng_ust_type_sequence:
208 return max_t(size_t, get_type_max_align(lttng_ust_get_type_sequence(type)->elem_type),
209 lttng_ust_get_type_sequence(type)->alignment);
210 case lttng_ust_type_struct:
211 {
212 unsigned int i;
213 size_t field_align = 0;
214 struct lttng_ust_type_struct *struct_type = lttng_ust_get_type_struct(type);
215
216 for (i = 0; i < struct_type->nr_fields; i++) {
217 field_align = max_t(size_t,
218 get_type_max_align(struct_type->fields[i]->type),
219 field_align);
220 }
221 return field_align;
222 }
223 default:
224 WARN_ON_ONCE(1);
225 return 0;
226 }
227}
228
229/*
230 * lttng_context_update() should be called at least once between context
231 * modification and trace start.
232 */
233void lttng_context_update(struct lttng_ust_ctx *ctx)
234{
235 int i;
236 size_t largest_align = 8; /* in bits */
237
238 for (i = 0; i < ctx->nr_fields; i++) {
239 size_t field_align = 8;
240
241 field_align = get_type_max_align(ctx->fields[i]->event_field->type);
242 largest_align = max_t(size_t, largest_align, field_align);
243 }
244 ctx->largest_align = largest_align >> 3; /* bits to bytes */
245}
246
247/*
248 * Remove last context field.
249 */
250void lttng_remove_context_field(struct lttng_ust_ctx **ctx_p,
251 struct lttng_ust_ctx_field *field)
252{
253 struct lttng_ust_ctx *ctx;
254
255 ctx = *ctx_p;
256 ctx->nr_fields--;
257 assert(ctx->fields[ctx->nr_fields] == field);
258 lttng_ust_destroy_type(field->event_field->type);
259 free((char *) field->event_field->name);
260 free(field->event_field);
261 free(field);
262 ctx->fields[ctx->nr_fields] = NULL;
263}
264
265void lttng_destroy_context(struct lttng_ust_ctx *ctx)
266{
267 int i;
268
269 if (!ctx)
270 return;
271 for (i = 0; i < ctx->nr_fields; i++) {
272 if (ctx->fields[i]->destroy)
273 ctx->fields[i]->destroy(ctx->fields[i]);
274 lttng_ust_destroy_type(ctx->fields[i]->event_field->type);
275 free((char *) ctx->fields[i]->event_field->name);
276 free(ctx->fields[i]->event_field);
277 free(ctx->fields[i]);
278 }
279 free(ctx->fields);
280 free(ctx);
281}
282
283/*
284 * Can be safely performed concurrently with tracing using the struct
285 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
286 * contexts.
287 *
288 * This does not allow adding, removing, or changing typing of the
289 * contexts, since this needs to stay invariant for metadata. However,
290 * it allows updating the handlers associated with all contexts matching
291 * a provider (by name) while tracing is using it, in a way that ensures
292 * a single RCU read-side critical section see either all old, or all
293 * new handlers.
294 */
295int lttng_ust_context_set_provider_rcu(struct lttng_ust_ctx **_ctx,
296 const char *name,
297 size_t (*get_size)(struct lttng_ust_ctx_field *field, size_t offset),
298 void (*record)(struct lttng_ust_ctx_field *field,
299 struct lttng_ust_lib_ring_buffer_ctx *ctx,
300 struct lttng_ust_channel_buffer *chan),
301 void (*get_value)(struct lttng_ust_ctx_field *field,
302 struct lttng_ust_ctx_value *value))
303{
304 int i, ret;
305 struct lttng_ust_ctx *ctx = *_ctx, *new_ctx;
306 struct lttng_ust_ctx_field **new_fields;
307
308 if (!ctx || !lttng_find_context_provider(ctx, name))
309 return 0;
310 /*
311 * We have at least one instance of context for the provider.
312 */
313 new_ctx = zmalloc(sizeof(*new_ctx));
314 if (!new_ctx)
315 return -ENOMEM;
316 new_ctx->struct_size = sizeof(*new_ctx);
317 *new_ctx = *ctx;
318 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
319 if (!new_fields) {
320 ret = -ENOMEM;
321 goto field_error;
322 }
323 /* Copy pointers */
324 memcpy(new_fields, ctx->fields,
325 sizeof(*new_fields) * ctx->allocated_fields);
326 for (i = 0; i < ctx->nr_fields; i++) {
327 if (strncmp(new_fields[i]->event_field->name,
328 name, strlen(name)) != 0)
329 continue;
330 new_fields[i]->get_size = get_size;
331 new_fields[i]->record = record;
332 new_fields[i]->get_value = get_value;
333 }
334 new_ctx->fields = new_fields;
335 lttng_ust_rcu_assign_pointer(*_ctx, new_ctx);
336 lttng_ust_urcu_synchronize_rcu();
337 free(ctx->fields);
338 free(ctx);
339 return 0;
340
341field_error:
342 free(new_ctx);
343 return ret;
344}
345
346int lttng_context_init_all(struct lttng_ust_ctx **ctx)
347{
348 int ret;
349
350 ret = lttng_add_pthread_id_to_ctx(ctx);
351 if (ret) {
352 WARN("Cannot add context lttng_add_pthread_id_to_ctx");
353 goto error;
354 }
355 ret = lttng_add_vtid_to_ctx(ctx);
356 if (ret) {
357 WARN("Cannot add context lttng_add_vtid_to_ctx");
358 goto error;
359 }
360 ret = lttng_add_vpid_to_ctx(ctx);
361 if (ret) {
362 WARN("Cannot add context lttng_add_vpid_to_ctx");
363 goto error;
364 }
365 ret = lttng_add_procname_to_ctx(ctx);
366 if (ret) {
367 WARN("Cannot add context lttng_add_procname_to_ctx");
368 goto error;
369 }
370 ret = lttng_add_cpu_id_to_ctx(ctx);
371 if (ret) {
372 WARN("Cannot add context lttng_add_cpu_id_to_ctx");
373 goto error;
374 }
375 ret = lttng_add_cgroup_ns_to_ctx(ctx);
376 if (ret) {
377 WARN("Cannot add context lttng_add_cgroup_ns_to_ctx");
378 goto error;
379 }
380 ret = lttng_add_ipc_ns_to_ctx(ctx);
381 if (ret) {
382 WARN("Cannot add context lttng_add_ipc_ns_to_ctx");
383 goto error;
384 }
385 ret = lttng_add_mnt_ns_to_ctx(ctx);
386 if (ret) {
387 WARN("Cannot add context lttng_add_mnt_ns_to_ctx");
388 goto error;
389 }
390 ret = lttng_add_net_ns_to_ctx(ctx);
391 if (ret) {
392 WARN("Cannot add context lttng_add_net_ns_to_ctx");
393 goto error;
394 }
395 ret = lttng_add_pid_ns_to_ctx(ctx);
396 if (ret) {
397 WARN("Cannot add context lttng_add_pid_ns_to_ctx");
398 goto error;
399 }
400 ret = lttng_add_time_ns_to_ctx(ctx);
401 if (ret) {
402 WARN("Cannot add context lttng_add_time_ns_to_ctx");
403 goto error;
404 }
405 ret = lttng_add_user_ns_to_ctx(ctx);
406 if (ret) {
407 WARN("Cannot add context lttng_add_user_ns_to_ctx");
408 goto error;
409 }
410 ret = lttng_add_uts_ns_to_ctx(ctx);
411 if (ret) {
412 WARN("Cannot add context lttng_add_uts_ns_to_ctx");
413 goto error;
414 }
415 ret = lttng_add_vuid_to_ctx(ctx);
416 if (ret) {
417 WARN("Cannot add context lttng_add_vuid_to_ctx");
418 goto error;
419 }
420 ret = lttng_add_veuid_to_ctx(ctx);
421 if (ret) {
422 WARN("Cannot add context lttng_add_veuid_to_ctx");
423 goto error;
424 }
425 ret = lttng_add_vsuid_to_ctx(ctx);
426 if (ret) {
427 WARN("Cannot add context lttng_add_vsuid_to_ctx");
428 goto error;
429 }
430 ret = lttng_add_vgid_to_ctx(ctx);
431 if (ret) {
432 WARN("Cannot add context lttng_add_vgid_to_ctx");
433 goto error;
434 }
435 ret = lttng_add_vegid_to_ctx(ctx);
436 if (ret) {
437 WARN("Cannot add context lttng_add_vegid_to_ctx");
438 goto error;
439 }
440 ret = lttng_add_vsgid_to_ctx(ctx);
441 if (ret) {
442 WARN("Cannot add context lttng_add_vsgid_to_ctx");
443 goto error;
444 }
445 lttng_context_update(*ctx);
446 return 0;
447
448error:
449 lttng_destroy_context(*ctx);
450 return ret;
451}
This page took 0.025413 seconds and 4 git commands to generate.