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