diff --git a/quic/api/Observer.h b/quic/api/Observer.h index 1dda2d70d..767e36289 100644 --- a/quic/api/Observer.h +++ b/quic/api/Observer.h @@ -12,8 +12,13 @@ #include #include +namespace folly { +class EventBase; +} + namespace quic { class QuicSocket; + /** * ===== Instrumentation Observer API ===== */ @@ -250,6 +255,32 @@ class LifecycleObserver { QuicSocket* /* socket */, const folly::Optional< std::pair>& /* errorOpt */) noexcept = 0; + + /** + * evbAttach() will be invoked when a new event base is attached to this + * socket. This will be called from the new event base's thread. + * + * @param socket Socket on which the new event base was attached. + * @param evb The new event base that is getting attached. + */ + virtual void evbAttach( + QuicSocket* /* socket */, + folly::EventBase* /* evb */) noexcept { + // do nothing + } + + /** + * evbDetach() will be invoked when an existing event base is detached + * from the socket. This will be called from the existing event base's thread. + * + * @param socket Socket on which the existing EVB is getting detached. + * @param evb The existing event base that is getting detached. + */ + virtual void evbDetach( + QuicSocket* /* socket */, + folly::EventBase* /* evb */) noexcept { + // do nothing + } }; } // namespace quic diff --git a/quic/api/QuicTransportBase.cpp b/quic/api/QuicTransportBase.cpp index 25280a6ca..ab6810408 100644 --- a/quic/api/QuicTransportBase.cpp +++ b/quic/api/QuicTransportBase.cpp @@ -2940,6 +2940,10 @@ void QuicTransportBase::attachEventBase(folly::EventBase* evb) { updateReadLooper(); updatePeekLooper(); updateWriteLooper(false); + + for (const auto& cb : lifecycleObservers_) { + cb->evbAttach(this, evb_); + } } void QuicTransportBase::detachEventBase() { @@ -2958,6 +2962,10 @@ void QuicTransportBase::detachEventBase() { readLooper_->detachEventBase(); peekLooper_->detachEventBase(); writeLooper_->detachEventBase(); + + for (const auto& cb : lifecycleObservers_) { + cb->evbDetach(this, evb_); + } evb_ = nullptr; } diff --git a/quic/api/test/Mocks.h b/quic/api/test/Mocks.h index 45e7f6e9a..667815fbd 100644 --- a/quic/api/test/Mocks.h +++ b/quic/api/test/Mocks.h @@ -312,6 +312,8 @@ class MockLifecycleObserver : public LifecycleObserver { GMOCK_METHOD1_(, noexcept, , observerAttach, void(QuicSocket*)); GMOCK_METHOD1_(, noexcept, , observerDetach, void(QuicSocket*)); GMOCK_METHOD1_(, noexcept, , destroy, void(QuicSocket*)); + GMOCK_METHOD2_(, noexcept, , evbAttach, void(QuicSocket*, folly::EventBase*)); + GMOCK_METHOD2_(, noexcept, , evbDetach, void(QuicSocket*, folly::EventBase*)); GMOCK_METHOD2_( , noexcept, diff --git a/quic/api/test/QuicTransportBaseTest.cpp b/quic/api/test/QuicTransportBaseTest.cpp index 8ed4d34f6..9af639e87 100644 --- a/quic/api/test/QuicTransportBaseTest.cpp +++ b/quic/api/test/QuicTransportBaseTest.cpp @@ -3577,6 +3577,41 @@ TEST_F(QuicTransportImplTest, LifecycleObserverMultipleAttachDestroyTransport) { Mock::VerifyAndClearExpectations(cb2.get()); } +TEST_F(QuicTransportImplTest, LifecycleObserverDetachAndAttachEvb) { + auto cb = std::make_unique>(); + folly::EventBase evb2; + + EXPECT_CALL(*cb, observerAttach(transport.get())); + transport->addLifecycleObserver(cb.get()); + Mock::VerifyAndClearExpectations(cb.get()); + + // Detach the event base evb and attach a new event base evb2 + EXPECT_CALL(*cb, evbDetach(transport.get(), evb.get())); + transport->detachEventBase(); + EXPECT_EQ(nullptr, transport->getEventBase()); + Mock::VerifyAndClearExpectations(cb.get()); + + EXPECT_CALL(*cb, evbAttach(transport.get(), &evb2)); + transport->attachEventBase(&evb2); + EXPECT_EQ(&evb2, transport->getEventBase()); + Mock::VerifyAndClearExpectations(cb.get()); + + // Detach the event base evb and re-attach the old event base evb + EXPECT_CALL(*cb, evbDetach(transport.get(), &evb2)); + transport->detachEventBase(); + EXPECT_EQ(nullptr, transport->getEventBase()); + Mock::VerifyAndClearExpectations(cb.get()); + + EXPECT_CALL(*cb, evbAttach(transport.get(), evb.get())); + transport->attachEventBase(evb.get()); + EXPECT_EQ(evb.get(), transport->getEventBase()); + Mock::VerifyAndClearExpectations(cb.get()); + + EXPECT_CALL(*cb, observerDetach(transport.get())); + EXPECT_TRUE(transport->removeLifecycleObserver(cb.get())); + Mock::VerifyAndClearExpectations(cb.get()); +} + TEST_F(QuicTransportImplTest, InstrumentationObserverAttachRemove) { auto cb = std::make_unique>(); transport->addInstrumentationObserver(cb.get());