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 | ||
d2f71f12 PP |
29 | #define BT_LOG_TAG "STREAM-CLASS" |
30 | #include <babeltrace/lib-logging-internal.h> | |
31 | ||
11b0cdc8 | 32 | #include <babeltrace/ctf-writer/clock.h> |
ac0c6bdd PP |
33 | #include <babeltrace/ctf-writer/clock-internal.h> |
34 | #include <babeltrace/ctf-ir/clock-class-internal.h> | |
11b0cdc8 | 35 | #include <babeltrace/ctf-writer/event.h> |
272df73e | 36 | #include <babeltrace/ctf-ir/event-class-internal.h> |
11b0cdc8 | 37 | #include <babeltrace/ctf-ir/event-internal.h> |
2e33ac5a PP |
38 | #include <babeltrace/ctf-ir/field-types-internal.h> |
39 | #include <babeltrace/ctf-ir/fields-internal.h> | |
11b0cdc8 JG |
40 | #include <babeltrace/ctf-writer/stream.h> |
41 | #include <babeltrace/ctf-ir/stream-class-internal.h> | |
09840de5 | 42 | #include <babeltrace/ctf-ir/validation-internal.h> |
8bf65fbd | 43 | #include <babeltrace/ctf-ir/visitor-internal.h> |
11b0cdc8 | 44 | #include <babeltrace/ctf-writer/functor-internal.h> |
654c1444 | 45 | #include <babeltrace/ctf-ir/utils.h> |
8c4a29ba | 46 | #include <babeltrace/ctf-ir/utils-internal.h> |
83509119 | 47 | #include <babeltrace/ref.h> |
3d9990ac PP |
48 | #include <babeltrace/compiler-internal.h> |
49 | #include <babeltrace/align-internal.h> | |
50 | #include <babeltrace/endian-internal.h> | |
8b45963b | 51 | #include <babeltrace/assert-internal.h> |
44ea72c5 | 52 | #include <babeltrace/assert-pre-internal.h> |
dc3fffef | 53 | #include <inttypes.h> |
544d0515 | 54 | #include <stdint.h> |
e011d2c1 | 55 | #include <stdbool.h> |
11b0cdc8 JG |
56 | |
57 | static | |
839d52a5 | 58 | void bt_stream_class_destroy(struct bt_object *obj); |
11b0cdc8 | 59 | static |
839d52a5 | 60 | int init_event_header(struct bt_stream_class *stream_class); |
11b0cdc8 | 61 | static |
839d52a5 | 62 | int init_packet_context(struct bt_stream_class *stream_class); |
11b0cdc8 | 63 | |
839d52a5 | 64 | struct bt_stream_class *bt_stream_class_create(const char *name) |
11b0cdc8 | 65 | { |
839d52a5 | 66 | struct bt_stream_class *stream_class; |
12c8a1a3 | 67 | int ret; |
e0e2946b | 68 | |
d2f71f12 | 69 | BT_LOGD("Creating default stream class object: name=\"%s\"", name); |
839d52a5 | 70 | stream_class = bt_stream_class_create_empty(name); |
e0e2946b | 71 | if (!stream_class) { |
d2f71f12 | 72 | BT_LOGD_STR("Cannot create empty stream class."); |
e0e2946b PP |
73 | goto error; |
74 | } | |
75 | ||
76 | ret = init_event_header(stream_class); | |
77 | if (ret) { | |
d2f71f12 | 78 | BT_LOGE_STR("Cannot initialize stream class's event header field type."); |
e0e2946b PP |
79 | goto error; |
80 | } | |
81 | ||
82 | ret = init_packet_context(stream_class); | |
83 | if (ret) { | |
d2f71f12 | 84 | BT_LOGE_STR("Cannot initialize stream class's packet context field type."); |
e0e2946b PP |
85 | goto error; |
86 | } | |
87 | ||
d2f71f12 PP |
88 | BT_LOGD("Created default stream class object: addr=%p, name=\"%s\"", |
89 | stream_class, name); | |
e0e2946b PP |
90 | return stream_class; |
91 | ||
92 | error: | |
93 | BT_PUT(stream_class); | |
94 | return stream_class; | |
95 | } | |
96 | ||
839d52a5 | 97 | struct bt_stream_class *bt_stream_class_create_empty(const char *name) |
e0e2946b | 98 | { |
839d52a5 | 99 | struct bt_stream_class *stream_class = NULL; |
11b0cdc8 | 100 | |
d2f71f12 PP |
101 | BT_LOGD("Creating empty stream class object: name=\"%s\"", name); |
102 | ||
839d52a5 | 103 | stream_class = g_new0(struct bt_stream_class, 1); |
11b0cdc8 | 104 | if (!stream_class) { |
d2f71f12 | 105 | BT_LOGE_STR("Failed to allocate one stream class."); |
11b0cdc8 JG |
106 | goto error; |
107 | } | |
108 | ||
109 | stream_class->name = g_string_new(name); | |
110 | stream_class->event_classes = g_ptr_array_new_with_free_func( | |
e6a8e8e4 | 111 | (GDestroyNotify) bt_object_release); |
11b0cdc8 | 112 | if (!stream_class->event_classes) { |
d2f71f12 | 113 | BT_LOGE_STR("Failed to allocate a GPtrArray."); |
83509119 | 114 | goto error; |
11b0cdc8 JG |
115 | } |
116 | ||
0b9ce69f JG |
117 | stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash, |
118 | g_int64_equal, g_free, NULL); | |
d2f71f12 PP |
119 | if (!stream_class->event_classes_ht) { |
120 | BT_LOGE_STR("Failed to allocate a GHashTable."); | |
121 | goto error; | |
122 | } | |
0b9ce69f | 123 | |
839d52a5 | 124 | bt_object_init(stream_class, bt_stream_class_destroy); |
d2f71f12 PP |
125 | BT_LOGD("Created empty stream class object: addr=%p, name=\"%s\"", |
126 | stream_class, name); | |
11b0cdc8 JG |
127 | return stream_class; |
128 | ||
11b0cdc8 | 129 | error: |
e0e2946b | 130 | BT_PUT(stream_class); |
11b0cdc8 JG |
131 | return stream_class; |
132 | } | |
133 | ||
839d52a5 PP |
134 | struct bt_trace *bt_stream_class_get_trace( |
135 | struct bt_stream_class *stream_class) | |
142c5610 | 136 | { |
44ea72c5 PP |
137 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
138 | return bt_get(bt_stream_class_borrow_trace(stream_class)); | |
142c5610 JG |
139 | } |
140 | ||
839d52a5 PP |
141 | const char *bt_stream_class_get_name( |
142 | struct bt_stream_class *stream_class) | |
69dc4535 | 143 | { |
44ea72c5 PP |
144 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
145 | return stream_class->name->len > 0 ? stream_class->name->str : NULL; | |
69dc4535 JG |
146 | } |
147 | ||
839d52a5 | 148 | int bt_stream_class_set_name(struct bt_stream_class *stream_class, |
3ea33115 JG |
149 | const char *name) |
150 | { | |
151 | int ret = 0; | |
152 | ||
d2f71f12 PP |
153 | if (!stream_class) { |
154 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); | |
155 | ret = -1; | |
156 | goto end; | |
157 | } | |
158 | ||
159 | if (stream_class->frozen) { | |
160 | BT_LOGW("Invalid parameter: stream class is frozen: " | |
161 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
162 | stream_class, bt_stream_class_get_name(stream_class), |
163 | bt_stream_class_get_id(stream_class)); | |
3ea33115 JG |
164 | ret = -1; |
165 | goto end; | |
166 | } | |
167 | ||
a262eee7 PP |
168 | if (!name) { |
169 | g_string_assign(stream_class->name, ""); | |
170 | } else { | |
171 | if (strlen(name) == 0) { | |
172 | BT_LOGW("Invalid parameter: name is empty."); | |
173 | ret = -1; | |
174 | goto end; | |
175 | } | |
176 | ||
177 | g_string_assign(stream_class->name, name); | |
178 | } | |
179 | ||
d2f71f12 PP |
180 | BT_LOGV("Set stream class's name: " |
181 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
182 | stream_class, bt_stream_class_get_name(stream_class), |
183 | bt_stream_class_get_id(stream_class)); | |
3ea33115 JG |
184 | end: |
185 | return ret; | |
186 | } | |
187 | ||
839d52a5 PP |
188 | struct bt_ctf_clock *bt_stream_class_get_clock( |
189 | struct bt_stream_class *stream_class) | |
2f100782 JG |
190 | { |
191 | struct bt_ctf_clock *clock = NULL; | |
192 | ||
d2f71f12 PP |
193 | if (!stream_class) { |
194 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); | |
195 | goto end; | |
196 | } | |
197 | ||
198 | if (!stream_class->clock) { | |
199 | BT_LOGV("Stream class has no clock: " | |
200 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
201 | stream_class, bt_stream_class_get_name(stream_class), |
202 | bt_stream_class_get_id(stream_class)); | |
2f100782 JG |
203 | goto end; |
204 | } | |
205 | ||
ac0c6bdd | 206 | clock = bt_get(stream_class->clock); |
2f100782 JG |
207 | end: |
208 | return clock; | |
209 | } | |
210 | ||
839d52a5 | 211 | int bt_stream_class_set_clock(struct bt_stream_class *stream_class, |
11b0cdc8 JG |
212 | struct bt_ctf_clock *clock) |
213 | { | |
214 | int ret = 0; | |
839d52a5 | 215 | struct bt_field_type *timestamp_field = NULL; |
11b0cdc8 | 216 | |
d2f71f12 PP |
217 | if (!stream_class || !clock) { |
218 | BT_LOGW("Invalid parameter: stream class or clock is NULL: " | |
219 | "stream-class-addr=%p, clock-addr=%p", | |
220 | stream_class, clock); | |
221 | ret = -1; | |
222 | goto end; | |
223 | } | |
224 | ||
225 | if (stream_class->frozen) { | |
226 | BT_LOGW("Invalid parameter: stream class is frozen: " | |
227 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
228 | stream_class, bt_stream_class_get_name(stream_class), |
229 | bt_stream_class_get_id(stream_class)); | |
11b0cdc8 JG |
230 | ret = -1; |
231 | goto end; | |
232 | } | |
233 | ||
ac0c6bdd PP |
234 | /* Replace the current clock of this stream class. */ |
235 | bt_put(stream_class->clock); | |
236 | stream_class->clock = bt_get(clock); | |
d2f71f12 PP |
237 | BT_LOGV("Set stream class's clock: " |
238 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
239 | "clock-addr=%p, clock-name=\"%s\"", | |
839d52a5 PP |
240 | stream_class, bt_stream_class_get_name(stream_class), |
241 | bt_stream_class_get_id(stream_class), | |
d2f71f12 PP |
242 | stream_class->clock, |
243 | bt_ctf_clock_get_name(stream_class->clock)); | |
11b0cdc8 | 244 | |
11b0cdc8 | 245 | end: |
ac0c6bdd | 246 | bt_put(timestamp_field); |
11b0cdc8 JG |
247 | return ret; |
248 | } | |
249 | ||
839d52a5 | 250 | int64_t bt_stream_class_get_id(struct bt_stream_class *stream_class) |
2f100782 JG |
251 | { |
252 | int64_t ret; | |
253 | ||
44ea72c5 | 254 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
d2f71f12 PP |
255 | |
256 | if (!stream_class->id_set) { | |
257 | BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"", | |
258 | stream_class, | |
839d52a5 | 259 | bt_stream_class_get_name(stream_class)); |
9ac68eb1 | 260 | ret = (int64_t) -1; |
2f100782 JG |
261 | goto end; |
262 | } | |
263 | ||
9ac68eb1 | 264 | ret = stream_class->id; |
44ea72c5 | 265 | |
2f100782 JG |
266 | end: |
267 | return ret; | |
268 | } | |
269 | ||
5ca83563 | 270 | BT_HIDDEN |
839d52a5 PP |
271 | void _bt_stream_class_set_id( |
272 | struct bt_stream_class *stream_class, int64_t id) | |
5ca83563 | 273 | { |
8b45963b | 274 | BT_ASSERT(stream_class); |
5ca83563 JG |
275 | stream_class->id = id; |
276 | stream_class->id_set = 1; | |
d2f71f12 PP |
277 | BT_LOGV("Set stream class's ID (internal): " |
278 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
279 | stream_class, bt_stream_class_get_name(stream_class), |
280 | bt_stream_class_get_id(stream_class)); | |
5ca83563 JG |
281 | } |
282 | ||
9ac68eb1 PP |
283 | struct event_class_set_stream_class_id_data { |
284 | int64_t stream_class_id; | |
29664b2a PP |
285 | int ret; |
286 | }; | |
287 | ||
29664b2a | 288 | BT_HIDDEN |
839d52a5 PP |
289 | int bt_stream_class_set_id_no_check( |
290 | struct bt_stream_class *stream_class, int64_t id) | |
2f100782 | 291 | { |
839d52a5 | 292 | _bt_stream_class_set_id(stream_class, id); |
9cf5d083 | 293 | return 0; |
2f100782 JG |
294 | } |
295 | ||
839d52a5 | 296 | int bt_stream_class_set_id(struct bt_stream_class *stream_class, |
9ac68eb1 | 297 | uint64_t id_param) |
29664b2a PP |
298 | { |
299 | int ret = 0; | |
9ac68eb1 | 300 | int64_t id = (int64_t) id_param; |
29664b2a | 301 | |
d2f71f12 PP |
302 | if (!stream_class) { |
303 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); | |
304 | ret = -1; | |
305 | goto end; | |
306 | } | |
307 | ||
308 | if (stream_class->frozen) { | |
309 | BT_LOGW("Invalid parameter: stream class is frozen: " | |
310 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
311 | stream_class, bt_stream_class_get_name(stream_class), |
312 | bt_stream_class_get_id(stream_class)); | |
d2f71f12 PP |
313 | ret = -1; |
314 | goto end; | |
315 | } | |
316 | ||
317 | if (id < 0) { | |
318 | BT_LOGW("Invalid parameter: invalid stream class's ID: " | |
319 | "stream-class-addr=%p, stream-class-name=\"%s\", " | |
320 | "stream-class-id=%" PRId64 ", id=%" PRIu64, | |
839d52a5 PP |
321 | stream_class, bt_stream_class_get_name(stream_class), |
322 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 323 | id_param); |
29664b2a PP |
324 | ret = -1; |
325 | goto end; | |
326 | } | |
327 | ||
839d52a5 | 328 | ret = bt_stream_class_set_id_no_check(stream_class, id); |
d2f71f12 PP |
329 | if (ret == 0) { |
330 | BT_LOGV("Set stream class's ID: " | |
331 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
332 | stream_class, bt_stream_class_get_name(stream_class), |
333 | bt_stream_class_get_id(stream_class)); | |
d2f71f12 | 334 | } |
29664b2a PP |
335 | end: |
336 | return ret; | |
337 | } | |
338 | ||
0d23acbe PP |
339 | static |
340 | void event_class_exists(gpointer element, gpointer query) | |
341 | { | |
839d52a5 | 342 | struct bt_event_class *event_class_a = element; |
0d23acbe | 343 | struct search_query *search_query = query; |
839d52a5 | 344 | struct bt_event_class *event_class_b = search_query->value; |
0d23acbe PP |
345 | int64_t id_a, id_b; |
346 | ||
347 | if (search_query->value == element) { | |
348 | search_query->found = 1; | |
349 | goto end; | |
350 | } | |
351 | ||
0d23acbe PP |
352 | /* |
353 | * Two event classes cannot share the same ID in a given | |
354 | * stream class. | |
355 | */ | |
839d52a5 PP |
356 | id_a = bt_event_class_get_id(event_class_a); |
357 | id_b = bt_event_class_get_id(event_class_b); | |
0d23acbe PP |
358 | |
359 | if (id_a < 0 || id_b < 0) { | |
360 | /* at least one ID is not set: will be automatically set later */ | |
361 | goto end; | |
362 | } | |
363 | ||
364 | if (id_a == id_b) { | |
66871d36 | 365 | BT_LOGW("Event class with this ID already exists in the stream class: " |
d2f71f12 | 366 | "id=%" PRId64 ", name=\"%s\"", |
839d52a5 | 367 | id_a, bt_event_class_get_name(event_class_a)); |
0d23acbe PP |
368 | search_query->found = 1; |
369 | goto end; | |
370 | } | |
371 | ||
372 | end: | |
373 | return; | |
374 | } | |
375 | ||
839d52a5 PP |
376 | int bt_stream_class_add_event_class( |
377 | struct bt_stream_class *stream_class, | |
378 | struct bt_event_class *event_class) | |
11b0cdc8 JG |
379 | { |
380 | int ret = 0; | |
0b9ce69f | 381 | int64_t *event_id = NULL; |
839d52a5 PP |
382 | struct bt_trace *trace = NULL; |
383 | struct bt_stream_class *old_stream_class = NULL; | |
384 | struct bt_validation_output validation_output = { 0 }; | |
385 | struct bt_field_type *packet_header_type = NULL; | |
386 | struct bt_field_type *packet_context_type = NULL; | |
387 | struct bt_field_type *event_header_type = NULL; | |
388 | struct bt_field_type *stream_event_ctx_type = NULL; | |
389 | struct bt_field_type *event_context_type = NULL; | |
390 | struct bt_field_type *event_payload_type = NULL; | |
391 | const enum bt_validation_flag validation_flags = | |
392 | BT_VALIDATION_FLAG_EVENT; | |
8c4a29ba | 393 | struct bt_clock_class *expected_clock_class = NULL; |
11b0cdc8 | 394 | |
e011d2c1 PP |
395 | if (!stream_class || !event_class) { |
396 | BT_LOGW("Invalid parameter: stream class or event class is NULL: " | |
397 | "stream-class-addr=%p, event-class-addr=%p", | |
398 | stream_class, event_class); | |
399 | ret = -1; | |
400 | goto end; | |
401 | } | |
402 | ||
d2f71f12 PP |
403 | BT_LOGD("Adding event class to stream class: " |
404 | "stream-class-addr=%p, stream-class-name=\"%s\", " | |
405 | "stream-class-id=%" PRId64 ", event-class-addr=%p, " | |
406 | "event-class-name=\"%s\", event-class-id=%" PRId64, | |
839d52a5 PP |
407 | stream_class, bt_stream_class_get_name(stream_class), |
408 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 409 | event_class, |
839d52a5 PP |
410 | bt_event_class_get_name(event_class), |
411 | bt_event_class_get_id(event_class)); | |
d2f71f12 | 412 | |
839d52a5 | 413 | trace = bt_stream_class_get_trace(stream_class); |
5acf2ae6 | 414 | if (trace && trace->is_static) { |
8c4a29ba PP |
415 | BT_LOGW("Invalid parameter: stream class's trace is static: " |
416 | "trace-addr=%p, trace-name=\"%s\"", | |
417 | trace, bt_trace_get_name(trace)); | |
5acf2ae6 PP |
418 | ret = -1; |
419 | goto end; | |
420 | } | |
421 | ||
8c4a29ba PP |
422 | if (stream_class->frozen) { |
423 | /* | |
424 | * We only check that the event class to be added has a | |
425 | * single class which matches the stream class's | |
426 | * expected clock class if the stream class is frozen. | |
427 | * If it's not, then this event class is added "as is" | |
428 | * and the validation will be performed when calling | |
429 | * either bt_trace_add_stream_class() or | |
430 | * bt_event_create(). This is because the stream class's | |
431 | * field types (packet context, event header, event | |
432 | * context) could change before the next call to one of | |
433 | * those two functions. | |
434 | */ | |
435 | expected_clock_class = bt_get(stream_class->clock_class); | |
436 | ||
437 | /* | |
438 | * At this point, `expected_clock_class` can be NULL, | |
439 | * and bt_event_class_validate_single_clock_class() | |
440 | * below can set it. | |
441 | */ | |
442 | ret = bt_event_class_validate_single_clock_class( | |
443 | event_class, &expected_clock_class); | |
444 | if (ret) { | |
445 | BT_LOGW("Event class contains a field type which is not " | |
446 | "recursively mapped to its stream class's " | |
447 | "expected clock class: " | |
448 | "stream-class-addr=%p, " | |
449 | "stream-class-id=%" PRId64 ", " | |
450 | "stream-class-name=\"%s\", " | |
451 | "expected-clock-class-addr=%p, " | |
452 | "expected-clock-class-name=\"%s\"", | |
453 | stream_class, | |
454 | bt_stream_class_get_id(stream_class), | |
455 | bt_stream_class_get_name(stream_class), | |
456 | expected_clock_class, | |
457 | expected_clock_class ? | |
458 | bt_clock_class_get_name(expected_clock_class) : | |
459 | NULL); | |
460 | goto end; | |
461 | } | |
462 | } | |
463 | ||
0b9ce69f JG |
464 | event_id = g_new(int64_t, 1); |
465 | if (!event_id) { | |
d2f71f12 | 466 | BT_LOGE_STR("Failed to allocate one int64_t."); |
0b9ce69f JG |
467 | ret = -1; |
468 | goto end; | |
469 | } | |
470 | ||
11b0cdc8 JG |
471 | /* Check for duplicate event classes */ |
472 | struct search_query query = { .value = event_class, .found = 0 }; | |
0d23acbe PP |
473 | g_ptr_array_foreach(stream_class->event_classes, event_class_exists, |
474 | &query); | |
11b0cdc8 | 475 | if (query.found) { |
d2f71f12 | 476 | BT_LOGW_STR("Another event class part of this stream class has the same ID."); |
11b0cdc8 JG |
477 | ret = -1; |
478 | goto end; | |
479 | } | |
480 | ||
839d52a5 | 481 | old_stream_class = bt_event_class_get_stream_class(event_class); |
e6a8e8e4 JG |
482 | if (old_stream_class) { |
483 | /* Event class is already associated to a stream class. */ | |
d2f71f12 PP |
484 | BT_LOGW("Event class is already part of another stream class: " |
485 | "event-class-stream-class-addr=%p, " | |
486 | "event-class-stream-class-name=\"%s\", " | |
487 | "event-class-stream-class-id=%" PRId64, | |
488 | old_stream_class, | |
839d52a5 PP |
489 | bt_stream_class_get_name(old_stream_class), |
490 | bt_stream_class_get_id(old_stream_class)); | |
e6a8e8e4 JG |
491 | ret = -1; |
492 | goto end; | |
493 | } | |
494 | ||
e6a8e8e4 | 495 | if (trace) { |
09840de5 PP |
496 | /* |
497 | * If the stream class is associated with a trace, then | |
498 | * both those objects are frozen. Also, this event class | |
499 | * is about to be frozen. | |
500 | * | |
501 | * Therefore the event class must be validated here. | |
502 | * The trace and stream class should be valid at this | |
503 | * point. | |
504 | */ | |
8b45963b PP |
505 | BT_ASSERT(trace->valid); |
506 | BT_ASSERT(stream_class->valid); | |
09840de5 | 507 | packet_header_type = |
839d52a5 | 508 | bt_trace_get_packet_header_type(trace); |
09840de5 | 509 | packet_context_type = |
839d52a5 | 510 | bt_stream_class_get_packet_context_type( |
09840de5 PP |
511 | stream_class); |
512 | event_header_type = | |
839d52a5 | 513 | bt_stream_class_get_event_header_type(stream_class); |
09840de5 | 514 | stream_event_ctx_type = |
839d52a5 | 515 | bt_stream_class_get_event_context_type( |
09840de5 PP |
516 | stream_class); |
517 | event_context_type = | |
839d52a5 | 518 | bt_event_class_get_context_type(event_class); |
09840de5 | 519 | event_payload_type = |
839d52a5 PP |
520 | bt_event_class_get_payload_type(event_class); |
521 | ret = bt_validate_class_types( | |
09840de5 PP |
522 | trace->environment, packet_header_type, |
523 | packet_context_type, event_header_type, | |
524 | stream_event_ctx_type, event_context_type, | |
525 | event_payload_type, trace->valid, | |
526 | stream_class->valid, event_class->valid, | |
527 | &validation_output, validation_flags); | |
528 | BT_PUT(packet_header_type); | |
529 | BT_PUT(packet_context_type); | |
530 | BT_PUT(event_header_type); | |
531 | BT_PUT(stream_event_ctx_type); | |
532 | BT_PUT(event_context_type); | |
533 | BT_PUT(event_payload_type); | |
534 | ||
26079216 | 535 | if (ret) { |
09840de5 PP |
536 | /* |
537 | * This means something went wrong during the | |
538 | * validation process, not that the objects are | |
539 | * invalid. | |
540 | */ | |
d2f71f12 | 541 | BT_LOGE("Failed to validate event class: ret=%d", ret); |
09840de5 PP |
542 | goto end; |
543 | } | |
544 | ||
545 | if ((validation_output.valid_flags & validation_flags) != | |
546 | validation_flags) { | |
547 | /* Invalid event class */ | |
66871d36 | 548 | BT_LOGW("Invalid trace, stream class, or event class: " |
d2f71f12 PP |
549 | "valid-flags=0x%x", |
550 | validation_output.valid_flags); | |
09840de5 | 551 | ret = -1; |
26079216 JG |
552 | goto end; |
553 | } | |
554 | } | |
555 | ||
09840de5 | 556 | /* Only set an event ID if none was explicitly set before */ |
839d52a5 | 557 | *event_id = bt_event_class_get_id(event_class); |
24626e8b | 558 | if (*event_id < 0) { |
d2f71f12 PP |
559 | BT_LOGV("Event class has no ID: automatically setting it: " |
560 | "id=%" PRId64, stream_class->next_event_id); | |
561 | ||
839d52a5 | 562 | if (bt_event_class_set_id(event_class, |
d2f71f12 PP |
563 | stream_class->next_event_id)) { |
564 | BT_LOGE("Cannot set event class's ID: id=%" PRId64, | |
565 | stream_class->next_event_id); | |
2f100782 JG |
566 | ret = -1; |
567 | goto end; | |
568 | } | |
d2f71f12 | 569 | stream_class->next_event_id++; |
0b9ce69f | 570 | *event_id = stream_class->next_event_id; |
2f100782 JG |
571 | } |
572 | ||
e6a8e8e4 | 573 | bt_object_set_parent(event_class, stream_class); |
09840de5 PP |
574 | |
575 | if (trace) { | |
576 | /* | |
577 | * At this point we know that the function will be | |
578 | * successful. Therefore we can replace the event | |
579 | * class's field types with what's in the validation | |
580 | * output structure and mark this event class as valid. | |
581 | */ | |
839d52a5 | 582 | bt_validation_replace_types(NULL, NULL, event_class, |
09840de5 PP |
583 | &validation_output, validation_flags); |
584 | event_class->valid = 1; | |
585 | ||
586 | /* | |
587 | * Put what was not moved in | |
839d52a5 | 588 | * bt_validation_replace_types(). |
09840de5 | 589 | */ |
839d52a5 | 590 | bt_validation_output_put_types(&validation_output); |
09840de5 PP |
591 | } |
592 | ||
593 | /* Add to the event classes of the stream class */ | |
11b0cdc8 | 594 | g_ptr_array_add(stream_class->event_classes, event_class); |
0b9ce69f JG |
595 | g_hash_table_insert(stream_class->event_classes_ht, event_id, |
596 | event_class); | |
597 | event_id = NULL; | |
09840de5 PP |
598 | |
599 | /* Freeze the event class */ | |
839d52a5 | 600 | bt_event_class_freeze(event_class); |
5ca83563 | 601 | |
8c4a29ba PP |
602 | /* |
603 | * It is safe to set the stream class's unique clock class | |
604 | * now if the stream class is frozen. | |
605 | */ | |
606 | if (stream_class->frozen && expected_clock_class) { | |
8b45963b | 607 | BT_ASSERT(!stream_class->clock_class || |
8c4a29ba PP |
608 | stream_class->clock_class == expected_clock_class); |
609 | BT_MOVE(stream_class->clock_class, expected_clock_class); | |
610 | } | |
611 | ||
9b888ff3 JG |
612 | /* Notifiy listeners of the trace's schema modification. */ |
613 | if (trace) { | |
839d52a5 PP |
614 | struct bt_visitor_object obj = { .object = event_class, |
615 | .type = BT_VISITOR_OBJECT_TYPE_EVENT_CLASS }; | |
9b888ff3 | 616 | |
839d52a5 | 617 | (void) bt_trace_object_modification(&obj, trace); |
9b888ff3 | 618 | } |
d2f71f12 PP |
619 | |
620 | BT_LOGD("Added event class to stream class: " | |
621 | "stream-class-addr=%p, stream-class-name=\"%s\", " | |
622 | "stream-class-id=%" PRId64 ", event-class-addr=%p, " | |
623 | "event-class-name=\"%s\", event-class-id=%" PRId64, | |
839d52a5 PP |
624 | stream_class, bt_stream_class_get_name(stream_class), |
625 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 626 | event_class, |
839d52a5 PP |
627 | bt_event_class_get_name(event_class), |
628 | bt_event_class_get_id(event_class)); | |
d2f71f12 | 629 | |
11b0cdc8 | 630 | end: |
e6a8e8e4 JG |
631 | BT_PUT(trace); |
632 | BT_PUT(old_stream_class); | |
839d52a5 | 633 | bt_validation_output_put_types(&validation_output); |
8c4a29ba | 634 | bt_put(expected_clock_class); |
8b45963b PP |
635 | BT_ASSERT(!packet_header_type); |
636 | BT_ASSERT(!packet_context_type); | |
637 | BT_ASSERT(!event_header_type); | |
638 | BT_ASSERT(!stream_event_ctx_type); | |
639 | BT_ASSERT(!event_context_type); | |
640 | BT_ASSERT(!event_payload_type); | |
0b9ce69f | 641 | g_free(event_id); |
09840de5 | 642 | |
11b0cdc8 JG |
643 | return ret; |
644 | } | |
645 | ||
839d52a5 PP |
646 | int64_t bt_stream_class_get_event_class_count( |
647 | struct bt_stream_class *stream_class) | |
69dc4535 | 648 | { |
544d0515 | 649 | int64_t ret; |
69dc4535 JG |
650 | |
651 | if (!stream_class) { | |
d2f71f12 | 652 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); |
9ac68eb1 | 653 | ret = (int64_t) -1; |
69dc4535 JG |
654 | goto end; |
655 | } | |
656 | ||
9ac68eb1 | 657 | ret = (int64_t) stream_class->event_classes->len; |
69dc4535 JG |
658 | end: |
659 | return ret; | |
660 | } | |
661 | ||
839d52a5 PP |
662 | struct bt_event_class *bt_stream_class_get_event_class_by_index( |
663 | struct bt_stream_class *stream_class, uint64_t index) | |
69dc4535 | 664 | { |
44ea72c5 PP |
665 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
666 | BT_ASSERT_PRE(index < stream_class->event_classes->len, | |
667 | "Index is out of bounds: index=%" PRIu64 ", " | |
668 | "count=%u", | |
669 | index, stream_class->event_classes->len); | |
670 | return bt_get(g_ptr_array_index(stream_class->event_classes, index)); | |
69dc4535 JG |
671 | } |
672 | ||
839d52a5 PP |
673 | struct bt_event_class *bt_stream_class_get_event_class_by_id( |
674 | struct bt_stream_class *stream_class, uint64_t id) | |
0863f950 | 675 | { |
9ac68eb1 | 676 | int64_t id_key = (int64_t) id; |
0863f950 | 677 | |
44ea72c5 PP |
678 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
679 | BT_ASSERT_PRE(id_key >= 0, | |
680 | "Invalid event class ID: %" PRIu64, id); | |
681 | return bt_get(g_hash_table_lookup(stream_class->event_classes_ht, | |
682 | &id_key)); | |
0863f950 PP |
683 | } |
684 | ||
839d52a5 PP |
685 | struct bt_field_type *bt_stream_class_get_packet_context_type( |
686 | struct bt_stream_class *stream_class) | |
12c8a1a3 | 687 | { |
44ea72c5 PP |
688 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
689 | return bt_get(stream_class->packet_context_type); | |
12c8a1a3 JG |
690 | } |
691 | ||
839d52a5 PP |
692 | int bt_stream_class_set_packet_context_type( |
693 | struct bt_stream_class *stream_class, | |
694 | struct bt_field_type *packet_context_type) | |
12c8a1a3 JG |
695 | { |
696 | int ret = 0; | |
697 | ||
d2f71f12 PP |
698 | if (!stream_class) { |
699 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); | |
700 | ret = -1; | |
701 | goto end; | |
702 | } | |
703 | ||
704 | if (stream_class->frozen) { | |
705 | BT_LOGW("Invalid parameter: stream class is frozen: " | |
706 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
707 | stream_class, bt_stream_class_get_name(stream_class), |
708 | bt_stream_class_get_id(stream_class)); | |
12c8a1a3 JG |
709 | ret = -1; |
710 | goto end; | |
711 | } | |
712 | ||
835b2d10 | 713 | if (packet_context_type && |
839d52a5 PP |
714 | bt_field_type_get_type_id(packet_context_type) != |
715 | BT_FIELD_TYPE_ID_STRUCT) { | |
835b2d10 | 716 | /* A packet context must be a structure. */ |
d2f71f12 PP |
717 | BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: " |
718 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
719 | "packet-context-ft-addr=%p, packet-context-ft-id=%s", | |
839d52a5 PP |
720 | stream_class, bt_stream_class_get_name(stream_class), |
721 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 722 | packet_context_type, |
839d52a5 PP |
723 | bt_field_type_id_string( |
724 | bt_field_type_get_type_id(packet_context_type))); | |
12c8a1a3 JG |
725 | ret = -1; |
726 | goto end; | |
727 | } | |
728 | ||
83509119 JG |
729 | bt_put(stream_class->packet_context_type); |
730 | bt_get(packet_context_type); | |
12c8a1a3 | 731 | stream_class->packet_context_type = packet_context_type; |
d2f71f12 PP |
732 | BT_LOGV("Set stream class's packet context field type: " |
733 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
734 | "packet-context-ft-addr=%p", | |
839d52a5 PP |
735 | stream_class, bt_stream_class_get_name(stream_class), |
736 | bt_stream_class_get_id(stream_class), | |
d2f71f12 PP |
737 | packet_context_type); |
738 | ||
12c8a1a3 JG |
739 | end: |
740 | return ret; | |
741 | } | |
742 | ||
839d52a5 PP |
743 | struct bt_field_type *bt_stream_class_get_event_header_type( |
744 | struct bt_stream_class *stream_class) | |
662e778c | 745 | { |
839d52a5 | 746 | struct bt_field_type *ret = NULL; |
662e778c | 747 | |
44ea72c5 | 748 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
d2f71f12 PP |
749 | |
750 | if (!stream_class->event_header_type) { | |
751 | BT_LOGV("Stream class has no event header field type: " | |
752 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
753 | stream_class, bt_stream_class_get_name(stream_class), |
754 | bt_stream_class_get_id(stream_class)); | |
662e778c JG |
755 | goto end; |
756 | } | |
757 | ||
44ea72c5 PP |
758 | ret = bt_get(stream_class->event_header_type); |
759 | ||
662e778c JG |
760 | end: |
761 | return ret; | |
762 | } | |
763 | ||
839d52a5 PP |
764 | int bt_stream_class_set_event_header_type( |
765 | struct bt_stream_class *stream_class, | |
766 | struct bt_field_type *event_header_type) | |
662e778c JG |
767 | { |
768 | int ret = 0; | |
769 | ||
d2f71f12 PP |
770 | if (!stream_class) { |
771 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); | |
772 | ret = -1; | |
773 | goto end; | |
774 | } | |
775 | ||
776 | if (stream_class->frozen) { | |
777 | BT_LOGW("Invalid parameter: stream class is frozen: " | |
778 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
779 | stream_class, bt_stream_class_get_name(stream_class), |
780 | bt_stream_class_get_id(stream_class)); | |
662e778c JG |
781 | ret = -1; |
782 | goto end; | |
783 | } | |
784 | ||
835b2d10 | 785 | if (event_header_type && |
839d52a5 PP |
786 | bt_field_type_get_type_id(event_header_type) != |
787 | BT_FIELD_TYPE_ID_STRUCT) { | |
835b2d10 | 788 | /* An event header must be a structure. */ |
d2f71f12 PP |
789 | BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: " |
790 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
791 | "event-header-ft-addr=%p, event-header-ft-id=%s", | |
839d52a5 PP |
792 | stream_class, bt_stream_class_get_name(stream_class), |
793 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 794 | event_header_type, |
839d52a5 PP |
795 | bt_field_type_id_string( |
796 | bt_field_type_get_type_id(event_header_type))); | |
662e778c JG |
797 | ret = -1; |
798 | goto end; | |
799 | } | |
800 | ||
83509119 | 801 | bt_put(stream_class->event_header_type); |
835b2d10 | 802 | stream_class->event_header_type = bt_get(event_header_type); |
d2f71f12 PP |
803 | BT_LOGV("Set stream class's event header field type: " |
804 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
805 | "event-header-ft-addr=%p", | |
839d52a5 PP |
806 | stream_class, bt_stream_class_get_name(stream_class), |
807 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 808 | event_header_type); |
662e778c JG |
809 | end: |
810 | return ret; | |
811 | } | |
812 | ||
839d52a5 PP |
813 | struct bt_field_type *bt_stream_class_get_event_context_type( |
814 | struct bt_stream_class *stream_class) | |
af181248 | 815 | { |
839d52a5 | 816 | struct bt_field_type *ret = NULL; |
af181248 | 817 | |
44ea72c5 | 818 | BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class"); |
d2f71f12 PP |
819 | |
820 | if (!stream_class->event_context_type) { | |
af181248 JG |
821 | goto end; |
822 | } | |
823 | ||
44ea72c5 PP |
824 | ret = bt_get(stream_class->event_context_type); |
825 | ||
af181248 JG |
826 | end: |
827 | return ret; | |
828 | } | |
829 | ||
839d52a5 PP |
830 | int bt_stream_class_set_event_context_type( |
831 | struct bt_stream_class *stream_class, | |
832 | struct bt_field_type *event_context_type) | |
af181248 JG |
833 | { |
834 | int ret = 0; | |
835 | ||
d2f71f12 PP |
836 | if (!stream_class) { |
837 | BT_LOGW_STR("Invalid parameter: stream class is NULL."); | |
838 | ret = -1; | |
839 | goto end; | |
840 | } | |
841 | ||
842 | if (stream_class->frozen) { | |
843 | BT_LOGW("Invalid parameter: stream class is frozen: " | |
844 | "addr=%p, name=\"%s\", id=%" PRId64, | |
839d52a5 PP |
845 | stream_class, bt_stream_class_get_name(stream_class), |
846 | bt_stream_class_get_id(stream_class)); | |
af181248 JG |
847 | ret = -1; |
848 | goto end; | |
849 | } | |
850 | ||
835b2d10 | 851 | if (event_context_type && |
839d52a5 PP |
852 | bt_field_type_get_type_id(event_context_type) != |
853 | BT_FIELD_TYPE_ID_STRUCT) { | |
835b2d10 | 854 | /* A packet context must be a structure. */ |
d2f71f12 PP |
855 | BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: " |
856 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
857 | "event-context-ft-addr=%p, event-context-ft-id=%s", | |
839d52a5 PP |
858 | stream_class, bt_stream_class_get_name(stream_class), |
859 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 860 | event_context_type, |
839d52a5 PP |
861 | bt_field_type_id_string( |
862 | bt_field_type_get_type_id(event_context_type))); | |
af181248 JG |
863 | ret = -1; |
864 | goto end; | |
865 | } | |
866 | ||
83509119 | 867 | bt_put(stream_class->event_context_type); |
835b2d10 | 868 | stream_class->event_context_type = bt_get(event_context_type); |
d2f71f12 PP |
869 | BT_LOGV("Set stream class's event context field type: " |
870 | "addr=%p, name=\"%s\", id=%" PRId64 ", " | |
871 | "event-context-ft-addr=%p", | |
839d52a5 PP |
872 | stream_class, bt_stream_class_get_name(stream_class), |
873 | bt_stream_class_get_id(stream_class), | |
d2f71f12 | 874 | event_context_type); |
af181248 JG |
875 | end: |
876 | return ret; | |
877 | } | |
878 | ||
d2f71f12 | 879 | /* Pre-2.0 CTF writer backward compatibility */ |
839d52a5 | 880 | void bt_ctf_stream_class_get(struct bt_stream_class *stream_class) |
11b0cdc8 | 881 | { |
83509119 | 882 | bt_get(stream_class); |
11b0cdc8 JG |
883 | } |
884 | ||
d2f71f12 | 885 | /* Pre-2.0 CTF writer backward compatibility */ |
839d52a5 | 886 | void bt_ctf_stream_class_put(struct bt_stream_class *stream_class) |
11b0cdc8 | 887 | { |
83509119 | 888 | bt_put(stream_class); |
11b0cdc8 JG |
889 | } |
890 | ||
8bf65fbd | 891 | static |
544d0515 | 892 | int64_t get_event_class_count(void *element) |
8bf65fbd | 893 | { |
839d52a5 PP |
894 | return bt_stream_class_get_event_class_count( |
895 | (struct bt_stream_class *) element); | |
8bf65fbd JG |
896 | } |
897 | ||
898 | static | |
899 | void *get_event_class(void *element, int i) | |
900 | { | |
839d52a5 PP |
901 | return bt_stream_class_get_event_class_by_index( |
902 | (struct bt_stream_class *) element, i); | |
8bf65fbd JG |
903 | } |
904 | ||
905 | static | |
839d52a5 | 906 | int visit_event_class(void *object, bt_visitor visitor,void *data) |
8bf65fbd | 907 | { |
839d52a5 | 908 | struct bt_visitor_object obj = |
d9a13d86 | 909 | { .object = object, |
839d52a5 | 910 | .type = BT_VISITOR_OBJECT_TYPE_EVENT_CLASS }; |
8bf65fbd | 911 | |
d9a13d86 | 912 | return visitor(&obj, data); |
8bf65fbd JG |
913 | } |
914 | ||
839d52a5 PP |
915 | int bt_stream_class_visit(struct bt_stream_class *stream_class, |
916 | bt_visitor visitor, void *data) | |
8bf65fbd JG |
917 | { |
918 | int ret; | |
839d52a5 | 919 | struct bt_visitor_object obj = |
d9a13d86 | 920 | { .object = stream_class, |
839d52a5 | 921 | .type = BT_VISITOR_OBJECT_TYPE_STREAM_CLASS }; |
8bf65fbd JG |
922 | |
923 | if (!stream_class || !visitor) { | |
d2f71f12 PP |
924 | BT_LOGW("Invalid parameter: stream class or visitor is NULL: " |
925 | "stream-class-addr=%p, visitor=%p", | |
926 | stream_class, visitor); | |
8bf65fbd JG |
927 | ret = -1; |
928 | goto end; | |
929 | } | |
930 | ||
d9a13d86 | 931 | ret = visitor_helper(&obj, get_event_class_count, |
8bf65fbd JG |
932 | get_event_class, |
933 | visit_event_class, visitor, data); | |
d2f71f12 | 934 | BT_LOGV("visitor_helper() returned: ret=%d", ret); |
8bf65fbd JG |
935 | end: |
936 | return ret; | |
937 | } | |
938 | ||
11b0cdc8 | 939 | BT_HIDDEN |
839d52a5 | 940 | void bt_stream_class_freeze(struct bt_stream_class *stream_class) |
11b0cdc8 | 941 | { |
d2f71f12 | 942 | if (!stream_class || stream_class->frozen) { |
11b0cdc8 JG |
943 | return; |
944 | } | |
945 | ||
d2f71f12 | 946 | BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64, |
839d52a5 PP |
947 | stream_class, bt_stream_class_get_name(stream_class), |
948 | bt_stream_class_get_id(stream_class)); | |
11b0cdc8 | 949 | stream_class->frozen = 1; |
839d52a5 PP |
950 | bt_field_type_freeze(stream_class->event_header_type); |
951 | bt_field_type_freeze(stream_class->packet_context_type); | |
952 | bt_field_type_freeze(stream_class->event_context_type); | |
ac0c6bdd PP |
953 | |
954 | if (stream_class->clock) { | |
839d52a5 | 955 | bt_clock_class_freeze(stream_class->clock->clock_class); |
ac0c6bdd | 956 | } |
11b0cdc8 JG |
957 | } |
958 | ||
11b0cdc8 | 959 | BT_HIDDEN |
839d52a5 | 960 | int bt_stream_class_serialize(struct bt_stream_class *stream_class, |
11b0cdc8 JG |
961 | struct metadata_context *context) |
962 | { | |
9ac68eb1 | 963 | int ret = 0; |
11b0cdc8 | 964 | size_t i; |
839d52a5 PP |
965 | struct bt_trace *trace; |
966 | struct bt_field_type *packet_header_type = NULL; | |
11b0cdc8 | 967 | |
d2f71f12 PP |
968 | BT_LOGD("Serializing stream class's metadata: " |
969 | "stream-class-addr=%p, stream-class-name=\"%s\", " | |
970 | "stream-class-id=%" PRId64 ", metadata-context-addr=%p", | |
839d52a5 PP |
971 | stream_class, bt_stream_class_get_name(stream_class), |
972 | bt_stream_class_get_id(stream_class), context); | |
11b0cdc8 JG |
973 | g_string_assign(context->field_name, ""); |
974 | context->current_indentation_level = 1; | |
975 | if (!stream_class->id_set) { | |
d2f71f12 | 976 | BT_LOGW_STR("Stream class's ID is not set."); |
11b0cdc8 JG |
977 | ret = -1; |
978 | goto end; | |
979 | } | |
980 | ||
ac04c350 JG |
981 | g_string_append(context->string, "stream {\n"); |
982 | ||
983 | /* | |
984 | * The reference to the trace is only borrowed since the | |
985 | * serialization of the stream class might have been triggered | |
986 | * by the trace's destruction. In such a case, the trace's | |
987 | * reference count would, unexepectedly, go through the sequence | |
988 | * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction | |
989 | * and serialization. | |
990 | */ | |
839d52a5 | 991 | trace = bt_stream_class_borrow_trace(stream_class); |
8b45963b | 992 | BT_ASSERT(trace); |
839d52a5 | 993 | packet_header_type = bt_trace_get_packet_header_type(trace); |
ac04c350 JG |
994 | trace = NULL; |
995 | if (packet_header_type) { | |
839d52a5 | 996 | struct bt_field_type *stream_id_type; |
ac04c350 JG |
997 | |
998 | stream_id_type = | |
839d52a5 | 999 | bt_field_type_structure_get_field_type_by_name( |
ac04c350 JG |
1000 | packet_header_type, "stream_id"); |
1001 | if (stream_id_type) { | |
1002 | /* | |
1003 | * Only set the stream's id if the trace's packet header | |
1004 | * contains a stream_id field. This field is only | |
1005 | * needed if the trace contains only one stream | |
1006 | * class. | |
1007 | */ | |
1008 | g_string_append_printf(context->string, | |
1009 | "\tid = %" PRId64 ";\n", stream_class->id); | |
1010 | } | |
1011 | bt_put(stream_id_type); | |
1012 | } | |
e011d2c1 PP |
1013 | if (stream_class->event_header_type) { |
1014 | BT_LOGD_STR("Serializing stream class's event header field type's metadata."); | |
1015 | g_string_append(context->string, "\tevent.header := "); | |
839d52a5 | 1016 | ret = bt_field_type_serialize(stream_class->event_header_type, |
e011d2c1 PP |
1017 | context); |
1018 | if (ret) { | |
1019 | BT_LOGW("Cannot serialize stream class's event header field type's metadata: " | |
1020 | "ret=%d", ret); | |
1021 | goto end; | |
1022 | } | |
1023 | g_string_append(context->string, ";"); | |
11b0cdc8 JG |
1024 | } |
1025 | ||
e011d2c1 | 1026 | |
98edd02c | 1027 | if (stream_class->packet_context_type) { |
e011d2c1 PP |
1028 | BT_LOGD_STR("Serializing stream class's packet context field type's metadata."); |
1029 | g_string_append(context->string, "\n\n\tpacket.context := "); | |
839d52a5 | 1030 | ret = bt_field_type_serialize(stream_class->packet_context_type, |
98edd02c JG |
1031 | context); |
1032 | if (ret) { | |
66871d36 | 1033 | BT_LOGW("Cannot serialize stream class's packet context field type's metadata: " |
d2f71f12 | 1034 | "ret=%d", ret); |
98edd02c JG |
1035 | goto end; |
1036 | } | |
e011d2c1 | 1037 | g_string_append(context->string, ";"); |
11b0cdc8 JG |
1038 | } |
1039 | ||
1040 | if (stream_class->event_context_type) { | |
e011d2c1 PP |
1041 | BT_LOGD_STR("Serializing stream class's event context field type's metadata."); |
1042 | g_string_append(context->string, "\n\n\tevent.context := "); | |
839d52a5 | 1043 | ret = bt_field_type_serialize( |
11b0cdc8 JG |
1044 | stream_class->event_context_type, context); |
1045 | if (ret) { | |
66871d36 | 1046 | BT_LOGW("Cannot serialize stream class's event context field type's metadata: " |
d2f71f12 | 1047 | "ret=%d", ret); |
11b0cdc8 JG |
1048 | goto end; |
1049 | } | |
e011d2c1 | 1050 | g_string_append(context->string, ";"); |
11b0cdc8 JG |
1051 | } |
1052 | ||
e011d2c1 PP |
1053 | g_string_append(context->string, "\n};\n\n"); |
1054 | ||
11b0cdc8 | 1055 | for (i = 0; i < stream_class->event_classes->len; i++) { |
839d52a5 | 1056 | struct bt_event_class *event_class = |
11b0cdc8 JG |
1057 | stream_class->event_classes->pdata[i]; |
1058 | ||
839d52a5 | 1059 | ret = bt_event_class_serialize(event_class, context); |
11b0cdc8 | 1060 | if (ret) { |
66871d36 | 1061 | BT_LOGW("Cannot serialize event class's metadata: " |
d2f71f12 PP |
1062 | "event-class-addr=%p, event-class-name=\"%s\", " |
1063 | "event-class-id=%" PRId64, | |
1064 | event_class, | |
839d52a5 PP |
1065 | bt_event_class_get_name(event_class), |
1066 | bt_event_class_get_id(event_class)); | |
11b0cdc8 JG |
1067 | goto end; |
1068 | } | |
1069 | } | |
1070 | end: | |
ac04c350 | 1071 | bt_put(packet_header_type); |
11b0cdc8 JG |
1072 | context->current_indentation_level = 0; |
1073 | return ret; | |
1074 | } | |
1075 | ||
1076 | static | |
839d52a5 | 1077 | void bt_stream_class_destroy(struct bt_object *obj) |
11b0cdc8 | 1078 | { |
839d52a5 | 1079 | struct bt_stream_class *stream_class; |
11b0cdc8 | 1080 | |
839d52a5 | 1081 | stream_class = container_of(obj, struct bt_stream_class, base); |
d2f71f12 | 1082 | BT_LOGD("Destroying stream class: addr=%p, name=\"%s\", id=%" PRId64, |
839d52a5 PP |
1083 | stream_class, bt_stream_class_get_name(stream_class), |
1084 | bt_stream_class_get_id(stream_class)); | |
83509119 | 1085 | bt_put(stream_class->clock); |
8c4a29ba | 1086 | bt_put(stream_class->clock_class); |
11b0cdc8 | 1087 | |
0b9ce69f JG |
1088 | if (stream_class->event_classes_ht) { |
1089 | g_hash_table_destroy(stream_class->event_classes_ht); | |
1090 | } | |
11b0cdc8 | 1091 | if (stream_class->event_classes) { |
8c8cb0f2 | 1092 | BT_LOGD_STR("Destroying event classes."); |
11b0cdc8 JG |
1093 | g_ptr_array_free(stream_class->event_classes, TRUE); |
1094 | } | |
1095 | ||
1096 | if (stream_class->name) { | |
1097 | g_string_free(stream_class->name, TRUE); | |
1098 | } | |
1099 | ||
8c8cb0f2 | 1100 | BT_LOGD_STR("Putting event header field type."); |
83509119 | 1101 | bt_put(stream_class->event_header_type); |
8c8cb0f2 | 1102 | BT_LOGD_STR("Putting packet context field type."); |
83509119 | 1103 | bt_put(stream_class->packet_context_type); |
8c8cb0f2 | 1104 | BT_LOGD_STR("Putting event context field type."); |
83509119 | 1105 | bt_put(stream_class->event_context_type); |
11b0cdc8 JG |
1106 | g_free(stream_class); |
1107 | } | |
1108 | ||
1109 | static | |
839d52a5 | 1110 | int init_event_header(struct bt_stream_class *stream_class) |
11b0cdc8 JG |
1111 | { |
1112 | int ret = 0; | |
839d52a5 PP |
1113 | struct bt_field_type *event_header_type = |
1114 | bt_field_type_structure_create(); | |
1115 | struct bt_field_type *_uint32_t = | |
11b0cdc8 | 1116 | get_field_type(FIELD_TYPE_ALIAS_UINT32_T); |
839d52a5 | 1117 | struct bt_field_type *_uint64_t = |
11b0cdc8 JG |
1118 | get_field_type(FIELD_TYPE_ALIAS_UINT64_T); |
1119 | ||
1120 | if (!event_header_type) { | |
d2f71f12 | 1121 | BT_LOGE_STR("Cannot create empty structure field type."); |
11b0cdc8 JG |
1122 | ret = -1; |
1123 | goto end; | |
1124 | } | |
1125 | ||
839d52a5 | 1126 | ret = bt_field_type_structure_add_field(event_header_type, |
11b0cdc8 JG |
1127 | _uint32_t, "id"); |
1128 | if (ret) { | |
d2f71f12 | 1129 | BT_LOGE_STR("Cannot add `id` field to event header field type."); |
11b0cdc8 JG |
1130 | goto end; |
1131 | } | |
1132 | ||
839d52a5 | 1133 | ret = bt_field_type_structure_add_field(event_header_type, |
11b0cdc8 JG |
1134 | _uint64_t, "timestamp"); |
1135 | if (ret) { | |
d2f71f12 | 1136 | BT_LOGE_STR("Cannot add `timestamp` field to event header field type."); |
11b0cdc8 JG |
1137 | goto end; |
1138 | } | |
1139 | ||
e0e2946b | 1140 | BT_MOVE(stream_class->event_header_type, event_header_type); |
11b0cdc8 JG |
1141 | end: |
1142 | if (ret) { | |
83509119 | 1143 | bt_put(event_header_type); |
11b0cdc8 JG |
1144 | } |
1145 | ||
83509119 JG |
1146 | bt_put(_uint32_t); |
1147 | bt_put(_uint64_t); | |
11b0cdc8 JG |
1148 | return ret; |
1149 | } | |
1150 | ||
1151 | static | |
839d52a5 | 1152 | int init_packet_context(struct bt_stream_class *stream_class) |
11b0cdc8 JG |
1153 | { |
1154 | int ret = 0; | |
839d52a5 PP |
1155 | struct bt_field_type *packet_context_type = |
1156 | bt_field_type_structure_create(); | |
1157 | struct bt_field_type *_uint64_t = | |
11b0cdc8 | 1158 | get_field_type(FIELD_TYPE_ALIAS_UINT64_T); |
839d52a5 | 1159 | struct bt_field_type *ts_begin_end_uint64_t; |
11b0cdc8 JG |
1160 | |
1161 | if (!packet_context_type) { | |
d2f71f12 | 1162 | BT_LOGE_STR("Cannot create empty structure field type."); |
11b0cdc8 JG |
1163 | ret = -1; |
1164 | goto end; | |
1165 | } | |
1166 | ||
839d52a5 | 1167 | ts_begin_end_uint64_t = bt_field_type_copy(_uint64_t); |
e011d2c1 PP |
1168 | if (!ts_begin_end_uint64_t) { |
1169 | BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields."); | |
1170 | ret = -1; | |
1171 | goto end; | |
1172 | } | |
1173 | ||
11b0cdc8 JG |
1174 | /* |
1175 | * We create a stream packet context as proposed in the CTF | |
1176 | * specification. | |
1177 | */ | |
839d52a5 | 1178 | ret = bt_field_type_structure_add_field(packet_context_type, |
e011d2c1 | 1179 | ts_begin_end_uint64_t, "timestamp_begin"); |
11b0cdc8 | 1180 | if (ret) { |
d2f71f12 | 1181 | BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type."); |
11b0cdc8 JG |
1182 | goto end; |
1183 | } | |
1184 | ||
839d52a5 | 1185 | ret = bt_field_type_structure_add_field(packet_context_type, |
e011d2c1 | 1186 | ts_begin_end_uint64_t, "timestamp_end"); |
11b0cdc8 | 1187 | if (ret) { |
d2f71f12 | 1188 | BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type."); |
11b0cdc8 JG |
1189 | goto end; |
1190 | } | |
1191 | ||
839d52a5 | 1192 | ret = bt_field_type_structure_add_field(packet_context_type, |
11b0cdc8 JG |
1193 | _uint64_t, "content_size"); |
1194 | if (ret) { | |
d2f71f12 | 1195 | BT_LOGE_STR("Cannot add `content_size` field to event header field type."); |
11b0cdc8 JG |
1196 | goto end; |
1197 | } | |
1198 | ||
839d52a5 | 1199 | ret = bt_field_type_structure_add_field(packet_context_type, |
11b0cdc8 JG |
1200 | _uint64_t, "packet_size"); |
1201 | if (ret) { | |
d2f71f12 | 1202 | BT_LOGE_STR("Cannot add `packet_size` field to event header field type."); |
11b0cdc8 JG |
1203 | goto end; |
1204 | } | |
1205 | ||
839d52a5 | 1206 | ret = bt_field_type_structure_add_field(packet_context_type, |
11b0cdc8 JG |
1207 | _uint64_t, "events_discarded"); |
1208 | if (ret) { | |
d2f71f12 | 1209 | BT_LOGE_STR("Cannot add `events_discarded` field to event header field type."); |
11b0cdc8 JG |
1210 | goto end; |
1211 | } | |
1212 | ||
e0e2946b | 1213 | BT_MOVE(stream_class->packet_context_type, packet_context_type); |
11b0cdc8 JG |
1214 | end: |
1215 | if (ret) { | |
83509119 | 1216 | bt_put(packet_context_type); |
11b0cdc8 JG |
1217 | goto end; |
1218 | } | |
1219 | ||
83509119 | 1220 | bt_put(_uint64_t); |
e011d2c1 PP |
1221 | bt_put(ts_begin_end_uint64_t); |
1222 | return ret; | |
1223 | } | |
1224 | ||
1225 | static | |
839d52a5 | 1226 | int try_map_clock_class(struct bt_stream_class *stream_class, |
6506cd61 | 1227 | struct bt_field_type *parent_ft, const char *field_name) |
e011d2c1 | 1228 | { |
839d52a5 | 1229 | struct bt_clock_class *mapped_clock_class = NULL; |
e011d2c1 | 1230 | int ret = 0; |
6506cd61 PP |
1231 | struct bt_field_type *ft = |
1232 | bt_field_type_structure_get_field_type_by_name(parent_ft, | |
1233 | field_name); | |
1234 | ||
8b45963b | 1235 | BT_ASSERT(stream_class->clock); |
e011d2c1 PP |
1236 | |
1237 | if (!ft) { | |
1238 | /* Field does not exist: not an error */ | |
1239 | goto end; | |
1240 | } | |
1241 | ||
8b45963b | 1242 | BT_ASSERT(bt_field_type_is_integer(ft)); |
e011d2c1 | 1243 | mapped_clock_class = |
839d52a5 | 1244 | bt_field_type_integer_get_mapped_clock_class(ft); |
e011d2c1 | 1245 | if (!mapped_clock_class) { |
6506cd61 PP |
1246 | struct bt_field_type *ft_copy; |
1247 | ||
e011d2c1 PP |
1248 | if (!stream_class->clock) { |
1249 | BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: " | |
1250 | "stream-class-addr=%p, stream-class-name=\"%s\", " | |
1251 | "stream-class-id=%" PRId64 ", ft-addr=%p", | |
839d52a5 PP |
1252 | stream_class, bt_stream_class_get_name(stream_class), |
1253 | bt_stream_class_get_id(stream_class), ft); | |
e011d2c1 PP |
1254 | ret = -1; |
1255 | goto end; | |
1256 | } | |
1257 | ||
6506cd61 PP |
1258 | ft_copy = bt_field_type_copy(ft); |
1259 | if (!ft_copy) { | |
1260 | BT_LOGE("Failed to copy integer field type: ft-addr=%p", | |
1261 | ft); | |
e011d2c1 PP |
1262 | } |
1263 | ||
6506cd61 PP |
1264 | ret = bt_field_type_integer_set_mapped_clock_class_no_check( |
1265 | ft_copy, stream_class->clock->clock_class); | |
8b45963b | 1266 | BT_ASSERT(ret == 0); |
6506cd61 PP |
1267 | ret = bt_field_type_structure_replace_field(parent_ft, |
1268 | field_name, ft_copy); | |
1269 | bt_put(ft_copy); | |
e011d2c1 PP |
1270 | BT_LOGV("Automatically mapped field type to stream class's clock class: " |
1271 | "stream-class-addr=%p, stream-class-name=\"%s\", " | |
6506cd61 PP |
1272 | "stream-class-id=%" PRId64 ", ft-addr=%p, " |
1273 | "ft-copy-addr=%p", | |
839d52a5 | 1274 | stream_class, bt_stream_class_get_name(stream_class), |
6506cd61 | 1275 | bt_stream_class_get_id(stream_class), ft, ft_copy); |
e011d2c1 PP |
1276 | } |
1277 | ||
1278 | end: | |
6506cd61 | 1279 | bt_put(ft); |
e011d2c1 PP |
1280 | bt_put(mapped_clock_class); |
1281 | return ret; | |
1282 | } | |
1283 | ||
1284 | BT_HIDDEN | |
839d52a5 PP |
1285 | int bt_stream_class_map_clock_class( |
1286 | struct bt_stream_class *stream_class, | |
1287 | struct bt_field_type *packet_context_type, | |
1288 | struct bt_field_type *event_header_type) | |
e011d2c1 | 1289 | { |
e011d2c1 PP |
1290 | int ret = 0; |
1291 | ||
8b45963b | 1292 | BT_ASSERT(stream_class); |
e011d2c1 | 1293 | |
6506cd61 PP |
1294 | if (!stream_class->clock) { |
1295 | /* No clock class to map to */ | |
1296 | goto end; | |
1297 | } | |
1298 | ||
e011d2c1 | 1299 | if (packet_context_type) { |
6506cd61 PP |
1300 | if (try_map_clock_class(stream_class, packet_context_type, |
1301 | "timestamp_begin")) { | |
e011d2c1 PP |
1302 | BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class."); |
1303 | ret = -1; | |
1304 | goto end; | |
1305 | } | |
1306 | ||
6506cd61 PP |
1307 | if (try_map_clock_class(stream_class, packet_context_type, |
1308 | "timestamp_end")) { | |
e011d2c1 PP |
1309 | BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class."); |
1310 | ret = -1; | |
1311 | goto end; | |
1312 | } | |
e011d2c1 PP |
1313 | } |
1314 | ||
1315 | if (event_header_type) { | |
6506cd61 PP |
1316 | if (try_map_clock_class(stream_class, event_header_type, |
1317 | "timestamp")) { | |
e011d2c1 PP |
1318 | BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class."); |
1319 | ret = -1; | |
1320 | goto end; | |
1321 | } | |
e011d2c1 PP |
1322 | } |
1323 | ||
1324 | end: | |
11b0cdc8 JG |
1325 | return ret; |
1326 | } | |
8c4a29ba PP |
1327 | |
1328 | BT_HIDDEN | |
1329 | int bt_stream_class_validate_single_clock_class( | |
1330 | struct bt_stream_class *stream_class, | |
1331 | struct bt_clock_class **expected_clock_class) | |
1332 | { | |
1333 | int ret; | |
1334 | uint64_t i; | |
1335 | ||
8b45963b PP |
1336 | BT_ASSERT(stream_class); |
1337 | BT_ASSERT(expected_clock_class); | |
8c4a29ba PP |
1338 | ret = bt_validate_single_clock_class(stream_class->packet_context_type, |
1339 | expected_clock_class); | |
1340 | if (ret) { | |
1341 | BT_LOGW("Stream class's packet context field type " | |
1342 | "is not recursively mapped to the " | |
1343 | "expected clock class: " | |
1344 | "stream-class-addr=%p, " | |
1345 | "stream-class-name=\"%s\", " | |
1346 | "stream-class-id=%" PRId64 ", " | |
1347 | "ft-addr=%p", | |
1348 | stream_class, | |
1349 | bt_stream_class_get_name(stream_class), | |
1350 | stream_class->id, | |
1351 | stream_class->packet_context_type); | |
1352 | goto end; | |
1353 | } | |
1354 | ||
1355 | ret = bt_validate_single_clock_class(stream_class->event_header_type, | |
1356 | expected_clock_class); | |
1357 | if (ret) { | |
1358 | BT_LOGW("Stream class's event header field type " | |
1359 | "is not recursively mapped to the " | |
1360 | "expected clock class: " | |
1361 | "stream-class-addr=%p, " | |
1362 | "stream-class-name=\"%s\", " | |
1363 | "stream-class-id=%" PRId64 ", " | |
1364 | "ft-addr=%p", | |
1365 | stream_class, | |
1366 | bt_stream_class_get_name(stream_class), | |
1367 | stream_class->id, | |
1368 | stream_class->event_header_type); | |
1369 | goto end; | |
1370 | } | |
1371 | ||
1372 | ret = bt_validate_single_clock_class(stream_class->event_context_type, | |
1373 | expected_clock_class); | |
1374 | if (ret) { | |
1375 | BT_LOGW("Stream class's event context field type " | |
1376 | "is not recursively mapped to the " | |
1377 | "expected clock class: " | |
1378 | "stream-class-addr=%p, " | |
1379 | "stream-class-name=\"%s\", " | |
1380 | "stream-class-id=%" PRId64 ", " | |
1381 | "ft-addr=%p", | |
1382 | stream_class, | |
1383 | bt_stream_class_get_name(stream_class), | |
1384 | stream_class->id, | |
1385 | stream_class->event_context_type); | |
1386 | goto end; | |
1387 | } | |
1388 | ||
1389 | for (i = 0; i < stream_class->event_classes->len; i++) { | |
1390 | struct bt_event_class *event_class = | |
1391 | g_ptr_array_index(stream_class->event_classes, i); | |
1392 | ||
8b45963b | 1393 | BT_ASSERT(event_class); |
8c4a29ba PP |
1394 | ret = bt_event_class_validate_single_clock_class(event_class, |
1395 | expected_clock_class); | |
1396 | if (ret) { | |
1397 | BT_LOGW("Stream class's event class contains a " | |
1398 | "field type which is not recursively mapped to " | |
1399 | "the expected clock class: " | |
1400 | "stream-class-addr=%p, " | |
1401 | "stream-class-name=\"%s\", " | |
1402 | "stream-class-id=%" PRId64, | |
1403 | stream_class, | |
1404 | bt_stream_class_get_name(stream_class), | |
1405 | stream_class->id); | |
1406 | goto end; | |
1407 | } | |
1408 | } | |
1409 | ||
1410 | end: | |
1411 | return ret; | |
1412 | } |