fix mem problems

This commit is contained in:
Bartosz Wieczorek 2025-11-07 11:23:05 +01:00
parent 2db84fb720
commit e58f3fc139
4 changed files with 68 additions and 64 deletions

View File

@ -4,8 +4,10 @@ project(Ranczo-IO)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_compile_options(-g -fsanitize=address,undefined,float-divide-by-zero,float-cast-overflow,null -fsanitize-address-use-after-scope -fno-sanitize-recover=all -fno-sanitize=alignment -fno-omit-frame-pointer)
add_link_options(-g -fsanitize=address,undefined,float-divide-by-zero,float-cast-overflow,null -fsanitize-address-use-after-scope -fno-sanitize-recover=all -fno-sanitize=alignment -fno-omit-frame-pointer)
# add_compile_options(-g -fsanitize=address,undefined,float-divide-by-zero,float-cast-overflow,null -fsanitize-address-use-after-scope -fno-sanitize-recover=all -fno-sanitize=alignment -fno-omit-frame-pointer)
# add_link_options(-g -fsanitize=address,undefined,float-divide-by-zero,float-cast-overflow,null -fsanitize-address-use-after-scope -fno-sanitize-recover=all -fno-sanitize=alignment -fno-omit-frame-pointer)
add_compile_options(-g -fno-omit-frame-pointer)
include(CheckIPOSupported)
check_ipo_supported(RESULT supported OUTPUT error)
@ -106,8 +108,10 @@ FetchContent_Declare(fmt
FetchContent_MakeAvailable(fmt)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_compile_definitions(BOOST_ASIO_ENABLE_HANDLER_TRACKING=1)
# add_compile_definitions(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
add_subdirectory(libs)
add_subdirectory(services)
add_subdirectory(tests)
# 139929 bartosz+ 20 0 20,0t 157036 57964 S 0,0 1,0 0:02.58 ranczo-io_flor

View File

@ -16,6 +16,7 @@ set(MODBUS_INCLUDES "${MODBUS_PREFIX}/include")
file(MAKE_DIRECTORY "${MODBUS_PREFIX}")
file(MAKE_DIRECTORY "${MODBUS_BUILD}")
file(MAKE_DIRECTORY "${MODBUS_INCLUDES}")
# Some environments need -fPIC for static archives used in shared libs
set(_LIBMODBUS_ENV "CFLAGS=-fPIC" "CPPFLAGS=-fPIC" "CXXFLAGS=-fPIC")

View File

@ -1,14 +1,17 @@
#include "spdlog/spdlog.h"
#include <boost/smart_ptr/shared_ptr.hpp>
#include <cstdint>
#include <modbus/modbus.h>
#include "config.hpp"
#include <spdlog/spdlog.h>
#include <ranczo-io/utils/modbus.hpp>
#include <boost/asio.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/this_coro.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <modbus/modbus.h>
#include <cerrno>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
@ -31,7 +34,7 @@ awaitable_expected< void > ModbusTcpContext::async_connect() {
return unexpected(errno_errc());
std::unique_ptr< modbus_t, CtxDeleter > ctx(raw);
if(::modbus_connect(ctx.get()) == -1){
if(::modbus_connect(ctx.get()) == -1) {
spdlog::error("Modbus failed to conenct to {}:{}", host_.c_str(), port_);
return unexpected(errno_errc());
}
@ -108,31 +111,17 @@ awaitable_expected< T > ModbusTcpContext::async_call(Maker && maker) {
std::move(initiator), asio::use_awaitable_t<>{});
}
struct ModbusDeviceLog{
int unit;
uint16_t address;
std::string ctx;
ModbusDeviceLog(int unit, uint16_t address, std::string_view ctx): unit{unit}, address{address}, ctx{ctx.data(), ctx.size()} {
spdlog::trace("Modbus BEGIN {}/{} : {}", unit, address, ctx);
}
~ModbusDeviceLog(){
spdlog::trace("Modbus END {}/{} : {}", unit, address, ctx);
}
};
awaitable_expected< uint16_t > ModbusDevice::async_read_holding_register(uint16_t address) {
address -= 1;
ModbusDeviceLog _{unit_id_, address, "async_read_holding_register"};
auto ctx = ctx_; // kopia shared_ptr dla bezpieczeństwa w tasku
co_return co_await ctx->call_with_lock< std::uint16_t >([this, address](modbus_t * c) -> expected< std::uint16_t > {
ModbusDeviceLog _{unit_id_, address, "async_read_holding_register:lambda"};
if(::modbus_set_slave(c, unit_id_) == -1){
if(::modbus_set_slave(c, unit_id_) == -1) {
spdlog::error("Modbus modbus_set_slave for {}/{} failed with {}", unit_id_, address, errno);
return unexpected(errno_errc());
}
uint16_t val = 0;
int rc = ::modbus_read_registers(c, static_cast< int >(address), 1, &val);
if(rc == -1){
if(rc == -1) {
spdlog::error("Modbus modbus_read_registers for {}/{} failed with {}", unit_id_, address, errno);
return unexpected(errno_errc());
}
@ -140,20 +129,20 @@ awaitable_expected< uint16_t > ModbusDevice::async_read_holding_register(uint16_
});
}
awaitable_expected<void> ModbusDevice::async_write_coil(uint16_t address, bool value) {
awaitable_expected< void > ModbusDevice::async_write_coil(uint16_t address, bool value) {
auto ctx = ctx_;
ModbusDeviceLog _{unit_id_, address, "async_write_coil"};
co_return co_await ctx->call_with_lock<void>(
[this, address, value](modbus_t* c) -> expected<void> {
ModbusDeviceLog _{unit_id_, address, "async_write_coil:lambda"};
if (::modbus_set_slave(c, unit_id_) == -1)
return unexpected(errno_errc());
const int rc = ::modbus_write_bit(c, static_cast<int>(address), value ? 1 : 0);
if (rc == -1)
return unexpected(errno_errc());
return {};
}
);
co_return co_await ctx->call_with_lock< void >([this, address, value](modbus_t * c) -> expected< void > {
if(::modbus_set_slave(c, unit_id_) == -1){
spdlog::error("Modbus modbus_set_slave for {}/{} failed with {}", unit_id_, address, errno);
return unexpected(errno_errc());
}
const int rc = ::modbus_write_bit(c, static_cast< int >(address), value ? 1 : 0);
if(rc == -1){
spdlog::error("Modbus modbus_write_bit for {}/{} failed with {}", unit_id_, address, errno);
return unexpected(errno_errc());
}
return {};
});
}
} // namespace ranczo

View File

@ -1,20 +1,19 @@
#include <boost/algorithm/string/compare.hpp>
#include <boost/regex/config.hpp>
#include <map>
#include <optional>
#include <ranczo-io/utils/mqtt_client.hpp>
#include <boost/algorithm/string/compare.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/this_coro.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/json/serialize.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/regex/config.hpp>
#include <spdlog/spdlog.h>
@ -48,9 +47,6 @@ namespace ranczo {
using namespace std::chrono_literals;
using namespace std::string_view_literals;
std::atomic< bool > running = true;
boost::asio::io_context * g_io = nullptr;
struct ZoneInfo {
std::string room;
int zone; // no _zone
@ -132,41 +128,34 @@ inline ranczo::awaitable_expected< void > forward_floor_temperature_all_rooms(ra
co_return ranczo::_void{};
}
void signal_handler(int signum) {
spdlog::warn("Signal received: {}, stopping io_context...", signum);
running = false;
if(g_io) {
g_io->stop(); // <--- This stops io_context.run()
}
}
int main() {
spdlog::set_level(spdlog::level::trace);
std::vector< std::shared_ptr< ranczo::TemperatureController > > _heaters;
boost::asio::io_context io_context;
g_io = &io_context;
// Register signal handler
spdlog::info("Registering signal handlers");
std::signal(SIGINT, signal_handler);
std::signal(SIGTERM, signal_handler);
// promisa do „zatrzymaj program”
std::promise<void> stop_promise;
auto stop_future = stop_promise.get_future();
boost::asio::executor_work_guard< boost::asio::io_context::executor_type > work_guard = boost::asio::make_work_guard(io_context);
boost::asio::any_io_executor io_executor = io_context.get_executor();
spdlog::info("Create Modbus TCP context");
auto modbus_relayBoardsCtx = ranczo::ModbusTcpContext::create(io_context, // używamy istniejącego io_context
"192.168.10.10", // host Modbus TCP
2502, // port Modbus TCP
1 // rozmiar puli dla libmodbus
);
boost::asio::any_io_executor io_executor = io_context.get_executor();
auto fut = boost::asio::co_spawn(
io_executor,
[modbus_relayBoardsCtx]() -> ranczo::awaitable_expected< void > { co_return co_await modbus_relayBoardsCtx->async_connect(); },
boost::asio::use_future);
boost::asio::executor_work_guard< boost::asio::io_context::executor_type > work_guard = boost::asio::make_work_guard(io_context);
std::jthread io_thread([&] {
spdlog::info("io_context thread started");
io_context.run();
@ -216,7 +205,7 @@ int main() {
spdlog::debug("make_ramp_thermostat {} / {} : create Relay Thermostat", room, zone);
return std::make_shared< ranczo::RelayThermostat >(io_executor, mqttClient, std::move(relay), std::move(thermo), room, zone);
};
// // Floor 0
_heaters.emplace_back(make_ramp_thermostat("livingroom"sv, 1, make_relay(16, 2))); // 3 strefy
_heaters.emplace_back(make_ramp_thermostat("livingroom"sv, 2, make_relay(16, 10)));
@ -242,11 +231,32 @@ int main() {
/// TODO czujnik temperatury
// _heaters.emplace_back(relayThermostatFactory("corridor_up"sv, 1, relay(0, 0)));
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
signals.async_wait([&](const boost::system::error_code& ec, int signo){
if (ec) return; // canceled podczas shutdown
spdlog::warn("Signal {} received", signo);
// Zainicjuj graceful shutdown na wątku io_context (bezpiecznie):
boost::asio::post(io_context, [&]{
spdlog::info("Graceful shutdown start");
_heaters.clear(); // remove all heaters
mqttProxyClient.cancel();
modbusDevices.clear();
// modbus_relayBoardsCtx->async_close();
work_guard.reset();
io_context.stop(); // ok na tym samym wątku
spdlog::info("Graceful shutdown posted");
});
stop_promise.set_value(); // pobudzi main
});
for(auto & heater : _heaters) {
co_spawn(io_context, heater->start(), boost::asio::detached);
}
if(io_thread.joinable())
io_thread.join();