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