Implement dynamic types, and application context provider support
[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
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_context_is_app(const char *name)
59 {
60 if (strncmp(name, "$app.", strlen("$app.")) != 0) {
61 return 0;
62 }
63 return 1;
64 }
65
66 int lttng_get_context_index(struct lttng_ctx *ctx, const char *name)
67 {
68 unsigned int i;
69 const char *subname;
70
71 if (!ctx)
72 return -1;
73 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
74 subname = name + strlen("$ctx.");
75 } else {
76 subname = name;
77 }
78 for (i = 0; i < ctx->nr_fields; i++) {
79 /* Skip allocated (but non-initialized) contexts */
80 if (!ctx->fields[i].event_field.name)
81 continue;
82 if (!strcmp(ctx->fields[i].event_field.name, subname))
83 return i;
84 }
85 return -1;
86 }
87
88 static int lttng_find_context_provider(struct lttng_ctx *ctx, const char *name)
89 {
90 unsigned int i;
91
92 for (i = 0; i < ctx->nr_fields; i++) {
93 /* Skip allocated (but non-initialized) contexts */
94 if (!ctx->fields[i].event_field.name)
95 continue;
96 if (!strncmp(ctx->fields[i].event_field.name, name,
97 strlen(name)))
98 return 1;
99 }
100 return 0;
101 }
102
103 /*
104 * Note: as we append context information, the pointer location may change.
105 */
106 struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p)
107 {
108 struct lttng_ctx_field *field;
109 struct lttng_ctx *ctx;
110
111 if (!*ctx_p) {
112 *ctx_p = zmalloc(sizeof(struct lttng_ctx));
113 if (!*ctx_p)
114 return NULL;
115 (*ctx_p)->largest_align = 1;
116 }
117 ctx = *ctx_p;
118 if (ctx->nr_fields + 1 > ctx->allocated_fields) {
119 struct lttng_ctx_field *new_fields;
120
121 ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
122 new_fields = zmalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field));
123 if (!new_fields)
124 return NULL;
125 if (ctx->fields)
126 memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
127 free(ctx->fields);
128 ctx->fields = new_fields;
129 }
130 field = &ctx->fields[ctx->nr_fields];
131 ctx->nr_fields++;
132 return field;
133 }
134
135 int lttng_context_add_rcu(struct lttng_ctx **ctx_p,
136 const struct lttng_ctx_field *f)
137 {
138 struct lttng_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
139 struct lttng_ctx_field *new_fields = NULL;
140 struct lttng_ctx_field *nf;
141
142 if (old_ctx) {
143 new_ctx = zmalloc(sizeof(struct lttng_ctx));
144 if (!new_ctx)
145 return -ENOMEM;
146 *new_ctx = *old_ctx;
147 new_fields = zmalloc(new_ctx->allocated_fields
148 * sizeof(struct lttng_ctx_field));
149 if (!new_fields) {
150 free(new_ctx);
151 return -ENOMEM;
152 }
153 memcpy(new_fields, old_ctx->fields,
154 sizeof(*old_ctx->fields) * old_ctx->nr_fields);
155 new_ctx->fields = new_fields;
156 }
157 nf = lttng_append_context(&new_ctx);
158 if (!nf) {
159 free(new_fields);
160 free(new_ctx);
161 return -ENOMEM;
162 }
163 *nf = *f;
164 lttng_context_update(new_ctx);
165 rcu_assign_pointer(*ctx_p, new_ctx);
166 synchronize_trace();
167 if (old_ctx) {
168 free(old_ctx->fields);
169 free(old_ctx);
170 }
171 return 0;
172 }
173
174 /*
175 * lttng_context_update() should be called at least once between context
176 * modification and trace start.
177 */
178 void lttng_context_update(struct lttng_ctx *ctx)
179 {
180 int i;
181 size_t largest_align = 8; /* in bits */
182
183 for (i = 0; i < ctx->nr_fields; i++) {
184 struct lttng_type *type;
185 size_t field_align = 8;
186
187 type = &ctx->fields[i].event_field.type;
188 switch (type->atype) {
189 case atype_integer:
190 field_align = type->u.basic.integer.alignment;
191 break;
192 case atype_array:
193 {
194 struct lttng_basic_type *btype;
195
196 btype = &type->u.array.elem_type;
197 switch (btype->atype) {
198 case atype_integer:
199 field_align = btype->u.basic.integer.alignment;
200 break;
201 case atype_string:
202 break;
203
204 case atype_array:
205 case atype_sequence:
206 default:
207 WARN_ON_ONCE(1);
208 break;
209 }
210 break;
211 }
212 case atype_sequence:
213 {
214 struct lttng_basic_type *btype;
215
216 btype = &type->u.sequence.length_type;
217 switch (btype->atype) {
218 case atype_integer:
219 field_align = btype->u.basic.integer.alignment;
220 break;
221
222 case atype_string:
223 case atype_array:
224 case atype_sequence:
225 default:
226 WARN_ON_ONCE(1);
227 break;
228 }
229
230 btype = &type->u.sequence.elem_type;
231 switch (btype->atype) {
232 case atype_integer:
233 field_align = max_t(size_t,
234 field_align,
235 btype->u.basic.integer.alignment);
236 break;
237
238 case atype_string:
239 break;
240
241 case atype_array:
242 case atype_sequence:
243 default:
244 WARN_ON_ONCE(1);
245 break;
246 }
247 break;
248 }
249 case atype_string:
250 break;
251 case atype_dynamic:
252 break;
253 case atype_enum:
254 default:
255 WARN_ON_ONCE(1);
256 break;
257 }
258 largest_align = max_t(size_t, largest_align, field_align);
259 }
260 ctx->largest_align = largest_align >> 3; /* bits to bytes */
261 }
262
263 /*
264 * Remove last context field.
265 */
266 void lttng_remove_context_field(struct lttng_ctx **ctx_p,
267 struct lttng_ctx_field *field)
268 {
269 struct lttng_ctx *ctx;
270
271 ctx = *ctx_p;
272 ctx->nr_fields--;
273 assert(&ctx->fields[ctx->nr_fields] == field);
274 assert(field->field_name == NULL);
275 memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
276 }
277
278 void lttng_destroy_context(struct lttng_ctx *ctx)
279 {
280 int i;
281
282 if (!ctx)
283 return;
284 for (i = 0; i < ctx->nr_fields; i++) {
285 if (ctx->fields[i].destroy)
286 ctx->fields[i].destroy(&ctx->fields[i]);
287 free(ctx->fields[i].field_name);
288 }
289 free(ctx->fields);
290 free(ctx);
291 }
292
293 /*
294 * Can be safely performed concurrently with tracing using the struct
295 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
296 * contexts.
297 *
298 * This does not allow adding, removing, or changing typing of the
299 * contexts, since this needs to stay invariant for metadata. However,
300 * it allows updating the handlers associated with all contexts matching
301 * a provider (by name) while tracing is using it, in a way that ensures
302 * a single RCU read-side critical section see either all old, or all
303 * new handlers.
304 */
305 int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
306 const char *name,
307 size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
308 void (*record)(struct lttng_ctx_field *field,
309 struct lttng_ust_lib_ring_buffer_ctx *ctx,
310 struct lttng_channel *chan),
311 void (*get_value)(struct lttng_ctx_field *field,
312 struct lttng_ctx_value *value))
313 {
314 int i, ret;
315 struct lttng_ctx *ctx = *_ctx, *new_ctx;
316 struct lttng_ctx_field *new_fields;
317
318 if (!ctx || !lttng_find_context_provider(ctx, name))
319 return 0;
320 /*
321 * We have at least one instance of context for the provider.
322 */
323 new_ctx = zmalloc(sizeof(*new_ctx));
324 if (!new_ctx)
325 return -ENOMEM;
326 *new_ctx = *ctx;
327 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
328 if (!new_fields) {
329 ret = -ENOMEM;
330 goto field_error;
331 }
332 memcpy(new_fields, ctx->fields,
333 sizeof(*new_fields) * ctx->allocated_fields);
334 for (i = 0; i < ctx->nr_fields; i++) {
335 if (strncmp(new_fields[i].event_field.name,
336 name, strlen(name)) != 0)
337 continue;
338 new_fields[i].get_size = get_size;
339 new_fields[i].record = record;
340 new_fields[i].get_value = get_value;
341 }
342 new_ctx->fields = new_fields;
343 rcu_assign_pointer(*_ctx, new_ctx);
344 synchronize_trace();
345 free(ctx->fields);
346 free(ctx);
347 return 0;
348
349 field_error:
350 free(new_ctx);
351 return ret;
352 }
353
354 int lttng_session_context_init(struct lttng_ctx **ctx)
355 {
356 int ret;
357
358 ret = lttng_add_pthread_id_to_ctx(ctx);
359 if (ret) {
360 WARN("Cannot add context lttng_add_pthread_id_to_ctx");
361 goto error;
362 }
363 ret = lttng_add_vtid_to_ctx(ctx);
364 if (ret) {
365 WARN("Cannot add context lttng_add_vtid_to_ctx");
366 goto error;
367 }
368 ret = lttng_add_vpid_to_ctx(ctx);
369 if (ret) {
370 WARN("Cannot add context lttng_add_vpid_to_ctx");
371 goto error;
372 }
373 ret = lttng_add_procname_to_ctx(ctx);
374 if (ret) {
375 WARN("Cannot add context lttng_add_procname_to_ctx");
376 goto error;
377 }
378 ret = lttng_add_cpu_id_to_ctx(ctx);
379 if (ret) {
380 WARN("Cannot add context lttng_add_cpu_id_to_ctx");
381 goto error;
382 }
383 lttng_context_update(*ctx);
384 return 0;
385
386 error:
387 lttng_destroy_context(*ctx);
388 return ret;
389 }
This page took 0.03815 seconds and 5 git commands to generate.