X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Fctf-ir%2Fclock-class.c;h=2dd6536a6d0f11054b6d3984604b3c4dd4d4f4b3;hb=c057dea051159b06050ab5d6b640dfb7e1654ba7;hp=7390c66395e46297218b9c5099d55a3c72adfead;hpb=ee389f014f52d42ba945428973d9bcfc368922b3;p=babeltrace.git diff --git a/lib/ctf-ir/clock-class.c b/lib/ctf-ir/clock-class.c index 7390c663..2dd6536a 100644 --- a/lib/ctf-ir/clock-class.c +++ b/lib/ctf-ir/clock-class.c @@ -29,7 +29,9 @@ #define BT_LOG_TAG "CLOCK-CLASS" #include +#include #include +#include #include #include #include @@ -91,13 +93,38 @@ end: return ret; } -struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name) +static +bool validate_freq(struct bt_ctf_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; +} + +struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name, + uint64_t freq) { int ret; - struct bt_ctf_clock_class *clock_class; + struct bt_ctf_clock_class *clock_class = NULL; BT_LOGD("Creating default clock class object: name=\"%s\"", name); + + if (!validate_freq(NULL, name, freq)) { + /* validate_freq() logs errors */ + goto error; + } + clock_class = g_new0(struct bt_ctf_clock_class, 1); if (!clock_class) { BT_LOGE_STR("Failed to allocate one clock class."); @@ -105,7 +132,7 @@ struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name) } clock_class->precision = 1; - clock_class->frequency = 1000000000; + clock_class->frequency = freq; bt_object_init(clock_class, bt_ctf_clock_class_destroy); if (name) { @@ -118,13 +145,6 @@ struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name) } } - ret = bt_uuid_generate(clock_class->uuid); - if (ret) { - BT_LOGE_STR("Failed to generate a UUID."); - goto error; - } - - clock_class->uuid_set = 1; BT_LOGD("Created clock class object: addr=%p, name=\"%s\"", clock_class, name); return clock_class; @@ -217,15 +237,20 @@ int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class, { 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_ctf_clock_class_get_name(clock_class)); ret = -1; goto end; } + if (!validate_freq(clock_class, bt_ctf_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)); @@ -489,7 +514,14 @@ static uint64_t ns_from_value(uint64_t frequency, uint64_t value) if (frequency == 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; @@ -532,12 +564,16 @@ void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class, 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->uuid_set) { + 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); @@ -552,7 +588,7 @@ void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class, 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"); + clock_class->absolute ? "true" : "false"); g_string_append(context->string, "};\n\n"); } @@ -591,6 +627,138 @@ void bt_ctf_clock_value_destroy(struct bt_object *obj) g_free(value); } +static +void set_ns_from_epoch(struct bt_ctf_clock_value *clock_value) +{ + struct bt_ctf_clock_class *clock_class = clock_value->clock_class; + int64_t diff; + int64_t s_ns; + uint64_t u_ns; + uint64_t cycles; + + /* Initialize nanosecond timestamp to clock's offset in seconds */ + if (clock_class->offset_s <= (INT64_MIN / 1000000000) || + clock_class->offset_s >= (INT64_MAX / 1000000000)) { + /* + * Overflow: offset in seconds converted to nanoseconds + * is outside the int64_t range. + */ + clock_value->ns_from_epoch_overflows = true; + goto end; + } + + clock_value->ns_from_epoch = clock_class->offset_s * (int64_t) 1000000000; + + /* Add offset in cycles */ + if (clock_class->offset < 0) { + cycles = (uint64_t) (-clock_class->offset); + } else { + cycles = (uint64_t) clock_class->offset; + } + + u_ns = ns_from_value(clock_class->frequency, cycles); + + if (u_ns == -1ULL || u_ns >= INT64_MAX) { + /* + * Overflow: offset in cycles converted to nanoseconds + * is outside the int64_t range. + */ + clock_value->ns_from_epoch_overflows = true; + goto end; + } + + s_ns = (int64_t) u_ns; + assert(s_ns >= 0); + + if (clock_class->offset < 0) { + if (clock_value->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 = clock_value->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. + */ + clock_value->ns_from_epoch_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 (clock_value->ns_from_epoch <= 0) { + goto offset_ok; + } + + diff = INT64_MAX - clock_value->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. + */ + clock_value->ns_from_epoch_overflows = true; + goto end; + } + } + +offset_ok: + clock_value->ns_from_epoch += s_ns; + + /* Add clock value (cycles) */ + u_ns = ns_from_value(clock_class->frequency, clock_value->value); + + if (u_ns == -1ULL || u_ns >= INT64_MAX) { + /* + * Overflow: value converted to nanoseconds is outside + * the int64_t range. + */ + clock_value->ns_from_epoch_overflows = true; + goto end; + } + + s_ns = (int64_t) u_ns; + assert(s_ns >= 0); + + /* Clock value (cycles) is always positive */ + if (clock_value->ns_from_epoch <= 0) { + goto value_ok; + } + + diff = INT64_MAX - clock_value->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. + */ + clock_value->ns_from_epoch_overflows = true; + goto end; + } + +value_ok: + clock_value->ns_from_epoch += s_ns; + +end: + if (clock_value->ns_from_epoch_overflows) { + clock_value->ns_from_epoch = 0; + } +} + struct bt_ctf_clock_value *bt_ctf_clock_value_create( struct bt_ctf_clock_class *clock_class, uint64_t value) { @@ -614,9 +782,14 @@ struct bt_ctf_clock_value *bt_ctf_clock_value_create( bt_object_init(ret, bt_ctf_clock_value_destroy); ret->clock_class = bt_get(clock_class); ret->value = value; + set_ns_from_epoch(ret); + bt_ctf_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_ctf_clock_class_get_name(clock_class), + ret->ns_from_epoch, ret->ns_from_epoch_overflows); + end: return ret; } @@ -643,7 +816,6 @@ int bt_ctf_clock_value_get_value_ns_from_epoch(struct bt_ctf_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,17 +825,21 @@ 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; }