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