From e58f3fc139267500832cc87d4e2d050d69c27f62 Mon Sep 17 00:00:00 2001 From: Bartosz Wieczorek Date: Fri, 7 Nov 2025 11:23:05 +0100 Subject: [PATCH] fix mem problems --- CMakeLists.txt | 10 ++++-- libs/modbus.cmake | 1 + libs/modbus.cpp | 57 ++++++++++++----------------- services/floorheat_svc/main.cpp | 64 +++++++++++++++++++-------------- 4 files changed, 68 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df09576..7aee3b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/libs/modbus.cmake b/libs/modbus.cmake index da8240c..6fda05a 100644 --- a/libs/modbus.cmake +++ b/libs/modbus.cmake @@ -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") diff --git a/libs/modbus.cpp b/libs/modbus.cpp index bc955e7..532fa72 100644 --- a/libs/modbus.cpp +++ b/libs/modbus.cpp @@ -1,14 +1,17 @@ -#include "spdlog/spdlog.h" -#include -#include -#include +#include "config.hpp" +#include + #include #include #include #include +#include + +#include #include +#include #include #include #include @@ -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 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( - [this, address, value](modbus_t* c) -> expected { - 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(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 diff --git a/services/floorheat_svc/main.cpp b/services/floorheat_svc/main.cpp index e5814a9..2dccc66 100644 --- a/services/floorheat_svc/main.cpp +++ b/services/floorheat_svc/main.cpp @@ -1,20 +1,19 @@ -#include -#include #include #include #include +#include +#include #include #include #include #include +#include #include #include #include - #include - -#include +#include #include @@ -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 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();