Skip to content

Commit 1e7d813

Browse files
committed
hmon: add C++ interface to logic monitor
Add C++ interface to logic monitor.
1 parent 743411c commit 1e7d813

10 files changed

Lines changed: 1274 additions & 3 deletions

File tree

src/health_monitoring_lib/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ PROC_MACRO_DEPS = [
2828
CC_SOURCES = [
2929
"cpp/common.cpp",
3030
"cpp/deadline_monitor.cpp",
31+
"cpp/logic_monitor.cpp",
3132
"cpp/health_monitor.cpp",
3233
]
3334

3435
CC_HDRS = [
3536
"cpp/include/score/hm/common.h",
3637
"cpp/include/score/hm/tag.h",
3738
"cpp/include/score/hm/deadline/deadline_monitor.h",
39+
"cpp/include/score/hm/logic/logic_monitor.h",
3840
"cpp/include/score/hm/health_monitor.h",
3941
]
4042

src/health_monitoring_lib/cpp/health_monitor.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern "C" {
1818
using namespace score::hm;
1919
using namespace score::hm::internal;
2020
using namespace score::hm::deadline;
21+
using namespace score::hm::logic;
2122

2223
// Functions below must match functions defined in `crate::ffi`.
2324

@@ -30,9 +31,15 @@ FFICode health_monitor_builder_build(FFIHandle health_monitor_builder_handle,
3031
FFICode health_monitor_builder_add_deadline_monitor(FFIHandle health_monitor_builder_handle,
3132
const MonitorTag* monitor_tag,
3233
FFIHandle deadline_monitor_builder_handle);
34+
FFICode health_monitor_builder_add_logic_monitor(FFIHandle health_monitor_builder_handle,
35+
const MonitorTag* monitor_tag,
36+
FFIHandle logic_monitor_builder_handle);
3337
FFICode health_monitor_get_deadline_monitor(FFIHandle health_monitor_handle,
3438
const MonitorTag* monitor_tag,
3539
FFIHandle* deadline_monitor_handle_out);
40+
FFICode health_monitor_get_logic_monitor(FFIHandle health_monitor_handle,
41+
const MonitorTag* monitor_tag,
42+
FFIHandle* logic_monitor_handle_out);
3643
FFICode health_monitor_start(FFIHandle health_monitor_handle);
3744
FFICode health_monitor_destroy(FFIHandle health_monitor_handle);
3845
}
@@ -71,6 +78,20 @@ HealthMonitorBuilder HealthMonitorBuilder::add_deadline_monitor(const MonitorTag
7178
return std::move(*this);
7279
}
7380

81+
HealthMonitorBuilder HealthMonitorBuilder::add_logic_monitor(const MonitorTag& monitor_tag,
82+
LogicMonitorBuilder&& monitor) &&
83+
{
84+
auto monitor_handle = monitor.drop_by_rust();
85+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value());
86+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(health_monitor_builder_handle_.as_rust_handle().has_value());
87+
88+
auto result{health_monitor_builder_add_logic_monitor(
89+
health_monitor_builder_handle_.as_rust_handle().value(), &monitor_tag, monitor_handle.value())};
90+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
91+
92+
return std::move(*this);
93+
}
94+
7495
HealthMonitorBuilder HealthMonitorBuilder::with_internal_processing_cycle(std::chrono::milliseconds cycle_duration) &&
7596
{
7697
internal_processing_cycle_duration_ = cycle_duration;
@@ -122,6 +143,18 @@ score::cpp::expected<DeadlineMonitor, Error> HealthMonitor::get_deadline_monitor
122143
return score::cpp::expected<DeadlineMonitor, Error>(DeadlineMonitor{handle});
123144
}
124145

146+
score::cpp::expected<LogicMonitor, Error> HealthMonitor::get_logic_monitor(const MonitorTag& monitor_tag)
147+
{
148+
FFIHandle handle{nullptr};
149+
auto result{health_monitor_get_logic_monitor(health_monitor_, &monitor_tag, &handle)};
150+
if (result != kSuccess)
151+
{
152+
return score::cpp::unexpected(static_cast<Error>(result));
153+
}
154+
155+
return score::cpp::expected<LogicMonitor, Error>(LogicMonitor{handle});
156+
}
157+
125158
void HealthMonitor::start()
126159
{
127160
auto result{health_monitor_start(health_monitor_)};

src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include <score/hm/common.h>
1717
#include <score/hm/deadline/deadline_monitor.h>
18+
#include <score/hm/logic/logic_monitor.h>
1819
#include <score/hm/tag.h>
1920

2021
namespace score::hm
@@ -42,6 +43,9 @@ class HealthMonitorBuilder final
4243
HealthMonitorBuilder add_deadline_monitor(const MonitorTag& monitor_tag,
4344
deadline::DeadlineMonitorBuilder&& monitor) &&;
4445

46+
/// Adds a logic monitor for a specific identifier tag.
47+
HealthMonitorBuilder add_logic_monitor(const MonitorTag& monitor_tag, logic::LogicMonitorBuilder&& monitor) &&;
48+
4549
/// Sets the cycle duration for supervisor API notifications.
4650
/// This duration determines how often the health monitor notifies the supervisor that the system is alive.
4751
HealthMonitorBuilder with_supervisor_api_cycle(std::chrono::milliseconds cycle_duration) &&;
@@ -72,6 +76,7 @@ class HealthMonitor final
7276
~HealthMonitor();
7377

7478
score::cpp::expected<deadline::DeadlineMonitor, Error> get_deadline_monitor(const MonitorTag& monitor_tag);
79+
score::cpp::expected<logic::LogicMonitor, Error> get_logic_monitor(const MonitorTag& monitor_tag);
7580

7681
void start();
7782

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/********************************************************************************
2+
* Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Apache License Version 2.0 which is available at
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* SPDX-License-Identifier: Apache-2.0
12+
********************************************************************************/
13+
#ifndef SCORE_HM_LOGIC_LOGIC_MONITOR_H
14+
#define SCORE_HM_LOGIC_LOGIC_MONITOR_H
15+
16+
#include "score/hm/common.h"
17+
#include "score/hm/tag.h"
18+
#include <score/expected.hpp>
19+
20+
namespace score::hm
21+
{
22+
// Forward declaration
23+
class HealthMonitor;
24+
class HealthMonitorBuilder;
25+
} // namespace score::hm
26+
27+
namespace score::hm::logic
28+
{
29+
30+
class LogicMonitorBuilder final : public internal::RustDroppable<LogicMonitorBuilder>
31+
{
32+
public:
33+
/// Create a new `LogicMonitorBuilder`.
34+
///
35+
/// - `initial_state` - starting point, implicitly added to the list of allowed states.
36+
LogicMonitorBuilder(const StateTag& initial_state);
37+
38+
LogicMonitorBuilder(const LogicMonitorBuilder&) = delete;
39+
LogicMonitorBuilder& operator=(const LogicMonitorBuilder&) = delete;
40+
41+
LogicMonitorBuilder(LogicMonitorBuilder&&) = default;
42+
LogicMonitorBuilder& operator=(LogicMonitorBuilder&&) = delete;
43+
44+
/// Add allowed state.
45+
LogicMonitorBuilder add_state(const StateTag& state) &&;
46+
47+
/// Add allowed transition.
48+
LogicMonitorBuilder add_transition(const StateTag& from_state, const StateTag& to_state) &&;
49+
50+
protected:
51+
std::optional<internal::FFIHandle> __drop_by_rust_impl()
52+
{
53+
return monitor_builder_handle_.drop_by_rust();
54+
}
55+
56+
private:
57+
internal::DroppableFFIHandle monitor_builder_handle_;
58+
59+
// Allow to hide drop_by_rust implementation
60+
friend class internal::RustDroppable<LogicMonitorBuilder>;
61+
62+
// Allow HealthMonitorBuilder to access drop_by_rust implementation
63+
friend class ::score::hm::HealthMonitorBuilder;
64+
};
65+
66+
class LogicMonitor final
67+
{
68+
public:
69+
LogicMonitor(const LogicMonitor&) = delete;
70+
LogicMonitor& operator=(const LogicMonitor&) = delete;
71+
72+
LogicMonitor(LogicMonitor&& other) noexcept = default;
73+
LogicMonitor& operator=(LogicMonitor&& other) noexcept = default;
74+
75+
/// Perform transition to a new state.
76+
score::cpp::expected<StateTag, Error> transition(const StateTag& state);
77+
78+
/// Current monitor state.
79+
score::cpp::expected<StateTag, Error> state();
80+
81+
private:
82+
explicit LogicMonitor(internal::FFIHandle monitor_handle);
83+
84+
// Only `HealthMonitor` is allowed to create `LogicMonitor` instances.
85+
friend class score::hm::HealthMonitor;
86+
internal::DroppableFFIHandle monitor_handle_;
87+
};
88+
89+
} // namespace score::hm::logic
90+
91+
#endif // SCORE_HM_LOGIC_LOGIC_MONITOR_H

src/health_monitoring_lib/cpp/include/score/hm/tag.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace score::hm
2323
class Tag
2424
{
2525
public:
26+
/// Create an empty tag.
27+
Tag() : data_{nullptr}, length_{0} {}
28+
2629
/// Create a new tag from a C-style string.
2730
template <size_t N>
2831
explicit Tag(const char (&tag)[N]) : data_(tag), length_(N - 1)
@@ -49,6 +52,13 @@ class DeadlineTag : public Tag
4952
using Tag::Tag;
5053
};
5154

55+
/// State tag.
56+
class StateTag : public Tag
57+
{
58+
public:
59+
using Tag::Tag;
60+
};
61+
5262
} // namespace score::hm
5363

5464
#endif // SCORE_HM_TAG_H
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/********************************************************************************
2+
* Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Apache License Version 2.0 which is available at
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* SPDX-License-Identifier: Apache-2.0
12+
********************************************************************************/
13+
#include "score/hm/logic/logic_monitor.h"
14+
#include <score/assert.hpp>
15+
16+
namespace
17+
{
18+
extern "C" {
19+
using namespace score::hm;
20+
using namespace score::hm::internal;
21+
using namespace score::hm::logic;
22+
23+
FFICode logic_monitor_builder_create(const StateTag* initial_state, FFIHandle* logic_monitor_builder_handle_out);
24+
FFICode logic_monitor_builder_destroy(FFIHandle logic_monitor_builder_handle);
25+
FFICode logic_monitor_builder_add_state(FFIHandle logic_monitor_builder_handle, const StateTag* state);
26+
FFICode logic_monitor_builder_add_transition(FFIHandle logic_monitor_builder_handle,
27+
const StateTag* from_state,
28+
const StateTag* to_state);
29+
FFICode logic_monitor_destroy(FFIHandle logic_monitor_handle);
30+
FFICode logic_monitor_transition(FFIHandle logic_monitor_handle, const StateTag* to_state);
31+
FFICode logic_monitor_state(FFIHandle logic_monitor_handle, StateTag* state_out);
32+
}
33+
34+
FFIHandle logic_monitor_builder_create_wrapper(const StateTag& initial_state)
35+
{
36+
FFIHandle handle{nullptr};
37+
auto result{logic_monitor_builder_create(&initial_state, &handle)};
38+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
39+
return handle;
40+
}
41+
} // namespace
42+
43+
namespace score::hm::logic
44+
{
45+
LogicMonitorBuilder::LogicMonitorBuilder(const StateTag& initial_state)
46+
: monitor_builder_handle_{logic_monitor_builder_create_wrapper(initial_state), &logic_monitor_builder_destroy}
47+
{
48+
}
49+
50+
LogicMonitorBuilder LogicMonitorBuilder::add_state(const StateTag& state) &&
51+
{
52+
auto monitor_builder_handle{monitor_builder_handle_.as_rust_handle()};
53+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_builder_handle.has_value());
54+
55+
auto result{logic_monitor_builder_add_state(monitor_builder_handle.value(), &state)};
56+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
57+
58+
return std::move(*this);
59+
}
60+
61+
LogicMonitorBuilder LogicMonitorBuilder::add_transition(const StateTag& from_state, const StateTag& to_state) &&
62+
{
63+
auto monitor_builder_handle{monitor_builder_handle_.as_rust_handle()};
64+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_builder_handle.has_value());
65+
66+
auto result{logic_monitor_builder_add_transition(monitor_builder_handle.value(), &from_state, &to_state)};
67+
SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess);
68+
69+
return std::move(*this);
70+
}
71+
72+
LogicMonitor::LogicMonitor(FFIHandle monitor_handle) : monitor_handle_{monitor_handle, &logic_monitor_destroy} {}
73+
74+
score::cpp::expected<StateTag, Error> LogicMonitor::transition(const StateTag& state)
75+
{
76+
auto monitor_handle{monitor_handle_.as_rust_handle()};
77+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value());
78+
79+
auto result{logic_monitor_transition(monitor_handle.value(), &state)};
80+
if (result != kSuccess)
81+
{
82+
return score::cpp::unexpected(static_cast<Error>(result));
83+
}
84+
85+
return score::cpp::expected<StateTag, Error>(state);
86+
}
87+
88+
score::cpp::expected<StateTag, Error> LogicMonitor::state()
89+
{
90+
auto monitor_handle{monitor_handle_.as_rust_handle()};
91+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value());
92+
93+
StateTag state_tag;
94+
auto result{logic_monitor_state(monitor_handle.value(), &state_tag)};
95+
if (result != kSuccess)
96+
{
97+
return score::cpp::unexpected(static_cast<Error>(result));
98+
}
99+
100+
return score::cpp::expected<StateTag, Error>(state_tag);
101+
}
102+
103+
} // namespace score::hm::logic

