noinst_LTLIBRARIES = \
argpar/libargpar.la \
autodisc/libautodisc.la \
+ clock-correlation-validator/libclock-correlation-validator.la \
common/libcommon.la \
compat/libcompat.la \
cpp-common/libcpp-common.la \
autodisc/autodisc.c \
autodisc/autodisc.h
+clock_correlation_validator_libclock_correlation_validator_la_SOURCES = \
+ clock-correlation-validator/clock-correlation-validator.cpp \
+ clock-correlation-validator/clock-correlation-validator.h \
+ clock-correlation-validator/clock-correlation-validator.hpp
+
common_libcommon_la_SOURCES = \
common/align.h \
common/assert.c \
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2024 EfficiOS, Inc.
+ */
+
+#include "cpp-common/bt2/clock-class.hpp"
+#include "cpp-common/bt2/message.hpp"
+#include "cpp-common/bt2/wrap.hpp"
+
+#include "clock-correlation-validator.h"
+#include "clock-correlation-validator.hpp"
+
+namespace bt2ccv {
+
+void ClockCorrelationValidator::_validate(const bt2::ConstMessage msg)
+{
+ bt2::OptionalBorrowedObject<bt2::ConstClockClass> clockCls;
+ bt2::OptionalBorrowedObject<bt2::ConstStreamClass> streamCls;
+
+ switch (msg.type()) {
+ case bt2::MessageType::STREAM_BEGINNING:
+ streamCls = msg.asStreamBeginning().stream().cls();
+ clockCls = streamCls->defaultClockClass();
+ break;
+
+ case bt2::MessageType::MESSAGE_ITERATOR_INACTIVITY:
+ clockCls = msg.asMessageIteratorInactivity().clockSnapshot().clockClass();
+ break;
+
+ default:
+ bt_common_abort();
+ }
+
+ switch (_mExpectation) {
+ case PropsExpectation::UNSET:
+ /*
+ * This is the first analysis of a message with a clock
+ * snapshot: record the properties of that clock, against which
+ * we'll compare the clock properties of the following messages.
+ */
+ if (!clockCls) {
+ _mExpectation = PropsExpectation::NONE;
+ } else if (clockCls->originIsUnixEpoch()) {
+ _mExpectation = PropsExpectation::ORIGIN_UNIX;
+ } else if (const auto uuid = clockCls->uuid()) {
+ _mExpectation = PropsExpectation::ORIGIN_OTHER_UUID;
+ _mUuid = *uuid;
+ } else {
+ _mExpectation = PropsExpectation::ORIGIN_OTHER_NO_UUID;
+ _mClockClass = clockCls->shared();
+ }
+
+ break;
+
+ case PropsExpectation::NONE:
+ if (clockCls) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_NO_CLOCK_CLASS_GOT_ONE,
+ bt2s::nullopt,
+ *clockCls,
+ {},
+ streamCls};
+ }
+
+ break;
+
+ case PropsExpectation::ORIGIN_UNIX:
+ if (!clockCls) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_UNIX_GOT_NONE,
+ bt2s::nullopt,
+ {},
+ {},
+ streamCls};
+ }
+
+ if (!clockCls->originIsUnixEpoch()) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_UNIX_GOT_OTHER,
+ bt2s::nullopt,
+ *clockCls,
+ {},
+ streamCls};
+ }
+
+ break;
+
+ case PropsExpectation::ORIGIN_OTHER_UUID:
+ {
+ if (!clockCls) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_NONE,
+ bt2s::nullopt,
+ {},
+ {},
+ streamCls};
+ }
+
+ if (clockCls->originIsUnixEpoch()) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_UNIX,
+ bt2s::nullopt,
+ *clockCls,
+ {},
+ streamCls};
+ }
+
+ const auto uuid = clockCls->uuid();
+
+ if (!uuid) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_NO_UUID,
+ bt2s::nullopt,
+ *clockCls,
+ {},
+ streamCls};
+ }
+
+ if (*uuid != _mUuid) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID,
+ _mUuid,
+ *clockCls,
+ {},
+ streamCls};
+ }
+
+ break;
+ }
+
+ case PropsExpectation::ORIGIN_OTHER_NO_UUID:
+ if (!clockCls) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_NO_UUID_GOT_NONE,
+ bt2s::nullopt,
+ {},
+ {},
+ streamCls};
+ }
+
+ if (clockCls->libObjPtr() != _mClockClass->libObjPtr()) {
+ throw ClockCorrelationError {
+ ClockCorrelationError::Type::EXPECTING_ORIGIN_NO_UUID_GOT_OTHER, bt2s::nullopt,
+ *clockCls, *_mClockClass, streamCls};
+ }
+
+ break;
+
+ default:
+ bt_common_abort();
+ }
+}
+
+} /* namespace bt2ccv */
+
+bt_clock_correlation_validator *bt_clock_correlation_validator_create() noexcept
+{
+ try {
+ return reinterpret_cast<bt_clock_correlation_validator *>(
+ new bt2ccv::ClockCorrelationValidator);
+ } catch (const std::bad_alloc&) {
+ return nullptr;
+ }
+}
+
+bool bt_clock_correlation_validator_validate_message(
+ bt_clock_correlation_validator * const validator, const bt_message * const msg,
+ bt_clock_correlation_validator_error_type * const type, bt_uuid * const expectedUuidOut,
+ const bt_clock_class ** const actualClockClsOut,
+ const bt_clock_class ** const expectedClockClsOut) noexcept
+{
+ try {
+ reinterpret_cast<bt2ccv::ClockCorrelationValidator *>(validator)->validate(bt2::wrap(msg));
+ return true;
+ } catch (const bt2ccv::ClockCorrelationError& error) {
+ *type = static_cast<bt_clock_correlation_validator_error_type>(error.type());
+
+ if (error.expectedUuid()) {
+ *expectedUuidOut = error.expectedUuid()->data();
+ } else {
+ *expectedUuidOut = nullptr;
+ }
+
+ if (error.actualClockCls()) {
+ *actualClockClsOut = error.actualClockCls()->libObjPtr();
+ } else {
+ *actualClockClsOut = nullptr;
+ }
+
+ if (error.expectedClockCls()) {
+ *expectedClockClsOut = error.expectedClockCls()->libObjPtr();
+ } else {
+ *expectedClockClsOut = nullptr;
+ }
+
+ return false;
+ }
+}
+
+void bt_clock_correlation_validator_destroy(
+ bt_clock_correlation_validator * const validator) noexcept
+{
+ delete reinterpret_cast<bt2ccv::ClockCorrelationValidator *>(validator);
+}
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2024 EfficiOS, Inc.
+ */
+
+#ifndef CLOCK_CORRELATION_VALIDATOR_CLOCK_CORRELATION_VALIDATOR_H
+#define CLOCK_CORRELATION_VALIDATOR_CLOCK_CORRELATION_VALIDATOR_H
+
+#include <glib.h>
+#include <stdbool.h>
+#include <babeltrace2/babeltrace.h>
+
+#include "common/macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_clock_class;
+struct bt_message;
+
+enum bt_clock_correlation_validator_error_type
+{
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_NO_CLOCK_CLASS_GOT_ONE,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UNIX_GOT_NONE,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UNIX_GOT_OTHER,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_NONE,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_UNIX,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_NO_UUID,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_NO_UUID_GOT_NONE,
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_NO_UUID_GOT_OTHER,
+};
+
+struct bt_clock_correlation_validator *bt_clock_correlation_validator_create(
+ void) BT_NOEXCEPT;
+
+bool bt_clock_correlation_validator_validate_message(
+ struct bt_clock_correlation_validator *validator,
+ const struct bt_message *msg,
+ enum bt_clock_correlation_validator_error_type *type,
+ bt_uuid *expected_uuid,
+ const struct bt_clock_class ** const actual_clock_cls,
+ const struct bt_clock_class ** const expected_clock_cls) BT_NOEXCEPT;
+
+void bt_clock_correlation_validator_destroy(
+ struct bt_clock_correlation_validator *validator) BT_NOEXCEPT;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CLOCK_CORRELATION_VALIDATOR_CLOCK_CORRELATION_VALIDATOR_H */
--- /dev/null
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright 2024 EfficiOS, Inc.
+ */
+
+#ifndef CLOCK_CORRELATION_VALIDATOR_CLOCK_CORRELATION_VALIDATOR_HPP
+#define CLOCK_CORRELATION_VALIDATOR_CLOCK_CORRELATION_VALIDATOR_HPP
+
+#include "cpp-common/bt2/message.hpp"
+
+#include "clock-correlation-validator/clock-correlation-validator.h"
+
+namespace bt2ccv {
+
+class ClockCorrelationError final : public std::runtime_error
+{
+public:
+ enum class Type
+ {
+ EXPECTING_NO_CLOCK_CLASS_GOT_ONE =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_NO_CLOCK_CLASS_GOT_ONE,
+ EXPECTING_ORIGIN_UNIX_GOT_NONE =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UNIX_GOT_NONE,
+ EXPECTING_ORIGIN_UNIX_GOT_OTHER =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UNIX_GOT_OTHER,
+ EXPECTING_ORIGIN_UUID_GOT_NONE =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_NONE,
+ EXPECTING_ORIGIN_UUID_GOT_UNIX =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_UNIX,
+ EXPECTING_ORIGIN_UUID_GOT_NO_UUID =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_NO_UUID,
+ EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_UUID_GOT_OTHER_UUID,
+ EXPECTING_ORIGIN_NO_UUID_GOT_NONE =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_NO_UUID_GOT_NONE,
+ EXPECTING_ORIGIN_NO_UUID_GOT_OTHER =
+ BT_CLOCK_CORRELATION_VALIDATOR_ERROR_TYPE_EXPECTING_ORIGIN_NO_UUID_GOT_OTHER,
+ };
+
+ explicit ClockCorrelationError(
+ Type type, const bt2s::optional<bt2c::UuidView> expectedUuid,
+ const bt2::OptionalBorrowedObject<bt2::ConstClockClass> actualClockCls,
+ const bt2::OptionalBorrowedObject<bt2::ConstClockClass> expectedClockCls,
+ const bt2::OptionalBorrowedObject<bt2::ConstStreamClass> streamCls) noexcept :
+ std::runtime_error {"Clock classes are not correlatable"},
+ _mType {type}, _mExpectedUuid {expectedUuid}, _mActualClockCls {actualClockCls},
+ _mExpectedClockCls {expectedClockCls}, _mStreamCls {streamCls}
+
+ {
+ }
+
+ Type type() const noexcept
+ {
+ return _mType;
+ }
+
+ bt2s::optional<bt2c::UuidView> expectedUuid() const noexcept
+ {
+ return _mExpectedUuid;
+ }
+
+ bt2::OptionalBorrowedObject<bt2::ConstClockClass> actualClockCls() const noexcept
+ {
+ return _mActualClockCls;
+ }
+
+ bt2::OptionalBorrowedObject<bt2::ConstClockClass> expectedClockCls() const noexcept
+ {
+ return _mExpectedClockCls;
+ }
+
+ bt2::OptionalBorrowedObject<bt2::ConstStreamClass> streamCls() const noexcept
+ {
+ return _mStreamCls;
+ }
+
+private:
+ Type _mType;
+ bt2s::optional<bt2c::UuidView> _mExpectedUuid;
+ bt2::OptionalBorrowedObject<bt2::ConstClockClass> _mActualClockCls;
+ bt2::OptionalBorrowedObject<bt2::ConstClockClass> _mExpectedClockCls;
+ bt2::OptionalBorrowedObject<bt2::ConstStreamClass> _mStreamCls;
+};
+
+class ClockCorrelationValidator final
+{
+private:
+ enum class PropsExpectation
+ {
+ /* We haven't recorded clock properties yet. */
+ UNSET,
+
+ /* Expect to have no clock. */
+ NONE,
+
+ /* Expect a clock with a Unix epoch origin. */
+ ORIGIN_UNIX,
+
+ /* Expect a clock without a Unix epoch origin, but with a UUID. */
+ ORIGIN_OTHER_UUID,
+
+ /* Expect a clock without a Unix epoch origin and without a UUID. */
+ ORIGIN_OTHER_NO_UUID,
+ };
+
+public:
+ void validate(const bt2::ConstMessage msg)
+ {
+ if (!msg.isStreamBeginning() && !msg.isMessageIteratorInactivity()) {
+ return;
+ }
+
+ this->_validate(msg);
+ }
+
+private:
+ void _validate(const bt2::ConstMessage msg);
+
+ PropsExpectation _mExpectation = PropsExpectation::UNSET;
+
+ /*
+ * Expected UUID of the clock, if `_mExpectation` is
+ * `PropsExpectation::ORIGIN_OTHER_UUID`.
+ *
+ * If the origin of the clock is the Unix epoch, then the UUID is
+ * irrelevant because the clock will have a correlation with other
+ * clocks having the same origin.
+ */
+ bt2c::Uuid _mUuid;
+
+ /*
+ * Expected clock class, if `_mExpectation` is
+ * `ClockExpectation::ORIGIN_OTHER_NO_UUID`.
+ *
+ * If the first analyzed clock class has an unknown origin and no
+ * UUID, then all subsequent analyzed clock classes must be the same
+ * instance.
+ *
+ * To make sure that the clock class pointed to by this member
+ * doesn't get freed and another one reallocated at the same
+ * address, which could potentially bypass the clock expectation
+ * check, we keep a strong reference, ensuring that the clock class
+ * lives at least as long as the owner of this validator.
+ */
+ bt2::ConstClockClass::Shared _mClockClass;
+};
+
+} /* namespace bt2ccv */
+
+#endif /* CLOCK_CORRELATION_VALIDATOR_CLOCK_CORRELATION_VALIDATOR_HPP */
#define BT_EXPORT __attribute__((visibility("default")))
#endif
+/*
+ * BT_NOEXCEPT: defined to `noexcept` if compiling as C++, else empty.
+ */
+#if defined(__cplusplus)
+#define BT_NOEXCEPT noexcept
+#else
+#define BT_NOEXCEPT
+#endif
+
/* Enable `txt` if developer mode is enabled. */
#ifdef BT_DEV_MODE
#define BT_IF_DEV_MODE(txt) txt