Remove array, sequence, enum, struct legacy types
[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_nestable:
176 {
177 const struct lttng_type *nested_type;
178
179 nested_type = type->u.array_nestable.elem_type;
180 switch (nested_type->atype) {
181 case atype_integer:
182 field_align = nested_type->u.integer.alignment;
183 break;
184 case atype_string:
185 break;
186
187 case atype_array_nestable:
188 case atype_sequence_nestable:
189 default:
190 WARN_ON_ONCE(1);
191 break;
192 }
193 field_align = max_t(size_t, field_align,
194 type->u.array_nestable.alignment);
195 break;
196 }
197 case atype_sequence_nestable:
198 {
199 const struct lttng_type *nested_type;
200
201 nested_type = type->u.sequence_nestable.elem_type;
202 switch (nested_type->atype) {
203 case atype_integer:
204 field_align = nested_type->u.integer.alignment;
205 break;
206
207 case atype_string:
208 break;
209
210 case atype_array_nestable:
211 case atype_sequence_nestable:
212 default:
213 WARN_ON_ONCE(1);
214 break;
215 }
216 field_align = max_t(size_t, field_align,
217 type->u.sequence_nestable.alignment);
218 break;
219 }
220 case atype_string:
221 break;
222 case atype_dynamic:
223 break;
224 case atype_enum_nestable:
225 default:
226 WARN_ON_ONCE(1);
227 break;
228 }
229 largest_align = max_t(size_t, largest_align, field_align);
230 }
231 ctx->largest_align = largest_align >> 3; /* bits to bytes */
232 }
233
234 /*
235 * Remove last context field.
236 */
237 void lttng_remove_context_field(struct lttng_ctx **ctx_p,
238 struct lttng_ctx_field *field)
239 {
240 struct lttng_ctx *ctx;
241
242 ctx = *ctx_p;
243 ctx->nr_fields--;
244 assert(&ctx->fields[ctx->nr_fields] == field);
245 assert(field->field_name == NULL);
246 memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
247 }
248
249 void lttng_destroy_context(struct lttng_ctx *ctx)
250 {
251 int i;
252
253 if (!ctx)
254 return;
255 for (i = 0; i < ctx->nr_fields; i++) {
256 if (ctx->fields[i].destroy)
257 ctx->fields[i].destroy(&ctx->fields[i]);
258 free(ctx->fields[i].field_name);
259 }
260 free(ctx->fields);
261 free(ctx);
262 }
263
264 /*
265 * Can be safely performed concurrently with tracing using the struct
266 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
267 * contexts.
268 *
269 * This does not allow adding, removing, or changing typing of the
270 * contexts, since this needs to stay invariant for metadata. However,
271 * it allows updating the handlers associated with all contexts matching
272 * a provider (by name) while tracing is using it, in a way that ensures
273 * a single RCU read-side critical section see either all old, or all
274 * new handlers.
275 */
276 int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
277 const char *name,
278 size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
279 void (*record)(struct lttng_ctx_field *field,
280 struct lttng_ust_lib_ring_buffer_ctx *ctx,
281 struct lttng_channel *chan),
282 void (*get_value)(struct lttng_ctx_field *field,
283 struct lttng_ctx_value *value))
284 {
285 int i, ret;
286 struct lttng_ctx *ctx = *_ctx, *new_ctx;
287 struct lttng_ctx_field *new_fields;
288
289 if (!ctx || !lttng_find_context_provider(ctx, name))
290 return 0;
291 /*
292 * We have at least one instance of context for the provider.
293 */
294 new_ctx = zmalloc(sizeof(*new_ctx));
295 if (!new_ctx)
296 return -ENOMEM;
297 *new_ctx = *ctx;
298 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
299 if (!new_fields) {
300 ret = -ENOMEM;
301 goto field_error;
302 }
303 memcpy(new_fields, ctx->fields,
304 sizeof(*new_fields) * ctx->allocated_fields);
305 for (i = 0; i < ctx->nr_fields; i++) {
306 if (strncmp(new_fields[i].event_field.name,
307 name, strlen(name)) != 0)
308 continue;
309 new_fields[i].get_size = get_size;
310 new_fields[i].record = record;
311 new_fields[i].get_value = get_value;
312 }
313 new_ctx->fields = new_fields;
314 lttng_ust_rcu_assign_pointer(*_ctx, new_ctx);
315 lttng_ust_urcu_synchronize_rcu();
316 free(ctx->fields);
317 free(ctx);
318 return 0;
319
320 field_error:
321 free(new_ctx);
322 return ret;
323 }
324
325 int lttng_context_init_all(struct lttng_ctx **ctx)
326 {
327 int ret;
328
329 ret = lttng_add_pthread_id_to_ctx(ctx);
330 if (ret) {
331 WARN("Cannot add context lttng_add_pthread_id_to_ctx");
332 goto error;
333 }
334 ret = lttng_add_vtid_to_ctx(ctx);
335 if (ret) {
336 WARN("Cannot add context lttng_add_vtid_to_ctx");
337 goto error;
338 }
339 ret = lttng_add_vpid_to_ctx(ctx);
340 if (ret) {
341 WARN("Cannot add context lttng_add_vpid_to_ctx");
342 goto error;
343 }
344 ret = lttng_add_procname_to_ctx(ctx);
345 if (ret) {
346 WARN("Cannot add context lttng_add_procname_to_ctx");
347 goto error;
348 }
349 ret = lttng_add_cpu_id_to_ctx(ctx);
350 if (ret) {
351 WARN("Cannot add context lttng_add_cpu_id_to_ctx");
352 goto error;
353 }
354 ret = lttng_add_cgroup_ns_to_ctx(ctx);
355 if (ret) {
356 WARN("Cannot add context lttng_add_cgroup_ns_to_ctx");
357 goto error;
358 }
359 ret = lttng_add_ipc_ns_to_ctx(ctx);
360 if (ret) {
361 WARN("Cannot add context lttng_add_ipc_ns_to_ctx");
362 goto error;
363 }
364 ret = lttng_add_mnt_ns_to_ctx(ctx);
365 if (ret) {
366 WARN("Cannot add context lttng_add_mnt_ns_to_ctx");
367 goto error;
368 }
369 ret = lttng_add_net_ns_to_ctx(ctx);
370 if (ret) {
371 WARN("Cannot add context lttng_add_net_ns_to_ctx");
372 goto error;
373 }
374 ret = lttng_add_pid_ns_to_ctx(ctx);
375 if (ret) {
376 WARN("Cannot add context lttng_add_pid_ns_to_ctx");
377 goto error;
378 }
379 ret = lttng_add_time_ns_to_ctx(ctx);
380 if (ret) {
381 WARN("Cannot add context lttng_add_time_ns_to_ctx");
382 goto error;
383 }
384 ret = lttng_add_user_ns_to_ctx(ctx);
385 if (ret) {
386 WARN("Cannot add context lttng_add_user_ns_to_ctx");
387 goto error;
388 }
389 ret = lttng_add_uts_ns_to_ctx(ctx);
390 if (ret) {
391 WARN("Cannot add context lttng_add_uts_ns_to_ctx");
392 goto error;
393 }
394 ret = lttng_add_vuid_to_ctx(ctx);
395 if (ret) {
396 WARN("Cannot add context lttng_add_vuid_to_ctx");
397 goto error;
398 }
399 ret = lttng_add_veuid_to_ctx(ctx);
400 if (ret) {
401 WARN("Cannot add context lttng_add_veuid_to_ctx");
402 goto error;
403 }
404 ret = lttng_add_vsuid_to_ctx(ctx);
405 if (ret) {
406 WARN("Cannot add context lttng_add_vsuid_to_ctx");
407 goto error;
408 }
409 ret = lttng_add_vgid_to_ctx(ctx);
410 if (ret) {
411 WARN("Cannot add context lttng_add_vgid_to_ctx");
412 goto error;
413 }
414 ret = lttng_add_vegid_to_ctx(ctx);
415 if (ret) {
416 WARN("Cannot add context lttng_add_vegid_to_ctx");
417 goto error;
418 }
419 ret = lttng_add_vsgid_to_ctx(ctx);
420 if (ret) {
421 WARN("Cannot add context lttng_add_vsgid_to_ctx");
422 goto error;
423 }
424 lttng_context_update(*ctx);
425 return 0;
426
427 error:
428 lttng_destroy_context(*ctx);
429 return ret;
430 }
This page took 0.039004 seconds and 5 git commands to generate.