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