From b3bf0e2cb9771bb320288b6401e4ac35f5bba60a Mon Sep 17 00:00:00 2001 From: Hayodea Hekol Date: Sun, 2 Nov 2025 19:08:47 -0400 Subject: [PATCH] StimBuff,commonLibs: Add libattachmentSupport, move fnptrs into .cpp files We move the methods in StimulusBuffer whose addresses are taken during program execution into a separate static lib. This guarantees that they'll have their own, single vaddr at runtime, at least within each independent code module. --- commonLibs/CMakeLists.txt | 1 + commonLibs/attachmentSupport/CMakeLists.txt | 15 +++ .../attachmentSupport/attachmentSupport.cpp | 106 ++++++++++++++++++ include/user/stimulusBuffer.h | 89 +-------------- stimBuffApis/livoxGen1/CMakeLists.txt | 1 + 5 files changed, 124 insertions(+), 88 deletions(-) create mode 100644 commonLibs/attachmentSupport/CMakeLists.txt create mode 100644 commonLibs/attachmentSupport/attachmentSupport.cpp diff --git a/commonLibs/CMakeLists.txt b/commonLibs/CMakeLists.txt index a508a5a..968d0d9 100644 --- a/commonLibs/CMakeLists.txt +++ b/commonLibs/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(xcbXorg) add_subdirectory(livoxProto1) +add_subdirectory(attachmentSupport) diff --git a/commonLibs/attachmentSupport/CMakeLists.txt b/commonLibs/attachmentSupport/CMakeLists.txt new file mode 100644 index 0000000..2daca7f --- /dev/null +++ b/commonLibs/attachmentSupport/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(attachmentSupport STATIC + attachmentSupport.cpp +) + +set_target_properties(attachmentSupport PROPERTIES + POSITION_INDEPENDENT_CODE ON +) + +target_include_directories(attachmentSupport PUBLIC + ${Boost_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR}/include +) + +target_link_libraries(attachmentSupport ${Boost_LIBRARIES}) diff --git a/commonLibs/attachmentSupport/attachmentSupport.cpp b/commonLibs/attachmentSupport/attachmentSupport.cpp new file mode 100644 index 0000000..935384c --- /dev/null +++ b/commonLibs/attachmentSupport/attachmentSupport.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace smo { +namespace stim_buff { + +void StimulusBuffer::stop() +{ + shouldContinue.store(false); + + // Set up a timeout bridge using the io_service + boost::asio::deadline_timer delayTimer(ioService); + AsynchronousBridge bridge(ioService); + + // Set up the delay to let in-flight operation finish + delayTimer.expires_from_now( + boost::posix_time::milliseconds(getStopDelayMs())); + + delayTimer.async_wait( + [&bridge](const boost::system::error_code& error) + { + (void)error; + + // Always signal complete, whether timeout expired or was cancelled + bridge.setAsyncOperationComplete(); + }); + + bridge.waitForAsyncOperationCompleteOrIoServiceStopped(); + + std::cout << __func__ << ": Stopped stimulus buffer for device " + << deviceAttachmentSpec.deviceSelector << std::endl; + + // After delay, cancel timer and perform cleanup + timer.cancel(); +} + +void StimulusBuffer::scheduleNextTimeout(int delayMs) +{ +std::cout << __func__ << ": being executed on thread " + << smoHooksPtr->ComponentThread_getSelf()->name << std::endl; + + if (!shouldContinue.load()) + { return; } + + // Schedule the next timeout using the provided delay + timer.expires_from_now( + boost::posix_time::milliseconds(delayMs)); + + timer.async_wait( + std::bind( + &StimulusBuffer::onTimeout, this, std::placeholders::_1)); +} + +void StimulusBuffer::onTimeout(const boost::system::error_code& error) +{ +std::cout << __func__ << ": being executed on thread " + << smoHooksPtr->ComponentThread_getSelf()->name << std::endl; + // Timer was cancelled, which is expected when stopping + if (error == boost::asio::error::operation_aborted) { + return; + } + + if (error) + { + std::cerr << "StimulusBuffer: Timer error: " << error.message() + << std::endl; + return; + } + + if (!shouldContinue.load()) + { return; } + + /** EXPLANATION: + * We need to ensure that there's only ever one stimframe being produced + * during any CONFIG_STIMBUFF_FRAME_PERIOD_MS period. To guarantee this, we + * use a spinlock. + * + * When a new frame is to be produced, the async producer will first acquire + * the frameAssemblyLimiter spinlock. This way, when the next timeout is + * fired it can check whether its predecessor stimframe has finished being + * produced. If the preceding stimframe is still being produced, then we'll + * sleep for CONFIG_STIMBUFF_FRAME_RETRY_DELAY_MS ms before trying again. + */ + int nextWakeupDelayMs; + if (frameAssemblyRateLimiter.tryAcquire()) + { nextWakeupDelayMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS; } + else + { nextWakeupDelayMs = CONFIG_STIMBUFF_FRAME_RETRY_DELAY_MS; } + + // Call the derived class's frame production handler + stimFrameProductionTimesliceInd(); + // Note: The lock should be released when frame production completes + + // Schedule next timeout with the pre-determined duration + scheduleNextTimeout(nextWakeupDelayMs); +} + +} // namespace stim_buff +} // namespace smo diff --git a/include/user/stimulusBuffer.h b/include/user/stimulusBuffer.h index 9af4c78..af75399 100644 --- a/include/user/stimulusBuffer.h +++ b/include/user/stimulusBuffer.h @@ -103,96 +103,9 @@ private: std::atomic shouldContinue; boost::asio::deadline_timer timer; - void scheduleNextTimeout(int delayMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS) - { - if (!shouldContinue.load()) - { return; } - - // Schedule the next timeout using the provided delay - timer.expires_from_now( - boost::posix_time::milliseconds(delayMs)); - - timer.async_wait( - std::bind( - &StimulusBuffer::onTimeout, this, std::placeholders::_1)); - } + void scheduleNextTimeout(int delayMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS); }; -/** Inline methods - ******************************************************************************/ - -inline void StimulusBuffer::stop() -{ - shouldContinue.store(false); - - // Set up a timeout bridge using the io_service - boost::asio::deadline_timer delayTimer(ioService); - AsynchronousBridge bridge(ioService); - - // Set up the delay to let in-flight operation finish - delayTimer.expires_from_now( - boost::posix_time::milliseconds(getStopDelayMs())); - - delayTimer.async_wait( - [&bridge](const boost::system::error_code& error) - { - (void)error; - - // Always signal complete, whether timeout expired or was cancelled - bridge.setAsyncOperationComplete(); - }); - - bridge.waitForAsyncOperationCompleteOrIoServiceStopped(); - - std::cout << __func__ << ": Stopped stimulus buffer for device " - << deviceAttachmentSpec.deviceSelector << std::endl; - - // After delay, cancel timer and perform cleanup - timer.cancel(); -} - -inline void StimulusBuffer::onTimeout(const boost::system::error_code& error) -{ - // Timer was cancelled, which is expected when stopping - if (error == boost::asio::error::operation_aborted) { - return; - } - - if (error) - { - std::cerr << "StimulusBuffer: Timer error: " << error.message() - << std::endl; - return; - } - - if (!shouldContinue.load()) - { return; } - - /** EXPLANATION: - * We need to ensure that there's only ever one stimframe being produced - * during any CONFIG_STIMBUFF_FRAME_PERIOD_MS period. To guarantee this, we - * use a spinlock. - * - * When a new frame is to be produced, the async producer will first acquire - * the frameAssemblyLimiter spinlock. This way, when the next timeout is - * fired it can check whether its predecessor stimframe has finished being - * produced. If the preceding stimframe is still being produced, then we'll - * sleep for CONFIG_STIMBUFF_FRAME_RETRY_DELAY_MS ms before trying again. - */ - int nextWakeupDelayMs; - if (frameAssemblyRateLimiter.tryAcquire()) - { nextWakeupDelayMs = CONFIG_STIMBUFF_FRAME_PERIOD_MS; } - else - { nextWakeupDelayMs = CONFIG_STIMBUFF_FRAME_RETRY_DELAY_MS; } - - // Call the derived class's frame production handler - stimFrameProductionTimesliceInd(); - // Note: The lock should be released when frame production completes - - // Schedule next timeout with the pre-determined duration - scheduleNextTimeout(nextWakeupDelayMs); -} - } // namespace stim_buff } // namespace smo diff --git a/stimBuffApis/livoxGen1/CMakeLists.txt b/stimBuffApis/livoxGen1/CMakeLists.txt index 44d88e8..b8ea75c 100644 --- a/stimBuffApis/livoxGen1/CMakeLists.txt +++ b/stimBuffApis/livoxGen1/CMakeLists.txt @@ -24,6 +24,7 @@ if(ENABLE_STIMBUFFAPI_livoxGen1) target_link_libraries(livoxGen1 ${Boost_LIBRARIES} ${URING_LIBRARIES} + attachmentSupport ) target_link_directories(livoxGen1 PUBLIC ${URING_LIBRARY_DIRS}