cleanup: Remove redefinition of CHAR_BIT
[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 <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
30 int 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
50 int 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
72 static 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 */
91 static
92 int 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
121 struct 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
141 error_add_context:
142 free(field->event_field);
143 error_alloc_event_field:
144 free(field);
145 error_alloc_field:
146 return NULL;
147 }
148
149 /*
150 * Takes ownership of @f on success.
151 */
152 int 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
193 static 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 */
233 void 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 */
250 void 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
265 void 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 */
295 int 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
341 field_error:
342 free(new_ctx);
343 return ret;
344 }
345
346 int 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
448 error:
449 lttng_destroy_context(*ctx);
450 return ret;
451 }
This page took 0.038552 seconds and 5 git commands to generate.