states->push_back(sig);
}
-/// @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() {
- std::list<int>* states = getSignalStates();
- if (!states->empty()) {
- states->pop_front();
- }
-}
-
}
namespace isc {
int
SignalSet::getNext() const {
std::list<int>* states = getSignalStates();
- if (states->empty()) {
- return (-1);
+ for (std::list<int>::iterator it = states->begin();
+ it != states->end(); ++it) {
+ if (local_signals_.find(*it) != local_signals_.end()) {
+ return (*it);
+ }
}
- return (*states->begin());
+ return (-1);
}
void
<< " from a signal set: signal is not owned by the"
" signal set");
}
+ // Remove globally registered signal.
getRegisteredSignals()->erase(sig);
+ // Remove unhandled signals from the queue.
+ for (std::list<int>::iterator it = getSignalStates()->begin();
+ it != getSignalStates()->end(); ++it) {
+ if (*it == sig) {
+ it = getSignalStates()->erase(it);
+ }
+ }
+ // Remove locally registered signal.
local_signals_.erase(sig);
}
sigprocmask(mask, &new_set, 0);
}
+void
+SignalSet::popNext() {
+ std::list<int>* states = getSignalStates();
+ for (std::list<int>::iterator it = states->begin();
+ it != states->end(); ++it) {
+ if (local_signals_.find(*it) != local_signals_.end()) {
+ states->erase(it);
+ return;
+ }
+ }
+}
+
void
SignalSet::remove(const int sig) {
// Unregister only if we own this signal.
using namespace isc;
using namespace isc::util::io;
+/// @brief Test fixture class for @c isc::util::io::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_() {
+ : signal_set_(),
+ secondary_signal_set_() {
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();
+ }
}
- void handleNext() {
- signal_set_->handleNext(boost::bind(&SignalSetTest::testHandler, _1));
- }
-
+ /// @brief Signal handler used by unit tests.
+ ///
+ /// @param signum Signal being handled.
static void testHandler(int signum) {
signum_ = signum;
++handler_calls_;
}
+ /// @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_;
};
int SignalSetTest::handler_calls_ = 0;
// second one should be dropped.
ASSERT_EQ(0, raise(SIGHUP));
// Execute the first handler (for SIGHUP).
- handleNext();
+ signal_set_->handleNext(boost::bind(&SignalSetTest::testHandler, _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());
- handleNext();
+ signal_set_->handleNext(boost::bind(&SignalSetTest::testHandler, _1));
EXPECT_EQ(2, handler_calls_);
EXPECT_EQ(SIGINT, signum_);
// There should be no more waiting handlers.
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(boost::bind(&SignalSetTest::testHandler,
+ _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(boost::bind(&SignalSetTest::testHandler, _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, twoSignalSets) {
+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.
- SignalSetPtr other_set;
- ASSERT_NO_THROW(other_set.reset(new SignalSet(SIGINT)));
+ ASSERT_NO_THROW(secondary_signal_set_.reset(new SignalSet(SIGINT)));
// The SIGHUP has been already registsred with the other signal
// set, so it should not be possible to register it again.
- ASSERT_THROW(other_set->add(SIGHUP), SignalSetError);
+ 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(other_set->remove(SIGHUP), SignalSetError);
+ 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(other_set->add(SIGINT), SignalSetError);
+ EXPECT_THROW(secondary_signal_set_->add(SIGINT), SignalSetError);
// But, we should be able to regsiter SIGHUP.
- EXPECT_NO_THROW(other_set->add(SIGHUP));
+ EXPECT_NO_THROW(secondary_signal_set_->add(SIGHUP));
}
/// Check that it is not possible to duplicate signals.