Commit | Line | Data |
---|---|---|
273b65be | 1 | /* |
0235b0db | 2 | * SPDX-License-Identifier: MIT |
273b65be | 3 | * |
de9dd397 | 4 | * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
273b65be | 5 | * |
0235b0db | 6 | * Babeltrace CTF Writer |
273b65be JG |
7 | */ |
8 | ||
7dd841e4 | 9 | #define BT_LOG_TAG "CTF-WRITER" |
67d2ce02 | 10 | #include "logging.h" |
20eee76e | 11 | |
16ca5ff0 PP |
12 | #include <errno.h> |
13 | #include <fcntl.h> | |
14 | #include <inttypes.h> | |
273b65be JG |
15 | #include <stdio.h> |
16 | #include <stdlib.h> | |
17 | #include <sys/stat.h> | |
273b65be | 18 | #include <unistd.h> |
273b65be | 19 | |
217cf9d3 | 20 | #include <babeltrace2-ctf-writer/object.h> |
578e048b MJ |
21 | |
22 | #include "common/assert.h" | |
23 | #include "compat/compiler.h" | |
24 | #include "compat/endian.h" | |
6162e6b7 | 25 | #include "common/uuid.h" |
578e048b MJ |
26 | |
27 | #include "clock.h" | |
28 | #include "fields.h" | |
29 | #include "field-types.h" | |
30 | #include "functor.h" | |
31 | #include "stream-class.h" | |
32 | #include "stream.h" | |
33 | #include "trace.h" | |
34 | #include "writer.h" | |
35 | ||
273b65be | 36 | static |
e1e02a22 | 37 | void bt_ctf_writer_destroy(struct bt_ctf_object *obj); |
83509119 | 38 | |
488e09a7 | 39 | static |
3dca2276 | 40 | int init_trace_packet_header(struct bt_ctf_trace *trace) |
488e09a7 PP |
41 | { |
42 | int ret = 0; | |
3dca2276 | 43 | struct bt_ctf_field_type *_uint32_t = |
488e09a7 | 44 | get_field_type(FIELD_TYPE_ALIAS_UINT32_T); |
3dca2276 | 45 | struct bt_ctf_field_type *_uint8_t = |
488e09a7 | 46 | get_field_type(FIELD_TYPE_ALIAS_UINT8_T); |
3dca2276 PP |
47 | struct bt_ctf_field_type *trace_packet_header_type = |
48 | bt_ctf_field_type_structure_create(); | |
49 | struct bt_ctf_field_type *uuid_array_type = | |
50 | bt_ctf_field_type_array_create(_uint8_t, 16); | |
488e09a7 PP |
51 | |
52 | if (!trace_packet_header_type || !uuid_array_type) { | |
53 | ret = -1; | |
54 | goto end; | |
55 | } | |
56 | ||
3dca2276 | 57 | ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, |
488e09a7 PP |
58 | _uint32_t, "magic"); |
59 | if (ret) { | |
60 | goto end; | |
61 | } | |
62 | ||
3dca2276 | 63 | ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, |
488e09a7 PP |
64 | uuid_array_type, "uuid"); |
65 | if (ret) { | |
66 | goto end; | |
67 | } | |
68 | ||
3dca2276 | 69 | ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type, |
488e09a7 PP |
70 | _uint32_t, "stream_id"); |
71 | if (ret) { | |
72 | goto end; | |
73 | } | |
74 | ||
3dca2276 | 75 | ret = bt_ctf_trace_set_packet_header_field_type(trace, |
488e09a7 PP |
76 | trace_packet_header_type); |
77 | if (ret) { | |
78 | goto end; | |
79 | } | |
80 | end: | |
e1e02a22 PP |
81 | bt_ctf_object_put_ref(uuid_array_type); |
82 | bt_ctf_object_put_ref(_uint32_t); | |
83 | bt_ctf_object_put_ref(_uint8_t); | |
84 | bt_ctf_object_put_ref(trace_packet_header_type); | |
488e09a7 PP |
85 | return ret; |
86 | } | |
87 | ||
1353b066 | 88 | BT_EXPORT |
273b65be JG |
89 | struct bt_ctf_writer *bt_ctf_writer_create(const char *path) |
90 | { | |
3f5808e5 | 91 | int ret; |
273b65be | 92 | struct bt_ctf_writer *writer = NULL; |
6162e6b7 | 93 | bt_uuid_t uuid; |
ebd04048 | 94 | char *metadata_path = NULL; |
273b65be JG |
95 | |
96 | if (!path) { | |
97 | goto error; | |
98 | } | |
99 | ||
100 | writer = g_new0(struct bt_ctf_writer, 1); | |
101 | if (!writer) { | |
102 | goto error; | |
103 | } | |
104 | ||
ebd04048 MJ |
105 | metadata_path = g_build_filename(path, "metadata", NULL); |
106 | ||
e1e02a22 | 107 | bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy); |
273b65be JG |
108 | writer->path = g_string_new(path); |
109 | if (!writer->path) { | |
110 | goto error_destroy; | |
111 | } | |
112 | ||
3dca2276 | 113 | writer->trace = bt_ctf_trace_create(); |
bc37ae52 JG |
114 | if (!writer->trace) { |
115 | goto error_destroy; | |
116 | } | |
117 | ||
488e09a7 PP |
118 | ret = init_trace_packet_header(writer->trace); |
119 | if (ret) { | |
120 | goto error_destroy; | |
121 | } | |
122 | ||
4a32fda0 | 123 | /* Generate a UUID for this writer's trace */ |
6162e6b7 | 124 | bt_uuid_generate(uuid); |
20eee76e | 125 | |
3dca2276 | 126 | ret = bt_ctf_trace_set_uuid(writer->trace, uuid); |
4a32fda0 PP |
127 | if (ret) { |
128 | goto error_destroy; | |
129 | } | |
130 | ||
e1e02a22 PP |
131 | bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base); |
132 | bt_ctf_object_put_ref(writer->trace); | |
3f5808e5 PP |
133 | |
134 | /* Default to little-endian */ | |
3dca2276 | 135 | ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE); |
98b15851 | 136 | BT_ASSERT_DBG(ret == 0); |
3f5808e5 | 137 | |
273b65be JG |
138 | /* Create trace directory if necessary and open a metadata file */ |
139 | if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) { | |
140 | perror("g_mkdir_with_parents"); | |
141 | goto error_destroy; | |
142 | } | |
143 | ||
ebd04048 MJ |
144 | writer->metadata_fd = open(metadata_path, |
145 | O_WRONLY | O_CREAT | O_TRUNC, | |
146 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); | |
147 | if (writer->metadata_fd < 0) { | |
273b65be JG |
148 | perror("open"); |
149 | goto error_destroy; | |
150 | } | |
151 | ||
ebd04048 | 152 | g_free(metadata_path); |
273b65be | 153 | return writer; |
bc37ae52 | 154 | |
273b65be | 155 | error_destroy: |
e1e02a22 | 156 | BT_CTF_OBJECT_PUT_REF_AND_RESET(writer); |
273b65be | 157 | error: |
ebd04048 | 158 | g_free(metadata_path); |
273b65be JG |
159 | return writer; |
160 | } | |
161 | ||
1353b066 | 162 | BT_EXPORT |
e1e02a22 | 163 | void bt_ctf_writer_destroy(struct bt_ctf_object *obj) |
273b65be JG |
164 | { |
165 | struct bt_ctf_writer *writer; | |
273b65be | 166 | |
83509119 | 167 | writer = container_of(obj, struct bt_ctf_writer, base); |
273b65be JG |
168 | bt_ctf_writer_flush_metadata(writer); |
169 | if (writer->path) { | |
170 | g_string_free(writer->path, TRUE); | |
171 | } | |
172 | ||
273b65be | 173 | if (writer->metadata_fd > 0) { |
9bb7e58b MD |
174 | if (close(writer->metadata_fd)) { |
175 | perror("close"); | |
9bb7e58b | 176 | } |
273b65be JG |
177 | } |
178 | ||
e1e02a22 | 179 | bt_ctf_object_try_spec_release(&writer->trace->common.base); |
273b65be JG |
180 | g_free(writer); |
181 | } | |
182 | ||
1353b066 | 183 | BT_EXPORT |
3dca2276 | 184 | struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer) |
a2540e85 | 185 | { |
3dca2276 | 186 | struct bt_ctf_trace *trace = NULL; |
a2540e85 JG |
187 | |
188 | if (!writer) { | |
189 | goto end; | |
190 | } | |
191 | ||
192 | trace = writer->trace; | |
e1e02a22 | 193 | bt_ctf_object_get_ref(trace); |
a2540e85 JG |
194 | end: |
195 | return trace; | |
196 | } | |
197 | ||
1353b066 | 198 | BT_EXPORT |
3dca2276 PP |
199 | struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, |
200 | struct bt_ctf_stream_class *stream_class) | |
273b65be | 201 | { |
3dca2276 | 202 | struct bt_ctf_stream *stream = NULL; |
319fd969 | 203 | int stream_class_count; |
00409097 | 204 | bt_ctf_bool stream_class_found = BT_CTF_FALSE; |
319fd969 | 205 | int i; |
273b65be JG |
206 | |
207 | if (!writer || !stream_class) { | |
208 | goto error; | |
209 | } | |
210 | ||
319fd969 | 211 | /* Make sure the stream class is part of the writer's trace */ |
3dca2276 | 212 | stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace); |
319fd969 | 213 | if (stream_class_count < 0) { |
273b65be JG |
214 | goto error; |
215 | } | |
216 | ||
319fd969 | 217 | for (i = 0; i < stream_class_count; i++) { |
3dca2276 PP |
218 | struct bt_ctf_stream_class *existing_stream_class = |
219 | bt_ctf_trace_get_stream_class_by_index( | |
9ac68eb1 | 220 | writer->trace, i); |
319fd969 PP |
221 | |
222 | if (existing_stream_class == stream_class) { | |
00409097 | 223 | stream_class_found = BT_CTF_TRUE; |
319fd969 PP |
224 | } |
225 | ||
e1e02a22 | 226 | BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class); |
319fd969 PP |
227 | |
228 | if (stream_class_found) { | |
229 | break; | |
230 | } | |
231 | } | |
232 | ||
233 | if (!stream_class_found) { | |
3dca2276 | 234 | int ret = bt_ctf_trace_add_stream_class(writer->trace, |
319fd969 PP |
235 | stream_class); |
236 | ||
237 | if (ret) { | |
238 | goto error; | |
239 | } | |
240 | } | |
241 | ||
3dca2276 | 242 | stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL); |
319fd969 | 243 | if (!stream) { |
273b65be JG |
244 | goto error; |
245 | } | |
246 | ||
273b65be | 247 | return stream; |
bc37ae52 | 248 | |
273b65be | 249 | error: |
e1e02a22 | 250 | BT_CTF_OBJECT_PUT_REF_AND_RESET(stream); |
83509119 | 251 | return stream; |
273b65be JG |
252 | } |
253 | ||
1353b066 | 254 | BT_EXPORT |
273b65be JG |
255 | int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, |
256 | const char *name, | |
257 | const char *value) | |
258 | { | |
bc37ae52 | 259 | int ret = -1; |
273b65be | 260 | |
bc37ae52 JG |
261 | if (!writer || !name || !value) { |
262 | goto end; | |
273b65be JG |
263 | } |
264 | ||
3dca2276 | 265 | ret = bt_ctf_trace_set_environment_field_string(writer->trace, |
bc37ae52 JG |
266 | name, value); |
267 | end: | |
273b65be JG |
268 | return ret; |
269 | } | |
270 | ||
1353b066 | 271 | BT_EXPORT |
d7503815 | 272 | int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer, |
9ac68eb1 | 273 | const char *name, int64_t value) |
d7503815 SM |
274 | { |
275 | int ret = -1; | |
276 | ||
277 | if (!writer || !name) { | |
278 | goto end; | |
279 | } | |
280 | ||
3dca2276 | 281 | ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name, |
d7503815 SM |
282 | value); |
283 | end: | |
284 | return ret; | |
285 | } | |
286 | ||
1353b066 | 287 | BT_EXPORT |
273b65be JG |
288 | int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, |
289 | struct bt_ctf_clock *clock) | |
290 | { | |
bc37ae52 | 291 | int ret = -1; |
273b65be JG |
292 | |
293 | if (!writer || !clock) { | |
12af6048 JG |
294 | goto end; |
295 | } | |
273b65be | 296 | |
3dca2276 | 297 | ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class); |
12af6048 JG |
298 | end: |
299 | return ret; | |
273b65be JG |
300 | } |
301 | ||
1353b066 | 302 | BT_EXPORT |
273b65be JG |
303 | char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer) |
304 | { | |
bc37ae52 | 305 | char *metadata_string = NULL; |
273b65be JG |
306 | |
307 | if (!writer) { | |
308 | goto end; | |
309 | } | |
310 | ||
3dca2276 | 311 | metadata_string = bt_ctf_trace_get_metadata_string( |
bc37ae52 | 312 | writer->trace); |
273b65be | 313 | end: |
bc37ae52 | 314 | return metadata_string; |
273b65be JG |
315 | } |
316 | ||
1353b066 | 317 | BT_EXPORT |
273b65be JG |
318 | void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer) |
319 | { | |
320 | int ret; | |
321 | char *metadata_string = NULL; | |
322 | ||
323 | if (!writer) { | |
324 | goto end; | |
325 | } | |
326 | ||
3dca2276 | 327 | metadata_string = bt_ctf_trace_get_metadata_string( |
bc37ae52 | 328 | writer->trace); |
273b65be JG |
329 | if (!metadata_string) { |
330 | goto end; | |
331 | } | |
332 | ||
333 | if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) { | |
334 | perror("lseek"); | |
335 | goto end; | |
336 | } | |
337 | ||
338 | if (ftruncate(writer->metadata_fd, 0)) { | |
339 | perror("ftruncate"); | |
340 | goto end; | |
341 | } | |
342 | ||
343 | ret = write(writer->metadata_fd, metadata_string, | |
344 | strlen(metadata_string)); | |
345 | if (ret < 0) { | |
346 | perror("write"); | |
347 | goto end; | |
348 | } | |
349 | end: | |
350 | g_free(metadata_string); | |
351 | } | |
352 | ||
1353b066 | 353 | BT_EXPORT |
273b65be | 354 | int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, |
3dca2276 | 355 | enum bt_ctf_byte_order byte_order) |
273b65be JG |
356 | { |
357 | int ret = 0; | |
273b65be JG |
358 | |
359 | if (!writer || writer->frozen) { | |
360 | ret = -1; | |
361 | goto end; | |
362 | } | |
363 | ||
3dca2276 | 364 | if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { |
013f35c6 PP |
365 | if (BYTE_ORDER == LITTLE_ENDIAN) { |
366 | byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN; | |
367 | } else { | |
368 | byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN; | |
369 | } | |
3f5808e5 PP |
370 | } |
371 | ||
3dca2276 | 372 | ret = bt_ctf_trace_set_native_byte_order(writer->trace, |
bc37ae52 | 373 | byte_order); |
273b65be JG |
374 | end: |
375 | return ret; | |
376 | } | |
377 | ||
3dca2276 | 378 | void bt_ctf_writer_freeze(struct bt_ctf_writer *writer) |
273b65be | 379 | { |
3dca2276 | 380 | writer->frozen = 1; |
273b65be JG |
381 | } |
382 | ||
3dca2276 PP |
383 | static |
384 | const unsigned int field_type_aliases_alignments[] = { | |
385 | [FIELD_TYPE_ALIAS_UINT5_T] = 1, | |
386 | [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8, | |
387 | [FIELD_TYPE_ALIAS_UINT27_T] = 1, | |
388 | [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8, | |
389 | }; | |
390 | ||
391 | static | |
392 | const unsigned int field_type_aliases_sizes[] = { | |
393 | [FIELD_TYPE_ALIAS_UINT5_T] = 5, | |
394 | [FIELD_TYPE_ALIAS_UINT8_T] = 8, | |
395 | [FIELD_TYPE_ALIAS_UINT16_T] = 16, | |
396 | [FIELD_TYPE_ALIAS_UINT27_T] = 27, | |
397 | [FIELD_TYPE_ALIAS_UINT32_T] = 32, | |
398 | [FIELD_TYPE_ALIAS_UINT64_T] = 64, | |
399 | }; | |
400 | ||
3dca2276 | 401 | struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) |
273b65be | 402 | { |
3dca2276 PP |
403 | int ret; |
404 | unsigned int alignment, size; | |
405 | struct bt_ctf_field_type *field_type = NULL; | |
406 | ||
407 | if (alias >= NR_FIELD_TYPE_ALIAS) { | |
408 | goto end; | |
409 | } | |
410 | ||
411 | alignment = field_type_aliases_alignments[alias]; | |
412 | size = field_type_aliases_sizes[alias]; | |
413 | field_type = bt_ctf_field_type_integer_create(size); | |
414 | ret = bt_ctf_field_type_set_alignment(field_type, alignment); | |
415 | if (ret) { | |
e1e02a22 | 416 | BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type); |
3dca2276 PP |
417 | } |
418 | end: | |
419 | return field_type; | |
273b65be JG |
420 | } |
421 | ||
16ca5ff0 | 422 | const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order) |
273b65be | 423 | { |
3dca2276 PP |
424 | const char *string; |
425 | ||
426 | switch (byte_order) { | |
16ca5ff0 | 427 | case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: |
3dca2276 PP |
428 | string = "le"; |
429 | break; | |
16ca5ff0 | 430 | case BT_CTF_BYTE_ORDER_BIG_ENDIAN: |
3dca2276 PP |
431 | string = "be"; |
432 | break; | |
16ca5ff0 | 433 | case BT_CTF_BYTE_ORDER_NATIVE: |
3dca2276 PP |
434 | string = "native"; |
435 | break; | |
436 | default: | |
498e7994 | 437 | bt_common_abort(); |
3dca2276 PP |
438 | } |
439 | ||
440 | return string; | |
273b65be | 441 | } |