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 | ||
273b65be JG |
88 | struct bt_ctf_writer *bt_ctf_writer_create(const char *path) |
89 | { | |
3f5808e5 | 90 | int ret; |
273b65be | 91 | struct bt_ctf_writer *writer = NULL; |
6162e6b7 | 92 | bt_uuid_t uuid; |
ebd04048 | 93 | char *metadata_path = NULL; |
273b65be JG |
94 | |
95 | if (!path) { | |
96 | goto error; | |
97 | } | |
98 | ||
99 | writer = g_new0(struct bt_ctf_writer, 1); | |
100 | if (!writer) { | |
101 | goto error; | |
102 | } | |
103 | ||
ebd04048 MJ |
104 | metadata_path = g_build_filename(path, "metadata", NULL); |
105 | ||
e1e02a22 | 106 | bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy); |
273b65be JG |
107 | writer->path = g_string_new(path); |
108 | if (!writer->path) { | |
109 | goto error_destroy; | |
110 | } | |
111 | ||
3dca2276 | 112 | writer->trace = bt_ctf_trace_create(); |
bc37ae52 JG |
113 | if (!writer->trace) { |
114 | goto error_destroy; | |
115 | } | |
116 | ||
488e09a7 PP |
117 | ret = init_trace_packet_header(writer->trace); |
118 | if (ret) { | |
119 | goto error_destroy; | |
120 | } | |
121 | ||
4a32fda0 | 122 | /* Generate a UUID for this writer's trace */ |
6162e6b7 | 123 | bt_uuid_generate(uuid); |
20eee76e | 124 | |
3dca2276 | 125 | ret = bt_ctf_trace_set_uuid(writer->trace, uuid); |
4a32fda0 PP |
126 | if (ret) { |
127 | goto error_destroy; | |
128 | } | |
129 | ||
e1e02a22 PP |
130 | bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base); |
131 | bt_ctf_object_put_ref(writer->trace); | |
3f5808e5 PP |
132 | |
133 | /* Default to little-endian */ | |
3dca2276 | 134 | ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE); |
98b15851 | 135 | BT_ASSERT_DBG(ret == 0); |
3f5808e5 | 136 | |
273b65be JG |
137 | /* Create trace directory if necessary and open a metadata file */ |
138 | if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) { | |
139 | perror("g_mkdir_with_parents"); | |
140 | goto error_destroy; | |
141 | } | |
142 | ||
ebd04048 MJ |
143 | writer->metadata_fd = open(metadata_path, |
144 | O_WRONLY | O_CREAT | O_TRUNC, | |
145 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); | |
146 | if (writer->metadata_fd < 0) { | |
273b65be JG |
147 | perror("open"); |
148 | goto error_destroy; | |
149 | } | |
150 | ||
ebd04048 | 151 | g_free(metadata_path); |
273b65be | 152 | return writer; |
bc37ae52 | 153 | |
273b65be | 154 | error_destroy: |
e1e02a22 | 155 | BT_CTF_OBJECT_PUT_REF_AND_RESET(writer); |
273b65be | 156 | error: |
ebd04048 | 157 | g_free(metadata_path); |
273b65be JG |
158 | return writer; |
159 | } | |
160 | ||
e1e02a22 | 161 | void bt_ctf_writer_destroy(struct bt_ctf_object *obj) |
273b65be JG |
162 | { |
163 | struct bt_ctf_writer *writer; | |
273b65be | 164 | |
83509119 | 165 | writer = container_of(obj, struct bt_ctf_writer, base); |
273b65be JG |
166 | bt_ctf_writer_flush_metadata(writer); |
167 | if (writer->path) { | |
168 | g_string_free(writer->path, TRUE); | |
169 | } | |
170 | ||
273b65be | 171 | if (writer->metadata_fd > 0) { |
9bb7e58b MD |
172 | if (close(writer->metadata_fd)) { |
173 | perror("close"); | |
9bb7e58b | 174 | } |
273b65be JG |
175 | } |
176 | ||
e1e02a22 | 177 | bt_ctf_object_try_spec_release(&writer->trace->common.base); |
273b65be JG |
178 | g_free(writer); |
179 | } | |
180 | ||
3dca2276 | 181 | struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer) |
a2540e85 | 182 | { |
3dca2276 | 183 | struct bt_ctf_trace *trace = NULL; |
a2540e85 JG |
184 | |
185 | if (!writer) { | |
186 | goto end; | |
187 | } | |
188 | ||
189 | trace = writer->trace; | |
e1e02a22 | 190 | bt_ctf_object_get_ref(trace); |
a2540e85 JG |
191 | end: |
192 | return trace; | |
193 | } | |
194 | ||
3dca2276 PP |
195 | struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer, |
196 | struct bt_ctf_stream_class *stream_class) | |
273b65be | 197 | { |
3dca2276 | 198 | struct bt_ctf_stream *stream = NULL; |
319fd969 | 199 | int stream_class_count; |
00409097 | 200 | bt_ctf_bool stream_class_found = BT_CTF_FALSE; |
319fd969 | 201 | int i; |
273b65be JG |
202 | |
203 | if (!writer || !stream_class) { | |
204 | goto error; | |
205 | } | |
206 | ||
319fd969 | 207 | /* Make sure the stream class is part of the writer's trace */ |
3dca2276 | 208 | stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace); |
319fd969 | 209 | if (stream_class_count < 0) { |
273b65be JG |
210 | goto error; |
211 | } | |
212 | ||
319fd969 | 213 | for (i = 0; i < stream_class_count; i++) { |
3dca2276 PP |
214 | struct bt_ctf_stream_class *existing_stream_class = |
215 | bt_ctf_trace_get_stream_class_by_index( | |
9ac68eb1 | 216 | writer->trace, i); |
319fd969 PP |
217 | |
218 | if (existing_stream_class == stream_class) { | |
00409097 | 219 | stream_class_found = BT_CTF_TRUE; |
319fd969 PP |
220 | } |
221 | ||
e1e02a22 | 222 | BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class); |
319fd969 PP |
223 | |
224 | if (stream_class_found) { | |
225 | break; | |
226 | } | |
227 | } | |
228 | ||
229 | if (!stream_class_found) { | |
3dca2276 | 230 | int ret = bt_ctf_trace_add_stream_class(writer->trace, |
319fd969 PP |
231 | stream_class); |
232 | ||
233 | if (ret) { | |
234 | goto error; | |
235 | } | |
236 | } | |
237 | ||
3dca2276 | 238 | stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL); |
319fd969 | 239 | if (!stream) { |
273b65be JG |
240 | goto error; |
241 | } | |
242 | ||
273b65be | 243 | return stream; |
bc37ae52 | 244 | |
273b65be | 245 | error: |
e1e02a22 | 246 | BT_CTF_OBJECT_PUT_REF_AND_RESET(stream); |
83509119 | 247 | return stream; |
273b65be JG |
248 | } |
249 | ||
250 | int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, | |
251 | const char *name, | |
252 | const char *value) | |
253 | { | |
bc37ae52 | 254 | int ret = -1; |
273b65be | 255 | |
bc37ae52 JG |
256 | if (!writer || !name || !value) { |
257 | goto end; | |
273b65be JG |
258 | } |
259 | ||
3dca2276 | 260 | ret = bt_ctf_trace_set_environment_field_string(writer->trace, |
bc37ae52 JG |
261 | name, value); |
262 | end: | |
273b65be JG |
263 | return ret; |
264 | } | |
265 | ||
d7503815 | 266 | int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer, |
9ac68eb1 | 267 | const char *name, int64_t value) |
d7503815 SM |
268 | { |
269 | int ret = -1; | |
270 | ||
271 | if (!writer || !name) { | |
272 | goto end; | |
273 | } | |
274 | ||
3dca2276 | 275 | ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name, |
d7503815 SM |
276 | value); |
277 | end: | |
278 | return ret; | |
279 | } | |
280 | ||
273b65be JG |
281 | int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, |
282 | struct bt_ctf_clock *clock) | |
283 | { | |
bc37ae52 | 284 | int ret = -1; |
273b65be JG |
285 | |
286 | if (!writer || !clock) { | |
12af6048 JG |
287 | goto end; |
288 | } | |
273b65be | 289 | |
3dca2276 | 290 | ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class); |
12af6048 JG |
291 | end: |
292 | return ret; | |
273b65be JG |
293 | } |
294 | ||
273b65be JG |
295 | char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer) |
296 | { | |
bc37ae52 | 297 | char *metadata_string = NULL; |
273b65be JG |
298 | |
299 | if (!writer) { | |
300 | goto end; | |
301 | } | |
302 | ||
3dca2276 | 303 | metadata_string = bt_ctf_trace_get_metadata_string( |
bc37ae52 | 304 | writer->trace); |
273b65be | 305 | end: |
bc37ae52 | 306 | return metadata_string; |
273b65be JG |
307 | } |
308 | ||
309 | void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer) | |
310 | { | |
311 | int ret; | |
312 | char *metadata_string = NULL; | |
313 | ||
314 | if (!writer) { | |
315 | goto end; | |
316 | } | |
317 | ||
3dca2276 | 318 | metadata_string = bt_ctf_trace_get_metadata_string( |
bc37ae52 | 319 | writer->trace); |
273b65be JG |
320 | if (!metadata_string) { |
321 | goto end; | |
322 | } | |
323 | ||
324 | if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) { | |
325 | perror("lseek"); | |
326 | goto end; | |
327 | } | |
328 | ||
329 | if (ftruncate(writer->metadata_fd, 0)) { | |
330 | perror("ftruncate"); | |
331 | goto end; | |
332 | } | |
333 | ||
334 | ret = write(writer->metadata_fd, metadata_string, | |
335 | strlen(metadata_string)); | |
336 | if (ret < 0) { | |
337 | perror("write"); | |
338 | goto end; | |
339 | } | |
340 | end: | |
341 | g_free(metadata_string); | |
342 | } | |
343 | ||
344 | int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, | |
3dca2276 | 345 | enum bt_ctf_byte_order byte_order) |
273b65be JG |
346 | { |
347 | int ret = 0; | |
273b65be JG |
348 | |
349 | if (!writer || writer->frozen) { | |
350 | ret = -1; | |
351 | goto end; | |
352 | } | |
353 | ||
3dca2276 | 354 | if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) { |
013f35c6 PP |
355 | if (BYTE_ORDER == LITTLE_ENDIAN) { |
356 | byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN; | |
357 | } else { | |
358 | byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN; | |
359 | } | |
3f5808e5 PP |
360 | } |
361 | ||
3dca2276 | 362 | ret = bt_ctf_trace_set_native_byte_order(writer->trace, |
bc37ae52 | 363 | byte_order); |
273b65be JG |
364 | end: |
365 | return ret; | |
366 | } | |
367 | ||
3dca2276 PP |
368 | BT_HIDDEN |
369 | void bt_ctf_writer_freeze(struct bt_ctf_writer *writer) | |
273b65be | 370 | { |
3dca2276 | 371 | writer->frozen = 1; |
273b65be JG |
372 | } |
373 | ||
3dca2276 PP |
374 | static |
375 | const unsigned int field_type_aliases_alignments[] = { | |
376 | [FIELD_TYPE_ALIAS_UINT5_T] = 1, | |
377 | [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8, | |
378 | [FIELD_TYPE_ALIAS_UINT27_T] = 1, | |
379 | [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8, | |
380 | }; | |
381 | ||
382 | static | |
383 | const unsigned int field_type_aliases_sizes[] = { | |
384 | [FIELD_TYPE_ALIAS_UINT5_T] = 5, | |
385 | [FIELD_TYPE_ALIAS_UINT8_T] = 8, | |
386 | [FIELD_TYPE_ALIAS_UINT16_T] = 16, | |
387 | [FIELD_TYPE_ALIAS_UINT27_T] = 27, | |
388 | [FIELD_TYPE_ALIAS_UINT32_T] = 32, | |
389 | [FIELD_TYPE_ALIAS_UINT64_T] = 64, | |
390 | }; | |
391 | ||
392 | BT_HIDDEN | |
393 | struct bt_ctf_field_type *get_field_type(enum field_type_alias alias) | |
273b65be | 394 | { |
3dca2276 PP |
395 | int ret; |
396 | unsigned int alignment, size; | |
397 | struct bt_ctf_field_type *field_type = NULL; | |
398 | ||
399 | if (alias >= NR_FIELD_TYPE_ALIAS) { | |
400 | goto end; | |
401 | } | |
402 | ||
403 | alignment = field_type_aliases_alignments[alias]; | |
404 | size = field_type_aliases_sizes[alias]; | |
405 | field_type = bt_ctf_field_type_integer_create(size); | |
406 | ret = bt_ctf_field_type_set_alignment(field_type, alignment); | |
407 | if (ret) { | |
e1e02a22 | 408 | BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type); |
3dca2276 PP |
409 | } |
410 | end: | |
411 | return field_type; | |
273b65be JG |
412 | } |
413 | ||
319fd969 | 414 | BT_HIDDEN |
16ca5ff0 | 415 | const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order) |
273b65be | 416 | { |
3dca2276 PP |
417 | const char *string; |
418 | ||
419 | switch (byte_order) { | |
16ca5ff0 | 420 | case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: |
3dca2276 PP |
421 | string = "le"; |
422 | break; | |
16ca5ff0 | 423 | case BT_CTF_BYTE_ORDER_BIG_ENDIAN: |
3dca2276 PP |
424 | string = "be"; |
425 | break; | |
16ca5ff0 | 426 | case BT_CTF_BYTE_ORDER_NATIVE: |
3dca2276 PP |
427 | string = "native"; |
428 | break; | |
429 | default: | |
498e7994 | 430 | bt_common_abort(); |
3dca2276 PP |
431 | } |
432 | ||
433 | return string; | |
273b65be | 434 | } |