+static
+void set_ns_from_epoch(struct bt_clock_value *clock_value)
+{
+ struct bt_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_clock_value *bt_clock_value_create(
+ struct bt_clock_class *clock_class, uint64_t value)