Commit | Line | Data |
---|---|---|
273b65be | 1 | /* |
ac0c6bdd | 2 | * clock-class.c |
273b65be | 3 | * |
ac0c6bdd | 4 | * Babeltrace CTF IR - Clock class |
273b65be | 5 | * |
de9dd397 | 6 | * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
273b65be 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 | ||
0f5e83e5 | 29 | #define BT_LOG_TAG "CLOCK-CLASS" |
40547d22 | 30 | #include <babeltrace/lib-logging-internal.h> |
0f5e83e5 | 31 | |
75c3fca1 | 32 | #include <babeltrace/compat/uuid-internal.h> |
ac0c6bdd | 33 | #include <babeltrace/ctf-ir/clock-class-internal.h> |
c057dea0 | 34 | #include <babeltrace/ctf-ir/clock-value-internal.h> |
654c1444 | 35 | #include <babeltrace/ctf-ir/utils.h> |
83509119 | 36 | #include <babeltrace/ref.h> |
3d9990ac | 37 | #include <babeltrace/compiler-internal.h> |
c55a9f58 | 38 | #include <babeltrace/types.h> |
ee389f01 | 39 | #include <babeltrace/compat/string-internal.h> |
273b65be | 40 | #include <inttypes.h> |
0f5e83e5 | 41 | #include <babeltrace/object-internal.h> |
f6ccaed9 | 42 | #include <babeltrace/assert-internal.h> |
5134570b | 43 | |
273b65be | 44 | static |
50842bdc | 45 | void bt_clock_class_destroy(struct bt_object *obj); |
273b65be | 46 | |
4c426c17 | 47 | BT_HIDDEN |
50842bdc | 48 | bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class) |
c06116f3 | 49 | { |
ac0c6bdd | 50 | return clock_class && clock_class->name; |
c06116f3 PP |
51 | } |
52 | ||
50842bdc | 53 | int bt_clock_class_set_name(struct bt_clock_class *clock_class, |
4c426c17 JG |
54 | const char *name) |
55 | { | |
56 | int ret = 0; | |
273b65be | 57 | |
5134570b PP |
58 | if (!clock_class) { |
59 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); | |
60 | ret = -1; | |
61 | goto end; | |
62 | } | |
63 | ||
64 | if (clock_class->frozen) { | |
2cf0acd7 | 65 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 66 | clock_class, bt_clock_class_get_name(clock_class)); |
c06116f3 PP |
67 | ret = -1; |
68 | goto end; | |
69 | } | |
70 | ||
f4cc9a21 | 71 | if (!bt_identifier_is_valid(name)) { |
5134570b | 72 | BT_LOGE("Clock class's name is not a valid CTF identifier: " |
2cf0acd7 | 73 | "addr=%p, name=\"%s\"", |
5134570b | 74 | clock_class, name); |
4c426c17 JG |
75 | ret = -1; |
76 | goto end; | |
273b65be JG |
77 | } |
78 | ||
ac0c6bdd PP |
79 | if (clock_class->name) { |
80 | g_string_assign(clock_class->name, name); | |
e1ae7645 | 81 | } else { |
ac0c6bdd PP |
82 | clock_class->name = g_string_new(name); |
83 | if (!clock_class->name) { | |
5134570b | 84 | BT_LOGE_STR("Failed to allocate a GString."); |
e1ae7645 JG |
85 | ret = -1; |
86 | goto end; | |
87 | } | |
273b65be JG |
88 | } |
89 | ||
2cf0acd7 | 90 | BT_LOGV("Set clock class's name: addr=%p, name=\"%s\"", |
5134570b PP |
91 | clock_class, name); |
92 | ||
4c426c17 JG |
93 | end: |
94 | return ret; | |
95 | } | |
96 | ||
f3534905 | 97 | static |
50842bdc | 98 | bool validate_freq(struct bt_clock_class *clock_class, |
f3534905 PP |
99 | const char *name, uint64_t freq) |
100 | { | |
101 | bool is_valid = true; | |
102 | ||
103 | if (freq == -1ULL || freq == 0) { | |
104 | BT_LOGW("Invalid parameter: frequency is invalid: " | |
105 | "addr=%p, name=\"%s\", freq=%" PRIu64, | |
106 | clock_class, name, freq); | |
107 | is_valid = false; | |
108 | goto end; | |
109 | } | |
110 | ||
111 | end: | |
112 | return is_valid; | |
113 | } | |
114 | ||
50842bdc | 115 | struct bt_clock_class *bt_clock_class_create(const char *name, |
f3534905 | 116 | uint64_t freq) |
4c426c17 JG |
117 | { |
118 | int ret; | |
50842bdc | 119 | struct bt_clock_class *clock_class = NULL; |
4c426c17 | 120 | |
5134570b PP |
121 | BT_LOGD("Creating default clock class object: name=\"%s\"", |
122 | name); | |
f3534905 PP |
123 | |
124 | if (!validate_freq(NULL, name, freq)) { | |
125 | /* validate_freq() logs errors */ | |
126 | goto error; | |
127 | } | |
128 | ||
50842bdc | 129 | clock_class = g_new0(struct bt_clock_class, 1); |
ac0c6bdd | 130 | if (!clock_class) { |
5134570b | 131 | BT_LOGE_STR("Failed to allocate one clock class."); |
4c426c17 JG |
132 | goto error; |
133 | } | |
134 | ||
ac0c6bdd | 135 | clock_class->precision = 1; |
f3534905 | 136 | clock_class->frequency = freq; |
50842bdc | 137 | bt_object_init(clock_class, bt_clock_class_destroy); |
85380e99 JG |
138 | |
139 | if (name) { | |
50842bdc | 140 | ret = bt_clock_class_set_name(clock_class, name); |
85380e99 | 141 | if (ret) { |
5134570b | 142 | BT_LOGE("Cannot set clock class's name: " |
2cf0acd7 | 143 | "addr=%p, name=\"%s\"", |
5134570b | 144 | clock_class, name); |
85380e99 JG |
145 | goto error; |
146 | } | |
273b65be JG |
147 | } |
148 | ||
2cf0acd7 PP |
149 | BT_LOGD("Created clock class object: addr=%p, name=\"%s\"", |
150 | clock_class, name); | |
ac0c6bdd | 151 | return clock_class; |
273b65be | 152 | error: |
ac0c6bdd PP |
153 | BT_PUT(clock_class); |
154 | return clock_class; | |
87d76bb1 JG |
155 | } |
156 | ||
50842bdc | 157 | const char *bt_clock_class_get_name(struct bt_clock_class *clock_class) |
87d76bb1 JG |
158 | { |
159 | const char *ret = NULL; | |
160 | ||
ac0c6bdd | 161 | if (!clock_class) { |
5134570b | 162 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
87d76bb1 JG |
163 | goto end; |
164 | } | |
165 | ||
ac0c6bdd PP |
166 | if (clock_class->name) { |
167 | ret = clock_class->name->str; | |
87d76bb1 JG |
168 | } |
169 | ||
170 | end: | |
171 | return ret; | |
172 | } | |
173 | ||
50842bdc PP |
174 | const char *bt_clock_class_get_description( |
175 | struct bt_clock_class *clock_class) | |
87d76bb1 JG |
176 | { |
177 | const char *ret = NULL; | |
178 | ||
ac0c6bdd | 179 | if (!clock_class) { |
5134570b | 180 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
87d76bb1 JG |
181 | goto end; |
182 | } | |
183 | ||
ac0c6bdd PP |
184 | if (clock_class->description) { |
185 | ret = clock_class->description->str; | |
87d76bb1 JG |
186 | } |
187 | end: | |
188 | return ret; | |
273b65be JG |
189 | } |
190 | ||
50842bdc | 191 | int bt_clock_class_set_description(struct bt_clock_class *clock_class, |
ac0c6bdd | 192 | const char *desc) |
273b65be JG |
193 | { |
194 | int ret = 0; | |
195 | ||
5134570b PP |
196 | if (!clock_class || !desc) { |
197 | BT_LOGW("Invalid parameter: clock class or description is NULL: " | |
2cf0acd7 | 198 | "clock-class-addr=%p, name=\"%s\", desc-addr=%p", |
50842bdc | 199 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 200 | desc); |
5134570b PP |
201 | ret = -1; |
202 | goto end; | |
203 | } | |
204 | ||
205 | if (clock_class->frozen) { | |
2cf0acd7 | 206 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 207 | clock_class, bt_clock_class_get_name(clock_class)); |
273b65be JG |
208 | ret = -1; |
209 | goto end; | |
210 | } | |
211 | ||
ac0c6bdd PP |
212 | clock_class->description = g_string_new(desc); |
213 | ret = clock_class->description ? 0 : -1; | |
2cf0acd7 PP |
214 | BT_LOGV("Set clock class's description: addr=%p, " |
215 | "name=\"%s\", desc=\"%s\"", | |
50842bdc | 216 | clock_class, bt_clock_class_get_name(clock_class), desc); |
273b65be JG |
217 | end: |
218 | return ret; | |
219 | } | |
220 | ||
50842bdc PP |
221 | uint64_t bt_clock_class_get_frequency( |
222 | struct bt_clock_class *clock_class) | |
87d76bb1 JG |
223 | { |
224 | uint64_t ret = -1ULL; | |
225 | ||
ac0c6bdd | 226 | if (!clock_class) { |
5134570b | 227 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
87d76bb1 JG |
228 | goto end; |
229 | } | |
230 | ||
ac0c6bdd | 231 | ret = clock_class->frequency; |
87d76bb1 JG |
232 | end: |
233 | return ret; | |
234 | } | |
235 | ||
50842bdc | 236 | int bt_clock_class_set_frequency(struct bt_clock_class *clock_class, |
ac0c6bdd | 237 | uint64_t freq) |
273b65be JG |
238 | { |
239 | int ret = 0; | |
240 | ||
f3534905 | 241 | if (!clock_class) { |
5134570b | 242 | BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: " |
f3534905 | 243 | "addr=%p, name=\"%s\"", |
50842bdc | 244 | clock_class, bt_clock_class_get_name(clock_class)); |
5134570b PP |
245 | ret = -1; |
246 | goto end; | |
247 | } | |
248 | ||
50842bdc | 249 | if (!validate_freq(clock_class, bt_clock_class_get_name(clock_class), |
f3534905 PP |
250 | freq)) { |
251 | /* validate_freq() logs errors */ | |
252 | goto end; | |
253 | } | |
254 | ||
5134570b | 255 | if (clock_class->frozen) { |
2cf0acd7 | 256 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 257 | clock_class, bt_clock_class_get_name(clock_class)); |
273b65be JG |
258 | ret = -1; |
259 | goto end; | |
260 | } | |
261 | ||
ac0c6bdd | 262 | clock_class->frequency = freq; |
2cf0acd7 | 263 | BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64, |
50842bdc | 264 | clock_class, bt_clock_class_get_name(clock_class), freq); |
273b65be JG |
265 | end: |
266 | return ret; | |
267 | } | |
268 | ||
50842bdc | 269 | uint64_t bt_clock_class_get_precision(struct bt_clock_class *clock_class) |
87d76bb1 JG |
270 | { |
271 | uint64_t ret = -1ULL; | |
272 | ||
ac0c6bdd | 273 | if (!clock_class) { |
5134570b | 274 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
87d76bb1 JG |
275 | goto end; |
276 | } | |
277 | ||
ac0c6bdd | 278 | ret = clock_class->precision; |
87d76bb1 JG |
279 | end: |
280 | return ret; | |
281 | } | |
282 | ||
50842bdc | 283 | int bt_clock_class_set_precision(struct bt_clock_class *clock_class, |
ac0c6bdd | 284 | uint64_t precision) |
273b65be JG |
285 | { |
286 | int ret = 0; | |
287 | ||
5134570b PP |
288 | if (!clock_class || precision == -1ULL) { |
289 | BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: " | |
2cf0acd7 | 290 | "addr=%p, name=\"%s\", precision=%" PRIu64, |
50842bdc | 291 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 292 | precision); |
5134570b PP |
293 | ret = -1; |
294 | goto end; | |
295 | } | |
296 | ||
297 | if (clock_class->frozen) { | |
2cf0acd7 | 298 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 299 | clock_class, bt_clock_class_get_name(clock_class)); |
273b65be JG |
300 | ret = -1; |
301 | goto end; | |
302 | } | |
303 | ||
ac0c6bdd | 304 | clock_class->precision = precision; |
2cf0acd7 | 305 | BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64, |
50842bdc | 306 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 307 | precision); |
273b65be JG |
308 | end: |
309 | return ret; | |
310 | } | |
311 | ||
50842bdc | 312 | int bt_clock_class_get_offset_s(struct bt_clock_class *clock_class, |
ac0c6bdd | 313 | int64_t *offset_s) |
87d76bb1 | 314 | { |
61cf588b | 315 | int ret = 0; |
87d76bb1 | 316 | |
ac0c6bdd | 317 | if (!clock_class || !offset_s) { |
5134570b | 318 | BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " |
2cf0acd7 | 319 | "clock-class-addr=%p, name=\"%s\", offset-addr=%p", |
50842bdc | 320 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 321 | offset_s); |
61cf588b | 322 | ret = -1; |
87d76bb1 JG |
323 | goto end; |
324 | } | |
325 | ||
ac0c6bdd | 326 | *offset_s = clock_class->offset_s; |
87d76bb1 JG |
327 | end: |
328 | return ret; | |
329 | } | |
330 | ||
50842bdc | 331 | int bt_clock_class_set_offset_s(struct bt_clock_class *clock_class, |
ac0c6bdd | 332 | int64_t offset_s) |
273b65be JG |
333 | { |
334 | int ret = 0; | |
335 | ||
5134570b PP |
336 | if (!clock_class) { |
337 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); | |
338 | ret = -1; | |
339 | goto end; | |
340 | } | |
341 | ||
342 | if (clock_class->frozen) { | |
2cf0acd7 | 343 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 344 | clock_class, bt_clock_class_get_name(clock_class)); |
273b65be JG |
345 | ret = -1; |
346 | goto end; | |
347 | } | |
348 | ||
ac0c6bdd | 349 | clock_class->offset_s = offset_s; |
2cf0acd7 PP |
350 | BT_LOGV("Set clock class's offset (seconds): " |
351 | "addr=%p, name=\"%s\", offset-s=%" PRId64, | |
50842bdc | 352 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 353 | offset_s); |
273b65be JG |
354 | end: |
355 | return ret; | |
356 | } | |
357 | ||
50842bdc | 358 | int bt_clock_class_get_offset_cycles(struct bt_clock_class *clock_class, |
ac0c6bdd | 359 | int64_t *offset) |
87d76bb1 | 360 | { |
61cf588b | 361 | int ret = 0; |
87d76bb1 | 362 | |
ac0c6bdd | 363 | if (!clock_class || !offset) { |
5134570b | 364 | BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " |
2cf0acd7 | 365 | "clock-class-addr=%p, name=\"%s\", offset-addr=%p", |
50842bdc | 366 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 367 | offset); |
61cf588b | 368 | ret = -1; |
87d76bb1 JG |
369 | goto end; |
370 | } | |
371 | ||
ac0c6bdd | 372 | *offset = clock_class->offset; |
87d76bb1 JG |
373 | end: |
374 | return ret; | |
375 | } | |
376 | ||
50842bdc | 377 | int bt_clock_class_set_offset_cycles(struct bt_clock_class *clock_class, |
ac0c6bdd | 378 | int64_t offset) |
273b65be JG |
379 | { |
380 | int ret = 0; | |
381 | ||
5134570b PP |
382 | if (!clock_class) { |
383 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); | |
384 | ret = -1; | |
385 | goto end; | |
386 | } | |
387 | ||
388 | if (clock_class->frozen) { | |
2cf0acd7 | 389 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 390 | clock_class, bt_clock_class_get_name(clock_class)); |
273b65be JG |
391 | ret = -1; |
392 | goto end; | |
393 | } | |
394 | ||
ac0c6bdd | 395 | clock_class->offset = offset; |
2cf0acd7 | 396 | BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64, |
50842bdc | 397 | clock_class, bt_clock_class_get_name(clock_class), offset); |
273b65be JG |
398 | end: |
399 | return ret; | |
400 | } | |
401 | ||
50842bdc | 402 | bt_bool bt_clock_class_is_absolute(struct bt_clock_class *clock_class) |
87d76bb1 JG |
403 | { |
404 | int ret = -1; | |
405 | ||
ac0c6bdd | 406 | if (!clock_class) { |
5134570b | 407 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
87d76bb1 JG |
408 | goto end; |
409 | } | |
410 | ||
ac0c6bdd | 411 | ret = clock_class->absolute; |
87d76bb1 JG |
412 | end: |
413 | return ret; | |
414 | } | |
415 | ||
50842bdc | 416 | int bt_clock_class_set_is_absolute(struct bt_clock_class *clock_class, |
a2b94977 | 417 | bt_bool is_absolute) |
273b65be JG |
418 | { |
419 | int ret = 0; | |
420 | ||
5134570b PP |
421 | if (!clock_class) { |
422 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); | |
423 | ret = -1; | |
424 | goto end; | |
425 | } | |
426 | ||
427 | if (clock_class->frozen) { | |
2cf0acd7 | 428 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 429 | clock_class, bt_clock_class_get_name(clock_class)); |
273b65be JG |
430 | ret = -1; |
431 | goto end; | |
432 | } | |
433 | ||
ac0c6bdd | 434 | clock_class->absolute = !!is_absolute; |
2cf0acd7 | 435 | BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d", |
50842bdc | 436 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 437 | is_absolute); |
273b65be JG |
438 | end: |
439 | return ret; | |
440 | } | |
441 | ||
50842bdc PP |
442 | const unsigned char *bt_clock_class_get_uuid( |
443 | struct bt_clock_class *clock_class) | |
85b743f4 JG |
444 | { |
445 | const unsigned char *ret; | |
446 | ||
5134570b PP |
447 | if (!clock_class) { |
448 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); | |
449 | ret = NULL; | |
450 | goto end; | |
451 | } | |
452 | ||
453 | if (!clock_class->uuid_set) { | |
2cf0acd7 | 454 | BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"", |
50842bdc | 455 | clock_class, bt_clock_class_get_name(clock_class)); |
85b743f4 JG |
456 | ret = NULL; |
457 | goto end; | |
458 | } | |
459 | ||
ac0c6bdd | 460 | ret = clock_class->uuid; |
85b743f4 JG |
461 | end: |
462 | return ret; | |
463 | } | |
464 | ||
50842bdc | 465 | int bt_clock_class_set_uuid(struct bt_clock_class *clock_class, |
ac0c6bdd | 466 | const unsigned char *uuid) |
85b743f4 JG |
467 | { |
468 | int ret = 0; | |
469 | ||
5134570b PP |
470 | if (!clock_class || !uuid) { |
471 | BT_LOGW("Invalid parameter: clock class or UUID is NULL: " | |
2cf0acd7 | 472 | "clock-class-addr=%p, name=\"%s\", uuid-addr=%p", |
50842bdc | 473 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 474 | uuid); |
5134570b PP |
475 | ret = -1; |
476 | goto end; | |
477 | } | |
478 | ||
479 | if (clock_class->frozen) { | |
2cf0acd7 | 480 | BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", |
50842bdc | 481 | clock_class, bt_clock_class_get_name(clock_class)); |
85b743f4 JG |
482 | ret = -1; |
483 | goto end; | |
484 | } | |
485 | ||
20eee76e | 486 | memcpy(clock_class->uuid, uuid, BABELTRACE_UUID_LEN); |
ac0c6bdd | 487 | clock_class->uuid_set = 1; |
2cf0acd7 | 488 | BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", " |
5134570b | 489 | "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", |
50842bdc | 490 | clock_class, bt_clock_class_get_name(clock_class), |
5134570b PP |
491 | (unsigned int) uuid[0], |
492 | (unsigned int) uuid[1], | |
493 | (unsigned int) uuid[2], | |
494 | (unsigned int) uuid[3], | |
495 | (unsigned int) uuid[4], | |
496 | (unsigned int) uuid[5], | |
497 | (unsigned int) uuid[6], | |
498 | (unsigned int) uuid[7], | |
499 | (unsigned int) uuid[8], | |
500 | (unsigned int) uuid[9], | |
501 | (unsigned int) uuid[10], | |
502 | (unsigned int) uuid[11], | |
503 | (unsigned int) uuid[12], | |
504 | (unsigned int) uuid[13], | |
505 | (unsigned int) uuid[14], | |
506 | (unsigned int) uuid[15]); | |
85b743f4 JG |
507 | end: |
508 | return ret; | |
509 | } | |
510 | ||
ac0c6bdd | 511 | static uint64_t ns_from_value(uint64_t frequency, uint64_t value) |
4ef18cab PP |
512 | { |
513 | uint64_t ns; | |
514 | ||
515 | if (frequency == 1000000000) { | |
516 | ns = value; | |
517 | } else { | |
036a7cac PP |
518 | double dblres = ((1e9 * (double) value) / (double) frequency); |
519 | ||
520 | if (dblres >= (double) UINT64_MAX) { | |
521 | /* Overflows uint64_t */ | |
522 | ns = -1ULL; | |
523 | } else { | |
524 | ns = (uint64_t) dblres; | |
525 | } | |
4ef18cab PP |
526 | } |
527 | ||
528 | return ns; | |
529 | } | |
530 | ||
273b65be | 531 | BT_HIDDEN |
50842bdc | 532 | void bt_clock_class_freeze(struct bt_clock_class *clock_class) |
273b65be | 533 | { |
ac0c6bdd | 534 | if (!clock_class) { |
5134570b | 535 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
273b65be JG |
536 | return; |
537 | } | |
538 | ||
5134570b | 539 | if (!clock_class->frozen) { |
2cf0acd7 | 540 | BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"", |
50842bdc | 541 | clock_class, bt_clock_class_get_name(clock_class)); |
5134570b PP |
542 | clock_class->frozen = 1; |
543 | } | |
273b65be JG |
544 | } |
545 | ||
546 | BT_HIDDEN | |
50842bdc | 547 | void bt_clock_class_serialize(struct bt_clock_class *clock_class, |
273b65be JG |
548 | struct metadata_context *context) |
549 | { | |
550 | unsigned char *uuid; | |
551 | ||
5134570b | 552 | BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, " |
2cf0acd7 | 553 | "name=\"%s\", metadata-context-addr=%p", clock_class, |
50842bdc | 554 | bt_clock_class_get_name(clock_class), context); |
5134570b | 555 | |
ac0c6bdd | 556 | if (!clock_class || !context) { |
5134570b | 557 | BT_LOGW("Invalid parameter: clock class or metadata context is NULL: " |
2cf0acd7 | 558 | "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p", |
50842bdc | 559 | clock_class, bt_clock_class_get_name(clock_class), |
2cf0acd7 | 560 | context); |
273b65be JG |
561 | return; |
562 | } | |
563 | ||
ac0c6bdd | 564 | uuid = clock_class->uuid; |
273b65be JG |
565 | g_string_append(context->string, "clock {\n"); |
566 | g_string_append_printf(context->string, "\tname = %s;\n", | |
ac0c6bdd | 567 | clock_class->name->str); |
ce57dd3c PP |
568 | |
569 | if (clock_class->uuid_set) { | |
570 | g_string_append_printf(context->string, | |
571 | "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", | |
572 | uuid[0], uuid[1], uuid[2], uuid[3], | |
573 | uuid[4], uuid[5], uuid[6], uuid[7], | |
574 | uuid[8], uuid[9], uuid[10], uuid[11], | |
575 | uuid[12], uuid[13], uuid[14], uuid[15]); | |
576 | } | |
577 | ||
ac0c6bdd | 578 | if (clock_class->description) { |
273b65be | 579 | g_string_append_printf(context->string, "\tdescription = \"%s\";\n", |
ac0c6bdd | 580 | clock_class->description->str); |
273b65be JG |
581 | } |
582 | ||
583 | g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n", | |
ac0c6bdd | 584 | clock_class->frequency); |
273b65be | 585 | g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n", |
ac0c6bdd | 586 | clock_class->precision); |
273b65be | 587 | g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n", |
ac0c6bdd | 588 | clock_class->offset_s); |
273b65be | 589 | g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n", |
ac0c6bdd | 590 | clock_class->offset); |
273b65be | 591 | g_string_append_printf(context->string, "\tabsolute = %s;\n", |
115d6070 | 592 | clock_class->absolute ? "true" : "false"); |
273b65be JG |
593 | g_string_append(context->string, "};\n\n"); |
594 | } | |
595 | ||
273b65be | 596 | static |
50842bdc | 597 | void bt_clock_class_destroy(struct bt_object *obj) |
273b65be | 598 | { |
50842bdc | 599 | struct bt_clock_class *clock_class; |
273b65be | 600 | |
50842bdc | 601 | clock_class = container_of(obj, struct bt_clock_class, base); |
2cf0acd7 | 602 | BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"", |
50842bdc | 603 | obj, bt_clock_class_get_name(clock_class)); |
ac0c6bdd PP |
604 | if (clock_class->name) { |
605 | g_string_free(clock_class->name, TRUE); | |
273b65be | 606 | } |
ac0c6bdd PP |
607 | if (clock_class->description) { |
608 | g_string_free(clock_class->description, TRUE); | |
273b65be JG |
609 | } |
610 | ||
ac0c6bdd | 611 | g_free(clock_class); |
273b65be | 612 | } |
4ef18cab | 613 | |
61ec14e6 | 614 | static |
50842bdc | 615 | void bt_clock_value_destroy(struct bt_object *obj) |
61ec14e6 | 616 | { |
50842bdc | 617 | struct bt_clock_value *value; |
61ec14e6 JG |
618 | |
619 | if (!obj) { | |
620 | return; | |
621 | } | |
622 | ||
50842bdc | 623 | value = container_of(obj, struct bt_clock_value, base); |
2cf0acd7 PP |
624 | BT_LOGD("Destroying clock value: addr=%p, clock-class-addr=%p, " |
625 | "clock-class-name=\"%s\"", obj, value->clock_class, | |
50842bdc | 626 | bt_clock_class_get_name(value->clock_class)); |
61ec14e6 JG |
627 | bt_put(value->clock_class); |
628 | g_free(value); | |
629 | } | |
630 | ||
036a7cac | 631 | static |
50842bdc | 632 | void set_ns_from_epoch(struct bt_clock_value *clock_value) |
036a7cac | 633 | { |
50842bdc | 634 | struct bt_clock_class *clock_class = clock_value->clock_class; |
036a7cac PP |
635 | int64_t diff; |
636 | int64_t s_ns; | |
637 | uint64_t u_ns; | |
638 | uint64_t cycles; | |
639 | ||
640 | /* Initialize nanosecond timestamp to clock's offset in seconds */ | |
641 | if (clock_class->offset_s <= (INT64_MIN / 1000000000) || | |
642 | clock_class->offset_s >= (INT64_MAX / 1000000000)) { | |
643 | /* | |
644 | * Overflow: offset in seconds converted to nanoseconds | |
645 | * is outside the int64_t range. | |
646 | */ | |
647 | clock_value->ns_from_epoch_overflows = true; | |
648 | goto end; | |
649 | } | |
650 | ||
651 | clock_value->ns_from_epoch = clock_class->offset_s * (int64_t) 1000000000; | |
652 | ||
653 | /* Add offset in cycles */ | |
654 | if (clock_class->offset < 0) { | |
655 | cycles = (uint64_t) (-clock_class->offset); | |
656 | } else { | |
657 | cycles = (uint64_t) clock_class->offset; | |
658 | } | |
659 | ||
660 | u_ns = ns_from_value(clock_class->frequency, cycles); | |
661 | ||
662 | if (u_ns == -1ULL || u_ns >= INT64_MAX) { | |
663 | /* | |
664 | * Overflow: offset in cycles converted to nanoseconds | |
665 | * is outside the int64_t range. | |
666 | */ | |
667 | clock_value->ns_from_epoch_overflows = true; | |
668 | goto end; | |
669 | } | |
670 | ||
671 | s_ns = (int64_t) u_ns; | |
f6ccaed9 | 672 | BT_ASSERT(s_ns >= 0); |
036a7cac PP |
673 | |
674 | if (clock_class->offset < 0) { | |
675 | if (clock_value->ns_from_epoch >= 0) { | |
676 | /* | |
677 | * Offset in cycles is negative so it must also | |
678 | * be negative once converted to nanoseconds. | |
679 | */ | |
680 | s_ns = -s_ns; | |
681 | goto offset_ok; | |
682 | } | |
683 | ||
684 | diff = clock_value->ns_from_epoch - INT64_MIN; | |
685 | ||
686 | if (s_ns >= diff) { | |
687 | /* | |
688 | * Overflow: current timestamp in nanoseconds | |
689 | * plus the offset in cycles converted to | |
690 | * nanoseconds is outside the int64_t range. | |
691 | */ | |
692 | clock_value->ns_from_epoch_overflows = true; | |
693 | goto end; | |
694 | } | |
695 | ||
696 | /* | |
697 | * Offset in cycles is negative so it must also be | |
698 | * negative once converted to nanoseconds. | |
699 | */ | |
700 | s_ns = -s_ns; | |
701 | } else { | |
702 | if (clock_value->ns_from_epoch <= 0) { | |
703 | goto offset_ok; | |
704 | } | |
705 | ||
706 | diff = INT64_MAX - clock_value->ns_from_epoch; | |
707 | ||
708 | if (s_ns >= diff) { | |
709 | /* | |
710 | * Overflow: current timestamp in nanoseconds | |
711 | * plus the offset in cycles converted to | |
712 | * nanoseconds is outside the int64_t range. | |
713 | */ | |
714 | clock_value->ns_from_epoch_overflows = true; | |
715 | goto end; | |
716 | } | |
717 | } | |
718 | ||
719 | offset_ok: | |
720 | clock_value->ns_from_epoch += s_ns; | |
721 | ||
722 | /* Add clock value (cycles) */ | |
723 | u_ns = ns_from_value(clock_class->frequency, clock_value->value); | |
724 | ||
725 | if (u_ns == -1ULL || u_ns >= INT64_MAX) { | |
726 | /* | |
727 | * Overflow: value converted to nanoseconds is outside | |
728 | * the int64_t range. | |
729 | */ | |
730 | clock_value->ns_from_epoch_overflows = true; | |
731 | goto end; | |
732 | } | |
733 | ||
734 | s_ns = (int64_t) u_ns; | |
f6ccaed9 | 735 | BT_ASSERT(s_ns >= 0); |
036a7cac PP |
736 | |
737 | /* Clock value (cycles) is always positive */ | |
738 | if (clock_value->ns_from_epoch <= 0) { | |
739 | goto value_ok; | |
740 | } | |
741 | ||
742 | diff = INT64_MAX - clock_value->ns_from_epoch; | |
743 | ||
744 | if (s_ns >= diff) { | |
745 | /* | |
746 | * Overflow: current timestamp in nanoseconds plus the | |
747 | * clock value converted to nanoseconds is outside the | |
748 | * int64_t range. | |
749 | */ | |
750 | clock_value->ns_from_epoch_overflows = true; | |
751 | goto end; | |
752 | } | |
753 | ||
754 | value_ok: | |
755 | clock_value->ns_from_epoch += s_ns; | |
756 | ||
757 | end: | |
758 | if (clock_value->ns_from_epoch_overflows) { | |
759 | clock_value->ns_from_epoch = 0; | |
760 | } | |
761 | } | |
762 | ||
50842bdc PP |
763 | struct bt_clock_value *bt_clock_value_create( |
764 | struct bt_clock_class *clock_class, uint64_t value) | |
4ef18cab | 765 | { |
50842bdc | 766 | struct bt_clock_value *ret = NULL; |
4ef18cab | 767 | |
5134570b | 768 | BT_LOGD("Creating clock value object: clock-class-addr=%p, " |
2cf0acd7 | 769 | "clock-class-name=\"%s\", value=%" PRIu64, clock_class, |
50842bdc | 770 | bt_clock_class_get_name(clock_class), value); |
5134570b | 771 | |
ac0c6bdd | 772 | if (!clock_class) { |
5134570b | 773 | BT_LOGW_STR("Invalid parameter: clock class is NULL."); |
4ef18cab PP |
774 | goto end; |
775 | } | |
776 | ||
50842bdc | 777 | ret = g_new0(struct bt_clock_value, 1); |
61ec14e6 | 778 | if (!ret) { |
5134570b | 779 | BT_LOGE_STR("Failed to allocate one clock value."); |
61ec14e6 JG |
780 | goto end; |
781 | } | |
782 | ||
50842bdc | 783 | bt_object_init(ret, bt_clock_value_destroy); |
ac0c6bdd | 784 | ret->clock_class = bt_get(clock_class); |
61ec14e6 | 785 | ret->value = value; |
036a7cac | 786 | set_ns_from_epoch(ret); |
50842bdc | 787 | bt_clock_class_freeze(clock_class); |
2cf0acd7 | 788 | BT_LOGD("Created clock value object: clock-value-addr=%p, " |
036a7cac PP |
789 | "clock-class-addr=%p, clock-class-name=\"%s\", " |
790 | "ns-from-epoch=%" PRId64 ", ns-from-epoch-overflows=%d", | |
50842bdc | 791 | ret, clock_class, bt_clock_class_get_name(clock_class), |
036a7cac PP |
792 | ret->ns_from_epoch, ret->ns_from_epoch_overflows); |
793 | ||
61ec14e6 JG |
794 | end: |
795 | return ret; | |
796 | } | |
4ef18cab | 797 | |
50842bdc PP |
798 | int bt_clock_value_get_value( |
799 | struct bt_clock_value *clock_value, uint64_t *raw_value) | |
61ec14e6 JG |
800 | { |
801 | int ret = 0; | |
4ef18cab | 802 | |
61ec14e6 | 803 | if (!clock_value || !raw_value) { |
5134570b PP |
804 | BT_LOGW("Invalid parameter: clock value or raw value is NULL: " |
805 | "clock-value-addr=%p, raw-value-addr=%p", | |
806 | clock_value, raw_value); | |
61ec14e6 JG |
807 | ret = -1; |
808 | goto end; | |
809 | } | |
4ef18cab | 810 | |
61ec14e6 | 811 | *raw_value = clock_value->value; |
4ef18cab | 812 | end: |
61ec14e6 JG |
813 | return ret; |
814 | } | |
815 | ||
50842bdc | 816 | int bt_clock_value_get_value_ns_from_epoch(struct bt_clock_value *value, |
61ec14e6 JG |
817 | int64_t *ret_value_ns) |
818 | { | |
819 | int ret = 0; | |
61ec14e6 JG |
820 | |
821 | if (!value || !ret_value_ns) { | |
5134570b PP |
822 | BT_LOGW("Invalid parameter: clock value or return value pointer is NULL: " |
823 | "clock-value-addr=%p, ret-value-addr=%p", | |
824 | value, ret_value_ns); | |
61ec14e6 JG |
825 | ret = -1; |
826 | goto end; | |
827 | } | |
828 | ||
036a7cac PP |
829 | if (value->ns_from_epoch_overflows) { |
830 | BT_LOGW("Clock value converted to nanoseconds from Epoch overflows the signed 64-bit integer range: " | |
831 | "clock-value-addr=%p, " | |
832 | "clock-class-offset-s=%" PRId64 ", " | |
833 | "clock-class-offset-cycles=%" PRId64 ", " | |
834 | "value=%" PRIu64, | |
835 | value, value->clock_class->offset_s, | |
836 | value->clock_class->offset, | |
837 | value->value); | |
838 | ret = -1; | |
839 | goto end; | |
840 | } | |
61ec14e6 | 841 | |
036a7cac | 842 | *ret_value_ns = value->ns_from_epoch; |
61ec14e6 | 843 | |
61ec14e6 JG |
844 | end: |
845 | return ret; | |
4ef18cab | 846 | } |
6f57e458 | 847 | |
50842bdc PP |
848 | struct bt_clock_class *bt_clock_value_get_class( |
849 | struct bt_clock_value *clock_value) | |
6f57e458 | 850 | { |
50842bdc | 851 | struct bt_clock_class *clock_class = NULL; |
6f57e458 PP |
852 | |
853 | if (!clock_value) { | |
5134570b | 854 | BT_LOGW_STR("Invalid parameter: clock value is NULL."); |
6f57e458 PP |
855 | goto end; |
856 | } | |
857 | ||
858 | clock_class = bt_get(clock_value->clock_class); | |
859 | ||
860 | end: | |
861 | return clock_class; | |
862 | } | |
93dda901 PP |
863 | |
864 | BT_HIDDEN | |
865 | int bt_clock_class_compare(struct bt_clock_class *clock_class_a, | |
866 | struct bt_clock_class *clock_class_b) | |
867 | { | |
868 | int ret = 1; | |
f6ccaed9 PP |
869 | BT_ASSERT(clock_class_a); |
870 | BT_ASSERT(clock_class_b); | |
93dda901 PP |
871 | |
872 | /* Name */ | |
873 | if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) { | |
874 | BT_LOGV("Clock classes differ: different names: " | |
875 | "cc-a-name=\"%s\", cc-b-name=\"%s\"", | |
876 | clock_class_a->name->str, | |
877 | clock_class_b->name->str); | |
878 | goto end; | |
879 | } | |
880 | ||
881 | /* Description */ | |
882 | if (clock_class_a->description) { | |
883 | if (!clock_class_b->description) { | |
884 | BT_LOGV_STR("Clock classes differ: clock class A has a " | |
885 | "description, but clock class B does not."); | |
886 | goto end; | |
887 | } | |
888 | ||
889 | if (strcmp(clock_class_a->name->str, clock_class_b->name->str) | |
890 | != 0) { | |
891 | BT_LOGV("Clock classes differ: different descriptions: " | |
892 | "cc-a-descr=\"%s\", cc-b-descr=\"%s\"", | |
893 | clock_class_a->description->str, | |
894 | clock_class_b->description->str); | |
895 | goto end; | |
896 | } | |
897 | } else { | |
898 | if (clock_class_b->description) { | |
899 | BT_LOGV_STR("Clock classes differ: clock class A has " | |
900 | "no description, but clock class B has one."); | |
901 | goto end; | |
902 | } | |
903 | } | |
904 | ||
905 | /* Frequency */ | |
906 | if (clock_class_a->frequency != clock_class_b->frequency) { | |
907 | BT_LOGV("Clock classes differ: different frequencies: " | |
908 | "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, | |
909 | clock_class_a->frequency, | |
910 | clock_class_b->frequency); | |
911 | goto end; | |
912 | } | |
913 | ||
914 | /* Precision */ | |
915 | if (clock_class_a->precision != clock_class_b->precision) { | |
916 | BT_LOGV("Clock classes differ: different precisions: " | |
917 | "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, | |
918 | clock_class_a->precision, | |
919 | clock_class_b->precision); | |
920 | goto end; | |
921 | } | |
922 | ||
923 | /* Offset (seconds) */ | |
924 | if (clock_class_a->offset_s != clock_class_b->offset_s) { | |
925 | BT_LOGV("Clock classes differ: different offsets (seconds): " | |
926 | "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, | |
927 | clock_class_a->offset_s, | |
928 | clock_class_b->offset_s); | |
929 | goto end; | |
930 | } | |
931 | ||
932 | /* Offset (cycles) */ | |
933 | if (clock_class_a->offset != clock_class_b->offset) { | |
934 | BT_LOGV("Clock classes differ: different offsets (cycles): " | |
935 | "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, | |
936 | clock_class_a->offset, | |
937 | clock_class_b->offset); | |
938 | goto end; | |
939 | } | |
940 | ||
941 | /* UUIDs */ | |
942 | if (clock_class_a->uuid_set) { | |
943 | if (!clock_class_b->uuid_set) { | |
944 | BT_LOGV_STR("Clock classes differ: clock class A has a " | |
945 | "UUID, but clock class B does not."); | |
946 | goto end; | |
947 | } | |
948 | ||
949 | if (memcmp(clock_class_a->uuid, clock_class_b->uuid, | |
950 | BABELTRACE_UUID_LEN) != 0) { | |
951 | BT_LOGV("Clock classes differ: different UUIDs: " | |
952 | "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", " | |
953 | "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", | |
954 | (unsigned int) clock_class_a->uuid[0], | |
955 | (unsigned int) clock_class_a->uuid[1], | |
956 | (unsigned int) clock_class_a->uuid[2], | |
957 | (unsigned int) clock_class_a->uuid[3], | |
958 | (unsigned int) clock_class_a->uuid[4], | |
959 | (unsigned int) clock_class_a->uuid[5], | |
960 | (unsigned int) clock_class_a->uuid[6], | |
961 | (unsigned int) clock_class_a->uuid[7], | |
962 | (unsigned int) clock_class_a->uuid[8], | |
963 | (unsigned int) clock_class_a->uuid[9], | |
964 | (unsigned int) clock_class_a->uuid[10], | |
965 | (unsigned int) clock_class_a->uuid[11], | |
966 | (unsigned int) clock_class_a->uuid[12], | |
967 | (unsigned int) clock_class_a->uuid[13], | |
968 | (unsigned int) clock_class_a->uuid[14], | |
969 | (unsigned int) clock_class_a->uuid[15], | |
970 | (unsigned int) clock_class_b->uuid[0], | |
971 | (unsigned int) clock_class_b->uuid[1], | |
972 | (unsigned int) clock_class_b->uuid[2], | |
973 | (unsigned int) clock_class_b->uuid[3], | |
974 | (unsigned int) clock_class_b->uuid[4], | |
975 | (unsigned int) clock_class_b->uuid[5], | |
976 | (unsigned int) clock_class_b->uuid[6], | |
977 | (unsigned int) clock_class_b->uuid[7], | |
978 | (unsigned int) clock_class_b->uuid[8], | |
979 | (unsigned int) clock_class_b->uuid[9], | |
980 | (unsigned int) clock_class_b->uuid[10], | |
981 | (unsigned int) clock_class_b->uuid[11], | |
982 | (unsigned int) clock_class_b->uuid[12], | |
983 | (unsigned int) clock_class_b->uuid[13], | |
984 | (unsigned int) clock_class_b->uuid[14], | |
985 | (unsigned int) clock_class_b->uuid[15]); | |
986 | goto end; | |
987 | } | |
988 | } else { | |
989 | if (clock_class_b->uuid_set) { | |
990 | BT_LOGV_STR("Clock classes differ: clock class A has " | |
991 | "no UUID, but clock class B has one."); | |
992 | goto end; | |
993 | } | |
994 | } | |
995 | ||
996 | /* Absolute */ | |
997 | if (!!clock_class_a->absolute != !!clock_class_b->absolute) { | |
998 | BT_LOGV("Clock classes differ: one is absolute, the other " | |
999 | "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d", | |
1000 | !!clock_class_a->absolute, | |
1001 | !!clock_class_b->absolute); | |
1002 | goto end; | |
1003 | } | |
1004 | ||
1005 | /* Equal */ | |
1006 | ret = 0; | |
1007 | ||
1008 | end: | |
1009 | return ret; | |
1010 | } |