Introduce LTTNG_UST_MAP_POPULATE_POLICY environment variable
[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 <string.h>
31 #include <assert.h>
32
33 /*
34 * The filter implementation requires that two consecutive "get" for the
35 * same context performed by the same thread return the same result.
36 */
37
38 int lttng_find_context(struct lttng_ctx *ctx, const char *name)
39 {
40 unsigned int i;
41 const char *subname;
42
43 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
44 subname = name + strlen("$ctx.");
45 } else {
46 subname = name;
47 }
48 for (i = 0; i < ctx->nr_fields; i++) {
49 /* Skip allocated (but non-initialized) contexts */
50 if (!ctx->fields[i].event_field.name)
51 continue;
52 if (!strcmp(ctx->fields[i].event_field.name, subname))
53 return 1;
54 }
55 return 0;
56 }
57
58 int lttng_get_context_index(struct lttng_ctx *ctx, const char *name)
59 {
60 unsigned int i;
61 const char *subname;
62
63 if (!ctx)
64 return -1;
65 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
66 subname = name + strlen("$ctx.");
67 } else {
68 subname = name;
69 }
70 for (i = 0; i < ctx->nr_fields; i++) {
71 /* Skip allocated (but non-initialized) contexts */
72 if (!ctx->fields[i].event_field.name)
73 continue;
74 if (!strcmp(ctx->fields[i].event_field.name, subname))
75 return i;
76 }
77 return -1;
78 }
79
80 static int lttng_find_context_provider(struct lttng_ctx *ctx, const char *name)
81 {
82 unsigned int i;
83
84 for (i = 0; i < ctx->nr_fields; i++) {
85 /* Skip allocated (but non-initialized) contexts */
86 if (!ctx->fields[i].event_field.name)
87 continue;
88 if (!strncmp(ctx->fields[i].event_field.name, name,
89 strlen(name)))
90 return 1;
91 }
92 return 0;
93 }
94
95 /*
96 * Note: as we append context information, the pointer location may change.
97 */
98 struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p)
99 {
100 struct lttng_ctx_field *field;
101 struct lttng_ctx *ctx;
102
103 if (!*ctx_p) {
104 *ctx_p = zmalloc(sizeof(struct lttng_ctx));
105 if (!*ctx_p)
106 return NULL;
107 (*ctx_p)->largest_align = 1;
108 }
109 ctx = *ctx_p;
110 if (ctx->nr_fields + 1 > ctx->allocated_fields) {
111 struct lttng_ctx_field *new_fields;
112
113 ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
114 new_fields = zmalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field));
115 if (!new_fields)
116 return NULL;
117 if (ctx->fields)
118 memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
119 free(ctx->fields);
120 ctx->fields = new_fields;
121 }
122 field = &ctx->fields[ctx->nr_fields];
123 ctx->nr_fields++;
124 return field;
125 }
126
127 int lttng_context_add_rcu(struct lttng_ctx **ctx_p,
128 const struct lttng_ctx_field *f)
129 {
130 struct lttng_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
131 struct lttng_ctx_field *new_fields = NULL;
132 struct lttng_ctx_field *nf;
133
134 if (old_ctx) {
135 new_ctx = zmalloc(sizeof(struct lttng_ctx));
136 if (!new_ctx)
137 return -ENOMEM;
138 *new_ctx = *old_ctx;
139 new_fields = zmalloc(new_ctx->allocated_fields
140 * sizeof(struct lttng_ctx_field));
141 if (!new_fields) {
142 free(new_ctx);
143 return -ENOMEM;
144 }
145 memcpy(new_fields, old_ctx->fields,
146 sizeof(*old_ctx->fields) * old_ctx->nr_fields);
147 new_ctx->fields = new_fields;
148 }
149 nf = lttng_append_context(&new_ctx);
150 if (!nf) {
151 free(new_fields);
152 free(new_ctx);
153 return -ENOMEM;
154 }
155 *nf = *f;
156 lttng_context_update(new_ctx);
157 rcu_assign_pointer(*ctx_p, new_ctx);
158 synchronize_trace();
159 if (old_ctx) {
160 free(old_ctx->fields);
161 free(old_ctx);
162 }
163 return 0;
164 }
165
166 /*
167 * lttng_context_update() should be called at least once between context
168 * modification and trace start.
169 */
170 void lttng_context_update(struct lttng_ctx *ctx)
171 {
172 int i;
173 size_t largest_align = 8; /* in bits */
174
175 for (i = 0; i < ctx->nr_fields; i++) {
176 struct lttng_type *type;
177 size_t field_align = 8;
178
179 type = &ctx->fields[i].event_field.type;
180 switch (type->atype) {
181 case atype_integer:
182 field_align = type->u.basic.integer.alignment;
183 break;
184 case atype_array:
185 {
186 struct lttng_basic_type *btype;
187
188 btype = &type->u.array.elem_type;
189 switch (btype->atype) {
190 case atype_integer:
191 field_align = btype->u.basic.integer.alignment;
192 break;
193 case atype_string:
194 break;
195
196 case atype_array:
197 case atype_sequence:
198 default:
199 WARN_ON_ONCE(1);
200 break;
201 }
202 break;
203 }
204 case atype_sequence:
205 {
206 struct lttng_basic_type *btype;
207
208 btype = &type->u.sequence.length_type;
209 switch (btype->atype) {
210 case atype_integer:
211 field_align = btype->u.basic.integer.alignment;
212 break;
213
214 case atype_string:
215 case atype_array:
216 case atype_sequence:
217 default:
218 WARN_ON_ONCE(1);
219 break;
220 }
221
222 btype = &type->u.sequence.elem_type;
223 switch (btype->atype) {
224 case atype_integer:
225 field_align = max_t(size_t,
226 field_align,
227 btype->u.basic.integer.alignment);
228 break;
229
230 case atype_string:
231 break;
232
233 case atype_array:
234 case atype_sequence:
235 default:
236 WARN_ON_ONCE(1);
237 break;
238 }
239 break;
240 }
241 case atype_string:
242 break;
243 case atype_dynamic:
244 break;
245 case atype_enum:
246 default:
247 WARN_ON_ONCE(1);
248 break;
249 }
250 largest_align = max_t(size_t, largest_align, field_align);
251 }
252 ctx->largest_align = largest_align >> 3; /* bits to bytes */
253 }
254
255 /*
256 * Remove last context field.
257 */
258 void lttng_remove_context_field(struct lttng_ctx **ctx_p,
259 struct lttng_ctx_field *field)
260 {
261 struct lttng_ctx *ctx;
262
263 ctx = *ctx_p;
264 ctx->nr_fields--;
265 assert(&ctx->fields[ctx->nr_fields] == field);
266 assert(field->field_name == NULL);
267 memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
268 }
269
270 void lttng_destroy_context(struct lttng_ctx *ctx)
271 {
272 int i;
273
274 if (!ctx)
275 return;
276 for (i = 0; i < ctx->nr_fields; i++) {
277 if (ctx->fields[i].destroy)
278 ctx->fields[i].destroy(&ctx->fields[i]);
279 free(ctx->fields[i].field_name);
280 }
281 free(ctx->fields);
282 free(ctx);
283 }
284
285 /*
286 * Can be safely performed concurrently with tracing using the struct
287 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
288 * contexts.
289 *
290 * This does not allow adding, removing, or changing typing of the
291 * contexts, since this needs to stay invariant for metadata. However,
292 * it allows updating the handlers associated with all contexts matching
293 * a provider (by name) while tracing is using it, in a way that ensures
294 * a single RCU read-side critical section see either all old, or all
295 * new handlers.
296 */
297 int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
298 const char *name,
299 size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
300 void (*record)(struct lttng_ctx_field *field,
301 struct lttng_ust_lib_ring_buffer_ctx *ctx,
302 struct lttng_channel *chan),
303 void (*get_value)(struct lttng_ctx_field *field,
304 struct lttng_ctx_value *value))
305 {
306 int i, ret;
307 struct lttng_ctx *ctx = *_ctx, *new_ctx;
308 struct lttng_ctx_field *new_fields;
309
310 if (!ctx || !lttng_find_context_provider(ctx, name))
311 return 0;
312 /*
313 * We have at least one instance of context for the provider.
314 */
315 new_ctx = zmalloc(sizeof(*new_ctx));
316 if (!new_ctx)
317 return -ENOMEM;
318 *new_ctx = *ctx;
319 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
320 if (!new_fields) {
321 ret = -ENOMEM;
322 goto field_error;
323 }
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 rcu_assign_pointer(*_ctx, new_ctx);
336 synchronize_trace();
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_session_context_init(struct lttng_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_user_ns_to_ctx(ctx);
401 if (ret) {
402 WARN("Cannot add context lttng_add_user_ns_to_ctx");
403 goto error;
404 }
405 ret = lttng_add_uts_ns_to_ctx(ctx);
406 if (ret) {
407 WARN("Cannot add context lttng_add_uts_ns_to_ctx");
408 goto error;
409 }
410 ret = lttng_add_vuid_to_ctx(ctx);
411 if (ret) {
412 WARN("Cannot add context lttng_add_vuid_to_ctx");
413 goto error;
414 }
415 ret = lttng_add_veuid_to_ctx(ctx);
416 if (ret) {
417 WARN("Cannot add context lttng_add_veuid_to_ctx");
418 goto error;
419 }
420 ret = lttng_add_vsuid_to_ctx(ctx);
421 if (ret) {
422 WARN("Cannot add context lttng_add_vsuid_to_ctx");
423 goto error;
424 }
425 ret = lttng_add_vgid_to_ctx(ctx);
426 if (ret) {
427 WARN("Cannot add context lttng_add_vgid_to_ctx");
428 goto error;
429 }
430 ret = lttng_add_vegid_to_ctx(ctx);
431 if (ret) {
432 WARN("Cannot add context lttng_add_vegid_to_ctx");
433 goto error;
434 }
435 ret = lttng_add_vsgid_to_ctx(ctx);
436 if (ret) {
437 WARN("Cannot add context lttng_add_vsgid_to_ctx");
438 goto error;
439 }
440 lttng_context_update(*ctx);
441 return 0;
442
443 error:
444 lttng_destroy_context(*ctx);
445 return ret;
446 }
447
448 /* For backward compatibility. Leave those exported symbols in place. */
449 struct lttng_ctx *lttng_static_ctx;
450
451 void lttng_context_init(void)
452 {
453 }
454
455 void lttng_context_exit(void)
456 {
457 }
This page took 0.0371 seconds and 4 git commands to generate.