Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to stop an application with ctrl+c with handleQuitSignals #925

Open
LoreMoretti opened this issue Jan 22, 2025 · 6 comments
Open
Labels
bug Something isn't working

Comments

@LoreMoretti
Copy link
Contributor

LoreMoretti commented Jan 22, 2025

I have written a cpp application which spawns 2 threads. Each thread is running an advanceable runner.

I am trying to use the BipedalLocomotion::System::handleQuitSignals to implement the logic that should stop the application when clicking ctrl+C.

It follows the portion of the application related to this logic:

  // handle the ctrl+c signal
  BipedalLocomotion::System::handleQuitSignals([&]() {
    plannerRunner.stop();
    controllerRunner.stop();
  });

  // barrier to synchronize the controller and the planner
  auto barrier = BipedalLocomotion::System::Barrier::create(2);

  // run the planner and controller
  auto plannerThread = plannerRunner.run(barrier);
  auto controllerThread = controllerRunner.run(barrier);

  // wait for the planner and controller threads to finish
  while (plannerRunner.isRunning() && controllerRunner.isRunning()) {
    using namespace std::chrono_literals;

    BipedalLocomotion::clock().yield();
    BipedalLocomotion::clock().sleepFor(200ms);
  }

  // stop the the planner and controller threads
  plannerRunner.stop();
  controllerRunner.stop();

What happens is that when clicking ctrl+c most of the times the application does not get stopped.

@GiulioRomualdi
Copy link
Member

This is really tricky and dangerous. I was wondering if you are using library which carch the ctrl-c.

Cc @traversaro

@traversaro
Copy link
Collaborator

What happens is that when clicking ctrl+c most of the times the application does not get stopped.

Can you check if the lambda is getting called or not? Can you provide more context of how the handleQuitSignals is being called? Are you calling it from a main() function?

@GiulioRomualdi GiulioRomualdi added the bug Something isn't working label Jan 24, 2025
@LoreMoretti
Copy link
Contributor Author

LoreMoretti commented Jan 28, 2025

Can you check if the lambda is getting called or not? Can you provide more context of how the handleQuitSignals is being called? Are you calling it from a main() function?

Yes I am calling it from a main() function.

I have verified that when clicking ctrl+c, the function handleQuitSignals does not get invoked.

@GiulioRomualdi
Copy link
Member

Are you able to provide a minimum example like a main wirh an empty synchronous thread running

@LoreMoretti
Copy link
Contributor Author

LoreMoretti commented Jan 30, 2025

Are you able to provide a minimum example like a main wirh an empty synchronous thread running

Here it is:

#include <BipedalLocomotion/ParametersHandler/YarpImplementation.h>
#include <BipedalLocomotion/System/AdvanceableRunner.h>
#include <BipedalLocomotion/System/Clock.h>
#include <BipedalLocomotion/System/QuitHandler.h>
#include <BipedalLocomotion/System/SharedResource.h>
#include <BipedalLocomotion/System/Sink.h>
#include <BipedalLocomotion/TextLogging/Logger.h>

class SimpleAdvanceable : public BipedalLocomotion::System::Sink<
                              BipedalLocomotion::System::EmptySignal> {
public:
  bool initialize(
      std::weak_ptr<BipedalLocomotion::ParametersHandler::IParametersHandler>
          handler) {
    return true;
  }

  bool advance() {
    BipedalLocomotion::log()->info("[advanceable] Advancing...");
    return true;
  }

  bool setInput(const Input &input) { return true; };
};

