Refactoring: context structures
[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_ust_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_ust_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_ust_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 * lttng_add_context leaves the new last context initialized to NULL.
89 */
90 static
91 int lttng_add_context(struct lttng_ust_ctx **ctx_p)
92 {
93 struct lttng_ust_ctx *ctx;
94
95 if (!*ctx_p) {
96 *ctx_p = zmalloc(sizeof(struct lttng_ust_ctx));
97 if (!*ctx_p)
98 return -ENOMEM;
99 (*ctx_p)->struct_size = sizeof(struct lttng_ust_ctx);
100 (*ctx_p)->largest_align = 1;
101 }
102 ctx = *ctx_p;
103 if (ctx->nr_fields + 1 > ctx->allocated_fields) {
104 struct lttng_ust_ctx_field **new_fields;
105
106 ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
107 new_fields = zmalloc(ctx->allocated_fields * sizeof(*new_fields));
108 if (!new_fields)
109 return -ENOMEM;
110 /* Copy pointers */
111 if (ctx->fields)
112 memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
113 free(ctx->fields);
114 ctx->fields = new_fields;
115 }
116 ctx->nr_fields++;
117 return 0;
118 }
119
120 struct lttng_ust_ctx_field *lttng_append_context(struct lttng_ust_ctx **ctx_p)
121 {
122 struct lttng_ust_ctx_field *field;
123 int ret;
124
125 field = zmalloc(sizeof(struct lttng_ust_ctx_field));
126 if (!field)
127 goto error_alloc_field;
128 field->struct_size = sizeof(struct lttng_ust_ctx_field);
129 field->event_field = zmalloc(sizeof(struct lttng_ust_event_field));
130 if (!field->event_field)
131 goto error_alloc_event_field;
132 field->event_field->struct_size = sizeof(struct lttng_ust_event_field);
133
134 ret = lttng_add_context(ctx_p);
135 if (ret)
136 goto error_add_context;
137 (*ctx_p)->fields[(*ctx_p)->nr_fields - 1] = field;
138 return field;
139
140 error_add_context:
141 free(field->event_field);
142 error_alloc_event_field:
143 free(field);
144 error_alloc_field:
145 return NULL;
146 }
147
148 /*
149 * Takes ownership of @f on success.
150 */
151 int lttng_context_add_rcu(struct lttng_ust_ctx **ctx_p,
152 struct lttng_ust_ctx_field *f)
153 {
154 struct lttng_ust_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
155 struct lttng_ust_ctx_field **new_fields = NULL;
156 int ret;
157
158 if (old_ctx) {
159 new_ctx = zmalloc(sizeof(struct lttng_ust_ctx));
160 if (!new_ctx)
161 return -ENOMEM;
162 new_ctx->struct_size = sizeof(struct lttng_ust_ctx);
163 *new_ctx = *old_ctx;
164 new_fields = zmalloc(new_ctx->allocated_fields * sizeof(*new_fields));
165 if (!new_fields) {
166 free(new_ctx);
167 return -ENOMEM;
168 }
169 /* Copy pointers */
170 memcpy(new_fields, old_ctx->fields,
171 sizeof(*old_ctx->fields) * old_ctx->nr_fields);
172 new_ctx->fields = new_fields;
173 }
174 ret = lttng_add_context(&new_ctx);
175 if (ret) {
176 free(new_fields);
177 free(new_ctx);
178 return ret;
179 }
180 /* Taking ownership of f. */
181 (*ctx_p)->fields[(*ctx_p)->nr_fields - 1] = f;
182 lttng_context_update(new_ctx);
183 lttng_ust_rcu_assign_pointer(*ctx_p, new_ctx);
184 lttng_ust_urcu_synchronize_rcu();
185 if (old_ctx) {
186 free(old_ctx->fields);
187 free(old_ctx);
188 }
189 return 0;
190 }
191
192 /*
193 * lttng_context_update() should be called at least once between context
194 * modification and trace start.
195 */
196 void lttng_context_update(struct lttng_ust_ctx *ctx)
197 {
198 int i;
199 size_t largest_align = 8; /* in bits */
200
201 for (i = 0; i < ctx->nr_fields; i++) {
202 struct lttng_type *type;
203 size_t field_align = 8;
204
205 type = &ctx->fields[i]->event_field->type;
206 switch (type->atype) {
207 case atype_integer:
208 field_align = type->u.integer.alignment;
209 break;
210 case atype_array_nestable:
211 {
212 const struct lttng_type *nested_type;
213
214 nested_type = type->u.array_nestable.elem_type;
215 switch (nested_type->atype) {
216 case atype_integer:
217 field_align = nested_type->u.integer.alignment;
218 break;
219 case atype_string:
220 break;
221
222 case atype_array_nestable:
223 case atype_sequence_nestable:
224 default:
225 WARN_ON_ONCE(1);
226 break;
227 }
228 field_align = max_t(size_t, field_align,
229 type->u.array_nestable.alignment);
230 break;
231 }
232 case atype_sequence_nestable:
233 {
234 const struct lttng_type *nested_type;
235
236 nested_type = type->u.sequence_nestable.elem_type;
237 switch (nested_type->atype) {
238 case atype_integer:
239 field_align = nested_type->u.integer.alignment;
240 break;
241
242 case atype_string:
243 break;
244
245 case atype_array_nestable:
246 case atype_sequence_nestable:
247 default:
248 WARN_ON_ONCE(1);
249 break;
250 }
251 field_align = max_t(size_t, field_align,
252 type->u.sequence_nestable.alignment);
253 break;
254 }
255 case atype_string:
256 break;
257 case atype_dynamic:
258 break;
259 case atype_enum_nestable:
260 default:
261 WARN_ON_ONCE(1);
262 break;
263 }
264 largest_align = max_t(size_t, largest_align, field_align);
265 }
266 ctx->largest_align = largest_align >> 3; /* bits to bytes */
267 }
268
269 /*
270 * Remove last context field.
271 */
272 void lttng_remove_context_field(struct lttng_ust_ctx **ctx_p,
273 struct lttng_ust_ctx_field *field)
274 {
275 struct lttng_ust_ctx *ctx;
276
277 ctx = *ctx_p;
278 ctx->nr_fields--;
279 assert(ctx->fields[ctx->nr_fields] == field);
280 assert(field->field_name == NULL);
281 ctx->fields[ctx->nr_fields] = NULL;
282 }
283
284 void lttng_destroy_context(struct lttng_ust_ctx *ctx)
285 {
286 int i;
287
288 if (!ctx)
289 return;
290 for (i = 0; i < ctx->nr_fields; i++) {
291 if (ctx->fields[i]->destroy)
292 ctx->fields[i]->destroy(ctx->fields[i]);
293 free(ctx->fields[i]->field_name);
294 free(ctx->fields[i]->event_field);
295 free(ctx->fields[i]);
296 }
297 free(ctx->fields);
298 free(ctx);
299 }
300
301 /*
302 * Can be safely performed concurrently with tracing using the struct
303 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
304 * contexts.
305 *
306 * This does not allow adding, removing, or changing typing of the
307 * contexts, since this needs to stay invariant for metadata. However,
308 * it allows updating the handlers associated with all contexts matching
309 * a provider (by name) while tracing is using it, in a way that ensures
310 * a single RCU read-side critical section see either all old, or all
311 * new handlers.
312 */
313 int lttng_ust_context_set_provider_rcu(struct lttng_ust_ctx **_ctx,
314 const char *name,
315 size_t (*get_size)(struct lttng_ust_ctx_field *field, size_t offset),
316 void (*record)(struct lttng_ust_ctx_field *field,
317 struct lttng_ust_lib_ring_buffer_ctx *ctx,
318 struct lttng_channel *chan),
319 void (*get_value)(struct lttng_ust_ctx_field *field,
320 struct lttng_ust_ctx_value *value))
321 {
322 int i, ret;
323 struct lttng_ust_ctx *ctx = *_ctx, *new_ctx;
324 struct lttng_ust_ctx_field **new_fields;
325
326 if (!ctx || !lttng_find_context_provider(ctx, name))
327 return 0;
328 /*
329 * We have at least one instance of context for the provider.
330 */
331 new_ctx = zmalloc(sizeof(*new_ctx));
332 if (!new_ctx)
333 return -ENOMEM;
334 new_ctx->struct_size = sizeof(*new_ctx);
335 *new_ctx = *ctx;
336 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
337 if (!new_fields) {
338 ret = -ENOMEM;
339 goto field_error;
340 }
341 /* Copy pointers */
342 memcpy(new_fields, ctx->fields,
343 sizeof(*new_fields) * ctx->allocated_fields);
344 for (i = 0; i < ctx->nr_fields; i++) {
345 if (strncmp(new_fields[i]->event_field->name,
346 name, strlen(name)) != 0)
347 continue;
348 new_fields[i]->get_size = get_size;
349 new_fields[i]->record = record;
350 new_fields[i]->get_value = get_value;
351 }
352 new_ctx->fields = new_fields;
353 lttng_ust_rcu_assign_pointer(*_ctx, new_ctx);
354 lttng_ust_urcu_synchronize_rcu();
355 free(ctx->fields);
356 free(ctx);
357 return 0;
358
359 field_error:
360 free(new_ctx);
361 return ret;
362 }
363
364 int lttng_context_init_all(struct lttng_ust_ctx **ctx)
365 {
366 int ret;
367
368 ret = lttng_add_pthread_id_to_ctx(ctx);
369 if (ret) {
370 WARN("Cannot add context lttng_add_pthread_id_to_ctx");
371 goto error;
372 }
373 ret = lttng_add_vtid_to_ctx(ctx);
374 if (ret) {
375 WARN("Cannot add context lttng_add_vtid_to_ctx");
376 goto error;
377 }
378 ret = lttng_add_vpid_to_ctx(ctx);
379 if (ret) {
380 WARN("Cannot add context lttng_add_vpid_to_ctx");
381 goto error;
382 }
383 ret = lttng_add_procname_to_ctx(ctx);
384 if (ret) {
385 WARN("Cannot add context lttng_add_procname_to_ctx");
386 goto error;
387 }
388 ret = lttng_add_cpu_id_to_ctx(ctx);
389 if (ret) {
390 WARN("Cannot add context lttng_add_cpu_id_to_ctx");
391 goto error;
392 }
393 ret = lttng_add_cgroup_ns_to_ctx(ctx);
394 if (ret) {
395 WARN("Cannot add context lttng_add_cgroup_ns_to_ctx");
396 goto error;
397 }
398 ret = lttng_add_ipc_ns_to_ctx(ctx);
399 if (ret) {
400 WARN("Cannot add context lttng_add_ipc_ns_to_ctx");
401 goto error;
402 }
403 ret = lttng_add_mnt_ns_to_ctx(ctx);
404 if (ret) {
405 WARN("Cannot add context lttng_add_mnt_ns_to_ctx");
406 goto error;
407 }
408 ret = lttng_add_net_ns_to_ctx(ctx);
409 if (ret) {
410 WARN("Cannot add context lttng_add_net_ns_to_ctx");
411 goto error;
412 }
413 ret = lttng_add_pid_ns_to_ctx(ctx);
414 if (ret) {
415 WARN("Cannot add context lttng_add_pid_ns_to_ctx");
416 goto error;
417 }
418 ret = lttng_add_time_ns_to_ctx(ctx);
419 if (ret) {
420 WARN("Cannot add context lttng_add_time_ns_to_ctx");
421 goto error;
422 }
423 ret = lttng_add_user_ns_to_ctx(ctx);
424 if (ret) {
425 WARN("Cannot add context lttng_add_user_ns_to_ctx");
426 goto error;
427 }
428 ret = lttng_add_uts_ns_to_ctx(ctx);
429 if (ret) {
430 WARN("Cannot add context lttng_add_uts_ns_to_ctx");
431 goto error;
432 }
433 ret = lttng_add_vuid_to_ctx(ctx);
434 if (ret) {
435 WARN("Cannot add context lttng_add_vuid_to_ctx");
436 goto error;
437 }
438 ret = lttng_add_veuid_to_ctx(ctx);
439 if (ret) {
440 WARN("Cannot add context lttng_add_veuid_to_ctx");
441 goto error;
442 }
443 ret = lttng_add_vsuid_to_ctx(ctx);
444 if (ret) {
445 WARN("Cannot add context lttng_add_vsuid_to_ctx");
446 goto error;
447 }
448 ret = lttng_add_vgid_to_ctx(ctx);
449 if (ret) {
450 WARN("Cannot add context lttng_add_vgid_to_ctx");
451 goto error;
452 }
453 ret = lttng_add_vegid_to_ctx(ctx);
454 if (ret) {
455 WARN("Cannot add context lttng_add_vegid_to_ctx");
456 goto error;
457 }
458 ret = lttng_add_vsgid_to_ctx(ctx);
459 if (ret) {
460 WARN("Cannot add context lttng_add_vsgid_to_ctx");
461 goto error;
462 }
463 lttng_context_update(*ctx);
464 return 0;
465
466 error:
467 lttng_destroy_context(*ctx);
468 return ret;
469 }
This page took 0.048487 seconds and 5 git commands to generate.