Enable EventBase switching for AsyncSocket even if it has registered events
authorFuat Geleri <geleri@fb.com>
Wed, 22 Nov 2017 22:20:42 +0000 (14:20 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Wed, 22 Nov 2017 22:27:03 +0000 (14:27 -0800)
Summary:
AsyncSocket will return isDetachable() -> false if there is a read callback set.
So,
 - ignore event registration status
 - unregister the events when detaching and
 - register them back when attaching again.

Reviewed By: afrind, eduardo-elizondo

Differential Revision: D6331787

fbshipit-source-id: fca4e6101f2d5666edbafa09116aa50f34cb084d

folly/io/async/AsyncSocket.cpp
folly/io/async/test/AsyncSocketTest2.cpp

index 67c86bf81676f5e269ac8e056aefc0bbda340a81..1dbaa220ceca5987833c8b114235eec30cce21a1 100644 (file)
@@ -1434,6 +1434,9 @@ void AsyncSocket::attachEventBase(EventBase* eventBase) {
 
   eventBase_ = eventBase;
   ioHandler_.attachEventBase(eventBase);
+
+  updateEventRegistration();
+
   writeTimeout_.attachEventBase(eventBase);
   if (evbChangeCb_) {
     evbChangeCb_->evbAttached(this);
@@ -1448,6 +1451,9 @@ void AsyncSocket::detachEventBase() {
   eventBase_->dcheckIsInEventBaseThread();
 
   eventBase_ = nullptr;
+
+  ioHandler_.unregisterHandler();
+
   ioHandler_.detachEventBase();
   writeTimeout_.detachEventBase();
   if (evbChangeCb_) {
@@ -1459,7 +1465,7 @@ bool AsyncSocket::isDetachable() const {
   DCHECK(eventBase_ != nullptr);
   eventBase_->dcheckIsInEventBaseThread();
 
-  return !ioHandler_.isHandlerRegistered() && !writeTimeout_.isScheduled();
+  return !writeTimeout_.isScheduled();
 }
 
 void AsyncSocket::cacheAddresses() {
index 7e714048e3508d2428ed41e2534077fdf78be677..54034e305c0b70da1be17c458cbf667f0dafe759 100644 (file)
@@ -2857,6 +2857,39 @@ TEST(AsyncSocketTest, EvbCallbacks) {
   socket->attachEventBase(&evb);
 }
 
+TEST(AsyncSocketTest, TestEvbDetachWtRegisteredIOHandlers) {
+  // Start listening on a local port
+  TestServer server;
+
+  // Connect using a AsyncSocket
+  EventBase evb;
+  std::shared_ptr<AsyncSocket> socket = AsyncSocket::newSocket(&evb);
+  ConnCallback cb;
+  socket->connect(&cb, server.getAddress(), 30);
+
+  evb.loop();
+
+  ASSERT_EQ(cb.state, STATE_SUCCEEDED);
+  EXPECT_LE(0, socket->getConnectTime().count());
+  EXPECT_EQ(socket->getConnectTimeout(), std::chrono::milliseconds(30));
+
+  // After the ioHandlers are registered, still should be able to detach/attach
+  ReadCallback rcb;
+  socket->setReadCB(&rcb);
+
+  auto cbEvbChg = std::make_unique<MockEvbChangeCallback>();
+  InSequence seq;
+  EXPECT_CALL(*cbEvbChg, evbDetached(socket.get())).Times(1);
+  EXPECT_CALL(*cbEvbChg, evbAttached(socket.get())).Times(1);
+
+  socket->setEvbChangedCallback(std::move(cbEvbChg));
+  EXPECT_TRUE(socket->isDetachable());
+  socket->detachEventBase();
+  socket->attachEventBase(&evb);
+
+  socket->close();
+}
+
 #ifdef FOLLY_HAVE_MSG_ERRQUEUE
 /* copied from include/uapi/linux/net_tstamp.h */
 /* SO_TIMESTAMPING gets an integer bit field comprised of these values */