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 2bf5def..4bfa997 100755 (executable)
@@ -407,6 +407,7 @@ if (BUILD_TESTS)
           AsyncSSLSocketTest.h
         SOURCES
           AsyncPipeTest.cpp
+          AsyncSignalHandlerTest.cpp
           AsyncSocketExceptionTest.cpp
           AsyncSocketTest.cpp
           AsyncSocketTest2.cpp
index c81116d..8c5c324 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()));
index f4b6bdf..0566553 100644 (file)
@@ -48,6 +48,30 @@ class 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.
    *
@@ -86,7 +110,7 @@ class AsyncSignalHandler {
 
   static void libeventCallback(libevent_fd_t signum, short events, void* arg);
 
-  EventBase* eventBase_;
+  EventBase* eventBase_{nullptr};
   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());
+}