allow AsyncSignalHandler to attach and detach from an EventBase
authorAdam Simpkins <simpkins@fb.com>
Tue, 27 Jun 2017 02:27:32 +0000 (19:27 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 27 Jun 2017 02:35:06 +0000 (19:35 -0700)
Summary:
Add attachEventBase() and detachEventBase() methods to AsyncSignalHandler,
similar to the methods of AsyncSocket.

The main benefit of this is that it allows creating an AsyncSignalHandler with
an initially null EventBase, and then attaching it to an EventBase at some
later point in time.

Reviewed By: yfeldblum

Differential Revision: D5315325

fbshipit-source-id: 8a4ca483a62ca86837ea0bb54fa9a70d59f2f04e

CMakeLists.txt
folly/io/async/AsyncSignalHandler.cpp
folly/io/async/AsyncSignalHandler.h
folly/io/async/test/AsyncSignalHandlerTest.cpp [new file with mode: 0644]

index 2bf5def679b86d837b26d6d5b3ba15bd70b7bf88..4bfa99744ae06ff38f6acd66bbf1a9d6a5e27480 100755 (executable)
@@ -407,6 +407,7 @@ if (BUILD_TESTS)
           AsyncSSLSocketTest.h
         SOURCES
           AsyncPipeTest.cpp
           AsyncSSLSocketTest.h
         SOURCES
           AsyncPipeTest.cpp
+          AsyncSignalHandlerTest.cpp
           AsyncSocketExceptionTest.cpp
           AsyncSocketTest.cpp
           AsyncSocketTest2.cpp
           AsyncSocketExceptionTest.cpp
           AsyncSocketTest.cpp
           AsyncSocketTest2.cpp
index c81116d75a92e49ece768fe6f7e2bcdf0f03d41a..8c5c3247345fa34419b3ff76d6f2847ee727bd6c 100644 (file)
@@ -38,6 +38,18 @@ AsyncSignalHandler::~AsyncSignalHandler() {
   }
 }
 
   }
 }
 
+void AsyncSignalHandler::attachEventBase(EventBase* eventBase) {
+  assert(eventBase_ == nullptr);
+  assert(signalEvents_.empty());
+  eventBase_ = eventBase;
+}
+
+void AsyncSignalHandler::detachEventBase() {
+  assert(eventBase_ != nullptr);
+  assert(signalEvents_.empty());
+  eventBase_ = nullptr;
+}
+
 void AsyncSignalHandler::registerSignalHandler(int signum) {
   pair<SignalEventMap::iterator, bool> ret =
     signalEvents_.insert(make_pair(signum, event()));
 void AsyncSignalHandler::registerSignalHandler(int signum) {
   pair<SignalEventMap::iterator, bool> ret =
     signalEvents_.insert(make_pair(signum, event()));
index f4b6bdf6b606b511adfc0920c4ccaca131369b9d..056655337cb7accbc3dd7adf0e34f9fc188ee5e6 100644 (file)
@@ -48,6 +48,30 @@ class AsyncSignalHandler {
   explicit AsyncSignalHandler(EventBase* eventBase);
   virtual ~AsyncSignalHandler();
 
   explicit AsyncSignalHandler(EventBase* eventBase);
   virtual ~AsyncSignalHandler();
 
+  /**
+   * Attach this AsyncSignalHandler to an EventBase.
+   *
+   * This should only be called if the AsyncSignalHandler is not currently
+   * registered for any signals and is not currently attached to an existing
+   * EventBase.
+   */
+  void attachEventBase(EventBase* eventBase);
+
+  /**
+   * Detach this AsyncSignalHandler from its EventBase.
+   *
+   * This should only be called if the AsyncSignalHandler is not currently
+   * registered for any signals.
+   */
+  void detachEventBase();
+
+  /**
+   * Get the EventBase used by this AsyncSignalHandler.
+   */
+  EventBase* getEventBase() const {
+    return eventBase_;
+  }
+
   /**
    * Register to receive callbacks about the specified signal.
    *
   /**
    * Register to receive callbacks about the specified signal.
    *
@@ -86,7 +110,7 @@ class AsyncSignalHandler {
 
   static void libeventCallback(libevent_fd_t signum, short events, void* arg);
 
 
   static void libeventCallback(libevent_fd_t signum, short events, void* arg);
 
-  EventBase* eventBase_;
+  EventBase* eventBase_{nullptr};
   SignalEventMap signalEvents_;
 };
 
   SignalEventMap signalEvents_;
 };
 
diff --git a/folly/io/async/test/AsyncSignalHandlerTest.cpp b/folly/io/async/test/AsyncSignalHandlerTest.cpp
new file mode 100644 (file)
index 0000000..3d6d41d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <folly/io/async/AsyncSignalHandler.h>
+#include <folly/io/async/EventBase.h>
+
+#include <folly/portability/GTest.h>
+
+using namespace folly;
+
+namespace {
+class TestSignalHandler : public AsyncSignalHandler {
+ public:
+  using AsyncSignalHandler::AsyncSignalHandler;
+
+  void signalReceived(int /* signum */) noexcept override {
+    called = true;
+  }
+
+  bool called{false};
+};
+}
+
+TEST(AsyncSignalHandler, basic) {
+  EventBase evb;
+  TestSignalHandler handler{&evb};
+
+  handler.registerSignalHandler(SIGUSR1);
+  kill(getpid(), SIGUSR1);
+
+  EXPECT_FALSE(handler.called);
+  evb.loopOnce(EVLOOP_NONBLOCK);
+  EXPECT_TRUE(handler.called);
+}
+
+TEST(AsyncSignalHandler, attachEventBase) {
+  TestSignalHandler handler{nullptr};
+  EXPECT_FALSE(handler.getEventBase());
+  EventBase evb;
+
+  handler.attachEventBase(&evb);
+  EXPECT_EQ(&evb, handler.getEventBase());
+
+  handler.registerSignalHandler(SIGUSR1);
+  kill(getpid(), SIGUSR1);
+  EXPECT_FALSE(handler.called);
+  evb.loopOnce(EVLOOP_NONBLOCK);
+  EXPECT_TRUE(handler.called);
+
+  handler.unregisterSignalHandler(SIGUSR1);
+  handler.detachEventBase();
+  EXPECT_FALSE(handler.getEventBase());
+}