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