Commit | Line | Data |
---|---|---|
1c822dfb JG |
1 | /* |
2 | * stream-class.c | |
3 | * | |
4 | * Babeltrace CTF IR - Stream Class | |
5 | * | |
6 | * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
7 | * | |
8 | * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
9 | * | |
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
11 | * of this software and associated documentation files (the "Software"), to deal | |
12 | * in the Software without restriction, including without limitation the rights | |
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
14 | * copies of the Software, and to permit persons to whom the Software is | |
15 | * furnished to do so, subject to the following conditions: | |
16 | * | |
17 | * The above copyright notice and this permission notice shall be included in | |
18 | * all copies or substantial portions of the Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
26 | * SOFTWARE. | |
27 | */ | |
28 | ||
29 | #include <babeltrace/ctf-writer/clock.h> | |
30 | #include <babeltrace/ctf-ir/clock-internal.h> | |
31 | #include <babeltrace/ctf-writer/event.h> | |
32 | #include <babeltrace/ctf-ir/event-class-internal.h> | |
33 | #include <babeltrace/ctf-ir/event-internal.h> | |
34 | #include <babeltrace/ctf-ir/field-types-internal.h> | |
35 | #include <babeltrace/ctf-ir/fields-internal.h> | |
36 | #include <babeltrace/ctf-writer/stream.h> | |
37 | #include <babeltrace/ctf-ir/stream-class-internal.h> | |
38 | #include <babeltrace/ctf-ir/validation-internal.h> | |
39 | #include <babeltrace/ctf-writer/functor-internal.h> | |
40 | #include <babeltrace/ctf-ir/utils.h> | |
41 | #include <babeltrace/ref.h> | |
42 | #include <babeltrace/compiler.h> | |
43 | #include <babeltrace/align.h> | |
44 | #include <babeltrace/endian.h> | |
45 | ||
46 | static | |
47 | void bt_ctf_stream_class_destroy(struct bt_object *obj); | |
48 | static | |
49 | int init_event_header(struct bt_ctf_stream_class *stream_class); | |
50 | static | |
51 | int init_packet_context(struct bt_ctf_stream_class *stream_class); | |
52 | ||
53 | struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name) | |
54 | { | |
55 | int ret; | |
56 | struct bt_ctf_stream_class *stream_class = NULL; | |
57 | ||
58 | if (name && bt_ctf_validate_identifier(name)) { | |
59 | goto error; | |
60 | } | |
61 | ||
62 | stream_class = g_new0(struct bt_ctf_stream_class, 1); | |
63 | if (!stream_class) { | |
64 | goto error; | |
65 | } | |
66 | ||
67 | stream_class->name = g_string_new(name); | |
68 | stream_class->event_classes = g_ptr_array_new_with_free_func( | |
69 | (GDestroyNotify) bt_object_release); | |
70 | if (!stream_class->event_classes) { | |
71 | goto error; | |
72 | } | |
73 | ||
74 | ret = init_event_header(stream_class); | |
75 | if (ret) { | |
76 | goto error; | |
77 | } | |
78 | ||
79 | ret = init_packet_context(stream_class); | |
80 | if (ret) { | |
81 | goto error; | |
82 | } | |
83 | ||
84 | bt_object_init(stream_class, bt_ctf_stream_class_destroy); | |
85 | return stream_class; | |
86 | ||
87 | error: | |
88 | BT_PUT(stream_class); | |
89 | return stream_class; | |
90 | } | |
91 | ||
0f757a27 | 92 | BT_HIDDEN |
1c822dfb JG |
93 | struct bt_ctf_trace *bt_ctf_stream_class_get_trace( |
94 | struct bt_ctf_stream_class *stream_class) | |
95 | { | |
96 | return (struct bt_ctf_trace *) bt_object_get_parent( | |
97 | stream_class); | |
98 | } | |
99 | ||
0f757a27 | 100 | BT_HIDDEN |
1c822dfb JG |
101 | const char *bt_ctf_stream_class_get_name( |
102 | struct bt_ctf_stream_class *stream_class) | |
103 | { | |
104 | const char *name = NULL; | |
105 | ||
106 | if (!stream_class) { | |
107 | goto end; | |
108 | } | |
109 | ||
110 | name = stream_class->name->str; | |
111 | end: | |
112 | return name; | |
113 | } | |
114 | ||
0f757a27 | 115 | BT_HIDDEN |
1c822dfb JG |
116 | int bt_ctf_stream_class_set_name(struct bt_ctf_stream_class *stream_class, |
117 | const char *name) | |
118 | { | |
119 | int ret = 0; | |
120 | ||
121 | if (!stream_class || stream_class->frozen) { | |
122 | ret = -1; | |
123 | goto end; | |
124 | } | |
125 | ||
126 | g_string_assign(stream_class->name, name); | |
127 | end: | |
128 | return ret; | |
129 | } | |
130 | ||
0f757a27 | 131 | BT_HIDDEN |
1c822dfb JG |
132 | struct bt_ctf_clock *bt_ctf_stream_class_get_clock( |
133 | struct bt_ctf_stream_class *stream_class) | |
134 | { | |
135 | struct bt_ctf_clock *clock = NULL; | |
136 | ||
137 | if (!stream_class || !stream_class->clock) { | |
138 | goto end; | |
139 | } | |
140 | ||
141 | clock = stream_class->clock; | |
142 | bt_get(clock); | |
143 | end: | |
144 | return clock; | |
145 | } | |
146 | ||
147 | int bt_ctf_stream_class_set_clock(struct bt_ctf_stream_class *stream_class, | |
148 | struct bt_ctf_clock *clock) | |
149 | { | |
150 | int ret = 0; | |
151 | struct bt_ctf_field_type *timestamp_field = NULL; | |
152 | ||
153 | if (!stream_class || !clock || stream_class->frozen) { | |
154 | ret = -1; | |
155 | goto end; | |
156 | } | |
157 | ||
158 | /* | |
159 | * Look for a "timestamp" field in the stream class' event header type | |
160 | * and map the stream's clock to that field if no current mapping is | |
161 | * currently set. | |
162 | */ | |
163 | timestamp_field = bt_ctf_field_type_structure_get_field_type_by_name( | |
164 | stream_class->event_header_type, "timestamp"); | |
165 | if (timestamp_field) { | |
166 | struct bt_ctf_clock *mapped_clock; | |
167 | ||
168 | mapped_clock = bt_ctf_field_type_integer_get_mapped_clock( | |
169 | timestamp_field); | |
170 | if (mapped_clock) { | |
171 | bt_put(mapped_clock); | |
172 | goto end; | |
173 | } | |
174 | ||
175 | ret = bt_ctf_field_type_integer_set_mapped_clock( | |
176 | timestamp_field, clock); | |
177 | if (ret) { | |
178 | goto end; | |
179 | } | |
180 | } | |
181 | ||
182 | if (stream_class->clock) { | |
183 | bt_put(stream_class->clock); | |
184 | } | |
185 | ||
186 | stream_class->clock = clock; | |
187 | bt_get(clock); | |
188 | end: | |
189 | if (timestamp_field) { | |
190 | bt_put(timestamp_field); | |
191 | } | |
192 | return ret; | |
193 | } | |
194 | ||
0f757a27 | 195 | BT_HIDDEN |
1c822dfb JG |
196 | int64_t bt_ctf_stream_class_get_id(struct bt_ctf_stream_class *stream_class) |
197 | { | |
198 | int64_t ret; | |
199 | ||
200 | if (!stream_class || !stream_class->id_set) { | |
201 | ret = -1; | |
202 | goto end; | |
203 | } | |
204 | ||
205 | ret = (int64_t) stream_class->id; | |
206 | end: | |
207 | return ret; | |
208 | } | |
209 | ||
210 | BT_HIDDEN | |
211 | int _bt_ctf_stream_class_set_id( | |
212 | struct bt_ctf_stream_class *stream_class, uint32_t id) | |
213 | { | |
214 | stream_class->id = id; | |
215 | stream_class->id_set = 1; | |
216 | return 0; | |
217 | } | |
218 | ||
219 | struct event_class_set_stream_id_data { | |
220 | uint32_t stream_id; | |
221 | int ret; | |
222 | }; | |
223 | ||
224 | static | |
225 | void event_class_set_stream_id(gpointer event_class, gpointer data) | |
226 | { | |
227 | struct event_class_set_stream_id_data *typed_data = data; | |
228 | ||
229 | typed_data->ret |= bt_ctf_event_class_set_stream_id(event_class, | |
230 | typed_data->stream_id); | |
231 | } | |
232 | ||
233 | BT_HIDDEN | |
234 | int bt_ctf_stream_class_set_id_no_check( | |
235 | struct bt_ctf_stream_class *stream_class, uint32_t id) | |
236 | { | |
237 | int ret = 0; | |
238 | struct event_class_set_stream_id_data data = | |
239 | { .stream_id = id, .ret = 0 }; | |
240 | ||
241 | /* | |
242 | * Make sure all event classes have their "stream_id" attribute | |
243 | * set to this value. | |
244 | */ | |
245 | g_ptr_array_foreach(stream_class->event_classes, | |
246 | event_class_set_stream_id, &data); | |
247 | ret = data.ret; | |
248 | if (ret) { | |
249 | goto end; | |
250 | } | |
251 | ||
252 | ret = _bt_ctf_stream_class_set_id(stream_class, id); | |
253 | if (ret) { | |
254 | goto end; | |
255 | } | |
256 | end: | |
257 | return ret; | |
258 | } | |
259 | ||
260 | int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class, | |
261 | uint32_t id) | |
262 | { | |
263 | int ret = 0; | |
264 | ||
265 | if (!stream_class || stream_class->frozen) { | |
266 | ret = -1; | |
267 | goto end; | |
268 | } | |
269 | ||
270 | ret = bt_ctf_stream_class_set_id_no_check(stream_class, id); | |
271 | end: | |
272 | return ret; | |
273 | } | |
274 | ||
275 | static | |
276 | void event_class_exists(gpointer element, gpointer query) | |
277 | { | |
278 | struct bt_ctf_event_class *event_class_a = element; | |
279 | struct search_query *search_query = query; | |
280 | struct bt_ctf_event_class *event_class_b = search_query->value; | |
281 | int64_t id_a, id_b; | |
282 | ||
283 | if (search_query->value == element) { | |
284 | search_query->found = 1; | |
285 | goto end; | |
286 | } | |
287 | ||
288 | /* | |
289 | * Two event classes cannot share the same name in a given | |
290 | * stream class. | |
291 | */ | |
292 | if (!strcmp(bt_ctf_event_class_get_name(event_class_a), | |
293 | bt_ctf_event_class_get_name(event_class_b))) { | |
294 | search_query->found = 1; | |
295 | goto end; | |
296 | } | |
297 | ||
298 | /* | |
299 | * Two event classes cannot share the same ID in a given | |
300 | * stream class. | |
301 | */ | |
302 | id_a = bt_ctf_event_class_get_id(event_class_a); | |
303 | id_b = bt_ctf_event_class_get_id(event_class_b); | |
304 | ||
305 | if (id_a < 0 || id_b < 0) { | |
306 | /* at least one ID is not set: will be automatically set later */ | |
307 | goto end; | |
308 | } | |
309 | ||
310 | if (id_a == id_b) { | |
311 | search_query->found = 1; | |
312 | goto end; | |
313 | } | |
314 | ||
315 | end: | |
316 | return; | |
317 | } | |
318 | ||
319 | int bt_ctf_stream_class_add_event_class( | |
320 | struct bt_ctf_stream_class *stream_class, | |
321 | struct bt_ctf_event_class *event_class) | |
322 | { | |
323 | int ret = 0; | |
324 | int64_t event_id; | |
325 | struct bt_ctf_trace *trace = NULL; | |
326 | struct bt_ctf_stream_class *old_stream_class = NULL; | |
327 | struct bt_ctf_validation_output validation_output = { 0 }; | |
328 | struct bt_ctf_field_type *packet_header_type = NULL; | |
329 | struct bt_ctf_field_type *packet_context_type = NULL; | |
330 | struct bt_ctf_field_type *event_header_type = NULL; | |
331 | struct bt_ctf_field_type *stream_event_ctx_type = NULL; | |
332 | struct bt_ctf_field_type *event_context_type = NULL; | |
333 | struct bt_ctf_field_type *event_payload_type = NULL; | |
334 | const enum bt_ctf_validation_flag validation_flags = | |
335 | BT_CTF_VALIDATION_FLAG_EVENT; | |
336 | ||
337 | if (!stream_class || !event_class) { | |
338 | ret = -1; | |
339 | goto end; | |
340 | } | |
341 | ||
342 | /* Check for duplicate event classes */ | |
343 | struct search_query query = { .value = event_class, .found = 0 }; | |
344 | g_ptr_array_foreach(stream_class->event_classes, event_class_exists, | |
345 | &query); | |
346 | if (query.found) { | |
347 | ret = -1; | |
348 | goto end; | |
349 | } | |
350 | ||
351 | old_stream_class = bt_ctf_event_class_get_stream_class(event_class); | |
352 | if (old_stream_class) { | |
353 | /* Event class is already associated to a stream class. */ | |
354 | ret = -1; | |
355 | goto end; | |
356 | } | |
357 | ||
358 | trace = bt_ctf_stream_class_get_trace(stream_class); | |
359 | if (trace) { | |
360 | /* | |
361 | * If the stream class is associated with a trace, then | |
362 | * both those objects are frozen. Also, this event class | |
363 | * is about to be frozen. | |
364 | * | |
365 | * Therefore the event class must be validated here. | |
366 | * The trace and stream class should be valid at this | |
367 | * point. | |
368 | */ | |
369 | assert(trace->valid); | |
370 | assert(stream_class->valid); | |
371 | packet_header_type = | |
372 | bt_ctf_trace_get_packet_header_type(trace); | |
373 | packet_context_type = | |
374 | bt_ctf_stream_class_get_packet_context_type( | |
375 | stream_class); | |
376 | event_header_type = | |
377 | bt_ctf_stream_class_get_event_header_type(stream_class); | |
378 | stream_event_ctx_type = | |
379 | bt_ctf_stream_class_get_event_context_type( | |
380 | stream_class); | |
381 | event_context_type = | |
382 | bt_ctf_event_class_get_context_type(event_class); | |
383 | event_payload_type = | |
384 | bt_ctf_event_class_get_payload_type(event_class); | |
385 | ret = bt_ctf_validate_class_types( | |
386 | trace->environment, packet_header_type, | |
387 | packet_context_type, event_header_type, | |
388 | stream_event_ctx_type, event_context_type, | |
389 | event_payload_type, trace->valid, | |
390 | stream_class->valid, event_class->valid, | |
391 | &validation_output, validation_flags); | |
392 | BT_PUT(packet_header_type); | |
393 | BT_PUT(packet_context_type); | |
394 | BT_PUT(event_header_type); | |
395 | BT_PUT(stream_event_ctx_type); | |
396 | BT_PUT(event_context_type); | |
397 | BT_PUT(event_payload_type); | |
398 | ||
399 | if (ret) { | |
400 | /* | |
401 | * This means something went wrong during the | |
402 | * validation process, not that the objects are | |
403 | * invalid. | |
404 | */ | |
405 | goto end; | |
406 | } | |
407 | ||
408 | if ((validation_output.valid_flags & validation_flags) != | |
409 | validation_flags) { | |
410 | /* Invalid event class */ | |
411 | ret = -1; | |
412 | goto end; | |
413 | } | |
414 | } | |
415 | ||
416 | /* Only set an event ID if none was explicitly set before */ | |
417 | event_id = bt_ctf_event_class_get_id(event_class); | |
418 | if (event_id < 0) { | |
419 | if (bt_ctf_event_class_set_id(event_class, | |
420 | stream_class->next_event_id++)) { | |
421 | ret = -1; | |
422 | goto end; | |
423 | } | |
424 | } | |
425 | ||
426 | ret = bt_ctf_event_class_set_stream_id(event_class, stream_class->id); | |
427 | if (ret) { | |
428 | goto end; | |
429 | } | |
430 | ||
431 | bt_object_set_parent(event_class, stream_class); | |
432 | ||
433 | if (trace) { | |
434 | /* | |
435 | * At this point we know that the function will be | |
436 | * successful. Therefore we can replace the event | |
437 | * class's field types with what's in the validation | |
438 | * output structure and mark this event class as valid. | |
439 | */ | |
440 | bt_ctf_validation_replace_types(NULL, NULL, event_class, | |
441 | &validation_output, validation_flags); | |
442 | event_class->valid = 1; | |
443 | ||
444 | /* | |
445 | * Put what was not moved in | |
446 | * bt_ctf_validation_replace_types(). | |
447 | */ | |
448 | bt_ctf_validation_output_put_types(&validation_output); | |
449 | } | |
450 | ||
451 | /* Add to the event classes of the stream class */ | |
452 | g_ptr_array_add(stream_class->event_classes, event_class); | |
453 | ||
454 | /* Freeze the event class */ | |
455 | bt_ctf_event_class_freeze(event_class); | |
456 | ||
457 | if (stream_class->byte_order) { | |
458 | /* | |
459 | * Only set native byte order if it has been initialized | |
460 | * when the stream class was added to a trace. | |
461 | * | |
462 | * If not set here, this will be set when the stream | |
463 | * class is added to a trace. | |
464 | */ | |
465 | bt_ctf_event_class_set_native_byte_order(event_class, | |
466 | stream_class->byte_order); | |
467 | } | |
468 | ||
469 | end: | |
470 | BT_PUT(trace); | |
471 | BT_PUT(old_stream_class); | |
472 | bt_ctf_validation_output_put_types(&validation_output); | |
473 | assert(!packet_header_type); | |
474 | assert(!packet_context_type); | |
475 | assert(!event_header_type); | |
476 | assert(!stream_event_ctx_type); | |
477 | assert(!event_context_type); | |
478 | assert(!event_payload_type); | |
479 | ||
480 | return ret; | |
481 | } | |
482 | ||
0f757a27 | 483 | BT_HIDDEN |
1c822dfb JG |
484 | int bt_ctf_stream_class_get_event_class_count( |
485 | struct bt_ctf_stream_class *stream_class) | |
486 | { | |
487 | int ret; | |
488 | ||
489 | if (!stream_class) { | |
490 | ret = -1; | |
491 | goto end; | |
492 | } | |
493 | ||
494 | ret = (int) stream_class->event_classes->len; | |
495 | end: | |
496 | return ret; | |
497 | } | |
498 | ||
0f757a27 | 499 | BT_HIDDEN |
1c822dfb JG |
500 | struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class( |
501 | struct bt_ctf_stream_class *stream_class, int index) | |
502 | { | |
503 | struct bt_ctf_event_class *event_class = NULL; | |
504 | ||
505 | if (!stream_class || index < 0 || | |
506 | index >= stream_class->event_classes->len) { | |
507 | goto end; | |
508 | } | |
509 | ||
510 | event_class = g_ptr_array_index(stream_class->event_classes, index); | |
511 | bt_get(event_class); | |
512 | end: | |
513 | return event_class; | |
514 | } | |
515 | ||
0f757a27 | 516 | BT_HIDDEN |
1c822dfb JG |
517 | struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_name( |
518 | struct bt_ctf_stream_class *stream_class, const char *name) | |
519 | { | |
520 | size_t i; | |
521 | struct bt_ctf_event_class *event_class = NULL; | |
522 | ||
523 | if (!stream_class || !name) { | |
524 | goto end; | |
525 | } | |
526 | ||
527 | for (i = 0; i < stream_class->event_classes->len; i++) { | |
528 | struct bt_ctf_event_class *cur_event_class = | |
529 | g_ptr_array_index(stream_class->event_classes, i); | |
530 | const char *cur_event_class_name = | |
531 | bt_ctf_event_class_get_name(cur_event_class); | |
532 | ||
533 | if (!strcmp(name, cur_event_class_name)) { | |
534 | event_class = cur_event_class; | |
535 | bt_get(event_class); | |
536 | goto end; | |
537 | } | |
538 | } | |
539 | end: | |
540 | return event_class; | |
541 | } | |
542 | ||
0f757a27 | 543 | BT_HIDDEN |
1c822dfb JG |
544 | struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id( |
545 | struct bt_ctf_stream_class *stream_class, uint32_t id) | |
546 | { | |
547 | size_t i; | |
548 | struct bt_ctf_event_class *event_class = NULL; | |
549 | ||
550 | if (!stream_class) { | |
551 | goto end; | |
552 | } | |
553 | ||
554 | for (i = 0; i < stream_class->event_classes->len; i++) { | |
555 | struct bt_ctf_event_class *current_event_class = | |
556 | g_ptr_array_index(stream_class->event_classes, i); | |
557 | ||
558 | if (bt_ctf_event_class_get_id(current_event_class) == id) { | |
559 | event_class = current_event_class; | |
560 | bt_get(event_class); | |
561 | goto end; | |
562 | } | |
563 | } | |
564 | end: | |
565 | return event_class; | |
566 | } | |
567 | ||
568 | struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type( | |
569 | struct bt_ctf_stream_class *stream_class) | |
570 | { | |
571 | struct bt_ctf_field_type *ret = NULL; | |
572 | ||
573 | if (!stream_class) { | |
574 | goto end; | |
575 | } | |
576 | ||
577 | assert(stream_class->packet_context_type); | |
578 | bt_get(stream_class->packet_context_type); | |
579 | ret = stream_class->packet_context_type; | |
580 | end: | |
581 | return ret; | |
582 | } | |
583 | ||
584 | int bt_ctf_stream_class_set_packet_context_type( | |
585 | struct bt_ctf_stream_class *stream_class, | |
586 | struct bt_ctf_field_type *packet_context_type) | |
587 | { | |
588 | int ret = 0; | |
589 | ||
590 | if (!stream_class || !packet_context_type || stream_class->frozen) { | |
591 | ret = -1; | |
592 | goto end; | |
593 | } | |
594 | ||
595 | assert(stream_class->packet_context_type); | |
596 | if (stream_class->packet_context_type == packet_context_type) { | |
597 | goto end; | |
598 | } | |
599 | if (bt_ctf_field_type_get_type_id(packet_context_type) != | |
600 | BT_CTF_TYPE_ID_STRUCT) { | |
601 | /* A packet context must be a structure */ | |
602 | ret = -1; | |
603 | goto end; | |
604 | } | |
605 | ||
606 | bt_put(stream_class->packet_context_type); | |
607 | bt_get(packet_context_type); | |
608 | stream_class->packet_context_type = packet_context_type; | |
609 | end: | |
610 | return ret; | |
611 | } | |
612 | ||
0f757a27 | 613 | BT_HIDDEN |
1c822dfb JG |
614 | struct bt_ctf_field_type *bt_ctf_stream_class_get_event_header_type( |
615 | struct bt_ctf_stream_class *stream_class) | |
616 | { | |
617 | struct bt_ctf_field_type *ret = NULL; | |
618 | ||
619 | if (!stream_class || !stream_class->event_header_type) { | |
620 | goto end; | |
621 | } | |
622 | ||
623 | assert(stream_class->event_header_type); | |
624 | bt_get(stream_class->event_header_type); | |
625 | ret = stream_class->event_header_type; | |
626 | end: | |
627 | return ret; | |
628 | } | |
629 | ||
0f757a27 | 630 | BT_HIDDEN |
1c822dfb JG |
631 | int bt_ctf_stream_class_set_event_header_type( |
632 | struct bt_ctf_stream_class *stream_class, | |
633 | struct bt_ctf_field_type *event_header_type) | |
634 | { | |
635 | int ret = 0; | |
636 | ||
637 | if (!stream_class || !event_header_type || stream_class->frozen) { | |
638 | ret = -1; | |
639 | goto end; | |
640 | } | |
641 | ||
642 | assert(stream_class->event_header_type); | |
643 | if (stream_class->event_header_type == event_header_type) { | |
644 | goto end; | |
645 | } | |
646 | if (bt_ctf_field_type_get_type_id(event_header_type) != | |
647 | BT_CTF_TYPE_ID_STRUCT) { | |
648 | /* An event header must be a structure */ | |
649 | ret = -1; | |
650 | goto end; | |
651 | } | |
652 | ||
653 | bt_put(stream_class->event_header_type); | |
654 | bt_get(event_header_type); | |
655 | stream_class->event_header_type = event_header_type; | |
656 | end: | |
657 | return ret; | |
658 | } | |
659 | ||
0f757a27 | 660 | BT_HIDDEN |
1c822dfb JG |
661 | struct bt_ctf_field_type *bt_ctf_stream_class_get_event_context_type( |
662 | struct bt_ctf_stream_class *stream_class) | |
663 | { | |
664 | struct bt_ctf_field_type *ret = NULL; | |
665 | ||
666 | if (!stream_class || !stream_class->event_context_type) { | |
667 | goto end; | |
668 | } | |
669 | ||
670 | assert(stream_class->event_context_type); | |
671 | bt_get(stream_class->event_context_type); | |
672 | ret = stream_class->event_context_type; | |
673 | end: | |
674 | return ret; | |
675 | } | |
676 | ||
0f757a27 | 677 | BT_HIDDEN |
1c822dfb JG |
678 | int bt_ctf_stream_class_set_event_context_type( |
679 | struct bt_ctf_stream_class *stream_class, | |
680 | struct bt_ctf_field_type *event_context_type) | |
681 | { | |
682 | int ret = 0; | |
683 | ||
684 | if (!stream_class || !event_context_type || stream_class->frozen) { | |
685 | ret = -1; | |
686 | goto end; | |
687 | } | |
688 | ||
689 | if (bt_ctf_field_type_get_type_id(event_context_type) != | |
690 | BT_CTF_TYPE_ID_STRUCT) { | |
691 | /* A packet context must be a structure */ | |
692 | ret = -1; | |
693 | goto end; | |
694 | } | |
695 | ||
696 | bt_put(stream_class->event_context_type); | |
697 | bt_get(event_context_type); | |
698 | stream_class->event_context_type = event_context_type; | |
699 | end: | |
700 | return ret; | |
701 | } | |
702 | ||
703 | void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class) | |
704 | { | |
705 | bt_get(stream_class); | |
706 | } | |
707 | ||
708 | void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class) | |
709 | { | |
710 | bt_put(stream_class); | |
711 | } | |
712 | ||
713 | BT_HIDDEN | |
714 | void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class) | |
715 | { | |
716 | if (!stream_class) { | |
717 | return; | |
718 | } | |
719 | ||
720 | stream_class->frozen = 1; | |
721 | bt_ctf_field_type_freeze(stream_class->event_header_type); | |
722 | bt_ctf_field_type_freeze(stream_class->packet_context_type); | |
723 | bt_ctf_field_type_freeze(stream_class->event_context_type); | |
724 | bt_ctf_clock_freeze(stream_class->clock); | |
725 | } | |
726 | ||
727 | BT_HIDDEN | |
728 | void bt_ctf_stream_class_set_byte_order( | |
729 | struct bt_ctf_stream_class *stream_class, int byte_order) | |
730 | { | |
731 | int i; | |
732 | ||
733 | assert(stream_class); | |
734 | assert(byte_order == LITTLE_ENDIAN || byte_order == BIG_ENDIAN); | |
735 | stream_class->byte_order = byte_order; | |
736 | ||
737 | /* Set native byte order to little or big endian */ | |
738 | bt_ctf_field_type_set_native_byte_order( | |
739 | stream_class->event_header_type, byte_order); | |
740 | bt_ctf_field_type_set_native_byte_order( | |
741 | stream_class->packet_context_type, byte_order); | |
742 | bt_ctf_field_type_set_native_byte_order( | |
743 | stream_class->event_context_type, byte_order); | |
744 | ||
745 | /* Set all events' native byte order */ | |
746 | for (i = 0; i < stream_class->event_classes->len; i++) { | |
747 | struct bt_ctf_event_class *event_class = | |
748 | g_ptr_array_index(stream_class->event_classes, i); | |
749 | ||
750 | bt_ctf_event_class_set_native_byte_order(event_class, | |
751 | byte_order); | |
752 | } | |
753 | } | |
754 | ||
755 | BT_HIDDEN | |
756 | int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, | |
757 | struct metadata_context *context) | |
758 | { | |
759 | int64_t ret = 0; | |
760 | size_t i; | |
761 | ||
762 | g_string_assign(context->field_name, ""); | |
763 | context->current_indentation_level = 1; | |
764 | if (!stream_class->id_set) { | |
765 | ret = -1; | |
766 | goto end; | |
767 | } | |
768 | ||
769 | g_string_append_printf(context->string, | |
770 | "stream {\n\tid = %" PRIu32 ";\n\tevent.header := ", | |
771 | stream_class->id); | |
772 | ret = bt_ctf_field_type_serialize(stream_class->event_header_type, | |
773 | context); | |
774 | if (ret) { | |
775 | goto end; | |
776 | } | |
777 | ||
778 | g_string_append(context->string, ";\n\n\tpacket.context := "); | |
779 | ret = bt_ctf_field_type_serialize(stream_class->packet_context_type, | |
780 | context); | |
781 | if (ret) { | |
782 | goto end; | |
783 | } | |
784 | ||
785 | if (stream_class->event_context_type) { | |
786 | g_string_append(context->string, ";\n\n\tevent.context := "); | |
787 | ret = bt_ctf_field_type_serialize( | |
788 | stream_class->event_context_type, context); | |
789 | if (ret) { | |
790 | goto end; | |
791 | } | |
792 | } | |
793 | ||
794 | g_string_append(context->string, ";\n};\n\n"); | |
795 | for (i = 0; i < stream_class->event_classes->len; i++) { | |
796 | struct bt_ctf_event_class *event_class = | |
797 | stream_class->event_classes->pdata[i]; | |
798 | ||
799 | ret = bt_ctf_event_class_serialize(event_class, context); | |
800 | if (ret) { | |
801 | goto end; | |
802 | } | |
803 | } | |
804 | end: | |
805 | context->current_indentation_level = 0; | |
806 | return ret; | |
807 | } | |
808 | ||
809 | static | |
810 | void bt_ctf_stream_class_destroy(struct bt_object *obj) | |
811 | { | |
812 | struct bt_ctf_stream_class *stream_class; | |
813 | ||
814 | stream_class = container_of(obj, struct bt_ctf_stream_class, base); | |
815 | bt_put(stream_class->clock); | |
816 | ||
817 | if (stream_class->event_classes) { | |
818 | g_ptr_array_free(stream_class->event_classes, TRUE); | |
819 | } | |
820 | ||
821 | if (stream_class->name) { | |
822 | g_string_free(stream_class->name, TRUE); | |
823 | } | |
824 | ||
825 | bt_put(stream_class->event_header_type); | |
826 | bt_put(stream_class->packet_context_type); | |
827 | bt_put(stream_class->event_context_type); | |
828 | g_free(stream_class); | |
829 | } | |
830 | ||
831 | static | |
832 | int init_event_header(struct bt_ctf_stream_class *stream_class) | |
833 | { | |
834 | int ret = 0; | |
835 | struct bt_ctf_field_type *event_header_type = | |
836 | bt_ctf_field_type_structure_create(); | |
837 | struct bt_ctf_field_type *_uint32_t = | |
838 | get_field_type(FIELD_TYPE_ALIAS_UINT32_T); | |
839 | struct bt_ctf_field_type *_uint64_t = | |
840 | get_field_type(FIELD_TYPE_ALIAS_UINT64_T); | |
841 | ||
842 | if (!event_header_type) { | |
843 | ret = -1; | |
844 | goto end; | |
845 | } | |
846 | ||
847 | ret = bt_ctf_field_type_structure_add_field(event_header_type, | |
848 | _uint32_t, "id"); | |
849 | if (ret) { | |
850 | goto end; | |
851 | } | |
852 | ||
853 | ret = bt_ctf_field_type_structure_add_field(event_header_type, | |
854 | _uint64_t, "timestamp"); | |
855 | if (ret) { | |
856 | goto end; | |
857 | } | |
858 | ||
859 | if (stream_class->event_header_type) { | |
860 | bt_put(stream_class->event_header_type); | |
861 | } | |
862 | stream_class->event_header_type = event_header_type; | |
863 | end: | |
864 | if (ret) { | |
865 | bt_put(event_header_type); | |
866 | } | |
867 | ||
868 | bt_put(_uint32_t); | |
869 | bt_put(_uint64_t); | |
870 | return ret; | |
871 | } | |
872 | ||
873 | static | |
874 | int init_packet_context(struct bt_ctf_stream_class *stream_class) | |
875 | { | |
876 | int ret = 0; | |
877 | struct bt_ctf_field_type *packet_context_type = | |
878 | bt_ctf_field_type_structure_create(); | |
879 | struct bt_ctf_field_type *_uint64_t = | |
880 | get_field_type(FIELD_TYPE_ALIAS_UINT64_T); | |
881 | ||
882 | if (!packet_context_type) { | |
883 | ret = -1; | |
884 | goto end; | |
885 | } | |
886 | ||
887 | /* | |
888 | * We create a stream packet context as proposed in the CTF | |
889 | * specification. | |
890 | */ | |
891 | ret = bt_ctf_field_type_structure_add_field(packet_context_type, | |
892 | _uint64_t, "timestamp_begin"); | |
893 | if (ret) { | |
894 | goto end; | |
895 | } | |
896 | ||
897 | ret = bt_ctf_field_type_structure_add_field(packet_context_type, | |
898 | _uint64_t, "timestamp_end"); | |
899 | if (ret) { | |
900 | goto end; | |
901 | } | |
902 | ||
903 | ret = bt_ctf_field_type_structure_add_field(packet_context_type, | |
904 | _uint64_t, "content_size"); | |
905 | if (ret) { | |
906 | goto end; | |
907 | } | |
908 | ||
909 | ret = bt_ctf_field_type_structure_add_field(packet_context_type, | |
910 | _uint64_t, "packet_size"); | |
911 | if (ret) { | |
912 | goto end; | |
913 | } | |
914 | ||
915 | ret = bt_ctf_field_type_structure_add_field(packet_context_type, | |
916 | _uint64_t, "events_discarded"); | |
917 | if (ret) { | |
918 | goto end; | |
919 | } | |
920 | ||
921 | bt_put(stream_class->packet_context_type); | |
922 | stream_class->packet_context_type = packet_context_type; | |
923 | end: | |
924 | if (ret) { | |
925 | bt_put(packet_context_type); | |
926 | goto end; | |
927 | } | |
928 | ||
929 | bt_put(_uint64_t); | |
930 | return ret; | |
931 | } |