1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
//
// Copyright (C) David Cosgrove 2025.
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#ifndef CONTROLCHANDLER_H
#define CONTROLCHANDLER_H
#include <atomic>
#include <csignal>
#include <stdexcept>
#include <RDGeneral/export.h>
namespace RDKit {
class ControlCCaught : public std::runtime_error {
public:
explicit ControlCCaught()
: std::runtime_error("The process was interrupted with Ctrl+c") {};
};
//! This class catches a control-C/SIGINT and sets the flag d_gotSignal
//! if one is received. It is intended to be used inside a long
//! C++ calculation called from Python which intercepts the signal
//! handler. The C++ code must check the value of d_gotSignal
//! periodically and act accordingly. The destructor resets
//! the signal handler and flag for next use, which is essential
//! because it's a static variable.
//! Example usage, inside a boost::python wrapper:
//! ResultsObject results;
//! {
//! NOGIL gil;
//! results = someFunction();
//! }
//! if (results.getCancelled()) {
//! throw_runtime_error("someFunction cancelled");
//! }
//! It's important that the exception is thrown once the GIL has been
//! released, otherwise a crash is inevitable at some future point.
class ControlCHandler {
public:
ControlCHandler() { d_prev_handler = std::signal(SIGINT, signalHandler); }
ControlCHandler(const ControlCHandler &) = delete;
ControlCHandler(ControlCHandler &&) = delete;
ControlCHandler &operator=(const ControlCHandler &) = delete;
ControlCHandler &operator=(ControlCHandler &&) = delete;
~ControlCHandler() {
std::signal(SIGINT, d_prev_handler);
d_gotSignal = false;
}
static bool getGotSignal() { return d_gotSignal; }
static void signalHandler(int signalNumber) {
if (signalNumber == SIGINT) {
d_gotSignal = true;
std::signal(SIGINT, d_prev_handler);
}
}
static void reset() {
d_gotSignal = false;
std::signal(SIGINT, signalHandler);
}
private:
inline static bool d_gotSignal{false};
inline static void (*d_prev_handler)(int);
};
} // namespace RDKit
#endif // CONTROLCHANDLER_H
|