src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,16 @@ TEST_F(HealthMonitorTest, TestName)
4444
.add_deadline(DeadlineTag("deadline_2"),
4545
TimeRange(std::chrono::milliseconds(100), std::chrono::milliseconds(200)));
4646

47+
// Setup logic monitor construction.
48+
const MonitorTag logic_monitor_tag{"logic_monitor"};
49+
StateTag from_state{"from_state"};
50+
StateTag to_state{"to_state"};
51+
auto logic_monitor_builder =
52+
logic::LogicMonitorBuilder{from_state}.add_state(to_state).add_transition(from_state, to_state);
53+
4754
auto hm = HealthMonitorBuilder()
4855
.add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder))
56+
.add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder))
4957
.with_internal_processing_cycle(std::chrono::milliseconds(50))
5058
.with_supervisor_api_cycle(std::chrono::milliseconds(50))
5159
.build();
@@ -62,9 +70,23 @@ TEST_F(HealthMonitorTest, TestName)
6270

6371
auto deadline_mon = std::move(*deadline_monitor_res);
6472

73+
// Obtain logic monitor from HMON.
74+
auto logic_monitor_res{hm.get_logic_monitor(logic_monitor_tag)};
75+
EXPECT_TRUE(logic_monitor_res.has_value());
76+
77+
{
78+
// Try again to get the same monitor.
79+
auto logic_monitor_res{hm.get_logic_monitor(logic_monitor_tag)};
80+
EXPECT_FALSE(logic_monitor_res.has_value());
81+
}
82+
83+
auto logic_monitor{std::move(*logic_monitor_res)};
84+
6585
// Start HMON.
6686
hm.start();
6787

88+
EXPECT_TRUE(logic_monitor.transition(to_state).has_value());
89+
6890
auto deadline_res = deadline_mon.get_deadline(DeadlineTag("deadline_1"));
6991

7092
{

0 commit comments

Comments
 (0)