X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=lib%2Fctf-ir%2Fclock-class.c;h=a4fd6ed626570712f3451f9f0a73236444d3df04;hp=7390c66395e46297218b9c5099d55a3c72adfead;hb=312c056ae3d374b253fa0cfe5ed576c0b0e5e569;hpb=ee389f014f52d42ba945428973d9bcfc368922b3 diff --git a/lib/ctf-ir/clock-class.c b/lib/ctf-ir/clock-class.c index 7390c663..a4fd6ed6 100644 --- a/lib/ctf-ir/clock-class.c +++ b/lib/ctf-ir/clock-class.c @@ -29,7 +29,10 @@ #define BT_LOG_TAG "CLOCK-CLASS" #include +#include +#include #include +#include #include #include #include @@ -37,17 +40,24 @@ #include #include #include +#include static -void bt_ctf_clock_class_destroy(struct bt_object *obj); +void bt_clock_class_destroy(struct bt_object *obj); + +static +struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class); + +static +void bt_clock_value_destroy(struct bt_clock_value *clock_value); BT_HIDDEN -bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class) +bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class) { return clock_class && clock_class->name; } -int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_name(struct bt_clock_class *clock_class, const char *name) { int ret = 0; @@ -60,13 +70,13 @@ int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } - if (bt_ctf_validate_identifier(name)) { - BT_LOGE("Clock class's name is not a valid CTF identifier: " + if (!bt_identifier_is_valid(name)) { + BT_LOGW("Clock class's name is not a valid CTF identifier: " "addr=%p, name=\"%s\"", clock_class, name); ret = -1; @@ -91,40 +101,74 @@ end: return ret; } -struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name) +static +bool validate_freq(struct bt_clock_class *clock_class, + const char *name, uint64_t freq) +{ + bool is_valid = true; + + if (freq == -1ULL || freq == 0) { + BT_LOGW("Invalid parameter: frequency is invalid: " + "addr=%p, name=\"%s\", freq=%" PRIu64, + clock_class, name, freq); + is_valid = false; + goto end; + } + +end: + return is_valid; +} + +static +void bt_clock_class_free_clock_value(struct bt_clock_value *clock_value, + struct bt_clock_class *clock_class) +{ + bt_clock_value_destroy(clock_value); +} + +struct bt_clock_class *bt_clock_class_create(const char *name, + uint64_t freq) { int ret; - struct bt_ctf_clock_class *clock_class; + struct bt_clock_class *clock_class = NULL; BT_LOGD("Creating default clock class object: name=\"%s\"", name); - clock_class = g_new0(struct bt_ctf_clock_class, 1); + + if (!validate_freq(NULL, name, freq)) { + /* validate_freq() logs errors */ + goto error; + } + + clock_class = g_new0(struct bt_clock_class, 1); if (!clock_class) { BT_LOGE_STR("Failed to allocate one clock class."); goto error; } clock_class->precision = 1; - clock_class->frequency = 1000000000; - bt_object_init(clock_class, bt_ctf_clock_class_destroy); + clock_class->frequency = freq; + bt_object_init(clock_class, bt_clock_class_destroy); if (name) { - ret = bt_ctf_clock_class_set_name(clock_class, name); + ret = bt_clock_class_set_name(clock_class, name); if (ret) { - BT_LOGE("Cannot set clock class's name: " - "addr=%p, name=\"%s\"", - clock_class, name); + /* bt_clock_class_set_name() logs errors */ goto error; } } - ret = bt_uuid_generate(clock_class->uuid); + ret = bt_object_pool_initialize(&clock_class->cv_pool, + (bt_object_pool_new_object_func) bt_clock_value_new, + (bt_object_pool_destroy_object_func) + bt_clock_class_free_clock_value, + clock_class); if (ret) { - BT_LOGE_STR("Failed to generate a UUID."); + BT_LOGE("Failed to initialize clock value pool: ret=%d", + ret); goto error; } - clock_class->uuid_set = 1; BT_LOGD("Created clock class object: addr=%p, name=\"%s\"", clock_class, name); return clock_class; @@ -133,7 +177,7 @@ error: return clock_class; } -const char *bt_ctf_clock_class_get_name(struct bt_ctf_clock_class *clock_class) +const char *bt_clock_class_get_name(struct bt_clock_class *clock_class) { const char *ret = NULL; @@ -150,8 +194,8 @@ end: return ret; } -const char *bt_ctf_clock_class_get_description( - struct bt_ctf_clock_class *clock_class) +const char *bt_clock_class_get_description( + struct bt_clock_class *clock_class) { const char *ret = NULL; @@ -167,7 +211,7 @@ end: return ret; } -int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_description(struct bt_clock_class *clock_class, const char *desc) { int ret = 0; @@ -175,7 +219,7 @@ int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class, if (!clock_class || !desc) { BT_LOGW("Invalid parameter: clock class or description is NULL: " "clock-class-addr=%p, name=\"%s\", desc-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), desc); ret = -1; goto end; @@ -183,7 +227,7 @@ int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } @@ -192,13 +236,13 @@ int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class, ret = clock_class->description ? 0 : -1; BT_LOGV("Set clock class's description: addr=%p, " "name=\"%s\", desc=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class), desc); + clock_class, bt_clock_class_get_name(clock_class), desc); end: return ret; } -uint64_t bt_ctf_clock_class_get_frequency( - struct bt_ctf_clock_class *clock_class) +uint64_t bt_clock_class_get_frequency( + struct bt_clock_class *clock_class) { uint64_t ret = -1ULL; @@ -212,35 +256,40 @@ end: return ret; } -int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_frequency(struct bt_clock_class *clock_class, uint64_t freq) { int ret = 0; - if (!clock_class || freq == -1ULL) { + if (!clock_class) { BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: " - "addr=%p, name=\"%s\", freq=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), - freq); + "addr=%p, name=\"%s\"", + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } + if (!validate_freq(clock_class, bt_clock_class_get_name(clock_class), + freq)) { + /* validate_freq() logs errors */ + goto end; + } + if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } clock_class->frequency = freq; BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), freq); + clock_class, bt_clock_class_get_name(clock_class), freq); end: return ret; } -uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_clock_class *clock_class) +uint64_t bt_clock_class_get_precision(struct bt_clock_class *clock_class) { uint64_t ret = -1ULL; @@ -254,7 +303,7 @@ end: return ret; } -int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_precision(struct bt_clock_class *clock_class, uint64_t precision) { int ret = 0; @@ -262,7 +311,7 @@ int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class, if (!clock_class || precision == -1ULL) { BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: " "addr=%p, name=\"%s\", precision=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), precision); ret = -1; goto end; @@ -270,20 +319,20 @@ int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } clock_class->precision = precision; BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64, - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), precision); end: return ret; } -int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_get_offset_s(struct bt_clock_class *clock_class, int64_t *offset_s) { int ret = 0; @@ -291,7 +340,7 @@ int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class, if (!clock_class || !offset_s) { BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " "clock-class-addr=%p, name=\"%s\", offset-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), offset_s); ret = -1; goto end; @@ -302,7 +351,7 @@ end: return ret; } -int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_offset_s(struct bt_clock_class *clock_class, int64_t offset_s) { int ret = 0; @@ -315,7 +364,7 @@ int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } @@ -323,13 +372,13 @@ int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class, clock_class->offset_s = offset_s; BT_LOGV("Set clock class's offset (seconds): " "addr=%p, name=\"%s\", offset-s=%" PRId64, - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), offset_s); end: return ret; } -int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_get_offset_cycles(struct bt_clock_class *clock_class, int64_t *offset) { int ret = 0; @@ -337,7 +386,7 @@ int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class, if (!clock_class || !offset) { BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: " "clock-class-addr=%p, name=\"%s\", offset-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), offset); ret = -1; goto end; @@ -348,7 +397,7 @@ end: return ret; } -int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_offset_cycles(struct bt_clock_class *clock_class, int64_t offset) { int ret = 0; @@ -361,19 +410,19 @@ int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } clock_class->offset = offset; BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64, - clock_class, bt_ctf_clock_class_get_name(clock_class), offset); + clock_class, bt_clock_class_get_name(clock_class), offset); end: return ret; } -bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_clock_class *clock_class) +bt_bool bt_clock_class_is_absolute(struct bt_clock_class *clock_class) { int ret = -1; @@ -387,7 +436,7 @@ end: return ret; } -int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_is_absolute(struct bt_clock_class *clock_class, bt_bool is_absolute) { int ret = 0; @@ -400,21 +449,21 @@ int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } clock_class->absolute = !!is_absolute; BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d", - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), is_absolute); end: return ret; } -const unsigned char *bt_ctf_clock_class_get_uuid( - struct bt_ctf_clock_class *clock_class) +const unsigned char *bt_clock_class_get_uuid( + struct bt_clock_class *clock_class) { const unsigned char *ret; @@ -426,7 +475,7 @@ const unsigned char *bt_ctf_clock_class_get_uuid( if (!clock_class->uuid_set) { BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = NULL; goto end; } @@ -436,7 +485,7 @@ end: return ret; } -int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class, +int bt_clock_class_set_uuid(struct bt_clock_class *clock_class, const unsigned char *uuid) { int ret = 0; @@ -444,7 +493,7 @@ int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class, if (!clock_class || !uuid) { BT_LOGW("Invalid parameter: clock class or UUID is NULL: " "clock-class-addr=%p, name=\"%s\", uuid-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), uuid); ret = -1; goto end; @@ -452,7 +501,7 @@ int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class, if (clock_class->frozen) { BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); + clock_class, bt_clock_class_get_name(clock_class)); ret = -1; goto end; } @@ -461,7 +510,7 @@ int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class, clock_class->uuid_set = 1; BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", " "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", - clock_class, bt_ctf_clock_class_get_name(clock_class), + clock_class, bt_clock_class_get_name(clock_class), (unsigned int) uuid[0], (unsigned int) uuid[1], (unsigned int) uuid[2], @@ -482,147 +531,340 @@ end: return ret; } -static uint64_t ns_from_value(uint64_t frequency, uint64_t value) +static inline +uint64_t ns_from_value(uint64_t frequency, uint64_t value) { uint64_t ns; - if (frequency == 1000000000) { + if (frequency == UINT64_C(1000000000)) { ns = value; } else { - ns = (uint64_t) ((1e9 * (double) value) / (double) frequency); + double dblres = ((1e9 * (double) value) / (double) frequency); + + if (dblres >= (double) UINT64_MAX) { + /* Overflows uint64_t */ + ns = -1ULL; + } else { + ns = (uint64_t) dblres; + } } return ns; } BT_HIDDEN -void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class) +void bt_clock_class_freeze(struct bt_clock_class *clock_class) { - if (!clock_class) { - BT_LOGW_STR("Invalid parameter: clock class is NULL."); + if (!clock_class || clock_class->frozen) { return; } - if (!clock_class->frozen) { - BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"", - clock_class, bt_ctf_clock_class_get_name(clock_class)); - clock_class->frozen = 1; - } + BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"", + clock_class, bt_clock_class_get_name(clock_class)); + clock_class->frozen = 1; } -BT_HIDDEN -void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class, - struct metadata_context *context) +static +void bt_clock_class_destroy(struct bt_object *obj) { - unsigned char *uuid; + struct bt_clock_class *clock_class; - BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, " - "name=\"%s\", metadata-context-addr=%p", clock_class, - bt_ctf_clock_class_get_name(clock_class), context); + clock_class = container_of(obj, struct bt_clock_class, base); + BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"", + obj, bt_clock_class_get_name(clock_class)); - if (!clock_class || !context) { - BT_LOGW("Invalid parameter: clock class or metadata context is NULL: " - "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p", - clock_class, bt_ctf_clock_class_get_name(clock_class), - context); - return; + if (clock_class->name) { + g_string_free(clock_class->name, TRUE); } - uuid = clock_class->uuid; - g_string_append(context->string, "clock {\n"); - g_string_append_printf(context->string, "\tname = %s;\n", - clock_class->name->str); - g_string_append_printf(context->string, - "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); if (clock_class->description) { - g_string_append_printf(context->string, "\tdescription = \"%s\";\n", - clock_class->description->str); + g_string_free(clock_class->description, TRUE); } - g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n", - clock_class->frequency); - g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n", - clock_class->precision); - g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n", - clock_class->offset_s); - g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n", - clock_class->offset); - g_string_append_printf(context->string, "\tabsolute = %s;\n", - clock_class->absolute ? "TRUE" : "FALSE"); - g_string_append(context->string, "};\n\n"); + bt_object_pool_finalize(&clock_class->cv_pool); + g_free(clock_class); } static -void bt_ctf_clock_class_destroy(struct bt_object *obj) +void bt_clock_value_destroy(struct bt_clock_value *clock_value) { - struct bt_ctf_clock_class *clock_class; + BT_LOGD("Destroying clock value: addr=%p, clock-class-addr=%p, " + "clock-class-name=\"%s\"", clock_value, + clock_value->clock_class, + bt_clock_class_get_name(clock_value->clock_class)); + bt_put(clock_value->clock_class); + g_free(clock_value); +} - clock_class = container_of(obj, struct bt_ctf_clock_class, base); - BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"", - obj, bt_ctf_clock_class_get_name(clock_class)); - if (clock_class->name) { - g_string_free(clock_class->name, TRUE); +static inline +int ns_from_epoch(struct bt_clock_class *clock_class, uint64_t value, + int64_t *ns_from_epoch, bool *overflows) +{ + int ret = 0; + int64_t diff; + int64_t s_ns; + uint64_t u_ns; + uint64_t cycles; + + *overflows = false; + + /* Initialize nanosecond timestamp to clock's offset in seconds */ + if (clock_class->offset_s <= (INT64_MIN / INT64_C(1000000000)) || + clock_class->offset_s >= (INT64_MAX / INT64_C(1000000000))) { + /* + * Overflow: offset in seconds converted to nanoseconds + * is outside the int64_t range. + */ + *overflows = true; + goto end; } - if (clock_class->description) { - g_string_free(clock_class->description, TRUE); + + *ns_from_epoch = clock_class->offset_s * INT64_C(1000000000); + + /* Add offset in cycles */ + if (clock_class->offset < 0) { + cycles = (uint64_t) -clock_class->offset; + } else { + cycles = (uint64_t) clock_class->offset; } - g_free(clock_class); -} + u_ns = ns_from_value(clock_class->frequency, cycles); -static -void bt_ctf_clock_value_destroy(struct bt_object *obj) -{ - struct bt_ctf_clock_value *value; + if (u_ns == UINT64_C(-1) || u_ns >= INT64_MAX) { + /* + * Overflow: offset in cycles converted to nanoseconds + * is outside the int64_t range. + */ + *overflows = true; + goto end; + } - if (!obj) { - return; + s_ns = (int64_t) u_ns; + BT_ASSERT(s_ns >= 0); + + if (clock_class->offset < 0) { + if (*ns_from_epoch >= 0) { + /* + * Offset in cycles is negative so it must also + * be negative once converted to nanoseconds. + */ + s_ns = -s_ns; + goto offset_ok; + } + + diff = *ns_from_epoch - INT64_MIN; + + if (s_ns >= diff) { + /* + * Overflow: current timestamp in nanoseconds + * plus the offset in cycles converted to + * nanoseconds is outside the int64_t range. + */ + *overflows = true; + goto end; + } + + /* + * Offset in cycles is negative so it must also be + * negative once converted to nanoseconds. + */ + s_ns = -s_ns; + } else { + if (*ns_from_epoch <= 0) { + goto offset_ok; + } + + diff = INT64_MAX - *ns_from_epoch; + + if (s_ns >= diff) { + /* + * Overflow: current timestamp in nanoseconds + * plus the offset in cycles converted to + * nanoseconds is outside the int64_t range. + */ + *overflows = true; + goto end; + } } - value = container_of(obj, struct bt_ctf_clock_value, base); - BT_LOGD("Destroying clock value: addr=%p, clock-class-addr=%p, " - "clock-class-name=\"%s\"", obj, value->clock_class, - bt_ctf_clock_class_get_name(value->clock_class)); - bt_put(value->clock_class); - g_free(value); +offset_ok: + *ns_from_epoch += s_ns; + + /* Add clock value (cycles) */ + u_ns = ns_from_value(clock_class->frequency, value); + + if (u_ns == -1ULL || u_ns >= INT64_MAX) { + /* + * Overflow: value converted to nanoseconds is outside + * the int64_t range. + */ + *overflows = true; + goto end; + } + + s_ns = (int64_t) u_ns; + BT_ASSERT(s_ns >= 0); + + /* Clock value (cycles) is always positive */ + if (*ns_from_epoch <= 0) { + goto value_ok; + } + + diff = INT64_MAX - *ns_from_epoch; + + if (s_ns >= diff) { + /* + * Overflow: current timestamp in nanoseconds plus the + * clock value converted to nanoseconds is outside the + * int64_t range. + */ + *overflows = true; + goto end; + } + +value_ok: + *ns_from_epoch += s_ns; + +end: + if (*overflows) { + *ns_from_epoch = 0; + ret = -1; + } + + return ret; +} + +static +void set_ns_from_epoch(struct bt_clock_value *clock_value) +{ + (void) ns_from_epoch(clock_value->clock_class, + clock_value->value, &clock_value->ns_from_epoch, + &clock_value->ns_from_epoch_overflows); } -struct bt_ctf_clock_value *bt_ctf_clock_value_create( - struct bt_ctf_clock_class *clock_class, uint64_t value) +static +struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class) { - struct bt_ctf_clock_value *ret = NULL; + struct bt_clock_value *ret = NULL; BT_LOGD("Creating clock value object: clock-class-addr=%p, " - "clock-class-name=\"%s\", value=%" PRIu64, clock_class, - bt_ctf_clock_class_get_name(clock_class), value); + "clock-class-name=\"%s\"", clock_class, + bt_clock_class_get_name(clock_class)); if (!clock_class) { BT_LOGW_STR("Invalid parameter: clock class is NULL."); goto end; } - ret = g_new0(struct bt_ctf_clock_value, 1); + ret = g_new0(struct bt_clock_value, 1); if (!ret) { BT_LOGE_STR("Failed to allocate one clock value."); goto end; } - bt_object_init(ret, bt_ctf_clock_value_destroy); + bt_object_init(ret, NULL); + bt_object_set_is_shared((void *) ret, false); ret->clock_class = bt_get(clock_class); - ret->value = value; + bt_clock_class_freeze(clock_class); BT_LOGD("Created clock value object: clock-value-addr=%p, " - "clock-class-addr=%p, clock-class-name=\"%s\"", - ret, clock_class, bt_ctf_clock_class_get_name(clock_class)); + "clock-class-addr=%p, clock-class-name=\"%s\", " + "ns-from-epoch=%" PRId64 ", ns-from-epoch-overflows=%d", + ret, clock_class, bt_clock_class_get_name(clock_class), + ret->ns_from_epoch, ret->ns_from_epoch_overflows); + end: return ret; } -int bt_ctf_clock_value_get_value( - struct bt_ctf_clock_value *clock_value, uint64_t *raw_value) +BT_HIDDEN +struct bt_clock_value *bt_clock_value_create(struct bt_clock_class *clock_class) +{ + struct bt_clock_value *clock_value = NULL; + + BT_ASSERT(clock_class); + clock_value = bt_object_pool_create_object(&clock_class->cv_pool); + if (!clock_value) { + BT_LIB_LOGE("Cannot allocate one clock value from clock class's clock value pool: " + "%![cc-]+K", clock_class); + goto error; + } + + if (!clock_value->clock_class) { + clock_value->clock_class = bt_get(clock_class); + } + + goto end; + +error: + if (clock_value) { + bt_clock_value_recycle(clock_value); + clock_value = NULL; + } + +end: + return clock_value; +} + +BT_HIDDEN +void bt_clock_value_recycle(struct bt_clock_value *clock_value) +{ + struct bt_clock_class *clock_class; + + BT_ASSERT(clock_value); + BT_LIB_LOGD("Recycling clock value: %!+k", clock_value); + + /* + * Those are the important ordered steps: + * + * 1. Reset the clock value object, but do NOT put its clock + * class's reference. This clock class contains the pool to + * which we're about to recycle this clock value object, so + * we must guarantee its existence thanks to this existing + * reference. + * + * 2. Move the clock class reference to our `clock_class` + * variable so that we can set the clock value's clock class + * member to NULL before recycling it. We CANNOT do this + * after we put the clock class reference because this + * bt_put() could destroy the clock class, also destroying + * its clock value pool, thus also destroying our clock value + * object (this would result in an invalid write access). + * + * 3. Recycle the clock value object. + * + * 4. Put our clock class reference. + */ + bt_clock_value_reset(clock_value); + bt_clock_value_set_is_frozen(clock_value, false); + clock_class = clock_value->clock_class; + BT_ASSERT(clock_class); + clock_value->clock_class = NULL; + bt_object_pool_recycle_object(&clock_class->cv_pool, clock_value); + bt_put(clock_class); +} + +BT_HIDDEN +void bt_clock_value_set_raw_value(struct bt_clock_value *clock_value, + uint64_t cycles) +{ + BT_ASSERT(clock_value); + + clock_value->value = cycles; + set_ns_from_epoch(clock_value); + bt_clock_value_set(clock_value); +} + +int bt_clock_value_set_value(struct bt_clock_value *clock_value, + uint64_t raw_value) +{ + BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value"); + BT_ASSERT_PRE_HOT(clock_value, "Clock value", ": %!+k", clock_value); + bt_clock_value_set_raw_value(clock_value, raw_value); + return 0; +} + +int bt_clock_value_get_value(struct bt_clock_value *clock_value, + uint64_t *raw_value) { int ret = 0; @@ -639,11 +881,10 @@ end: return ret; } -int bt_ctf_clock_value_get_value_ns_from_epoch(struct bt_ctf_clock_value *value, +int bt_clock_value_get_value_ns_from_epoch(struct bt_clock_value *value, int64_t *ret_value_ns) { int ret = 0; - int64_t ns; if (!value || !ret_value_ns) { BT_LOGW("Invalid parameter: clock value or return value pointer is NULL: " @@ -653,33 +894,215 @@ int bt_ctf_clock_value_get_value_ns_from_epoch(struct bt_ctf_clock_value *value, goto end; } - /* Initialize nanosecond timestamp to clock's offset in seconds. */ - ns = value->clock_class->offset_s * (int64_t) 1000000000; - - /* Add offset in cycles, converted to nanoseconds. */ - ns += ns_from_value(value->clock_class->frequency, - value->clock_class->offset); + if (value->ns_from_epoch_overflows) { + BT_LOGW("Clock value converted to nanoseconds from Epoch overflows the signed 64-bit integer range: " + "clock-value-addr=%p, " + "clock-class-offset-s=%" PRId64 ", " + "clock-class-offset-cycles=%" PRId64 ", " + "value=%" PRIu64, + value, value->clock_class->offset_s, + value->clock_class->offset, + value->value); + ret = -1; + goto end; + } - /* Add given value, converter to nanoseconds. */ - ns += ns_from_value(value->clock_class->frequency, value->value); + *ret_value_ns = value->ns_from_epoch; - *ret_value_ns = ns; end: return ret; } -struct bt_ctf_clock_class *bt_ctf_clock_value_get_class( - struct bt_ctf_clock_value *clock_value) +struct bt_clock_class *bt_clock_value_borrow_class( + struct bt_clock_value *clock_value) { - struct bt_ctf_clock_class *clock_class = NULL; + struct bt_clock_class *clock_class = NULL; if (!clock_value) { BT_LOGW_STR("Invalid parameter: clock value is NULL."); goto end; } - clock_class = bt_get(clock_value->clock_class); + clock_class = clock_value->clock_class; end: return clock_class; } + +BT_HIDDEN +int bt_clock_class_compare(struct bt_clock_class *clock_class_a, + struct bt_clock_class *clock_class_b) +{ + int ret = 1; + BT_ASSERT(clock_class_a); + BT_ASSERT(clock_class_b); + + /* Name */ + if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) { + BT_LOGV("Clock classes differ: different names: " + "cc-a-name=\"%s\", cc-b-name=\"%s\"", + clock_class_a->name->str, + clock_class_b->name->str); + goto end; + } + + /* Description */ + if (clock_class_a->description) { + if (!clock_class_b->description) { + BT_LOGV_STR("Clock classes differ: clock class A has a " + "description, but clock class B does not."); + goto end; + } + + if (strcmp(clock_class_a->name->str, clock_class_b->name->str) + != 0) { + BT_LOGV("Clock classes differ: different descriptions: " + "cc-a-descr=\"%s\", cc-b-descr=\"%s\"", + clock_class_a->description->str, + clock_class_b->description->str); + goto end; + } + } else { + if (clock_class_b->description) { + BT_LOGV_STR("Clock classes differ: clock class A has " + "no description, but clock class B has one."); + goto end; + } + } + + /* Frequency */ + if (clock_class_a->frequency != clock_class_b->frequency) { + BT_LOGV("Clock classes differ: different frequencies: " + "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, + clock_class_a->frequency, + clock_class_b->frequency); + goto end; + } + + /* Precision */ + if (clock_class_a->precision != clock_class_b->precision) { + BT_LOGV("Clock classes differ: different precisions: " + "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64, + clock_class_a->precision, + clock_class_b->precision); + goto end; + } + + /* Offset (seconds) */ + if (clock_class_a->offset_s != clock_class_b->offset_s) { + BT_LOGV("Clock classes differ: different offsets (seconds): " + "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, + clock_class_a->offset_s, + clock_class_b->offset_s); + goto end; + } + + /* Offset (cycles) */ + if (clock_class_a->offset != clock_class_b->offset) { + BT_LOGV("Clock classes differ: different offsets (cycles): " + "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64, + clock_class_a->offset, + clock_class_b->offset); + goto end; + } + + /* UUIDs */ + if (clock_class_a->uuid_set) { + if (!clock_class_b->uuid_set) { + BT_LOGV_STR("Clock classes differ: clock class A has a " + "UUID, but clock class B does not."); + goto end; + } + + if (memcmp(clock_class_a->uuid, clock_class_b->uuid, + BABELTRACE_UUID_LEN) != 0) { + BT_LOGV("Clock classes differ: different UUIDs: " + "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", " + "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"", + (unsigned int) clock_class_a->uuid[0], + (unsigned int) clock_class_a->uuid[1], + (unsigned int) clock_class_a->uuid[2], + (unsigned int) clock_class_a->uuid[3], + (unsigned int) clock_class_a->uuid[4], + (unsigned int) clock_class_a->uuid[5], + (unsigned int) clock_class_a->uuid[6], + (unsigned int) clock_class_a->uuid[7], + (unsigned int) clock_class_a->uuid[8], + (unsigned int) clock_class_a->uuid[9], + (unsigned int) clock_class_a->uuid[10], + (unsigned int) clock_class_a->uuid[11], + (unsigned int) clock_class_a->uuid[12], + (unsigned int) clock_class_a->uuid[13], + (unsigned int) clock_class_a->uuid[14], + (unsigned int) clock_class_a->uuid[15], + (unsigned int) clock_class_b->uuid[0], + (unsigned int) clock_class_b->uuid[1], + (unsigned int) clock_class_b->uuid[2], + (unsigned int) clock_class_b->uuid[3], + (unsigned int) clock_class_b->uuid[4], + (unsigned int) clock_class_b->uuid[5], + (unsigned int) clock_class_b->uuid[6], + (unsigned int) clock_class_b->uuid[7], + (unsigned int) clock_class_b->uuid[8], + (unsigned int) clock_class_b->uuid[9], + (unsigned int) clock_class_b->uuid[10], + (unsigned int) clock_class_b->uuid[11], + (unsigned int) clock_class_b->uuid[12], + (unsigned int) clock_class_b->uuid[13], + (unsigned int) clock_class_b->uuid[14], + (unsigned int) clock_class_b->uuid[15]); + goto end; + } + } else { + if (clock_class_b->uuid_set) { + BT_LOGV_STR("Clock classes differ: clock class A has " + "no UUID, but clock class B has one."); + goto end; + } + } + + /* Absolute */ + if (!!clock_class_a->absolute != !!clock_class_b->absolute) { + BT_LOGV("Clock classes differ: one is absolute, the other " + "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d", + !!clock_class_a->absolute, + !!clock_class_b->absolute); + goto end; + } + + /* Equal */ + ret = 0; + +end: + return ret; +} + +int bt_clock_class_cycles_to_ns(struct bt_clock_class *clock_class, + uint64_t cycles, int64_t *ns) +{ + int ret; + bool overflows; + + BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class"); + BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds"); + + ret = ns_from_epoch(clock_class, cycles, ns, &overflows); + if (ret) { + if (overflows) { + BT_LIB_LOGW("Cannot convert cycles to nanoseconds " + "from Epoch for given clock class: " + "value overflow: %![cc-]+K, cycles=%" PRIu64, + clock_class, cycles); + } else { + BT_LIB_LOGW("Cannot convert cycles to nanoseconds " + "from Epoch for given clock class: " + "%![cc-]+K, cycles=%" PRIu64, + clock_class, cycles); + } + + goto end; + } + +end: + return ret; +}