#define BT_LOG_TAG "CLOCK-CLASS"
#include <babeltrace/lib-logging-internal.h>
+#include <babeltrace/compat/uuid-internal.h>
#include <babeltrace/ctf-ir/clock-class-internal.h>
#include <babeltrace/ctf-ir/utils.h>
#include <babeltrace/ref.h>
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.");
}
clock_class->precision = 1;
- clock_class->frequency = 1000000000;
+ clock_class->frequency = freq;
bt_object_init(clock_class, bt_ctf_clock_class_destroy);
if (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;
{
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));
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;
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);
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");
}
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)
{
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_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;
}
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: "
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;
}