summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRazvan Becheriu <razvan@isc.org>2021-02-16 09:03:21 +0100
committerRazvan Becheriu <razvan@isc.org>2021-02-18 18:23:57 +0100
commit9adc0b96bfa4a1e23ff67b8990eeab0f9d862885 (patch)
tree66785fbc4aa159ffd7530cd1dd203dc55f240a47
parent[#899] fixed CI (diff)
downloadkea-9adc0b96bfa4a1e23ff67b8990eeab0f9d862885.tar.xz
kea-9adc0b96bfa4a1e23ff67b8990eeab0f9d862885.zip
[#899] use IOSignalSet to handle signals
-rw-r--r--src/bin/agent/tests/ca_controller_unittests.cc5
-rw-r--r--src/bin/d2/tests/d2_controller_unittests.cc2
-rw-r--r--src/bin/dhcp4/ctrl_dhcp4_srv.cc8
-rw-r--r--src/bin/dhcp4/dhcp4_srv.cc26
-rw-r--r--src/bin/dhcp4/tests/kea_controller_unittest.cc4
-rw-r--r--src/bin/dhcp6/ctrl_dhcp6_srv.cc8
-rw-r--r--src/bin/dhcp6/dhcp6_srv.cc25
-rw-r--r--src/bin/dhcp6/tests/kea_controller_unittest.cc4
-rw-r--r--src/bin/netconf/netconf_controller.cc1
-rw-r--r--src/bin/netconf/tests/netconf_controller_unittests.cc5
-rw-r--r--src/hooks/dhcp/run_script/run_script.cc5
-rw-r--r--src/hooks/dhcp/run_script/run_script.h44
-rw-r--r--src/hooks/dhcp/run_script/run_script_callouts.cc35
-rw-r--r--src/lib/asiolink/Makefile.am4
-rw-r--r--src/lib/asiolink/io_service_signal.cc (renamed from src/lib/process/io_service_signal.cc)20
-rw-r--r--src/lib/asiolink/io_service_signal.h (renamed from src/lib/process/io_service_signal.h)6
-rw-r--r--src/lib/asiolink/process_spawn.cc (renamed from src/lib/util/process_spawn.cc)73
-rw-r--r--src/lib/asiolink/process_spawn.h (renamed from src/lib/util/process_spawn.h)15
-rw-r--r--src/lib/asiolink/tests/Makefile.am7
-rw-r--r--src/lib/asiolink/tests/io_service_signal_unittests.cc (renamed from src/lib/process/tests/io_service_signal_unittests.cc)13
-rw-r--r--src/lib/asiolink/tests/process_spawn_app.sh.in (renamed from src/lib/util/tests/process_spawn_app.sh.in)0
-rw-r--r--src/lib/asiolink/tests/process_spawn_unittest.cc (renamed from src/lib/util/tests/process_spawn_unittest.cc)34
-rw-r--r--src/lib/asiolink/testutils/Makefile.am1
-rw-r--r--src/lib/dhcpsrv/memfile_lease_mgr.cc13
-rw-r--r--src/lib/dhcpsrv/memfile_lease_mgr.h2
-rw-r--r--src/lib/process/Makefile.am2
-rw-r--r--src/lib/process/d_controller.cc11
-rw-r--r--src/lib/process/d_controller.h12
-rw-r--r--src/lib/process/daemon.cc9
-rw-r--r--src/lib/process/daemon.h33
-rw-r--r--src/lib/process/process_messages.cc2
-rw-r--r--src/lib/process/process_messages.h1
-rw-r--r--src/lib/process/process_messages.mes6
-rw-r--r--src/lib/process/tests/Makefile.am1
-rw-r--r--src/lib/process/tests/d_controller_unittests.cc2
-rw-r--r--src/lib/process/testutils/d_test_stubs.h66
-rw-r--r--src/lib/util/Makefile.am4
-rw-r--r--src/lib/util/signal_set.cc415
-rw-r--r--src/lib/util/signal_set.h258
-rw-r--r--src/lib/util/tests/Makefile.am6
-rw-r--r--src/lib/util/tests/signal_set_unittest.cc242
41 files changed, 209 insertions, 1221 deletions
diff --git a/src/bin/agent/tests/ca_controller_unittests.cc b/src/bin/agent/tests/ca_controller_unittests.cc
index 2be67dfe46..2018ac28ce 100644
--- a/src/bin/agent/tests/ca_controller_unittests.cc
+++ b/src/bin/agent/tests/ca_controller_unittests.cc
@@ -5,6 +5,8 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+
+#include <asiolink/testutils/timed_signal.h>
#include <agent/ca_controller.h>
#include <agent/ca_process.h>
#include <agent/ca_command_mgr.h>
@@ -15,12 +17,13 @@
#include <sstream>
#include <unistd.h>
-using namespace std;
+using namespace isc::asiolink::test;
using namespace isc::agent;
using namespace isc::data;
using namespace isc::http;
using namespace isc::process;
using namespace boost::posix_time;
+using namespace std;
namespace {
diff --git a/src/bin/d2/tests/d2_controller_unittests.cc b/src/bin/d2/tests/d2_controller_unittests.cc
index 458c2a66d6..cc52354bf9 100644
--- a/src/bin/d2/tests/d2_controller_unittests.cc
+++ b/src/bin/d2/tests/d2_controller_unittests.cc
@@ -6,6 +6,7 @@
#include <config.h>
+#include <asiolink/testutils/timed_signal.h>
#include <cc/command_interpreter.h>
#include <d2/d2_controller.h>
#include <d2/d2_process.h>
@@ -18,6 +19,7 @@
#include <sstream>
+using namespace isc::asiolink::test;
using namespace isc::process;
using namespace boost::posix_time;
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
index 03f4765385..1f99921633 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
@@ -111,9 +111,11 @@ ControlledDhcpv4Srv::init(const std::string& file_name) {
// Set signal handlers. When the SIGHUP is received by the process
// the server reconfiguration will be triggered. When SIGTERM or
// SIGINT will be received, the server will start shutting down.
- signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
- // Set the pointer to the handler function.
- signal_handler_ = signalHandler;
+ signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
+
+ signal_set_->add(SIGINT);
+ signal_set_->add(SIGHUP);
+ signal_set_->add(SIGTERM);
}
void ControlledDhcpv4Srv::cleanup() {
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index ff7bdb54e7..15ad3325fd 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -990,37 +990,11 @@ Dhcpv4Srv::run_one() {
// second.
} catch (const SignalInterruptOnSelect&) {
- // Packet reception interrupted because a signal has been received.
- // This is not an error because we might have received a SIGTERM,
- // SIGINT, SIGHUP or SIGCHLD which are handled by the server. For
- // signals that are not handled by the server we rely on the default
- // behavior of the system.
- LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_BUFFER_WAIT_SIGNAL)
- .arg(signal_set_->getNext());
} catch (const std::exception& e) {
// Log all other errors.
LOG_ERROR(packet4_logger, DHCP4_BUFFER_RECEIVE_FAIL).arg(e.what());
}
- // Handle next signal received by the process. It must be called after
- // an attempt to receive a packet to properly handle server shut down.
- // The SIGTERM or SIGINT will be received prior to, or during execution
- // of select() (select is invoked by receivePacket()). When that
- // happens, select will be interrupted. The signal handler will be
- // invoked immediately after select(). The handler will set the
- // shutdown flag and cause the process to terminate before the next
- // select() function is called. If the function was called before
- // receivePacket the process could wait up to the duration of timeout
- // of select() to terminate.
- try {
- handleSignal();
- } catch (const std::exception& e) {
- // Standard exception occurred. Let's be on the safe side to
- // catch std::exception.
- LOG_ERROR(dhcp4_logger, DHCP4_HANDLE_SIGNAL_EXCEPTION)
- .arg(e.what());
- }
-
// Timeout may be reached or signal received, which breaks select()
// with no reception occurred. No need to log anything here because
// we have logged right after the call to receivePacket().
diff --git a/src/bin/dhcp4/tests/kea_controller_unittest.cc b/src/bin/dhcp4/tests/kea_controller_unittest.cc
index 1f4d0091e7..4fec95314b 100644
--- a/src/bin/dhcp4/tests/kea_controller_unittest.cc
+++ b/src/bin/dhcp4/tests/kea_controller_unittest.cc
@@ -186,8 +186,6 @@ public:
// stub implementation used in tests.
cb_control_.reset(new TestCBControlDHCPv4());
}
-
- using ControlledDhcpv4Srv::signal_handler_;
};
/// @brief test class for Kea configuration backend
@@ -1060,7 +1058,7 @@ testBackendReconfiguration(const std::string& backend_first,
// Explicitly calling signal handler for SIGHUP to trigger server
// reconfiguration.
- srv->signal_handler_(SIGHUP);
+ raise(SIGHUP);
// The backend should have been created and its type should be
// correct.
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index 7fed6c5c57..1afbbc63e3 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -186,9 +186,11 @@ ControlledDhcpv6Srv::init(const std::string& file_name) {
// Set signal handlers. When the SIGHUP is received by the process
// the server reconfiguration will be triggered. When SIGTERM or
// SIGINT will be received, the server will start shutting down.
- signal_set_.reset(new isc::util::SignalSet(SIGINT, SIGHUP, SIGTERM));
- // Set the pointer to the handler function.
- signal_handler_ = signalHandler;
+ signal_set_.reset(new IOSignalSet(getIOService(), signalHandler));
+
+ signal_set_->add(SIGINT);
+ signal_set_->add(SIGHUP);
+ signal_set_->add(SIGTERM);
}
void ControlledDhcpv6Srv::cleanup() {
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index d18e316b83..e0f984349b 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -574,35 +574,10 @@ void Dhcpv6Srv::run_one() {
// second.
} catch (const SignalInterruptOnSelect&) {
- // Packet reception interrupted because a signal has been received.
- // This is not an error because we might have received a SIGTERM,
- // SIGINT or SIGHUP which are handled by the server. For signals
- // that are not handled by the server we rely on the default
- // behavior of the system.
- LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_SIGNAL)
- .arg(signal_set_->getNext());
} catch (const std::exception& e) {
LOG_ERROR(packet6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
}
- // Handle next signal received by the process. It must be called after
- // an attempt to receive a packet to properly handle server shut down.
- // The SIGTERM or SIGINT will be received prior to, or during execution
- // of select() (select is invoked by receivePacket()). When that happens,
- // select will be interrupted. The signal handler will be invoked
- // immediately after select(). The handler will set the shutdown flag
- // and cause the process to terminate before the next select() function
- // is called. If the function was called before receivePacket the
- // process could wait up to the duration of timeout of select() to
- // terminate.
- try {
- handleSignal();
- } catch (const std::exception& e) {
- // An (a standard or ISC) exception occurred.
- LOG_ERROR(dhcp6_logger, DHCP6_HANDLE_SIGNAL_EXCEPTION)
- .arg(e.what());
- }
-
// Timeout may be reached or signal received, which breaks select()
// with no packet received
if (!query) {
diff --git a/src/bin/dhcp6/tests/kea_controller_unittest.cc b/src/bin/dhcp6/tests/kea_controller_unittest.cc
index d74924839b..a7e3c4de61 100644
--- a/src/bin/dhcp6/tests/kea_controller_unittest.cc
+++ b/src/bin/dhcp6/tests/kea_controller_unittest.cc
@@ -183,8 +183,6 @@ public:
// stub implementation used in tests.
cb_control_.reset(new TestCBControlDHCPv6());
}
-
- using ControlledDhcpv6Srv::signal_handler_;
};
@@ -1046,7 +1044,7 @@ testBackendReconfiguration(const std::string& backend_first,
// Explicitly calling signal handler for SIGHUP to trigger server
// reconfiguration.
- srv->signal_handler_(SIGHUP);
+ raise(SIGHUP);
// The backend should have been created and its type should be
// correct.
diff --git a/src/bin/netconf/netconf_controller.cc b/src/bin/netconf/netconf_controller.cc
index bdf2102c09..353a57fa59 100644
--- a/src/bin/netconf/netconf_controller.cc
+++ b/src/bin/netconf/netconf_controller.cc
@@ -10,6 +10,7 @@
#include <netconf/netconf_controller.h>
#include <netconf/netconf_process.h>
#include <netconf/parser_context.h>
+#include <signal.h>
using namespace isc::process;
diff --git a/src/bin/netconf/tests/netconf_controller_unittests.cc b/src/bin/netconf/tests/netconf_controller_unittests.cc
index 1b26a9f198..9d9806a738 100644
--- a/src/bin/netconf/tests/netconf_controller_unittests.cc
+++ b/src/bin/netconf/tests/netconf_controller_unittests.cc
@@ -5,6 +5,8 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+
+#include <asiolink/testutils/timed_signal.h>
#include <netconf/netconf_controller.h>
#include <netconf/netconf_process.h>
#include <cc/data.h>
@@ -12,12 +14,13 @@
#include <boost/pointer_cast.hpp>
#include <sstream>
-using namespace std;
+using namespace isc::asiolink::test;
using namespace isc::netconf;
using namespace isc::data;
using namespace isc::http;
using namespace isc::process;
using namespace boost::posix_time;
+using namespace std;
namespace {
diff --git a/src/hooks/dhcp/run_script/run_script.cc b/src/hooks/dhcp/run_script/run_script.cc
index bc0a06a87c..91b43442ed 100644
--- a/src/hooks/dhcp/run_script/run_script.cc
+++ b/src/hooks/dhcp/run_script/run_script.cc
@@ -8,6 +8,7 @@
#include <run_script.h>
+using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::hooks;
using namespace isc::util;
@@ -17,6 +18,8 @@ using namespace std;
namespace isc {
namespace run_script {
+IOServicePtr RunScriptImpl::io_service_;
+
RunScriptImpl::RunScriptImpl() : name_(), sync_(false) {
}
@@ -44,7 +47,7 @@ RunScriptImpl::configure(LibraryHandle& handle) {
void
RunScriptImpl::runScript(const ProcessArgs& args, const ProcessEnvVars& vars) {
- ProcessSpawn process(name_, args, vars);
+ ProcessSpawn process(io_service_, name_, args, vars);
process.spawn();
}
diff --git a/src/hooks/dhcp/run_script/run_script.h b/src/hooks/dhcp/run_script/run_script.h
index 692b43fad0..2e68240f4c 100644
--- a/src/hooks/dhcp/run_script/run_script.h
+++ b/src/hooks/dhcp/run_script/run_script.h
@@ -7,6 +7,7 @@
#ifndef RUN_SCRIPT_H
#define RUN_SCRIPT_H
+#include <asiolink/process_spawn.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dhcp/option6_ia.h>
@@ -15,7 +16,6 @@
#include <dhcpsrv/lease.h>
#include <dhcpsrv/subnet.h>
#include <hooks/library_handle.h>
-#include <util/process_spawn.h>
#include <string>
namespace isc {
@@ -30,12 +30,19 @@ public:
/// @brief Destructor.
~RunScriptImpl();
+ /// @brief Sets IO service to be used by the @ref ProcessSpawn instance.
+ ///
+ /// @param io_service The IOService object, used for all ASIO operations.
+ static void setIOService(const isc::asiolink::IOServicePtr& io_service) {
+ io_service_ = io_service;
+ }
+
/// @brief Extract boolean data and append to environment.
///
/// @param value The value to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractBoolean(isc::util::ProcessEnvVars& vars,
+ static void extractBoolean(isc::asiolink::ProcessEnvVars& vars,
const bool value,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -45,7 +52,7 @@ public:
/// @param value The value to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractInteger(isc::util::ProcessEnvVars& vars,
+ static void extractInteger(isc::asiolink::ProcessEnvVars& vars,
const uint64_t value,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -55,7 +62,7 @@ public:
/// @param value The value to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractString(isc::util::ProcessEnvVars& vars,
+ static void extractString(isc::asiolink::ProcessEnvVars& vars,
const std::string& value,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -65,7 +72,7 @@ public:
/// @param value The hwaddr to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractHWAddr(isc::util::ProcessEnvVars& vars,
+ static void extractHWAddr(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::HWAddrPtr& hwaddr,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -75,7 +82,7 @@ public:
/// @param value The duid to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractDUID(isc::util::ProcessEnvVars& vars,
+ static void extractDUID(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::DuidPtr duid,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -85,7 +92,7 @@ public:
/// @param value The option6IA to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractOptionIA(isc::util::ProcessEnvVars& vars,
+ static void extractOptionIA(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Option6IAPtr option6IA,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -95,7 +102,7 @@ public:
/// @param value The subnet4 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractSubnet4(isc::util::ProcessEnvVars& vars,
+ static void extractSubnet4(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Subnet4Ptr subnet4,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -105,7 +112,7 @@ public:
/// @param value The subnet6 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractSubnet6(isc::util::ProcessEnvVars& vars,
+ static void extractSubnet6(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Subnet6Ptr subnet6,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -115,7 +122,7 @@ public:
/// @param value The lease4 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractLease4(isc::util::ProcessEnvVars& vars,
+ static void extractLease4(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Lease4Ptr& lease4,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -125,7 +132,7 @@ public:
/// @param value The lease6 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractLease6(isc::util::ProcessEnvVars& vars,
+ static void extractLease6(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Lease6Ptr& lease6,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -135,7 +142,7 @@ public:
/// @param value The leases4 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractLeases4(isc::util::ProcessEnvVars& vars,
+ static void extractLeases4(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Lease4CollectionPtr& leases4,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -145,7 +152,7 @@ public:
/// @param value The leases6 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractLeases6(isc::util::ProcessEnvVars& vars,
+ static void extractLeases6(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Lease6CollectionPtr& leases6,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -155,7 +162,7 @@ public:
/// @param value The pkt4 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractPkt4(isc::util::ProcessEnvVars& vars,
+ static void extractPkt4(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Pkt4Ptr& pkt4,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -165,7 +172,7 @@ public:
/// @param value The pkt6 to be exported to target script environment.
/// @param prefix The prefix for the name of the environment variable.
/// @param sufix The sufix for the name of the environment variable.
- static void extractPkt6(isc::util::ProcessEnvVars& vars,
+ static void extractPkt6(isc::asiolink::ProcessEnvVars& vars,
const isc::dhcp::Pkt6Ptr& pkt6,
const std::string& prefix = "",
const std::string& sufix = "");
@@ -175,8 +182,8 @@ public:
/// @param args The arguments for the target script.
/// @param vars The environment variables made available for the target
/// script.
- void runScript(const isc::util::ProcessArgs& args,
- const isc::util::ProcessEnvVars& vars);
+ void runScript(const isc::asiolink::ProcessArgs& args,
+ const isc::asiolink::ProcessEnvVars& vars);
/// @brief Set name of the target script.
///
@@ -219,6 +226,9 @@ private:
/// exits, otherwise the call will return immediately after the script is
/// started.
bool sync_;
+
+ /// @brief The IOService object, used for all ASIO operations.
+ static isc::asiolink::IOServicePtr io_service_;
};
/// @brief The type of shared pointers to Run Script implementations.
diff --git a/src/hooks/dhcp/run_script/run_script_callouts.cc b/src/hooks/dhcp/run_script/run_script_callouts.cc
index c16c24b4a9..50ca846f8c 100644
--- a/src/hooks/dhcp/run_script/run_script_callouts.cc
+++ b/src/hooks/dhcp/run_script/run_script_callouts.cc
@@ -25,6 +25,7 @@ RunScriptImplPtr impl;
} // namespace isc
using namespace isc;
+using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::hooks;
@@ -63,6 +64,40 @@ int unload() {
return (0);
}
+/// @brief dhcp4_srv_configured callout implementation.
+///
+/// @param handle callout handle.
+int dhcp4_srv_configured(CalloutHandle& handle) {
+ try {
+ isc::asiolink::IOServicePtr io_service;
+ handle.getArgument("io_context", io_service);
+ RunScriptImpl::setIOService(io_service);
+
+ } catch (const std::exception& ex) {
+ LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR)
+ .arg(ex.what());
+ return (1);
+ }
+ return (0);
+}
+
+/// @brief dhcp6_srv_configured callout implementation.
+///
+/// @param handle callout handle.
+int dhcp6_srv_configured(CalloutHandle& handle) {
+ try {
+ isc::asiolink::IOServicePtr io_service;
+ handle.getArgument("io_context", io_service);
+ RunScriptImpl::setIOService(io_service);
+
+ } catch (const std::exception& ex) {
+ LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR)
+ .arg(ex.what());
+ return (1);
+ }
+ return (0);
+}
+
/// @brief handle @ref lease4_renew hook and set environment parameters for the
/// script.
/// IN: query4 subnet4 clientid hwaddr lease4
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index b3b1a2ff17..feb442baba 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -24,7 +24,9 @@ libkea_asiolink_la_SOURCES += io_asio_socket.h
libkea_asiolink_la_SOURCES += io_endpoint.cc io_endpoint.h
libkea_asiolink_la_SOURCES += io_error.h
libkea_asiolink_la_SOURCES += io_service.h io_service.cc
+libkea_asiolink_la_SOURCES += io_service_signal.cc io_service_signal.h
libkea_asiolink_la_SOURCES += io_socket.h io_socket.cc
+libkea_asiolink_la_SOURCES += process_spawn.h process_spawn.cc
libkea_asiolink_la_SOURCES += tcp_acceptor.h
libkea_asiolink_la_SOURCES += tcp_endpoint.h
libkea_asiolink_la_SOURCES += tcp_socket.h
@@ -55,7 +57,9 @@ libkea_asiolink_include_HEADERS = \
io_endpoint.h \
io_error.h \
io_service.h \
+ io_service_signal.h \
io_socket.h \
+ process_spawn.h \
tcp_acceptor.h \
tcp_endpoint.h \
tcp_socket.h \
diff --git a/src/lib/process/io_service_signal.cc b/src/lib/asiolink/io_service_signal.cc
index 0e80723f89..44c7658a14 100644
--- a/src/lib/process/io_service_signal.cc
+++ b/src/lib/asiolink/io_service_signal.cc
@@ -6,8 +6,7 @@
#include <config.h>
-#include <process/d_log.h>
-#include <process/io_service_signal.h>
+#include <asiolink/io_service_signal.h>
#include <exceptions/exceptions.h>
#include <boost/enable_shared_from_this.hpp>
@@ -15,17 +14,15 @@
#include <boost/asio/signal_set.hpp>
#include <functional>
-using namespace isc::asiolink;
namespace ph = std::placeholders;
namespace isc {
-namespace process {
+namespace asiolink {
/// @brief Implementation class of IOSignalSet.
class IOSignalSetImpl :
public boost::enable_shared_from_this<IOSignalSetImpl>,
- public boost::noncopyable
-{
+ public boost::noncopyable {
public:
/// @brief Constructor.
///
@@ -73,10 +70,6 @@ IOSignalSetImpl::callback(const boost::system::error_code& ec, int signum) {
try {
handler_(signum);
} catch (const std::exception& ex) {
- // We log it and swallow it so we don't undermine IOService::run.
- LOG_ERROR(dctl_logger, DCTL_SIGNAL_ERROR)
- .arg(signum)
- .arg(ex.what());
}
}
}
@@ -98,8 +91,7 @@ IOSignalSetImpl::add(int signum) {
}
IOSignalSet::IOSignalSet(IOServicePtr io_service, IOSignalHandler handler) :
- impl_(new IOSignalSetImpl(io_service, handler))
-{
+ impl_(new IOSignalSetImpl(io_service, handler)) {
// It can throw but the error is fatal...
impl_->install();
}
@@ -113,5 +105,5 @@ IOSignalSet::add(int signum) {
impl_->add(signum);
}
-} // end of isc::process namespace
-} // end of isc namespace
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/process/io_service_signal.h b/src/lib/asiolink/io_service_signal.h
index aa0691f054..7efabf9646 100644
--- a/src/lib/process/io_service_signal.h
+++ b/src/lib/asiolink/io_service_signal.h
@@ -12,7 +12,7 @@
#include <boost/shared_ptr.hpp>
namespace isc {
-namespace process {
+namespace asiolink {
/// @brief Defines a handler function for an IOSignal.
typedef std::function<void(int signum)> IOSignalHandler;
@@ -48,7 +48,7 @@ private:
/// @brief Defines a pointer to an IOSignalSet.
typedef boost::shared_ptr<IOSignalSet> IOSignalSetPtr;
-}; // end of isc::process namespace
-}; // end of isc namespace
+} // namespace asiolink
+} // namespace isc
#endif // IO_SERVICE_SIGNAL_H
diff --git a/src/lib/util/process_spawn.cc b/src/lib/asiolink/process_spawn.cc
index ad24597f14..55047439ac 100644
--- a/src/lib/util/process_spawn.cc
+++ b/src/lib/asiolink/process_spawn.cc
@@ -6,22 +6,24 @@
#include <config.h>
+#include <asiolink/io_service_signal.h>
+#include <asiolink/process_spawn.h>
#include <exceptions/exceptions.h>
-#include <util/process_spawn.h>
-#include <util/signal_set.h>
#include <cstring>
#include <functional>
#include <map>
+#include <mutex>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
+using namespace std;
namespace ph = std::placeholders;
namespace isc {
-namespace util {
+namespace asiolink {
/// @brief Type for process state
struct ProcessState {
@@ -37,11 +39,13 @@ struct ProcessState {
int status_;
};
+/// @brief ProcessStates container which stores a ProcessState for each process
+/// identified by PID.
typedef std::map<pid_t, ProcessState> ProcessStates;
/// @brief Implementation of the @c ProcessSpawn class.
///
-/// This pimpl idiom is used by the @c ProcessSpawn in this case to
+/// This impl idiom is used by the @c ProcessSpawn in this case to
/// avoid exposing the internals of the implementation, such as
/// custom handling of a SIGCHLD signal, and the conversion of the
/// arguments of the executable from the STL container to the array.
@@ -60,7 +64,8 @@ public:
/// @param executable A path to the program to be executed.
/// @param args Arguments for the program to be executed.
/// @param vars Environment variables for the program to be executed.
- ProcessSpawnImpl(const std::string& executable,
+ ProcessSpawnImpl(IOServicePtr io_service,
+ const std::string& executable,
const ProcessArgs& args,
const ProcessEnvVars& vars);
@@ -116,13 +121,6 @@ public:
private:
- /// @brief Access the single instance of the SignalSet which registers the
- /// @ref waitForProcess function as the SIGCHLD signal handler.
- ///
- /// @return The single instance of the @ref SignalSet which handles the
- /// SIGCHLD signal.
- SignalSetPtr signalSet();
-
/// @brief Copies the argument specified as a C++ string to the new
/// C string.
///
@@ -147,8 +145,8 @@ private:
/// was a different signal.
bool waitForProcess(int signum);
- /// @brief A signal set installing a handler for SIGCHLD.
- SignalSetPtr signals_;
+ /// @brief ASIO signal set.
+ IOSignalSetPtr io_signal_set_;
/// @brief A map holding the status codes of executed processes.
ProcessStates process_state_;
@@ -167,13 +165,20 @@ private:
/// @brief An storage container for all allocated C strings.
std::vector<CStringPtr> storage_;
+
+ /// @brief Mutex to protect internal state.
+ boost::shared_ptr<std::mutex> mutex_;
};
-ProcessSpawnImpl::ProcessSpawnImpl(const std::string& executable,
+ProcessSpawnImpl::ProcessSpawnImpl(IOServicePtr io_service,
+ const std::string& executable,
const ProcessArgs& args,
const ProcessEnvVars& vars)
- : signals_(signalSet()), process_state_(), executable_(executable),
- args_(new char*[args.size() + 2]), vars_(new char*[vars.size() + 1]) {
+ : executable_(executable), args_(new char*[args.size() + 2]),
+ vars_(new char*[vars.size() + 1]), mutex_(new std::mutex) {
+ io_signal_set_.reset(new IOSignalSet(io_service,
+ std::bind(&ProcessSpawnImpl::waitForProcess,
+ this, ph::_1)));
// Conversion of the arguments to the C-style array we start by setting
// all pointers within an array to NULL to indicate that they haven't
// been allocated yet.
@@ -194,22 +199,6 @@ ProcessSpawnImpl::ProcessSpawnImpl(const std::string& executable,
ProcessSpawnImpl::~ProcessSpawnImpl() {
}
-SignalSetPtr
-ProcessSpawnImpl::signalSet() {
- static SignalSetPtr signals(new SignalSet(SIGCHLD));
- auto registerHandle = [&]() -> bool {
- // Set the handler which is invoked immediately when the signal
- // is received.
- signals->setOnReceiptHandler(std::bind(&ProcessSpawnImpl::waitForProcess,
- this, ph::_1));
- return (true);
- };
- static bool init = registerHandle();
- (void)init;
-
- return (signals);
-}
-
std::string
ProcessSpawnImpl::getCommandLine() const {
std::ostringstream s;
@@ -258,8 +247,8 @@ ProcessSpawnImpl::spawn() {
// We're in the parent process.
try {
- process_state_.insert(
- std::pair<pid_t, ProcessState>(pid, ProcessState()));
+ lock_guard<std::mutex> lk(*mutex_);
+ process_state_.insert(std::pair<pid_t, ProcessState>(pid, ProcessState()));
} catch(...) {
pthread_sigmask(SIG_SETMASK, &osset, 0);
throw;
@@ -270,6 +259,7 @@ ProcessSpawnImpl::spawn() {
bool
ProcessSpawnImpl::isRunning(const pid_t pid) const {
+ lock_guard<std::mutex> lk(*mutex_);
ProcessStates::const_iterator proc = process_state_.find(pid);
if (proc == process_state_.end()) {
isc_throw(BadValue, "the process with the pid '" << pid
@@ -281,6 +271,7 @@ ProcessSpawnImpl::isRunning(const pid_t pid) const {
bool
ProcessSpawnImpl::isAnyRunning() const {
+ lock_guard<std::mutex> lk(*mutex_);
for (ProcessStates::const_iterator proc = process_state_.begin();
proc != process_state_.end(); ++proc) {
if (proc->second.running_) {
@@ -292,6 +283,7 @@ ProcessSpawnImpl::isAnyRunning() const {
int
ProcessSpawnImpl::getExitStatus(const pid_t pid) const {
+ lock_guard<std::mutex> lk(*mutex_);
ProcessStates::const_iterator proc = process_state_.find(pid);
if (proc == process_state_.end()) {
isc_throw(InvalidOperation, "the process with the pid '" << pid
@@ -325,6 +317,7 @@ ProcessSpawnImpl::waitForProcess(int signum) {
// after this signal handler does his work.
int errno_value = errno;
+ lock_guard<std::mutex> lk(*mutex_);
for (;;) {
int status = 0;
pid_t pid = waitpid(-1, &status, WNOHANG);
@@ -359,13 +352,15 @@ ProcessSpawnImpl::clearState(const pid_t pid) {
isc_throw(InvalidOperation, "unable to remove the status for the"
"process (pid: " << pid << ") which is still running");
}
+ lock_guard<std::mutex> lk(*mutex_);
process_state_.erase(pid);
}
-ProcessSpawn::ProcessSpawn(const std::string& executable,
+ProcessSpawn::ProcessSpawn(IOServicePtr io_service,
+ const std::string& executable,
const ProcessArgs& args,
const ProcessEnvVars& vars)
- : impl_(new ProcessSpawnImpl(executable, args, vars)) {
+ : impl_(new ProcessSpawnImpl(io_service, executable, args, vars)) {
}
ProcessSpawn::~ProcessSpawn() {
@@ -401,5 +396,5 @@ ProcessSpawn::clearState(const pid_t pid) {
return (impl_->clearState(pid));
}
-}
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/util/process_spawn.h b/src/lib/asiolink/process_spawn.h
index 3fb10669a8..b0b2971d0d 100644
--- a/src/lib/util/process_spawn.h
+++ b/src/lib/asiolink/process_spawn.h
@@ -7,6 +7,7 @@
#ifndef PROCESS_SPAWN_H
#define PROCESS_SPAWN_H
+#include <asiolink/io_service.h>
#include <exceptions/exceptions.h>
#include <boost/noncopyable.hpp>
#include <string>
@@ -15,7 +16,7 @@
#include <boost/shared_ptr.hpp>
namespace isc {
-namespace util {
+namespace asiolink {
/// @brief Exception thrown when error occurs during spawning a process.
class ProcessSpawnError : public Exception {
@@ -55,20 +56,18 @@ typedef std::vector<std::string> ProcessEnvVars;
/// such as the SIGCHLD signal handler. In addition making it
/// noncopyable keeps the static check code from flagging the
/// lack of a copy constructor as an issue.
-///
-/// @todo The SIGCHLD handling logic should be moved to the @c SignalSet
-/// class so as multiple instances of the @c ProcessSpawn use the same
-/// SIGCHLD signal handler.
class ProcessSpawn : boost::noncopyable {
public:
/// @brief Constructor.
///
+ /// @param io_service The IOService which handles signal handlers.
/// @param executable A path to the program to be executed.
/// @param args Arguments for the program to be executed.
/// @param vars Environment variables for the program to be executed.
- ProcessSpawn(const std::string& executable,
+ ProcessSpawn(isc::asiolink::IOServicePtr io_service,
+ const std::string& executable,
const ProcessArgs& args = ProcessArgs(),
const ProcessEnvVars& vars = ProcessEnvVars());
@@ -141,7 +140,7 @@ private:
ProcessSpawnImplPtr impl_;
};
-}
-}
+} // namespace asiolink
+} // namespace isc
#endif // PROCESS_SPAWN_H
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index c1e48c27b6..4d3cea43c9 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -2,6 +2,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/asiolink/tests\"
+AM_CPPFLAGS += -DTEST_DATA_TOPBUILDDIR=\"$(abs_top_builddir)\"
AM_CXXFLAGS = $(KEA_CXXFLAGS)
@@ -11,6 +12,10 @@ endif
CLEANFILES = *.gcno *.gcda test-socket
+DISTCLEANFILES = process_spawn_app.sh
+
+noinst_SCRIPTS = process_spawn_app.sh
+
TESTS_ENVIRONMENT = \
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
@@ -29,8 +34,10 @@ run_unittests_SOURCES += tcp_socket_unittest.cc
run_unittests_SOURCES += udp_endpoint_unittest.cc
run_unittests_SOURCES += udp_socket_unittest.cc
run_unittests_SOURCES += io_service_unittest.cc
+run_unittests_SOURCES += io_service_signal_unittests.cc
run_unittests_SOURCES += dummy_io_callback_unittest.cc
run_unittests_SOURCES += tcp_acceptor_unittest.cc
+run_unittests_SOURCES += process_spawn_unittest.cc
run_unittests_SOURCES += unix_domain_socket_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/lib/process/tests/io_service_signal_unittests.cc b/src/lib/asiolink/tests/io_service_signal_unittests.cc
index dbbe0cfbbb..7175d8f68b 100644
--- a/src/lib/process/tests/io_service_signal_unittests.cc
+++ b/src/lib/asiolink/tests/io_service_signal_unittests.cc
@@ -6,18 +6,21 @@
#include <config.h>
-#include <process/io_service_signal.h>
-#include <process/testutils/d_test_stubs.h>
+#include <exceptions/exceptions.h>
+#include <asiolink/interval_timer.h>
+#include <asiolink/io_service_signal.h>
+#include <asiolink/testutils/timed_signal.h>
#include <gtest/gtest.h>
#include <functional>
#include <queue>
+using namespace isc::asiolink::test;
namespace ph = std::placeholders;
namespace isc {
-namespace process {
+namespace asiolink {
/// @brief Test fixture for testing the use of IO service signals.
///
@@ -256,5 +259,5 @@ TEST_F(IOSignalTest, mixedSignals) {
EXPECT_EQ(sigusr2_cnt, (stop_at_count_/3));
}
-}; // end of isc::process namespace
-}; // end of isc namespace
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/util/tests/process_spawn_app.sh.in b/src/lib/asiolink/tests/process_spawn_app.sh.in
index 99997aa81c..99997aa81c 100644
--- a/src/lib/util/tests/process_spawn_app.sh.in
+++ b/src/lib/asiolink/tests/process_spawn_app.sh.in
diff --git a/src/lib/util/tests/process_spawn_unittest.cc b/src/lib/asiolink/tests/process_spawn_unittest.cc
index 6c181a8437..8d12e7745d 100644
--- a/src/lib/util/tests/process_spawn_unittest.cc
+++ b/src/lib/asiolink/tests/process_spawn_unittest.cc
@@ -6,7 +6,7 @@
#include <config.h>
-#include <util/process_spawn.h>
+#include <asiolink/process_spawn.h>
#include <gtest/gtest.h>
#include <signal.h>
#include <stdint.h>
@@ -17,7 +17,7 @@
namespace {
using namespace isc;
-using namespace isc::util;
+using namespace isc::asiolink;
using namespace std;
/// @brief Returns a location of the test script.
@@ -98,7 +98,8 @@ bool waitForProcessFast(const ProcessSpawn& process, const pid_t pid,
// case: fork() failing)
TEST(ProcessSpawn, sigchldBlocked) {
vector<string> args;
- ProcessSpawn process(getApp(), args);
+ IOServicePtr io_service(new asiolink::IOService());
+ ProcessSpawn process(io_service, getApp(), args);
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, SIGCHLD);
@@ -114,7 +115,8 @@ TEST(ProcessSpawn, spawnWithArgs) {
vector<string> args;
args.push_back("-e");
args.push_back("64");
- ProcessSpawn process(getApp(), args);
+ IOServicePtr io_service(new asiolink::IOService());
+ ProcessSpawn process(io_service, getApp(), args);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
@@ -133,7 +135,8 @@ TEST(ProcessSpawn, spawnWithArgsAndEnvVars) {
args.push_back("TEST_VARIABLE_VALUE");
vars.push_back("TEST_VARIABLE_NAME=TEST_VARIABLE_VALUE");
- ProcessSpawn process(getApp(), args, vars);
+ IOServicePtr io_service(new asiolink::IOService());
+ ProcessSpawn process(io_service, getApp(), args, vars);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
@@ -149,7 +152,8 @@ TEST(ProcessSpawn, spawnWithArgsAndEnvVars) {
TEST(ProcessSpawn, spawnTwoProcesses) {
vector<string> args;
args.push_back("-p");
- ProcessSpawn process(getApp(), args);
+ IOServicePtr io_service(new asiolink::IOService());
+ ProcessSpawn process(io_service, getApp(), args);
pid_t pid1 = 0;
ASSERT_NO_THROW(pid1 = process.spawn());
ASSERT_TRUE(waitForProcess(process, pid1, 2));
@@ -174,8 +178,9 @@ TEST(ProcessSpawn, spawnTwoProcesses) {
// This test verifies that the external application can be ran without
// arguments and that the exit code is gathered.
TEST(ProcessSpawn, spawnNoArgs) {
+ IOServicePtr io_service(new asiolink::IOService());
vector<string> args;
- ProcessSpawn process(getApp());
+ ProcessSpawn process(io_service, getApp());
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
@@ -187,7 +192,8 @@ TEST(ProcessSpawn, spawnNoArgs) {
// This test verifies that the EXIT_FAILURE code is returned when
// application can't be executed.
TEST(ProcessSpawn, invalidExecutable) {
- ProcessSpawn process("foo");
+ IOServicePtr io_service(new asiolink::IOService());
+ ProcessSpawn process(io_service, "foo");
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
@@ -199,6 +205,7 @@ TEST(ProcessSpawn, invalidExecutable) {
// This test verifies that the full command line for the process is
// returned.
TEST(ProcessSpawn, getCommandLine) {
+ IOServicePtr io_service(new asiolink::IOService());
// Note that cases below are enclosed in separate scopes to make
// sure that the ProcessSpawn object is destroyed before a new
// object is created. Current implementation doesn't allow for
@@ -211,13 +218,13 @@ TEST(ProcessSpawn, getCommandLine) {
args.push_back("-y");
args.push_back("foo");
args.push_back("bar");
- ProcessSpawn process("myapp", args);
+ ProcessSpawn process(io_service, "myapp", args);
EXPECT_EQ("myapp -x -y foo bar", process.getCommandLine());
}
{
// Case 2: no arguments.
- ProcessSpawn process("myapp");
+ ProcessSpawn process(io_service, "myapp");
EXPECT_EQ("myapp", process.getCommandLine());
}
}
@@ -225,12 +232,13 @@ TEST(ProcessSpawn, getCommandLine) {
// This test verifies that it is possible to check if the process is
// running.
TEST(ProcessSpawn, isRunning) {
+ IOServicePtr io_service(new asiolink::IOService());
// Run the process which sleeps for 10 seconds, so as we have
// enough time to check if it is running.
vector<string> args;
args.push_back("-s");
args.push_back("10");
- ProcessSpawn process(getApp(), args);
+ ProcessSpawn process(io_service, getApp(), args);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
EXPECT_TRUE(process.isRunning(pid));
@@ -244,7 +252,7 @@ TEST(ProcessSpawn, isRunning) {
// This test verifies that the signal handler does not modify value of
// errno.
TEST(ProcessSpawn, errnoInvariance) {
-
+ IOServicePtr io_service(new asiolink::IOService());
// Set errno to an arbitrary value. We'll later check that it was not
// stumped on.
errno = 123;
@@ -252,7 +260,7 @@ TEST(ProcessSpawn, errnoInvariance) {
vector<string> args;
args.push_back("-e");
args.push_back("64");
- ProcessSpawn process(getApp(), args);
+ ProcessSpawn process(io_service, getApp(), args);
pid_t pid = 0;
ASSERT_NO_THROW(pid = process.spawn());
diff --git a/src/lib/asiolink/testutils/Makefile.am b/src/lib/asiolink/testutils/Makefile.am
index ec4d1815b8..a20cae5432 100644
--- a/src/lib/asiolink/testutils/Makefile.am
+++ b/src/lib/asiolink/testutils/Makefile.am
@@ -12,6 +12,7 @@ if HAVE_GTEST
noinst_LTLIBRARIES = libasiolinktest.la
libasiolinktest_la_SOURCES = test_server_unix_socket.cc test_server_unix_socket.h
+libasiolinktest_la_SOURCES += timed_signal.cc timed_signal.h
libasiolinktest_la_CXXFLAGS = $(AM_CXXFLAGS)
libasiolinktest_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc
index 2891fa866d..da1b31c61b 100644
--- a/src/lib/dhcpsrv/memfile_lease_mgr.cc
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc
@@ -5,6 +5,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+
#include <database/database_connection.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_exceptions.h>
@@ -15,8 +16,6 @@
#include <exceptions/exceptions.h>
#include <util/multi_threading_mgr.h>
#include <util/pid_file.h>
-#include <util/process_spawn.h>
-#include <util/signal_set.h>
#include <cstdio>
#include <cstring>
#include <errno.h>
@@ -106,7 +105,7 @@ private:
/// @brief A pointer to the @c ProcessSpawn object used to execute
/// the LFC.
- boost::scoped_ptr<util::ProcessSpawn> process_;
+ boost::scoped_ptr<ProcessSpawn> process_;
/// @brief A pointer to the callback function executed by the timer.
asiolink::IntervalTimer::Callback callback_;
@@ -174,7 +173,7 @@ LFCSetup::setup(const uint32_t lfc_interval,
lease_file6->getFilename();
// Create the other names by appending suffixes to the base name.
- util::ProcessArgs args;
+ ProcessArgs args;
// Universe: v4 or v6.
args.push_back(lease_file4 ? "-4" : "-6");
@@ -204,7 +203,7 @@ LFCSetup::setup(const uint32_t lfc_interval,
args.push_back("ignored-path");
// Create the process (do not start it yet).
- process_.reset(new util::ProcessSpawn(executable, args));
+ process_.reset(new ProcessSpawn(LeaseMgr::getIOService(), executable, args));
// If we've been told to run it once now, invoke the callback directly.
if (run_once_now) {
@@ -630,7 +629,7 @@ const int Memfile_LeaseMgr::MAJOR_VERSION;
const int Memfile_LeaseMgr::MINOR_VERSION;
Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& parameters)
- : LeaseMgr(), lfc_setup_(), conn_(parameters), mutex_() {
+ : LeaseMgr(), lfc_setup_(), conn_(parameters), mutex_(new std::mutex) {
bool conversion_needed = false;
// Check the universe and use v4 file or v6 file.
@@ -666,8 +665,6 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& param
}
lfcSetup(conversion_needed);
}
-
- mutex_.reset(new std::mutex);
}
Memfile_LeaseMgr::~Memfile_LeaseMgr() {
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h
index 9e7ce5e986..f1dd01f215 100644
--- a/src/lib/dhcpsrv/memfile_lease_mgr.h
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.h
@@ -8,13 +8,13 @@
#define MEMFILE_LEASE_MGR_H
#include <asiolink/interval_timer.h>
+#include <asiolink/process_spawn.h>
#include <database/database_connection.h>
#include <dhcp/hwaddr.h>
#include <dhcpsrv/csv_lease_file4.h>
#include <dhcpsrv/csv_lease_file6.h>
#include <dhcpsrv/memfile_lease_storage.h>
#include <dhcpsrv/lease_mgr.h>
-#include <util/process_spawn.h>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
diff --git a/src/lib/process/Makefile.am b/src/lib/process/Makefile.am
index 33db11654d..9a07cb7c68 100644
--- a/src/lib/process/Makefile.am
+++ b/src/lib/process/Makefile.am
@@ -25,7 +25,6 @@ libkea_process_la_SOURCES += d_controller.cc d_controller.h
libkea_process_la_SOURCES += d_log.cc d_log.h
libkea_process_la_SOURCES += d_process.h
libkea_process_la_SOURCES += daemon.cc daemon.h
-libkea_process_la_SOURCES += io_service_signal.cc io_service_signal.h
libkea_process_la_SOURCES += log_parser.cc log_parser.h
libkea_process_la_SOURCES += logging_info.cc logging_info.h
libkea_process_la_SOURCES += process_messages.cc process_messages.h
@@ -93,7 +92,6 @@ libkea_process_include_HEADERS = \
d_controller.h \
d_log.h \
d_process.h \
- io_service_signal.h \
logging_info.h \
log_parser.h \
process_messages.h
diff --git a/src/lib/process/d_controller.cc b/src/lib/process/d_controller.cc
index 176967ea67..72bf80e027 100644
--- a/src/lib/process/d_controller.cc
+++ b/src/lib/process/d_controller.cc
@@ -18,7 +18,9 @@
#include <functional>
#include <sstream>
#include <unistd.h>
+#include <signal.h>
+using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::config;
namespace ph = std::placeholders;
@@ -231,8 +233,7 @@ DControllerBase::checkConfigOnly() {
}
void
-DControllerBase::parseArgs(int argc, char* argv[])
-{
+DControllerBase::parseArgs(int argc, char* argv[]) {
if (argc == 1) {
isc_throw(InvalidUsage, "");
@@ -312,8 +313,7 @@ DControllerBase::parseArgs(int argc, char* argv[])
}
bool
-DControllerBase::customOption(int /* option */, char* /*optarg*/)
-{
+DControllerBase::customOption(int /* option */, char* /*optarg*/) {
// Default implementation returns false.
return (false);
}
@@ -783,8 +783,7 @@ DControllerBase::processSignal(int signum) {
}
void
-DControllerBase::usage(const std::string & text)
-{
+DControllerBase::usage(const std::string & text) {
if (text != "") {
std::cerr << "Usage error: " << text << std::endl;
}
diff --git a/src/lib/process/d_controller.h b/src/lib/process/d_controller.h
index 4598288111..d13b30dbc7 100644
--- a/src/lib/process/d_controller.h
+++ b/src/lib/process/d_controller.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -8,13 +8,13 @@
#define D_CONTROLLER_H
#include <asiolink/io_service.h>
+#include <asiolink/io_service_signal.h>
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <log/logger_support.h>
#include <process/daemon.h>
#include <process/d_log.h>
#include <process/d_process.h>
-#include <process/io_service_signal.h>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
@@ -635,10 +635,10 @@ private:
DProcessBasePtr process_;
/// @brief Shared pointer to an IOService object, used for ASIO operations.
- asiolink::IOServicePtr io_service_;
+ isc::asiolink::IOServicePtr io_service_;
/// @brief ASIO signal set.
- IOSignalSetPtr io_signal_set_;
+ isc::asiolink::IOSignalSetPtr io_signal_set_;
/// @brief Singleton instance value.
static DControllerBasePtr controller_;
@@ -648,7 +648,7 @@ private:
friend class DControllerTest;
};
-}; // namespace isc::process
-}; // namespace isc
+} // namespace isc::process
+} // namespace isc
#endif
diff --git a/src/lib/process/daemon.cc b/src/lib/process/daemon.cc
index a7dba8af38..3757570843 100644
--- a/src/lib/process/daemon.cc
+++ b/src/lib/process/daemon.cc
@@ -36,7 +36,7 @@ std::string Daemon::proc_name_("");
std::string Daemon::default_logger_name_("kea");
Daemon::Daemon()
- : signal_set_(), signal_handler_(), config_file_(""),
+ : signal_set_(), config_file_(""),
pid_file_dir_(DATA_DIR), pid_file_(), am_file_author_(false),
exit_value_(EXIT_SUCCESS) {
@@ -55,18 +55,11 @@ Daemon::~Daemon() {
}
void Daemon::cleanup() {
-
}
void Daemon::shutdown() {
}
-void Daemon::handleSignal() {
- if (signal_set_ && signal_handler_) {
- signal_set_->handleNext(std::bind(signal_handler_, ph::_1));
- }
-}
-
void Daemon::configureLogger(const ConstElementPtr& log_config,
const ConfigPtr& storage) {
diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h
index 5c9b4260fa..f3a9e51aaf 100644
--- a/src/lib/process/daemon.h
+++ b/src/lib/process/daemon.h
@@ -10,7 +10,7 @@
#include <cc/data.h>
#include <process/config_base.h>
#include <util/pid_file.h>
-#include <util/signal_set.h>
+#include <asiolink/io_service_signal.h>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <string>
@@ -36,8 +36,8 @@ public:
/// implementations should derive from it.
///
/// Methods are not pure virtual, as we need to instantiate basic daemons (e.g.
-/// Dhcpv6Srv) in tests, without going through the hassles of implementing stub
-/// methods.
+/// Dhcpv4Srv and Dhcpv6Srv) in tests, without going through the hassles of
+/// implementing stub methods.
///
/// Classes derived from @c Daemon may install custom signal handlers using
/// @c isc::util::SignalSet class. This base class provides a declaration
@@ -232,31 +232,12 @@ public:
protected:
- /// @brief Invokes handler for the next received signal.
- ///
- /// This function provides a default implementation for the function
- /// handling next signal received by the process. It checks if a pointer
- /// to @c isc::util::SignalSet object and the signal handler function
- /// have been set. If they have been set, the signal handler is invoked for
- /// the the next signal registered in the @c SignalSet object.
- ///
- /// This function should be received in the main loop of the process.
- virtual void handleSignal();
-
/// @brief A pointer to the object installing custom signal handlers.
///
- /// This pointer needs to be initialized to point to the @c SignalSet
+ /// This pointer needs to be initialized to point to the @c IOSignalSet
/// object in the derived classes which need to handle signals received
/// by the process.
- isc::util::SignalSetPtr signal_set_;
-
- /// @brief Pointer to the common signal handler invoked by the handleSignal
- /// function.
- ///
- /// This pointer needs to be initialized to point to the signal handler
- /// function for signals being handled by the process. If signal handler
- /// it not initialized, the signals will not be handled.
- isc::util::SignalHandler signal_handler_;
+ isc::asiolink::IOSignalSetPtr signal_set_;
/// @brief Manufacture the pid file name
std::string makePIDFileName() const;
@@ -292,7 +273,7 @@ private:
int exit_value_;
};
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+} // namespace process
+} // namespace isc
#endif
diff --git a/src/lib/process/process_messages.cc b/src/lib/process/process_messages.cc
index f6dd5e145a..af290ed409 100644
--- a/src/lib/process/process_messages.cc
+++ b/src/lib/process/process_messages.cc
@@ -33,7 +33,6 @@ extern const isc::log::MessageID DCTL_RUN_PROCESS = "DCTL_RUN_PROCESS";
extern const isc::log::MessageID DCTL_SESSION_FAIL = "DCTL_SESSION_FAIL";
extern const isc::log::MessageID DCTL_SHUTDOWN = "DCTL_SHUTDOWN";
extern const isc::log::MessageID DCTL_SHUTDOWN_SIGNAL_RECVD = "DCTL_SHUTDOWN_SIGNAL_RECVD";
-extern const isc::log::MessageID DCTL_SIGNAL_ERROR = "DCTL_SIGNAL_ERROR";
extern const isc::log::MessageID DCTL_STANDALONE = "DCTL_STANDALONE";
extern const isc::log::MessageID DCTL_STARTING = "DCTL_STARTING";
extern const isc::log::MessageID DCTL_UNSUPPORTED_SIGNAL = "DCTL_UNSUPPORTED_SIGNAL";
@@ -70,7 +69,6 @@ const char* values[] = {
"DCTL_SESSION_FAIL", "%1 controller failed to establish Kea session: %1",
"DCTL_SHUTDOWN", "%1 has shut down, pid: %2, version: %3",
"DCTL_SHUTDOWN_SIGNAL_RECVD", "OS signal %1 received, starting shutdown",
- "DCTL_SIGNAL_ERROR", "signal handler for signal %1, threw an unexpected exception: %2",
"DCTL_STANDALONE", "%1 skipping message queue, running standalone",
"DCTL_STARTING", "%1 starting, pid: %2, version: %3 (%4)",
"DCTL_UNSUPPORTED_SIGNAL", "ignoring reception of unsupported signal: %1",
diff --git a/src/lib/process/process_messages.h b/src/lib/process/process_messages.h
index bb96e6a899..8e1334ea98 100644
--- a/src/lib/process/process_messages.h
+++ b/src/lib/process/process_messages.h
@@ -34,7 +34,6 @@ extern const isc::log::MessageID DCTL_RUN_PROCESS;
extern const isc::log::MessageID DCTL_SESSION_FAIL;
extern const isc::log::MessageID DCTL_SHUTDOWN;
extern const isc::log::MessageID DCTL_SHUTDOWN_SIGNAL_RECVD;
-extern const isc::log::MessageID DCTL_SIGNAL_ERROR;
extern const isc::log::MessageID DCTL_STANDALONE;
extern const isc::log::MessageID DCTL_STARTING;
extern const isc::log::MessageID DCTL_UNSUPPORTED_SIGNAL;
diff --git a/src/lib/process/process_messages.mes b/src/lib/process/process_messages.mes
index 00800b1772..2b5873601d 100644
--- a/src/lib/process/process_messages.mes
+++ b/src/lib/process/process_messages.mes
@@ -132,12 +132,6 @@ down. The argument specifies a name of the service.
This is a debug message indicating the application has received a signal
instructing it to shutdown.
-% DCTL_SIGNAL_ERROR signal handler for signal %1, threw an unexpected exception: %2
-This is an error message indicating that the application encountered an unexpected
-error after receiving a signal. This is a programmatic error and should be
-reported. While The application will likely continue to operating, it may be
-unable to respond correctly to signals.
-
% DCTL_STANDALONE %1 skipping message queue, running standalone
This is a debug message indicating that the controller is running in the
application in standalone mode. This means it will not connected to the Kea
diff --git a/src/lib/process/tests/Makefile.am b/src/lib/process/tests/Makefile.am
index 2fb87683e6..7ef567359b 100644
--- a/src/lib/process/tests/Makefile.am
+++ b/src/lib/process/tests/Makefile.am
@@ -28,7 +28,6 @@ libprocess_unittests_SOURCES += config_ctl_info_unittests.cc
libprocess_unittests_SOURCES += config_ctl_parser_unittests.cc
libprocess_unittests_SOURCES += d_controller_unittests.cc
libprocess_unittests_SOURCES += daemon_unittest.cc
-libprocess_unittests_SOURCES += io_service_signal_unittests.cc
libprocess_unittests_SOURCES += log_parser_unittests.cc
libprocess_unittests_SOURCES += logging_info_unittests.cc
libprocess_unittests_SOURCES += run_unittests.cc
diff --git a/src/lib/process/tests/d_controller_unittests.cc b/src/lib/process/tests/d_controller_unittests.cc
index 010cd4e914..f1cedb1006 100644
--- a/src/lib/process/tests/d_controller_unittests.cc
+++ b/src/lib/process/tests/d_controller_unittests.cc
@@ -7,6 +7,7 @@
#include <config.h>
#include <kea_version.h>
+#include <asiolink/testutils/timed_signal.h>
#include <cc/command_interpreter.h>
#include <process/testutils/d_test_stubs.h>
@@ -15,6 +16,7 @@
#include <sstream>
+using namespace isc::asiolink::test;
using namespace boost::posix_time;
namespace isc {
diff --git a/src/lib/process/testutils/d_test_stubs.h b/src/lib/process/testutils/d_test_stubs.h
index 11635e695d..ee3b0c9d21 100644
--- a/src/lib/process/testutils/d_test_stubs.h
+++ b/src/lib/process/testutils/d_test_stubs.h
@@ -721,69 +721,7 @@ public:
isc::data::ConstElementPtr answer_;
};
-/// @brief Implements a time-delayed signal
-///
-/// Given an IOService, a signal number, and a time period, this class will
-/// send (raise) the signal to the current process.
-class TimedSignal {
-public:
- /// @brief Constructor
- ///
- /// @param io_service IOService to run the timer
- /// @param signum OS signal value (e.g. SIGHUP, SIGUSR1 ...)
- /// @param milliseconds time in milliseconds to wait until the signal is
- /// raised.
- /// @param mode selects between a one-shot signal or a signal which repeats
- /// at "milliseconds" interval.
- TimedSignal(asiolink::IOService& io_service, int signum, int milliseconds,
- const asiolink::IntervalTimer::Mode& mode =
- asiolink::IntervalTimer::ONE_SHOT)
- : timer_(new asiolink::IntervalTimer(io_service)) {
- timer_->setup(SendSignalCallback(signum), milliseconds, mode);
- }
-
- /// @brief Cancels the given timer.
- void cancel() {
- if (timer_) {
- timer_->cancel();
- }
- }
-
- /// @brief Destructor.
- ~TimedSignal() {
- cancel();
- }
-
- /// @brief Callback for the TimeSignal's internal timer.
- class SendSignalCallback: public std::unary_function<void, void> {
- public:
-
- /// @brief Constructor
- ///
- /// @param signum OS signal value of the signal to send
- SendSignalCallback(int signum) : signum_(signum) {
- }
-
- /// @brief Callback method invoked when the timer expires
- ///
- /// Calls raise with the given signal which should generate that
- /// signal to the given process.
- void operator()() {
- ASSERT_EQ(0, raise(signum_));
- return;
- }
-
- private:
- /// @brief Stores the OS signal value to send.
- int signum_;
- };
-
-private:
- /// @brief Timer which controls when the signal is sent.
- asiolink::IntervalTimerPtr timer_;
-};
-
-}; // namespace isc::process
-}; // namespace isc
+} // namespace isc::process
+} // namespace isc
#endif
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index cee9b62d65..ac2ca57401 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -21,10 +21,8 @@ libkea_util_la_SOURCES += multi_threading_mgr.h multi_threading_mgr.cc
libkea_util_la_SOURCES += optional.h
libkea_util_la_SOURCES += pid_file.h pid_file.cc
libkea_util_la_SOURCES += pointer_util.h
-libkea_util_la_SOURCES += process_spawn.h process_spawn.cc
libkea_util_la_SOURCES += range_utilities.h
libkea_util_la_SOURCES += readwrite_mutex.h
-libkea_util_la_SOURCES += signal_set.cc signal_set.h
libkea_util_la_SOURCES += staged_value.h
libkea_util_la_SOURCES += state_model.cc state_model.h
libkea_util_la_SOURCES += stopwatch.cc stopwatch.h
@@ -71,10 +69,8 @@ libkea_util_include_HEADERS = \
optional.h \
pid_file.h \
pointer_util.h \
- process_spawn.h \
range_utilities.h \
readwrite_mutex.h \
- signal_set.h \
staged_value.h \
state_model.h \
stopwatch.h \
diff --git a/src/lib/util/signal_set.cc b/src/lib/util/signal_set.cc
deleted file mode 100644
index f0695ea13e..0000000000
--- a/src/lib/util/signal_set.cc
+++ /dev/null
@@ -1,415 +0,0 @@
-// Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <util/signal_set.h>
-
-#include <array>
-#include <cerrno>
-#include <cstring>
-#include <list>
-
-using namespace isc;
-using namespace isc::util;
-
-namespace {
-
-/// @brief Fixed size storage for the codes of received signals.
-///
-/// It is initialized with all zeros, which means that no signals
-/// have been received.
-std::array<int, 1024> received_signals;
-
-/// @brief Returns a pointer to the global set of registered signals.
-///
-/// Multiple instances of @c SignalSet may use this pointer to access
-/// and update the set. Note we use a smart pointer so callers can ensure
-/// the static object doesn't go out of scope before they are done with it
-/// during process exit.
-///
-/// @return Pointer to the global set of registered signals. This pointer
-/// is always initialized and points to a valid object.
-SigIntSetPtr getRegisteredSignals() {
- static SigIntSetPtr registered_signals(new SigIntSet());
- return (registered_signals);
-}
-
-/// @brief Returns a pointer to static collection of signals received.
-///
-/// Multiple instances of @c SignalSet may use this pointer to access
-/// and update the queue of signals received. Note we use a smart pointer
-/// so callers can ensure the static object doesn't go out of scope before
-/// they are done with it during process exit.
-///
-/// @return Static collection of signals received. This pointer is always
-/// initialized and points to a valid object.
-SigIntListPtr getSignalStates() {
- static SigIntListPtr signal_states(new SigIntList());
- return (signal_states);
-}
-
-/// @brief Internal signal handler for @c isc::util::SignalSet class.
-///
-/// This handler catches all registered signals. When a signal arrives it
-/// passes the signal to invokeOnReceiptHandler for "on-receipt" processing.
-/// If this processing returns true if exists without further action,
-/// otherwise it adds the signal number to the queue of received signals.
-/// It prevents adding duplicated signals. All duplicated signals are dropped.
-/// This prevents hammering a process to invoke handlers (e.g. DHCP server
-/// reconfiguration), when many of the same signals are received one after
-/// another.
-///
-/// @param sig Signal number.
-void internalHandler(int sig) {
- if (SignalSet::invokeOnReceiptHandler(sig)) {
- // Signal has been handled by the on-receipt handler.
- return;
- }
-
- // Signal is using post-receipt handling, see if we've
- // already received it.
- SigIntListPtr states = getSignalStates();
- for (std::list<int>::const_iterator it = states->begin();
- it != states->end(); ++it) {
- if (sig == *it) {
- return;
- }
- }
-
- // We haven't yet received this signal so we have to record its
- // reception. We're using the fixed size array to temporarily
- // store the received signal codes. We can't directly insert
- // the signal to the 'states' list because this would cause a
- // new allocation (malloc) which is not async-signal-safe.
- for (int i = 0; i < received_signals.size(); ++i) {
- // We have already recorded this signal.
- if (received_signals[i] == sig) {
- return;
-
- } else if (received_signals[i] == 0) {
- // We reached the end of the useful data in the storage.
- // Put the signal code into the storage.
- received_signals[i] = sig;
- break;
- }
- }
-}
-
-/// @brief Optional handler to execute at the time of signal receipt
-BoolSignalHandler onreceipt_handler_ = BoolSignalHandler();
-
-}; // end anon namespace
-
-namespace isc {
-namespace util {
-
-bool
-SignalSet::invokeOnReceiptHandler(int sig) {
- if (!onreceipt_handler_) {
- return (false);
- }
-
- // First we set the signal to SIG_IGN. This causes any repeat occurrences
- // to be discarded, not deferred as they would be if blocked. Note that
- // we save the current sig action so we can restore it later.
- struct sigaction sa;
- struct sigaction prev_sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_IGN;
- if (sigaction(sig, &sa, &prev_sa) < 0) {
- // Highly unlikely we can get here.
- const char* errmsg = strerror(errno);
- isc_throw(SignalSetError, "failed to set SIG_IGN for signal "
- << sig << ": " << errmsg);
- }
-
- // Call the registered handler.
- bool signal_processed = false;
- try {
- signal_processed = onreceipt_handler_(sig);
- } catch (const std::exception& ex) {
- // Restore the handler. We might fail to restore it, but we likely
- // have bigger issues anyway: for that reason, the return value is
- // ignored. To avoid complaints from static code checkers that notice
- // that the return values from other calls to sigaction() have been
- // used, the call to sigaction is explicitly cast to void to indicate
- // that the return value is intentionally being ignored.
- static_cast<void>(sigaction(sig, &prev_sa, 0));
- isc_throw(SignalSetError, "onreceipt_handler failed for signal "
- << sig << ": " << ex.what());
- }
-
- // Restore the sig action to re-enable handling this signal.
- if (sigaction(sig, &prev_sa, 0) < 0) {
- // Highly unlikely we can get here.
- const char* errmsg = strerror(errno);
- isc_throw(SignalSetError, "failed to restore handler for signal "
- << sig << ": " << errmsg);
- }
-
- return (signal_processed);
-}
-
-SignalSet::SignalSet(const int sig0)
- : blocked_(false) {
- // Copy static pointers to ensure they don't lose scope before we do.
- registered_signals_ = getRegisteredSignals();
- signal_states_ = getSignalStates();
- add(sig0);
-}
-
-SignalSet::SignalSet(const int sig0, const int sig1) :
- blocked_(false) {
- registered_signals_ = getRegisteredSignals();
- signal_states_ = getSignalStates();
- add(sig0);
- add(sig1);
-}
-
-SignalSet::SignalSet(const int sig0, const int sig1, const int sig2) :
- blocked_(false) {
- registered_signals_ = getRegisteredSignals();
- signal_states_ = getSignalStates();
- add(sig0);
- add(sig1);
- add(sig2);
-}
-
-SignalSet::~SignalSet() {
- // Set default signal handlers.
- try {
- clear();
- } catch (...) {
- // Not a good thing to throw from a destructor. in fact this should
- // not throw an exception because we just unregister the signals
- // that we have previously registered. So the signal codes are fine.
- }
-}
-
-void
-SignalSet::add(const int sig) {
- insert(sig);
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = internalHandler;
- sigfillset(&sa.sa_mask);
- if (sigaction(sig, &sa, 0) < 0) {
- const char* errmsg = strerror(errno);
- erase(sig);
- isc_throw(SignalSetError, "failed to register a signal handler for"
- " signal " << sig << ": " << errmsg);
- }
-}
-
-void
-SignalSet::block() {
- maskSignals(SIG_BLOCK);
- blocked_ = true;
-}
-
-void
-SignalSet::clear() {
- // Iterate over a copy of the registered signal set because the
- // remove function is erasing the elements and we don't want to
- // erase the elements we are iterating over. This would cause
- // a segfault.
- std::set<int> all_signals = local_signals_;
- for (std::set<int>::const_iterator it = all_signals.begin();
- it != all_signals.end(); ++it) {
- remove(*it);
- }
-}
-
-int
-SignalSet::getNext() {
- // Since we're operating on the global values that the signal
- // handler has access to, we have to temporarily block the
- // signals to not interfere with unsafe operations performed
- // by this method. Remember if the signals were blocked or
- // not to be able to determine whether they should be unblocked
- // when the function returns.
- bool was_blocked = blocked_;
- if (!was_blocked) {
- block();
- }
-
- // We may have some signals received. We need to iterate over those
- // and move them to the signal states structure.
- for (int i = 0; i < received_signals.size(); ++i) {
- // If we hit the end of useful data, break.
- if (received_signals[i] == 0) {
- break;
- }
- // Check if such signal has been already recorded.
- if (std::find(signal_states_->begin(), signal_states_->end(), received_signals[i])
- == signal_states_->end()) {
- signal_states_->push_back(received_signals[i]);
- }
- // Set the current element to 0 to indicate the end of
- // the useful data and process the next element.
- received_signals[i] = 0;
- }
-
- int sig = -1;
- for (std::list<int>::iterator it = signal_states_->begin();
- it != signal_states_->end(); ++it) {
- if (local_signals_.find(*it) != local_signals_.end()) {
- sig = *it;
- break;
- }
- }
-
- // If we blocked signals here locally, we have to unblock them.
- if (!was_blocked) {
- unblock();
- }
- return (sig);
-}
-
-void
-SignalSet::erase(const int sig) {
- if (local_signals_.find(sig) == local_signals_.end()) {
- isc_throw(SignalSetError, "failed to unregister signal " << sig
- << " from a signal set: signal is not owned by the"
- " signal set");
- }
-
- // Since we're operating on the global values that the signal
- // handler has access to, we have to temporarily block the
- // signals to not interfere with unsafe operations performed
- // by this method. Remember if the signals were blocked or
- // not to be able to determine whether they should be unblocked
- // when the function returns.
- bool was_blocked = blocked_;
- if (!was_blocked) {
- block();
- }
-
- // Remove globally registered signal.
- registered_signals_->erase(sig);
- // Remove unhandled signals from the queue.
- for (std::list<int>::iterator it = signal_states_->begin();
- it != signal_states_->end(); ++it) {
- if (*it == sig) {
- it = signal_states_->erase(it);
- }
- }
-
- // Remove locally registered signal.
- local_signals_.erase(sig);
-
- // If the signal is no longer supported by this signal set,
- // we have to unblock it, because other signal set instance
- // may be using it. We won't process it anyway after it is
- // removed from this set.
- unblock(sig);
-
- // Unblock all remaining signals if we have blocked them in
- // this function.
- if (!was_blocked) {
- unblock();
- }
-}
-
-void
-SignalSet::handleNext(SignalHandler signal_handler) {
- block();
- int signum = getNext();
- if (signum >= 0) {
- popNext();
- try {
- signal_handler(signum);
- } catch (...) {
- unblock();
- throw;
- }
- }
- unblock();
-}
-
-void
-SignalSet::insert(const int sig) {
- if ((registered_signals_->find(sig) != registered_signals_->end()) ||
- (local_signals_.find(sig) != local_signals_.end())) {
- isc_throw(SignalSetError, "attempt to register a duplicate signal "
- << sig);
- }
- registered_signals_->insert(sig);
- local_signals_.insert(sig);
-}
-
-void
-SignalSet::maskSignals(const int mask, const int sig) const {
- sigset_t new_set;
- sigemptyset(&new_set);
- if (sig < 0) {
- for (std::set<int>::const_iterator it = registered_signals_->begin();
- it != registered_signals_->end(); ++it) {
- sigaddset(&new_set, *it);
- }
- } else {
- sigaddset(&new_set, sig);
- }
- pthread_sigmask(mask, &new_set, 0);
-}
-
-void
-SignalSet::popNext() {
- for (std::list<int>::iterator it = signal_states_->begin();
- it != signal_states_->end(); ++it) {
- if (local_signals_.find(*it) != local_signals_.end()) {
- signal_states_->erase(it);
- return;
- }
- }
-}
-
-void
-SignalSet::remove(const int sig) {
- // Unregister only if we own this signal.
- if (local_signals_.find(sig) != local_signals_.end()) {
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
- sigfillset(&sa.sa_mask);
- if (sigaction(sig, &sa, 0) < 0) {
- isc_throw(SignalSetError, "unable to restore original signal"
- " handler for signal: " << sig);
- }
- erase(sig);
- } else {
- isc_throw(SignalSetError, "failed to unregister signal " << sig
- << ": this signal is not owned by the signal set");
- }
-}
-
-void
-SignalSet::unblock(int sig) {
- // There are two cases supported by this function. One is to
- // unblock some specific signal. Another one is to unblock all
- // signals supported by this function. The maskSignals function
- // will deal wih this internally but we marked signals as unblocked
- // only if we unblocked all of them (sig is negative).
- maskSignals(SIG_UNBLOCK, sig);
- if (sig < 0) {
- blocked_ = false;
- }
-}
-
-
-void
-SignalSet::setOnReceiptHandler(BoolSignalHandler handler) {
- onreceipt_handler_ = handler;
-}
-
-void
-SignalSet::clearOnReceiptHandler() {
- onreceipt_handler_ = BoolSignalHandler();
-}
-
-} // end of isc::util
-} // end of isc
diff --git a/src/lib/util/signal_set.h b/src/lib/util/signal_set.h
deleted file mode 100644
index ab63276202..0000000000
--- a/src/lib/util/signal_set.h
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef SIGNAL_SET_H
-#define SIGNAL_SET_H
-
-#include <exceptions/exceptions.h>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <functional>
-#include <set>
-#include <list>
-#include <pthread.h>
-#include <signal.h>
-
-namespace isc {
-namespace util {
-
-/// @brief Exception thrown when the @c isc::util::SignalSet class
-/// experiences an error.
-class SignalSetError : public Exception {
-public:
- SignalSetError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) { };
-};
-
-
-/// @brief Defines a set of integer signal identifiers: SIGHUP, SIGTERM...
-typedef std::set<int> SigIntSet;
-/// @brief Pointer to a set of signal identifiers
-typedef boost::shared_ptr<SigIntSet> SigIntSetPtr;
-
-/// @brief Defines a list of integer signal identifiers: SIGHUP, SIGTERM...
-typedef std::list<int> SigIntList;
-/// @brief Pointer to a list of signal identifiers
-typedef boost::shared_ptr<SigIntList> SigIntListPtr;
-
-
-/// @brief Forward declaration to the @c isc::util::SignalSet.
-class SignalSet;
-/// @brief Pointer to the @c isc::util::SignalSet.
-typedef boost::shared_ptr<SignalSet> SignalSetPtr;
-/// @brief Pointer to the signal handling function.
-typedef std::function<void(int signum)> SignalHandler;
-
-/// @brief Pointer to a signal handling function which returns bool result.
-///
-/// The handler is expected to return true if the signal it was given has
-/// been processed (i.e. should not be recorded for deferred processing) or
-/// false in which case it will be recorded.
-typedef std::function<bool(int signum)> BoolSignalHandler;
-
-/// @brief Represents a collection of signals handled in a customized way.
-///
-/// Kea processes must handle selected signals in a specialized way. For
-/// example: SIGINT and SIGTERM must perform a graceful shut down of the
-/// server. The SIGHUP signal is used to trigger server's reconfiguration.
-///
-/// This class allows the caller to register one or more signals to catch
-/// and process. Signals may be handled either immediately upon arrival and/or
-/// recorded and processed later. To process signals immediately, the caller
-/// must register an "on-receipt" handler. This handler is expected to return
-/// a true or false indicating whether or not the signal has been processed.
-/// Signal occurrences that are not processed by the on-receipt handler are
-/// remembered by SignalSet for deferred processing. The caller can then query
-/// SignalSet at their discretion to determine if any signal occurrences are
-/// pending and process them.
-///
-/// SignalSet uses an internal handler to catch all registered signals. When
-/// a signal arrives the internal handler will first attempt to invoke the
-/// on-receipt handler. If one has been registered it is passed the
-/// signal value as an argument and if it returns true upon completion, the
-/// internal handler will exit without further action. If the on-receipt
-/// handler returned false or one is not registered, then internal handler
-/// will record the signal value for deferred processing. Note that once a
-/// particular signal has been recorded, any further occurrences of that signal
-/// will be discarded until the original occurrence has been processed. This
-/// guards against rapid-fire occurrences of the same signal.
-///
-/// @note This class is not thread safe. It uses static variables and
-/// functions to track a global state of signal registration and received
-/// signals' queue. But the thread library is signal safe as new threads
-/// are created with all signals blocked.
-class SignalSet : public boost::noncopyable {
-public:
- /// @brief Constructor installing one signal.
- ///
- /// @param sig0 First signal.
- /// @throw SignalSetError If attempting to add duplicated signal or
- /// the signal is invalid.
- SignalSet(const int sig0);
-
- /// @brief Constructor installing two signals.
- ///
- /// @param sig0 First signal.
- /// @param sig1 Second signal.
- /// @throw SignalSetError If attempting to add duplicated signal or
- /// the signal is invalid.
- SignalSet(const int sig0, const int sig1);
-
- /// @brief Constructor installing three signals.
- ///
- /// @param sig0 First signal.
- /// @param sig1 Second signal.
- /// @param sig2 Third signal.
- /// @throw SignalSetError If attempting to add duplicated signal or
- /// the signal is invalid.
- SignalSet(const int sig0, const int sig1, const int sig2);
-
- /// @brief Destructor.
- ///
- /// Removes installed handlers.
- ~SignalSet();
-
- /// @brief Installs the handler for the specified signal.
- ///
- /// This function adds a signal to the set. When the signal is received
- /// by the process, it will be recorded and a signal can be later handled
- /// by the process.
- ///
- /// @param sig Signal code.
- /// @throw SignalSetError if signal being added duplicates an existing
- /// signal.
- void add(const int sig);
-
- /// @brief Uninstalls all signals.
- ///
- /// This function calls @c isc::util::SignalSet::remove for each
- /// installed signal.
- void clear();
-
- /// @brief Returns a code of the next received signal.
- ///
- /// @return A code of the next received signal or -1 if there are no
- /// more signals received.
- int getNext();
-
- /// @brief Calls a handler for the next received signal.
- ///
- /// This function handles the next received signal and removes it from the
- /// queue of received signals. While the function is executed, all custom
- /// signal handlers are blocked to prevent race condition.
- ///
- /// @param signal_handler A pointer to the signal handler function to
- /// be used to handle the signal.
- void handleNext(SignalHandler signal_handler);
-
- /// @brief Uninstalls signal handler for a specified signal.
- ///
- /// @param sig A code of the signal to be removed.
- void remove(const int sig);
-
- /// @brief Registers a handler as the onreceipt signal handler
- ///
- /// Sets the given handler as the handler to invoke immediately
- /// upon receipt of a a registered signal.
- ///
- /// @note Currently, the on-receipt handler is stored as a static
- /// value and hence there may only be one such handler at a time
- /// for a given process.
- ///
- /// @param handler the signal handler to register
- static void setOnReceiptHandler(BoolSignalHandler handler);
-
- /// @brief Unregisters the onreceipt signal handler
- static void clearOnReceiptHandler();
-
- /// @brief Invokes the onreceipt handler if it exists
- ///
- /// This static method is used by @c isc::util::SignalSet class to
- /// invoke the registered handler (if one) immediately upon receipt of
- /// a registered signal.
- ///
- /// Prior to invoking the handler, it sets signal action for the
- /// given signal to SIG_IGN which prevents any repeat signal
- /// occurrences from queuing while the handler is executing. Upon
- /// completion of the handler, the signal action is restored which
- /// re-enables receipt and handling of the signal.
- ///
- /// @param sig Signal number.
- /// @return Boolean false if no on-receipt handler was registered,
- /// otherwise it is the value returned by the on-receipt handler.
- static bool invokeOnReceiptHandler(int sig);
-
-private:
-
- /// @brief Blocks signals in the set.
- ///
- /// This function blocks the signals in a set to prevent race condition
- /// between the signal handler and the new signal coming in.
- void block();
-
- /// @brief Removes the signal from the set.
- ///
- /// This function removes only a signal which is owned by this signal set.
- ///
- /// @param sig Signal to be removed.
- /// @throw SignalSetError if the signal being removed is not owned by this
- /// signal set.
- void erase(const int sig);
-
- /// @brief Insert a signal to the set.
- ///
- /// @param sig Signal to be inserted.
- /// @throw SignalSetError if a signal being inserted has already been
- /// registered in this or other signal set.
- void insert(const int sig);
-
- /// @brief Applies a mask to all signals in the set.
- ///
- /// This function is used by @c SignalSet::block and @c SignalSet::unblock
- /// to apply the SIG_BLOCK and SIG_UNBLOCK mask to signals.
- ///
- /// @param mask A mask to be applied to all signals.
- /// @param sig Optional signal to be masked. If this value is negative all
- /// signals are masked.
- void maskSignals(const int mask, const int sig = -1) const;
-
- /// @brief Pops a next signal number from the static collection of signals.
- ///
- /// The static collection of signals is updated by the internal signal
- /// handler being invoked when one of the installed signals is received by
- /// the process. This function removes the first element of the collection.
- void popNext();
-
- /// @brief Unblocks signals in the set.
- ///
- /// This function unblocks the signals in a set.
- ///
- /// @param sig Optional signal to be unblocked. If this is negative, all
- /// registered signals are unblocked.
- void unblock(int sig = -1);
-
- /// @brief Indicates if receiving signals is blocked.
- bool blocked_;
-
- /// @brief Stores the set of signals registered in this signal set.
- std::set<int> local_signals_;
-
- /// @brief Shared pointer to static set of registered signals
- /// Set during construction to ensure static set does not lose scope
- /// before we do.
- SigIntSetPtr registered_signals_;
-
- /// @brief Shared pointer to static list of pending signals
- /// Set during construction to ensure static list does not lose scope
- /// before we do.
- SigIntListPtr signal_states_;
-};
-
-}
-}
-
-#endif // SIGNAL_SET_H
-
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
index f5b3598f07..d8354e967b 100644
--- a/src/lib/util/tests/Makefile.am
+++ b/src/lib/util/tests/Makefile.am
@@ -17,10 +17,6 @@ CLEANFILES = *.gcno *.gcda
# CSV files are created by unit tests for CSVFile class.
CLEANFILES += *.csv
-DISTCLEANFILES = process_spawn_app.sh
-
-noinst_SCRIPTS = process_spawn_app.sh
-
TESTS_ENVIRONMENT = \
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
@@ -48,7 +44,6 @@ run_unittests_SOURCES += memory_segment_common_unittest.cc
run_unittests_SOURCES += multi_threading_mgr_unittest.cc
run_unittests_SOURCES += optional_unittest.cc
run_unittests_SOURCES += pid_file_unittest.cc
-run_unittests_SOURCES += process_spawn_unittest.cc
run_unittests_SOURCES += qid_gen_unittest.cc
run_unittests_SOURCES += random_number_generator_unittest.cc
run_unittests_SOURCES += staged_value_unittest.cc
@@ -58,7 +53,6 @@ run_unittests_SOURCES += thread_pool_unittest.cc
run_unittests_SOURCES += time_utilities_unittest.cc
run_unittests_SOURCES += range_utilities_unittest.cc
run_unittests_SOURCES += readwrite_mutex_unittest.cc
-run_unittests_SOURCES += signal_set_unittest.cc
run_unittests_SOURCES += stopwatch_unittest.cc
run_unittests_SOURCES += unlock_guard_unittests.cc
run_unittests_SOURCES += utf8_unittest.cc
diff --git a/src/lib/util/tests/signal_set_unittest.cc b/src/lib/util/tests/signal_set_unittest.cc
deleted file mode 100644
index 90c25f583d..0000000000
--- a/src/lib/util/tests/signal_set_unittest.cc
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-#include <util/signal_set.h>
-#include <boost/shared_ptr.hpp>
-#include <gtest/gtest.h>
-#include <signal.h>
-
-namespace {
-
-using namespace isc;
-using namespace isc::util;
-namespace ph = std::placeholders;
-
-/// @brief Test fixture class for @c isc::util::SignalSet class.
-///
-/// This class contains a handler function which records the signal
-/// being handled. It allows for checking whether the signal set
-/// has invoked the handler for the expected signal.
-class SignalSetTest : public ::testing::Test {
-public:
-
- /// @brief Constructor.
- ///
- /// Resets the signal sets and variables being modified by the
- /// signal handler function.
- SignalSetTest()
- : signal_set_(),
- secondary_signal_set_(),
- onreceipt_trues_(0) {
- handler_calls_ = 0;
- signum_ = -1;
- }
-
- /// @brief Destructor.
- ///
- /// Uninstalls the signals from the signal sets.
- ~SignalSetTest() {
- if (signal_set_) {
- signal_set_->clear();
- }
- if (secondary_signal_set_) {
- secondary_signal_set_->clear();
- }
- }
-
- /// @brief Deferred processing signal handler used by unit tests.
- ///
- /// @param signum Signal being handled.
- static void testHandler(int signum) {
- signum_ = signum;
- ++handler_calls_;
- }
-
- /// @brief Immediate processing signal handler used by unit tests.
- ///
- /// The handler processes only SIGHUP. All others will pass through.
- ///
- /// @param signum Signal being handled.
- /// @return Boolean true if the handler has processed the signal, false
- /// otherwise.
- bool onReceiptHandler(int signum) {
- if (signum == SIGHUP) {
- ++onreceipt_trues_;
- return (true);
- }
-
- return (false);
- }
-
- /// @brief Number of handler calls so far.
- static int handler_calls_;
- /// @brief The last signal handled.
- static int signum_;
- /// @brief Test signal set object.
- SignalSetPtr signal_set_;
- /// @brief Second signal set object.
- SignalSetPtr secondary_signal_set_;
- /// @brief Number of true returns from onReceiptHandler so far.
- int onreceipt_trues_;
-};
-
-int SignalSetTest::handler_calls_ = 0;
-int SignalSetTest::signum_ = -1;
-
-/// Check that the signals are recorded by the signal handlers.
-TEST_F(SignalSetTest, twoSignals) {
- // Register handlers for two signals.
- ASSERT_NO_THROW(signal_set_.reset(new SignalSet(SIGHUP, SIGINT)));
- // Send SIGHUP signal to the process.
- ASSERT_EQ(0, raise(SIGHUP));
- // The SIGHUP should be the next one in the queue to be handled.
- EXPECT_EQ(SIGHUP, signal_set_->getNext());
- // But, no handlers should have been called yet.
- EXPECT_EQ(0, handler_calls_);
- // Send a different signal.
- ASSERT_EQ(0, raise(SIGINT));
- // The SIGHUP hasn't been handled yet so it should still be the first
- // one in the queue.
- EXPECT_EQ(SIGHUP, signal_set_->getNext());
- // No handlers have been called yet.
- EXPECT_EQ(0, handler_calls_);
- // Raise another SIGHUP before the first one has been handled. The
- // second one should be dropped.
- ASSERT_EQ(0, raise(SIGHUP));
- // Execute the first handler (for SIGHUP).
- signal_set_->handleNext(std::bind(&SignalSetTest::testHandler, ph::_1));
- // The handler should have been called once and the signal
- // handled should be SIGHUP.
- EXPECT_EQ(1, handler_calls_);
- EXPECT_EQ(SIGHUP, signum_);
- // Next signal to be handled should be SIGINT.
- EXPECT_EQ(SIGINT, signal_set_->getNext());
- signal_set_->handleNext(std::bind(&SignalSetTest::testHandler, ph::_1));
- EXPECT_EQ(2, handler_calls_);
- EXPECT_EQ(SIGINT, signum_);
- // There should be no more waiting handlers.
- EXPECT_EQ(-1, signal_set_->getNext());
- // Make sure that signals can be unregistered.
- EXPECT_NO_THROW(signal_set_->remove(SIGHUP));
- EXPECT_NO_THROW(signal_set_->remove(SIGINT));
-}
-
-/// Check that the signal set can only handle signals owned by it.
-TEST_F(SignalSetTest, twoSignalSets) {
- // Register handler for SIGHUP in the first signal set.
- signal_set_.reset(new SignalSet(SIGHUP));
- // Register handler for SIGINT in the second signal set.
- secondary_signal_set_.reset(new SignalSet(SIGINT));
- // Send SIGHUP.
- ASSERT_EQ(0, raise(SIGHUP));
- // Send SIGINT.
- ASSERT_EQ(0, raise(SIGINT));
- // Although the SIGHUP is the first signal received by the process
- // it is not owned by the secondary signal set. The first signal
- // to be handled by the secondary signal set is SIGINT.
- EXPECT_EQ(SIGINT, secondary_signal_set_->getNext());
- // The signal set owns SIGHUP so it should be the next to handle.
- EXPECT_EQ(SIGHUP, signal_set_->getNext());
- // Handle next signal owned by the secondary signal set.
- secondary_signal_set_->handleNext(std::bind(&SignalSetTest::testHandler, ph::_1));
- EXPECT_EQ(1, handler_calls_);
- EXPECT_EQ(SIGINT, signum_);
- // No more signals to be handled for this signal set.
- EXPECT_EQ(-1, secondary_signal_set_->getNext());
- // Handle next signal owned by the signal set.
- signal_set_->handleNext(std::bind(&SignalSetTest::testHandler, ph::_1));
- EXPECT_EQ(2, handler_calls_);
- EXPECT_EQ(SIGHUP, signum_);
- // No more signals to be handled by this signal set.
- EXPECT_EQ(-1, signal_set_->getNext());
-}
-
-// Check that each signal set removes only the signals that it has been used
-// to register.
-TEST_F(SignalSetTest, remove) {
- // Register handlers for SIGHUP using one signal set.
- ASSERT_NO_THROW(signal_set_.reset(new SignalSet(SIGHUP)));
- // Define another signal set and register a different signal.
- ASSERT_NO_THROW(secondary_signal_set_.reset(new SignalSet(SIGINT)));
- // The SIGHUP has been already registered with the other signal
- // set, so it should not be possible to register it again.
- ASSERT_THROW(secondary_signal_set_->add(SIGHUP), SignalSetError);
- // It shouldn't be possible to remove the signal registered in a different
- // signal set.
- ASSERT_THROW(secondary_signal_set_->remove(SIGHUP), SignalSetError);
- // Remove all signals from the first signal set. The signals registered
- // with the other signal signal set should be preserved.
- ASSERT_NO_THROW(signal_set_->clear());
- // Check indirectly that the SIGINT is still registered. An attempt to
- // register registered signal should result in failure.
- EXPECT_THROW(secondary_signal_set_->add(SIGINT), SignalSetError);
- // But, we should be able to register SIGHUP.
- EXPECT_NO_THROW(secondary_signal_set_->add(SIGHUP));
-}
-
-/// Check that it is not possible to duplicate signals.
-TEST_F(SignalSetTest, duplicates) {
- ASSERT_NO_THROW(signal_set_.reset(new SignalSet(SIGHUP)));
- // It shouldn't be possible to register the same signal.
- EXPECT_THROW(signal_set_->add(SIGHUP), SignalSetError);
- // But ok to register a different one.
- EXPECT_NO_THROW(signal_set_->add(SIGTERM));
- // Now, let's define other signal set.
- SignalSetPtr other;
- // SIGINT hasn't been registered in the first signal set
- // so it should be fine to register.
- ASSERT_NO_THROW(other.reset(new SignalSet(SIGINT)));
- // SIGHUP has been already registered in the first signal set so
- // an attempt to register it again should result in a failure.
- EXPECT_THROW(other->add(SIGHUP), SignalSetError);
-}
-
-/// Check that on-receipt processing works.
-TEST_F(SignalSetTest, onReceiptTests) {
- // Install an on-receipt handler.
- SignalSet::setOnReceiptHandler(std::bind(&SignalSetTest::onReceiptHandler,
- this, ph::_1));
- // Create a SignalSet for SIGHUP and SIGUSR1.
- ASSERT_NO_THROW(signal_set_.reset(new SignalSet(SIGHUP, SIGUSR1)));
-
- // Generate SIGHUP, which the on-receipt handler should process.
- // Verify that the on-receipt handler processed the signal and that
- // no signals are pending.
- ASSERT_EQ(0, raise(SIGHUP));
- EXPECT_EQ(1, onreceipt_trues_);
- EXPECT_EQ(-1, signal_set_->getNext());
-
- // Generate SIGHUP, which the on-receipt handler should NOT process.
- // Verify the on-receipt handler did not the signal and that SIGUSR1
- // is pending.
- ASSERT_EQ(0, raise(SIGUSR1));
- EXPECT_EQ(1, onreceipt_trues_);
- EXPECT_EQ(SIGUSR1, signal_set_->getNext());
-
- // Verify we can process SIGUSR1 with the deferred handler.
- signal_set_->handleNext(std::bind(&SignalSetTest::testHandler, ph::_1));
- EXPECT_EQ(1, handler_calls_);
- EXPECT_EQ(SIGUSR1, signum_);
-
- // Unregister the on-receipt handler.
- SignalSet::clearOnReceiptHandler();
-
- // Generate SIGHUP.
- // Verify that the on-receipt handler did not process the signal, and
- // that SIGHUP is pending.
- ASSERT_EQ(0, raise(SIGHUP));
- EXPECT_EQ(1, onreceipt_trues_);
- EXPECT_EQ(SIGHUP, signal_set_->getNext());
-
- // Verify we can process it with deferred handler.
- signal_set_->handleNext(std::bind(&SignalSetTest::testHandler, ph::_1));
- EXPECT_EQ(2, handler_calls_);
- EXPECT_EQ(SIGHUP, signum_);
-}
-
-} // end of anonymous namespace