int main(int argc, char *argv[]) {
  constexpr auto logPrefix = "[main]";

  // Create clock
  BipedalLocomotion::System::ClockBuilder::setFactory(
      std::make_shared<BipedalLocomotion::System::StdClockFactory>());

  // Instantiate and initialize the advanceable
  auto advanceable = std::make_unique<SimpleAdvanceable>();
  auto dummyHandler = std::make_shared<
      BipedalLocomotion::ParametersHandler::YarpImplementation>();
  advanceable->initialize(dummyHandler);

  // Instantiate and initialize the advanceable Runner
  BipedalLocomotion::System::AdvanceableRunner<SimpleAdvanceable>
      advanceableRunner;
  dummyHandler->setParameter("sampling_time", 0.01);
  dummyHandler->setParameter("name", "simpleAdvanceable");
  advanceableRunner.initialize(dummyHandler);

  auto emptyResource = BipedalLocomotion::System::SharedResource<
      SimpleAdvanceable::Input>::create();
  advanceableRunner.setInputResource(emptyResource);
  advanceableRunner.setOutputResource(emptyResource);
  advanceableRunner.setAdvanceable(std::move(advanceable));

  // handle the ctrl+c signal
  BipedalLocomotion::System::handleQuitSignals(
      [&]() { advanceableRunner.stop(); });

  // start the advanceableRunner thread
  auto advanceableThread = advanceableRunner.run();

  // wait for the advanceableRunner threads to finish
  while (advanceableRunner.isRunning()) {
    using namespace std::chrono_literals;

    BipedalLocomotion::clock().yield();
    BipedalLocomotion::clock().sleepFor(200ms);
  }

  // stop the the advanceableRunner
  advanceableRunner.stop();

  // join the advanceableRunner thread
  if (advanceableThread.joinable()) {
    advanceableThread.join();
    advanceableThread = std::thread();
  }

  return EXIT_SUCCESS;
}

With CMakeLists.txt:

# Copyright (C) 2013-2018 Fondazione Istituto Italiano di Tecnologia
#
# Licensed under either the GNU Lesser General Public License v3.0 :
# https://www.gnu.org/licenses/lgpl-3.0.html
# or the GNU Lesser General Public License v2.1 :
# https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
# at your option.

cmake_minimum_required(VERSION 3.16.0)

project(DebugQuitHandler CXX)

include(GNUInstallDirs)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}")

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

if(MSVC)
    set(CMAKE_DEBUG_POSTFIX "d")
endif()

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_EXTENSIONS OFF)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

option(BUILD_SHARED_LIBS "Build libraries as shared as opposed to static" ON)

# Enable RPATH support for installed binaries and libraries
option(ENABLE_RPATH "Enable RPATH for this library" ON)
mark_as_advanced(ENABLE_RPATH)
include(AddInstallRPATHSupport)
add_install_rpath_support(BIN_DIRS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
  LIB_DIRS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
  INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}"
  DEPENDS ENABLE_RPATH
  USE_LINK_PATH)

# Encourage user to specify a build type (e.g. Release, Debug, etc.), otherwise set it to Release.
if(NOT CMAKE_CONFIGURATION_TYPES)
    if(NOT CMAKE_BUILD_TYPE)
        message(STATUS "Setting build type to 'Release' as none was specified.")
        set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE "Release")
    endif()
endif()


################################################################################
########################## Mandatory dependencies ##############################

find_package(BipedalLocomotionFramework 0.19.0 REQUIRED)

########################## Optional dependencies ##############################

find_package(YARP QUIET)

# set(CONTROLLER_HEADERS include/MomentumBasedTorqueControl/Controller.h include/MomentumBasedTorqueControl/Planner.h include/MomentumBasedTorqueControl/QPproblem.h include/MomentumBasedTorqueControl/ChangeReferenceFrame.h)

set(MAIN_SOURCES main.cpp)
                 
# Define executable
add_executable(${PROJECT_NAME} ${MAIN_SOURCES})

# Link necessary libraries (uncomment if needed)
target_link_libraries(${PROJECT_NAME} PRIVATE YARP::YARP_os
    BipedalLocomotion::ParametersHandlerYarpImplementation
    BipedalLocomotion::TextLogging
    BipedalLocomotion::System)

# Set installation path
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})

Indeed this is working as expected.

I should understand what could be the cause in my more advanced use case.

@S-Dafarra
Copy link
Member

It could be that either

Can you check if the lambda is getting called or not? Can you provide more context of how the handleQuitSignals is being called? Are you calling it from a main() function?

Yes I am calling it from a main() function.

I have verified that when clicking ctrl+c, the function handleQuitSignals does not get invoked.

Just to understand, how did you verify this?
I wonder if it is an issue of starvation, but the handling of signals should not get locked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants