Commit 3d5e5974 authored by Stepan Palamarchuk's avatar Stepan Palamarchuk Committed by Facebook GitHub Bot

Introduce EventBase::Options

Summary:
This API allows for an easier way to configure EventBase without a need to introduce yet another constructor with variable amount of arguments.

In particular, we have an ad-hoc constructor for overriding just the wheel timer interval, but it's not possible to override it in other constructors.

Reviewed By: yfeldblum

Differential Revision: D23511659

fbshipit-source-id: 2f8de3a527ee07dbf2dc19f2e369014793d906c1
parent 8f60f633
...@@ -236,6 +236,19 @@ class EventFD : public folly::EventHandler, public folly::EventReadCallback { ...@@ -236,6 +236,19 @@ class EventFD : public folly::EventHandler, public folly::EventReadCallback {
std::unique_ptr<IoVec> ioVecPtr_; std::unique_ptr<IoVec> ioVecPtr_;
}; };
std::unique_ptr<folly::EventBase> getEventBase(
folly::PollIoBackend::Options opts) {
try {
auto factory = [opts] {
return std::make_unique<folly::IoUringBackend>(opts);
};
return std::make_unique<folly::EventBase>(
folly::EventBase::Options().setBackendFactory(std::move(factory)));
} catch (const folly::IoUringBackend::NotAvailable&) {
return nullptr;
}
}
void testEventFD(bool overflow, bool persist, bool asyncRead) { void testEventFD(bool overflow, bool persist, bool asyncRead) {
static constexpr size_t kBackendCapacity = 64; static constexpr size_t kBackendCapacity = 64;
static constexpr size_t kBackendMaxSubmit = 32; static constexpr size_t kBackendMaxSubmit = 32;
...@@ -245,31 +258,23 @@ void testEventFD(bool overflow, bool persist, bool asyncRead) { ...@@ -245,31 +258,23 @@ void testEventFD(bool overflow, bool persist, bool asyncRead) {
static constexpr size_t kEventFdCount = 16; static constexpr size_t kEventFdCount = 16;
auto total = kNumEventFds * kEventFdCount + kEventFdCount / 2; auto total = kNumEventFds * kEventFdCount + kEventFdCount / 2;
std::unique_ptr<folly::EventBaseBackendBase> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity).setMaxSubmit(kBackendMaxSubmit);
try { auto evbPtr = getEventBase(options);
folly::PollIoBackend::Options options; SKIP_IF(!evbPtr) << "Backend not available";
options.setCapacity(kBackendCapacity).setMaxSubmit(kBackendMaxSubmit);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
folly::EventBase evb(std::move(backend));
std::vector<std::unique_ptr<EventFD>> eventsVec; std::vector<std::unique_ptr<EventFD>> eventsVec;
eventsVec.reserve(kNumEventFds); eventsVec.reserve(kNumEventFds);
for (size_t i = 0; i < kNumEventFds; i++) { for (size_t i = 0; i < kNumEventFds; i++) {
auto ev = std::make_unique<EventFD>( auto ev = std::make_unique<EventFD>(
true, 2 * kEventFdCount, total, persist, &evb); true, 2 * kEventFdCount, total, persist, evbPtr.get());
ev->useAsyncReadCallback(asyncRead); ev->useAsyncReadCallback(asyncRead);
eventsVec.emplace_back(std::move(ev)); eventsVec.emplace_back(std::move(ev));
} }
evb.loop(); evbPtr->loop();
for (size_t i = 0; i < kNumEventFds; i++) { for (size_t i = 0; i < kNumEventFds; i++) {
CHECK_GE( CHECK_GE(
...@@ -284,30 +289,21 @@ void testInvalidFd(size_t numTotal, size_t numValid, size_t numInvalid) { ...@@ -284,30 +289,21 @@ void testInvalidFd(size_t numTotal, size_t numValid, size_t numInvalid) {
auto total = numTotal; auto total = numTotal;
std::unique_ptr<folly::EventBaseBackendBase> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity).setMaxSubmit(kBackendMaxSubmit);
try { auto evbPtr = getEventBase(options);
folly::PollIoBackend::Options options; SKIP_IF(!evbPtr) << "Backend not available";
options.setCapacity(kBackendCapacity).setMaxSubmit(kBackendMaxSubmit);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
folly::EventBase evb(std::move(backend));
std::vector<std::unique_ptr<EventFD>> eventsVec; std::vector<std::unique_ptr<EventFD>> eventsVec;
eventsVec.reserve(numTotal); eventsVec.reserve(numTotal);
for (size_t i = 0; i < numTotal; i++) { for (size_t i = 0; i < numTotal; i++) {
bool valid = (i % (numValid + numInvalid)) < numValid; bool valid = (i % (numValid + numInvalid)) < numValid;
eventsVec.emplace_back( eventsVec.emplace_back(std::make_unique<EventFD>(
std::make_unique<EventFD>(valid, 1, total, false /*persist*/, &evb)); valid, 1, total, false /*persist*/, evbPtr.get()));
} }
evb.loop(); evbPtr->loop();
for (size_t i = 0; i < numTotal; i++) { for (size_t i = 0; i < numTotal; i++) {
CHECK_GE(eventsVec[i]->getNum(), 1); CHECK_GE(eventsVec[i]->getNum(), 1);
...@@ -434,22 +430,13 @@ void testAsyncUDPRecvmsg(bool useRegisteredFds) { ...@@ -434,22 +430,13 @@ void testAsyncUDPRecvmsg(bool useRegisteredFds) {
static constexpr size_t kNumPackets = 32; static constexpr size_t kNumPackets = 32;
auto total = kNumPackets * kNumSockets; auto total = kNumPackets * kNumSockets;
std::unique_ptr<folly::EventBaseBackendBase> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity)
try { .setMaxSubmit(kBackendMaxSubmit)
folly::PollIoBackend::Options options; .setMaxGet(kBackendMaxGet)
options.setCapacity(kBackendCapacity) .setUseRegisteredFds(useRegisteredFds);
.setMaxSubmit(kBackendMaxSubmit) auto evbPtr = getEventBase(options);
.setMaxGet(kBackendMaxGet) SKIP_IF(!evbPtr) << "Backend not available";
.setUseRegisteredFds(useRegisteredFds);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
folly::EventBase evb(std::move(backend));
// create the server sockets // create the server sockets
std::vector<std::unique_ptr<folly::AsyncUDPServerSocket>> serverSocketVec; std::vector<std::unique_ptr<folly::AsyncUDPServerSocket>> serverSocketVec;
...@@ -464,13 +451,15 @@ void testAsyncUDPRecvmsg(bool useRegisteredFds) { ...@@ -464,13 +451,15 @@ void testAsyncUDPRecvmsg(bool useRegisteredFds) {
std::string data(kNumBytes, 'A'); std::string data(kNumBytes, 'A');
for (size_t i = 0; i < kNumSockets; i++) { for (size_t i = 0; i < kNumSockets; i++) {
auto clientSock = std::make_unique<folly::AsyncUDPSocket>(&evb); auto clientSock = std::make_unique<folly::AsyncUDPSocket>(evbPtr.get());
clientSock->bind(folly::SocketAddress("::1", 0)); clientSock->bind(folly::SocketAddress("::1", 0));
auto cb = std::make_unique<EventRecvmsgCallback>( auto cb = std::make_unique<EventRecvmsgCallback>(
data, clientSock->address(), kNumBytes, total, &evb); data, clientSock->address(), kNumBytes, total, evbPtr.get());
auto serverSock = std::make_unique<folly::AsyncUDPServerSocket>( auto serverSock = std::make_unique<folly::AsyncUDPServerSocket>(
&evb, 1500, folly::AsyncUDPServerSocket::DispatchMechanism::RoundRobin); evbPtr.get(),
1500,
folly::AsyncUDPServerSocket::DispatchMechanism::RoundRobin);
// set the event callback // set the event callback
serverSock->setEventCallback(cb.get()); serverSock->setEventCallback(cb.get());
// bind // bind
...@@ -494,7 +483,7 @@ void testAsyncUDPRecvmsg(bool useRegisteredFds) { ...@@ -494,7 +483,7 @@ void testAsyncUDPRecvmsg(bool useRegisteredFds) {
cbVec.emplace_back(std::move(cb)); cbVec.emplace_back(std::move(cb));
} }
evb.loopForever(); evbPtr->loopForever();
for (size_t i = 0; i < kNumSockets; i++) { for (size_t i = 0; i < kNumSockets; i++) {
CHECK_GE(cbVec[i]->getAsyncNum(), kNumPackets); CHECK_GE(cbVec[i]->getAsyncNum(), kNumPackets);
...@@ -608,20 +597,13 @@ TEST(IoUringBackend, FileReadWrite) { ...@@ -608,20 +597,13 @@ TEST(IoUringBackend, FileReadWrite) {
static constexpr size_t kBackendMaxSubmit = 32; static constexpr size_t kBackendMaxSubmit = 32;
static constexpr size_t kBackendMaxGet = 32; static constexpr size_t kBackendMaxGet = 32;
std::unique_ptr<folly::IoUringBackend> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity)
try { .setMaxSubmit(kBackendMaxSubmit)
folly::PollIoBackend::Options options; .setMaxGet(kBackendMaxGet)
options.setCapacity(kBackendCapacity) .setUseRegisteredFds(false);
.setMaxSubmit(kBackendMaxSubmit) auto evbPtr = getEventBase(options);
.setMaxGet(kBackendMaxGet) SKIP_IF(!evbPtr) << "Backend not available";
.setUseRegisteredFds(false);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
static constexpr size_t kNumBlocks = 512; static constexpr size_t kNumBlocks = 512;
static constexpr size_t kBlockSize = 4096; static constexpr size_t kBlockSize = 4096;
...@@ -635,9 +617,7 @@ TEST(IoUringBackend, FileReadWrite) { ...@@ -635,9 +617,7 @@ TEST(IoUringBackend, FileReadWrite) {
::close(fd); ::close(fd);
}; };
folly::EventBase evb(std::move(backend)); auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evbPtr->getBackend());
auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evb.getBackend());
CHECK(!!backendPtr); CHECK(!!backendPtr);
size_t num = 0; size_t num = 0;
...@@ -672,7 +652,7 @@ TEST(IoUringBackend, FileReadWrite) { ...@@ -672,7 +652,7 @@ TEST(IoUringBackend, FileReadWrite) {
std::move(writeCb)); std::move(writeCb));
} }
evb.loop(); evbPtr->loop();
EXPECT_EQ(num, kNumBlocks); EXPECT_EQ(num, kNumBlocks);
} }
...@@ -682,20 +662,13 @@ TEST(IoUringBackend, FileReadvWritev) { ...@@ -682,20 +662,13 @@ TEST(IoUringBackend, FileReadvWritev) {
static constexpr size_t kBackendMaxSubmit = 32; static constexpr size_t kBackendMaxSubmit = 32;
static constexpr size_t kBackendMaxGet = 32; static constexpr size_t kBackendMaxGet = 32;
std::unique_ptr<folly::IoUringBackend> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity)
try { .setMaxSubmit(kBackendMaxSubmit)
folly::PollIoBackend::Options options; .setMaxGet(kBackendMaxGet)
options.setCapacity(kBackendCapacity) .setUseRegisteredFds(false);
.setMaxSubmit(kBackendMaxSubmit) auto evbPtr = getEventBase(options);
.setMaxGet(kBackendMaxGet) SKIP_IF(!evbPtr) << "Backend not available";
.setUseRegisteredFds(false);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
static constexpr size_t kNumBlocks = 512; static constexpr size_t kNumBlocks = 512;
static constexpr size_t kNumIov = 4; static constexpr size_t kNumIov = 4;
...@@ -711,9 +684,7 @@ TEST(IoUringBackend, FileReadvWritev) { ...@@ -711,9 +684,7 @@ TEST(IoUringBackend, FileReadvWritev) {
::close(fd); ::close(fd);
}; };
folly::EventBase evb(std::move(backend)); auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evbPtr->getBackend());
auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evb.getBackend());
CHECK(!!backendPtr); CHECK(!!backendPtr);
size_t num = 0; size_t num = 0;
...@@ -764,7 +735,7 @@ TEST(IoUringBackend, FileReadvWritev) { ...@@ -764,7 +735,7 @@ TEST(IoUringBackend, FileReadvWritev) {
CHECK_EQ(res, lenVec[i]); CHECK_EQ(res, lenVec[i]);
CHECK(readDataVecVec[i] == writeDataVecVec[i]); CHECK(readDataVecVec[i] == writeDataVecVec[i]);
if (++num == kNumBlocks) { if (++num == kNumBlocks) {
evb.terminateLoopSoon(); evbPtr->terminateLoopSoon();
} }
}; };
...@@ -776,7 +747,7 @@ TEST(IoUringBackend, FileReadvWritev) { ...@@ -776,7 +747,7 @@ TEST(IoUringBackend, FileReadvWritev) {
fd, writeDataIov[i], i * kBlockSize, std::move(writeCb)); fd, writeDataIov[i], i * kBlockSize, std::move(writeCb));
} }
evb.loopForever(); evbPtr->loopForever();
EXPECT_EQ(num, kNumBlocks); EXPECT_EQ(num, kNumBlocks);
} }
...@@ -786,20 +757,13 @@ TEST(IoUringBackend, FileReadMany) { ...@@ -786,20 +757,13 @@ TEST(IoUringBackend, FileReadMany) {
static constexpr size_t kBackendMaxSubmit = 128; static constexpr size_t kBackendMaxSubmit = 128;
static constexpr size_t kBackendMaxGet = 128; static constexpr size_t kBackendMaxGet = 128;
std::unique_ptr<folly::IoUringBackend> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity)
try { .setMaxSubmit(kBackendMaxSubmit)
folly::PollIoBackend::Options options; .setMaxGet(kBackendMaxGet)
options.setCapacity(kBackendCapacity) .setUseRegisteredFds(false);
.setMaxSubmit(kBackendMaxSubmit) auto evbPtr = getEventBase(options);
.setMaxGet(kBackendMaxGet) SKIP_IF(!evbPtr) << "Backend not available";
.setUseRegisteredFds(false);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
static constexpr size_t kNumBlocks = 8 * 1024; static constexpr size_t kNumBlocks = 8 * 1024;
static constexpr size_t kBlockSize = 4096; static constexpr size_t kBlockSize = 4096;
...@@ -815,9 +779,7 @@ TEST(IoUringBackend, FileReadMany) { ...@@ -815,9 +779,7 @@ TEST(IoUringBackend, FileReadMany) {
::close(fd); ::close(fd);
}; };
folly::EventBase evb(std::move(backend)); auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evbPtr->getBackend());
auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evb.getBackend());
CHECK(!!backendPtr); CHECK(!!backendPtr);
size_t num = 0; size_t num = 0;
...@@ -846,7 +808,7 @@ TEST(IoUringBackend, FileReadMany) { ...@@ -846,7 +808,7 @@ TEST(IoUringBackend, FileReadMany) {
backendPtr->queueRead( backendPtr->queueRead(
fd, bigReadData.data(), bigReadData.size(), 0, std::move(bigReadCb)); fd, bigReadData.data(), bigReadData.size(), 0, std::move(bigReadCb));
evb.loop(); evbPtr->loop();
EXPECT_EQ(num, kNumBlocks); EXPECT_EQ(num, kNumBlocks);
} }
...@@ -856,20 +818,13 @@ TEST(IoUringBackend, FileWriteMany) { ...@@ -856,20 +818,13 @@ TEST(IoUringBackend, FileWriteMany) {
static constexpr size_t kBackendMaxSubmit = 128; static constexpr size_t kBackendMaxSubmit = 128;
static constexpr size_t kBackendMaxGet = 128; static constexpr size_t kBackendMaxGet = 128;
std::unique_ptr<folly::IoUringBackend> backend; folly::PollIoBackend::Options options;
options.setCapacity(kBackendCapacity)
try { .setMaxSubmit(kBackendMaxSubmit)
folly::PollIoBackend::Options options; .setMaxGet(kBackendMaxGet)
options.setCapacity(kBackendCapacity) .setUseRegisteredFds(false);
.setMaxSubmit(kBackendMaxSubmit) auto evbPtr = getEventBase(options);
.setMaxGet(kBackendMaxGet) SKIP_IF(!evbPtr) << "Backend not available";
.setUseRegisteredFds(false);
backend = std::make_unique<folly::IoUringBackend>(options);
} catch (const folly::IoUringBackend::NotAvailable&) {
}
SKIP_IF(!backend) << "Backend not available";
static constexpr size_t kNumBlocks = 8 * 1024; static constexpr size_t kNumBlocks = 8 * 1024;
static constexpr size_t kBlockSize = 4096; static constexpr size_t kBlockSize = 4096;
...@@ -885,9 +840,7 @@ TEST(IoUringBackend, FileWriteMany) { ...@@ -885,9 +840,7 @@ TEST(IoUringBackend, FileWriteMany) {
::close(fd); ::close(fd);
}; };
folly::EventBase evb(std::move(backend)); auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evbPtr->getBackend());
auto* backendPtr = dynamic_cast<folly::IoUringBackend*>(evb.getBackend());
CHECK(!!backendPtr); CHECK(!!backendPtr);
size_t num = 0; size_t num = 0;
...@@ -920,7 +873,7 @@ TEST(IoUringBackend, FileWriteMany) { ...@@ -920,7 +873,7 @@ TEST(IoUringBackend, FileWriteMany) {
std::move(writeCb)); std::move(writeCb));
} }
evb.loop(); evbPtr->loop();
EXPECT_EQ(num, kNumBlocks); EXPECT_EQ(num, kNumBlocks);
EXPECT_EQ(bFdatasync, true); EXPECT_EQ(bFdatasync, true);
...@@ -939,7 +892,7 @@ TEST(IoUringBackend, FileWriteMany) { ...@@ -939,7 +892,7 @@ TEST(IoUringBackend, FileWriteMany) {
backendPtr->queueWrite( backendPtr->queueWrite(
fd, bigWriteData.data(), bigWriteData.size(), 0, std::move(bigWriteCb)); fd, bigWriteData.data(), bigWriteData.size(), 0, std::move(bigWriteCb));
evb.loop(); evbPtr->loop();
EXPECT_EQ(bFsync, true); EXPECT_EQ(bFsync, true);
} }
......
...@@ -85,7 +85,11 @@ class EventFD : public EventHandler { ...@@ -85,7 +85,11 @@ class EventFD : public EventHandler {
class BackendEventBase : public EventBase { class BackendEventBase : public EventBase {
public: public:
explicit BackendEventBase(bool useRegisteredFds, size_t capacity = 32 * 1024) explicit BackendEventBase(bool useRegisteredFds, size_t capacity = 32 * 1024)
: EventBase(getBackend(useRegisteredFds, capacity), false) {} : EventBase(EventBase::Options()
.setBackendFactory([useRegisteredFds, capacity] {
return getBackend(useRegisteredFds, capacity);
})
.setSkipTimeMeasurement(true)) {}
private: private:
static std::unique_ptr<folly::EventBaseBackendBase> getBackend( static std::unique_ptr<folly::EventBaseBackendBase> getBackend(
......
...@@ -142,41 +142,23 @@ class EventBase::FunctionRunner ...@@ -142,41 +142,23 @@ class EventBase::FunctionRunner
* EventBase methods * EventBase methods
*/ */
EventBase::EventBase(bool enableTimeMeasurement) EventBase::EventBase(std::chrono::milliseconds tickInterval)
: runOnceCallbacks_(nullptr), : EventBase(Options().setTimerTickInterval(tickInterval)) {}
stop_(false),
loopThread_(),
queue_(nullptr),
fnRunner_(nullptr),
maxLatency_(0),
avgLoopTime_(std::chrono::seconds(2)),
maxLatencyLoopTime_(avgLoopTime_),
enableTimeMeasurement_(enableTimeMeasurement),
nextLoopCnt_(
std::size_t(-40)) // Early wrap-around so bugs will manifest soon
,
latestLoopCnt_(nextLoopCnt_),
startWork_(),
observer_(nullptr),
observerSampleCount_(0),
executionObserver_(nullptr) {
evb_ = getDefaultBackend();
VLOG(5) << "EventBase(): Created."; EventBase::EventBase(bool enableTimeMeasurement)
initNotificationQueue(); : EventBase(Options().setSkipTimeMeasurement(!enableTimeMeasurement)) {}
}
// takes ownership of the event_base // takes ownership of the event_base
EventBase::EventBase(event_base* evb, bool enableTimeMeasurement) EventBase::EventBase(event_base* evb, bool enableTimeMeasurement)
: EventBase( : EventBase(Options()
std::make_unique<EventBaseBackend>(evb), .setBackendFactory([evb] {
enableTimeMeasurement) {} return std::make_unique<EventBaseBackend>(evb);
})
// takes ownership of the backend .setSkipTimeMeasurement(!enableTimeMeasurement)) {}
EventBase::EventBase(
std::unique_ptr<EventBaseBackendBase>&& evb, EventBase::EventBase(Options options)
bool enableTimeMeasurement) : intervalDuration_(options.timerTickInterval),
: runOnceCallbacks_(nullptr), runOnceCallbacks_(nullptr),
stop_(false), stop_(false),
loopThread_(), loopThread_(),
queue_(nullptr), queue_(nullptr),
...@@ -184,7 +166,7 @@ EventBase::EventBase( ...@@ -184,7 +166,7 @@ EventBase::EventBase(
maxLatency_(0), maxLatency_(0),
avgLoopTime_(std::chrono::seconds(2)), avgLoopTime_(std::chrono::seconds(2)),
maxLatencyLoopTime_(avgLoopTime_), maxLatencyLoopTime_(avgLoopTime_),
enableTimeMeasurement_(enableTimeMeasurement), enableTimeMeasurement_(!options.skipTimeMeasurement),
nextLoopCnt_( nextLoopCnt_(
std::size_t(-40)) // Early wrap-around so bugs will manifest soon std::size_t(-40)) // Early wrap-around so bugs will manifest soon
, ,
...@@ -193,7 +175,8 @@ EventBase::EventBase( ...@@ -193,7 +175,8 @@ EventBase::EventBase(
observer_(nullptr), observer_(nullptr),
observerSampleCount_(0), observerSampleCount_(0),
executionObserver_(nullptr) { executionObserver_(nullptr) {
evb_ = evb ? std::move(evb) : getDefaultBackend(); evb_ =
options.backendFactory ? options.backendFactory() : getDefaultBackend();
initNotificationQueue(); initNotificationQueue();
} }
......
...@@ -282,6 +282,47 @@ class EventBase : public TimeoutManager, ...@@ -282,6 +282,47 @@ class EventBase : public TimeoutManager,
Function<void()> f_; Function<void()> f_;
}; };
struct Options {
Options() {}
/**
* Skip measuring event base loop durations.
*
* Disabling it would likely improve performance, but will disable some
* features that rely on time-measurement, including: observer, max latency
* and avg loop time.
*/
bool skipTimeMeasurement{false};
Options& setSkipTimeMeasurement(bool skip) {
skipTimeMeasurement = skip;
return *this;
}
/**
* Factory function for creating the backend.
*/
using BackendFactory =
folly::Function<std::unique_ptr<folly::EventBaseBackendBase>()>;
BackendFactory::SharedProxy backendFactory{nullptr};
Options& setBackendFactory(BackendFactory factoryFn) {
backendFactory = std::move(factoryFn).asSharedProxy();
return *this;
}
/**
* Granularity of the wheel timer in the EventBase.
*/
std::chrono::milliseconds timerTickInterval{
HHWheelTimer::DEFAULT_TICK_INTERVAL};
Options& setTimerTickInterval(std::chrono::milliseconds interval) {
timerTickInterval = interval;
return *this;
}
};
/** /**
* Create a new EventBase object. * Create a new EventBase object.
* *
...@@ -289,9 +330,7 @@ class EventBase : public TimeoutManager, ...@@ -289,9 +330,7 @@ class EventBase : public TimeoutManager,
* except that this also allows the timer granularity to be specified * except that this also allows the timer granularity to be specified
*/ */
explicit EventBase(std::chrono::milliseconds tickInterval) : EventBase(true) { explicit EventBase(std::chrono::milliseconds tickInterval);
intervalDuration_ = tickInterval;
}
/** /**
* Create a new EventBase object. * Create a new EventBase object.
...@@ -328,9 +367,8 @@ class EventBase : public TimeoutManager, ...@@ -328,9 +367,8 @@ class EventBase : public TimeoutManager,
* observer, max latency and avg loop time. * observer, max latency and avg loop time.
*/ */
explicit EventBase(event_base* evb, bool enableTimeMeasurement = true); explicit EventBase(event_base* evb, bool enableTimeMeasurement = true);
explicit EventBase(
std::unique_ptr<EventBaseBackendBase>&& evb, explicit EventBase(Options options);
bool enableTimeMeasurement = true);
~EventBase() override; ~EventBase() override;
/** /**
......
...@@ -66,7 +66,9 @@ EventBase* EventBaseManager::getEventBase() const { ...@@ -66,7 +66,9 @@ EventBase* EventBaseManager::getEventBase() const {
// have one? // have one?
auto* info = localStore_.get(); auto* info = localStore_.get();
if (!info) { if (!info) {
info = func_ ? new EventBaseInfo(func_()) : new EventBaseInfo(); auto evb = std::make_unique<EventBase>(
EventBase::Options().setBackendFactory(func_));
info = new EventBaseInfo(evb.release(), true);
localStore_.reset(info); localStore_.reset(info);
if (observer_) { if (observer_) {
......
...@@ -114,8 +114,6 @@ class EventBaseManager { ...@@ -114,8 +114,6 @@ class EventBaseManager {
private: private:
struct EventBaseInfo { struct EventBaseInfo {
EventBaseInfo(EventBase* evb, bool owned) : eventBase(evb), owned_(owned) {} EventBaseInfo(EventBase* evb, bool owned) : eventBase(evb), owned_(owned) {}
explicit EventBaseInfo(std::unique_ptr<EventBaseBackendBase>&& evb)
: eventBase(new EventBase(std::move(evb))), owned_(true) {}
EventBaseInfo() : eventBase(new EventBase), owned_(true) {} EventBaseInfo() : eventBase(new EventBase), owned_(true) {}
EventBase* eventBase; EventBase* eventBase;
......
...@@ -27,18 +27,14 @@ EventBaseThread::EventBaseThread( ...@@ -27,18 +27,14 @@ EventBaseThread::EventBaseThread(
bool autostart, bool autostart,
EventBaseManager* ebm, EventBaseManager* ebm,
folly::StringPiece threadName) folly::StringPiece threadName)
: ebm_(ebm) { : EventBaseThread(autostart, EventBase::Options(), ebm, threadName) {}
if (autostart) {
start(threadName);
}
}
EventBaseThread::EventBaseThread( EventBaseThread::EventBaseThread(
bool autostart, bool autostart,
std::unique_ptr<EventBaseBackendBase>&& evb, EventBase::Options eventBaseOptions,
EventBaseManager* ebm, EventBaseManager* ebm,
folly::StringPiece threadName) folly::StringPiece threadName)
: ebm_(ebm), evb_(std::move(evb)) { : ebm_(ebm), ebOpts_(std::move(eventBaseOptions)) {
if (autostart) { if (autostart) {
start(threadName); start(threadName);
} }
...@@ -65,8 +61,7 @@ void EventBaseThread::start(folly::StringPiece threadName) { ...@@ -65,8 +61,7 @@ void EventBaseThread::start(folly::StringPiece threadName) {
if (th_) { if (th_) {
return; return;
} }
th_ = std::make_unique<ScopedEventBaseThread>( th_ = std::make_unique<ScopedEventBaseThread>(ebOpts_, ebm_, threadName);
std::move(evb_), ebm_, threadName);
} }
void EventBaseThread::stop() { void EventBaseThread::stop() {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#pragma once #pragma once
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/io/async/EventBase.h>
#include <memory> #include <memory>
namespace folly { namespace folly {
...@@ -35,7 +36,7 @@ class EventBaseThread { ...@@ -35,7 +36,7 @@ class EventBaseThread {
folly::StringPiece threadName = folly::StringPiece()); folly::StringPiece threadName = folly::StringPiece());
EventBaseThread( EventBaseThread(
bool autostart, bool autostart,
std::unique_ptr<EventBaseBackendBase>&& evb, EventBase::Options eventBaseOptions,
EventBaseManager* ebm = nullptr, EventBaseManager* ebm = nullptr,
folly::StringPiece threadName = folly::StringPiece()); folly::StringPiece threadName = folly::StringPiece());
explicit EventBaseThread(EventBaseManager* ebm); explicit EventBaseThread(EventBaseManager* ebm);
...@@ -54,7 +55,7 @@ class EventBaseThread { ...@@ -54,7 +55,7 @@ class EventBaseThread {
private: private:
EventBaseManager* ebm_; EventBaseManager* ebm_;
std::unique_ptr<EventBaseBackendBase> evb_; EventBase::Options ebOpts_;
std::unique_ptr<ScopedEventBaseThread> th_; std::unique_ptr<ScopedEventBaseThread> th_;
}; };
} // namespace folly } // namespace folly
...@@ -58,17 +58,14 @@ ScopedEventBaseThread::ScopedEventBaseThread(EventBaseManager* ebm) ...@@ -58,17 +58,14 @@ ScopedEventBaseThread::ScopedEventBaseThread(EventBaseManager* ebm)
ScopedEventBaseThread::ScopedEventBaseThread( ScopedEventBaseThread::ScopedEventBaseThread(
EventBaseManager* ebm, EventBaseManager* ebm,
StringPiece name) StringPiece name)
: ScopedEventBaseThread( : ScopedEventBaseThread(EventBase::Options(), ebm, name) {}
std::unique_ptr<EventBaseBackendBase>(),
ebm,
name) {}
ScopedEventBaseThread::ScopedEventBaseThread( ScopedEventBaseThread::ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>&& backend, EventBase::Options eventBaseOptions,
EventBaseManager* ebm, EventBaseManager* ebm,
StringPiece name) StringPiece name)
: ebm_(ebm ? ebm : EventBaseManager::get()) { : ebm_(ebm ? ebm : EventBaseManager::get()) {
new (&eb_) EventBase(std::move(backend)); new (&eb_) EventBase(std::move(eventBaseOptions));
th_ = thread(run, ebm_, &eb_, &stop_, name); th_ = thread(run, ebm_, &eb_, &stop_, name);
eb_.waitUntilRunning(); eb_.waitUntilRunning();
} }
......
...@@ -42,8 +42,8 @@ class ScopedEventBaseThread : public IOExecutor, public SequencedExecutor { ...@@ -42,8 +42,8 @@ class ScopedEventBaseThread : public IOExecutor, public SequencedExecutor {
explicit ScopedEventBaseThread(StringPiece name); explicit ScopedEventBaseThread(StringPiece name);
explicit ScopedEventBaseThread(EventBaseManager* ebm); explicit ScopedEventBaseThread(EventBaseManager* ebm);
explicit ScopedEventBaseThread(EventBaseManager* ebm, StringPiece name); explicit ScopedEventBaseThread(EventBaseManager* ebm, StringPiece name);
explicit ScopedEventBaseThread( ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>&& backend, EventBase::Options eventBaseOptions,
EventBaseManager* ebm, EventBaseManager* ebm,
StringPiece name); StringPiece name);
~ScopedEventBaseThread(); ~ScopedEventBaseThread();
......
...@@ -19,10 +19,24 @@ ...@@ -19,10 +19,24 @@
#include <folly/io/async/test/Util.h> #include <folly/io/async/test/Util.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \ #define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \
auto backend = TypeParam::getBackend(); \ std::unique_ptr<EventBase> evb##Ptr; \
SKIP_IF(!backend) << "Backend not available"; \ try { \
EventBase evb(std::move(backend)) auto factory = [] { \
auto backend = TypeParam::getBackend(); \
if (!backend) { \
throw std::runtime_error("backend not available"); \
} \
return backend; \
}; \
evb##Ptr = std::make_unique<EventBase>( \
EventBase::Options().setBackendFactory(std::move(factory))); \
} catch (const std::runtime_error& e) { \
if (std::string("backend not available") == e.what()) { \
SKIP() << "Backend not available"; \
} \
} \
EventBase& evb = *evb##Ptr.get()
namespace folly { namespace folly {
namespace test { namespace test {
......
...@@ -35,10 +35,28 @@ ...@@ -35,10 +35,28 @@
#include <memory> #include <memory>
#include <thread> #include <thread>
#define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \ #define FOLLY_SKIP_IF_NULLPTR_BACKEND_WITH_OPTS(evb, opts) \
auto backend = TypeParam::getBackend(); \ std::unique_ptr<EventBase> evb##Ptr; \
SKIP_IF(!backend) << "Backend not available"; \ try { \
EventBase evb(std::move(backend)) auto factory = [] { \
auto backend = TypeParam::getBackend(); \
if (!backend) { \
throw std::runtime_error("backend not available"); \
} \
return backend; \
}; \
auto evbOpts = opts; \
evb##Ptr = std::make_unique<EventBase>( \
opts.setBackendFactory(std::move(factory))); \
} catch (const std::runtime_error& e) { \
if (std::string("backend not available") == e.what()) { \
SKIP() << "Backend not available"; \
} \
} \
EventBase& evb = *evb##Ptr.get()
#define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \
FOLLY_SKIP_IF_NULLPTR_BACKEND_WITH_OPTS(evb, EventBase::Options())
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Tests for read and write events // Tests for read and write events
...@@ -76,6 +94,27 @@ class EventBaseTest1 : public EventBaseTestBase { ...@@ -76,6 +94,27 @@ class EventBaseTest1 : public EventBaseTestBase {
EventBaseTest1() = default; EventBaseTest1() = default;
}; };
template <class Factory>
std::unique_ptr<EventBase> getEventBase(
folly::EventBase::Options opts = folly::EventBase::Options()) {
try {
auto factory = [] {
auto backend = Factory::getBackend();
if (!backend) {
throw std::runtime_error("backend not available");
}
return backend;
};
return std::make_unique<EventBase>(
opts.setBackendFactory(std::move(factory)));
} catch (const std::runtime_error& e) {
if (std::string("backend not available") == e.what()) {
return nullptr;
}
throw;
}
}
TYPED_TEST_CASE_P(EventBaseTest1); TYPED_TEST_CASE_P(EventBaseTest1);
enum { BUF_SIZE = 4096 }; enum { BUF_SIZE = 4096 };
...@@ -212,7 +251,9 @@ class TestHandler : public folly::EventHandler { ...@@ -212,7 +251,9 @@ class TestHandler : public folly::EventHandler {
* Test a READ event * Test a READ event
*/ */
TYPED_TEST_P(EventBaseTest, ReadEvent) { TYPED_TEST_P(EventBaseTest, ReadEvent) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Register for read events // Register for read events
...@@ -259,7 +300,9 @@ TYPED_TEST_P(EventBaseTest, ReadEvent) { ...@@ -259,7 +300,9 @@ TYPED_TEST_P(EventBaseTest, ReadEvent) {
* Test (READ | PERSIST) * Test (READ | PERSIST)
*/ */
TYPED_TEST_P(EventBaseTest, ReadPersist) { TYPED_TEST_P(EventBaseTest, ReadPersist) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Register for read events // Register for read events
...@@ -308,7 +351,9 @@ TYPED_TEST_P(EventBaseTest, ReadPersist) { ...@@ -308,7 +351,9 @@ TYPED_TEST_P(EventBaseTest, ReadPersist) {
* Test registering for READ when the socket is immediately readable * Test registering for READ when the socket is immediately readable
*/ */
TYPED_TEST_P(EventBaseTest, ReadImmediate) { TYPED_TEST_P(EventBaseTest, ReadImmediate) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Write some data to the socket so the other end will // Write some data to the socket so the other end will
...@@ -360,7 +405,9 @@ TYPED_TEST_P(EventBaseTest, ReadImmediate) { ...@@ -360,7 +405,9 @@ TYPED_TEST_P(EventBaseTest, ReadImmediate) {
* Test a WRITE event * Test a WRITE event
*/ */
TYPED_TEST_P(EventBaseTest, WriteEvent) { TYPED_TEST_P(EventBaseTest, WriteEvent) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -404,7 +451,9 @@ TYPED_TEST_P(EventBaseTest, WriteEvent) { ...@@ -404,7 +451,9 @@ TYPED_TEST_P(EventBaseTest, WriteEvent) {
* Test (WRITE | PERSIST) * Test (WRITE | PERSIST)
*/ */
TYPED_TEST_P(EventBaseTest, WritePersist) { TYPED_TEST_P(EventBaseTest, WritePersist) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -454,7 +503,9 @@ TYPED_TEST_P(EventBaseTest, WritePersist) { ...@@ -454,7 +503,9 @@ TYPED_TEST_P(EventBaseTest, WritePersist) {
* Test registering for WRITE when the socket is immediately writable * Test registering for WRITE when the socket is immediately writable
*/ */
TYPED_TEST_P(EventBaseTest, WriteImmediate) { TYPED_TEST_P(EventBaseTest, WriteImmediate) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Register for write events // Register for write events
...@@ -504,7 +555,9 @@ TYPED_TEST_P(EventBaseTest, WriteImmediate) { ...@@ -504,7 +555,9 @@ TYPED_TEST_P(EventBaseTest, WriteImmediate) {
* Test (READ | WRITE) when the socket becomes readable first * Test (READ | WRITE) when the socket becomes readable first
*/ */
TYPED_TEST_P(EventBaseTest, ReadWrite) { TYPED_TEST_P(EventBaseTest, ReadWrite) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -547,7 +600,9 @@ TYPED_TEST_P(EventBaseTest, ReadWrite) { ...@@ -547,7 +600,9 @@ TYPED_TEST_P(EventBaseTest, ReadWrite) {
* Test (READ | WRITE) when the socket becomes writable first * Test (READ | WRITE) when the socket becomes writable first
*/ */
TYPED_TEST_P(EventBaseTest, WriteRead) { TYPED_TEST_P(EventBaseTest, WriteRead) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -597,7 +652,9 @@ TYPED_TEST_P(EventBaseTest, WriteRead) { ...@@ -597,7 +652,9 @@ TYPED_TEST_P(EventBaseTest, WriteRead) {
* at the same time. * at the same time.
*/ */
TYPED_TEST_P(EventBaseTest, ReadWriteSimultaneous) { TYPED_TEST_P(EventBaseTest, ReadWriteSimultaneous) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -641,7 +698,9 @@ TYPED_TEST_P(EventBaseTest, ReadWriteSimultaneous) { ...@@ -641,7 +698,9 @@ TYPED_TEST_P(EventBaseTest, ReadWriteSimultaneous) {
* Test (READ | WRITE | PERSIST) * Test (READ | WRITE | PERSIST)
*/ */
TYPED_TEST_P(EventBaseTest, ReadWritePersist) { TYPED_TEST_P(EventBaseTest, ReadWritePersist) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Register for read and write events // Register for read and write events
...@@ -727,7 +786,9 @@ class PartialReadHandler : public TestHandler { ...@@ -727,7 +786,9 @@ class PartialReadHandler : public TestHandler {
* time around the loop. * time around the loop.
*/ */
TYPED_TEST_P(EventBaseTest, ReadPartial) { TYPED_TEST_P(EventBaseTest, ReadPartial) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Register for read events // Register for read events
...@@ -797,7 +858,9 @@ class PartialWriteHandler : public TestHandler { ...@@ -797,7 +858,9 @@ class PartialWriteHandler : public TestHandler {
* notified again the next time around the loop. * notified again the next time around the loop.
*/ */
TYPED_TEST_P(EventBaseTest, WritePartial) { TYPED_TEST_P(EventBaseTest, WritePartial) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -860,7 +923,9 @@ class DestroyHandler : public AsyncTimeout { ...@@ -860,7 +923,9 @@ class DestroyHandler : public AsyncTimeout {
* Test destroying a registered EventHandler * Test destroying a registered EventHandler
*/ */
TYPED_TEST_P(EventBaseTest, DestroyingHandler) { TYPED_TEST_P(EventBaseTest, DestroyingHandler) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
SocketPair sp; SocketPair sp;
// Fill up the write buffer before starting // Fill up the write buffer before starting
...@@ -899,7 +964,9 @@ TYPED_TEST_P(EventBaseTest, DestroyingHandler) { ...@@ -899,7 +964,9 @@ TYPED_TEST_P(EventBaseTest, DestroyingHandler) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
TYPED_TEST_P(EventBaseTest, RunAfterDelay) { TYPED_TEST_P(EventBaseTest, RunAfterDelay) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
TimePoint timestamp1(false); TimePoint timestamp1(false);
TimePoint timestamp2(false); TimePoint timestamp2(false);
...@@ -935,7 +1002,9 @@ TYPED_TEST_P(EventBaseTest, RunAfterDelayDestruction) { ...@@ -935,7 +1002,9 @@ TYPED_TEST_P(EventBaseTest, RunAfterDelayDestruction) {
TimePoint end(false); TimePoint end(false);
{ {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
start.reset(); start.reset();
// Run two normal timeouts // Run two normal timeouts
...@@ -979,7 +1048,9 @@ class TestTimeout : public AsyncTimeout { ...@@ -979,7 +1048,9 @@ class TestTimeout : public AsyncTimeout {
} // namespace } // namespace
TYPED_TEST_P(EventBaseTest, BasicTimeouts) { TYPED_TEST_P(EventBaseTest, BasicTimeouts) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
TestTimeout t1(&eb); TestTimeout t1(&eb);
TestTimeout t2(&eb); TestTimeout t2(&eb);
...@@ -1033,7 +1104,9 @@ class ReschedulingTimeout : public AsyncTimeout { ...@@ -1033,7 +1104,9 @@ class ReschedulingTimeout : public AsyncTimeout {
* Test rescheduling the same timeout multiple times * Test rescheduling the same timeout multiple times
*/ */
TYPED_TEST_P(EventBaseTest, ReuseTimeout) { TYPED_TEST_P(EventBaseTest, ReuseTimeout) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
std::vector<uint32_t> timeouts; std::vector<uint32_t> timeouts;
timeouts.push_back(10); timeouts.push_back(10);
...@@ -1065,7 +1138,9 @@ TYPED_TEST_P(EventBaseTest, ReuseTimeout) { ...@@ -1065,7 +1138,9 @@ TYPED_TEST_P(EventBaseTest, ReuseTimeout) {
* Test rescheduling a timeout before it has fired * Test rescheduling a timeout before it has fired
*/ */
TYPED_TEST_P(EventBaseTest, RescheduleTimeout) { TYPED_TEST_P(EventBaseTest, RescheduleTimeout) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
TestTimeout t1(&eb); TestTimeout t1(&eb);
TestTimeout t2(&eb); TestTimeout t2(&eb);
...@@ -1094,7 +1169,9 @@ TYPED_TEST_P(EventBaseTest, RescheduleTimeout) { ...@@ -1094,7 +1169,9 @@ TYPED_TEST_P(EventBaseTest, RescheduleTimeout) {
* Test cancelling a timeout * Test cancelling a timeout
*/ */
TYPED_TEST_P(EventBaseTest, CancelTimeout) { TYPED_TEST_P(EventBaseTest, CancelTimeout) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
std::vector<uint32_t> timeouts; std::vector<uint32_t> timeouts;
timeouts.push_back(10); timeouts.push_back(10);
...@@ -1134,7 +1211,9 @@ class DestroyTimeout : public AsyncTimeout { ...@@ -1134,7 +1211,9 @@ class DestroyTimeout : public AsyncTimeout {
* Test destroying a scheduled timeout object * Test destroying a scheduled timeout object
*/ */
TYPED_TEST_P(EventBaseTest, DestroyingTimeout) { TYPED_TEST_P(EventBaseTest, DestroyingTimeout) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
TestTimeout* t1 = new TestTimeout(&eb); TestTimeout* t1 = new TestTimeout(&eb);
TimePoint start; TimePoint start;
...@@ -1153,7 +1232,9 @@ TYPED_TEST_P(EventBaseTest, DestroyingTimeout) { ...@@ -1153,7 +1232,9 @@ TYPED_TEST_P(EventBaseTest, DestroyingTimeout) {
* Test the scheduled executor impl * Test the scheduled executor impl
*/ */
TYPED_TEST_P(EventBaseTest, ScheduledFn) { TYPED_TEST_P(EventBaseTest, ScheduledFn) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
TimePoint timestamp1(false); TimePoint timestamp1(false);
TimePoint timestamp2(false); TimePoint timestamp2(false);
...@@ -1176,7 +1257,9 @@ TYPED_TEST_P(EventBaseTest, ScheduledFn) { ...@@ -1176,7 +1257,9 @@ TYPED_TEST_P(EventBaseTest, ScheduledFn) {
} }
TYPED_TEST_P(EventBaseTest, ScheduledFnAt) { TYPED_TEST_P(EventBaseTest, ScheduledFnAt) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
TimePoint timestamp0(false); TimePoint timestamp0(false);
TimePoint timestamp1(false); TimePoint timestamp1(false);
...@@ -1215,10 +1298,11 @@ namespace { ...@@ -1215,10 +1298,11 @@ namespace {
struct RunInThreadData { struct RunInThreadData {
RunInThreadData( RunInThreadData(
std::unique_ptr<folly::EventBaseBackendBase>&& backend, folly::EventBaseBackendBase::FactoryFunc backendFactory,
int numThreads, int numThreads,
int opsPerThread_) int opsPerThread_)
: evb(std::move(backend)), : evb(folly::EventBase::Options().setBackendFactory(
std::move(backendFactory))),
opsPerThread(opsPerThread_), opsPerThread(opsPerThread_),
opsToGo(numThreads * opsPerThread) {} opsToGo(numThreads * opsPerThread) {}
...@@ -1256,7 +1340,8 @@ TYPED_TEST_P(EventBaseTest, RunInThread) { ...@@ -1256,7 +1340,8 @@ TYPED_TEST_P(EventBaseTest, RunInThread) {
constexpr uint32_t opsPerThread = 100; constexpr uint32_t opsPerThread = 100;
auto backend = TypeParam::getBackend(); auto backend = TypeParam::getBackend();
SKIP_IF(!backend) << "Backend not available"; SKIP_IF(!backend) << "Backend not available";
RunInThreadData data(std::move(backend), numThreads, opsPerThread); RunInThreadData data(
[] { return TypeParam::getBackend(); }, numThreads, opsPerThread);
std::deque<std::thread> threads; std::deque<std::thread> threads;
SCOPE_EXIT { SCOPE_EXIT {
...@@ -1320,18 +1405,16 @@ TYPED_TEST_P(EventBaseTest, RunInThread) { ...@@ -1320,18 +1405,16 @@ TYPED_TEST_P(EventBaseTest, RunInThread) {
TYPED_TEST_P(EventBaseTest, RunInEventBaseThreadAndWait) { TYPED_TEST_P(EventBaseTest, RunInEventBaseThreadAndWait) {
const size_t c = 256; const size_t c = 256;
std::vector<std::unique_ptr<std::atomic<size_t>>> atoms(c); std::vector<std::unique_ptr<std::atomic<size_t>>> atoms(c);
std::vector<std::unique_ptr<folly::EventBaseBackendBase>> backends(c);
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
auto& atom = atoms.at(i); auto& atom = atoms.at(i);
atom = std::make_unique<std::atomic<size_t>>(0); atom = std::make_unique<std::atomic<size_t>>(0);
auto backend = TypeParam::getBackend();
SKIP_IF(!backend) << i << " : Backend not available";
backends[i] = std::move(backend);
} }
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
threads.emplace_back([&atoms, &backends, i] { auto evbPtr = getEventBase<TypeParam>();
EventBase eb(std::move(backends[i])); SKIP_IF(!evbPtr) << "Backend not available";
threads.emplace_back([&atoms, i, evb = std::move(evbPtr)] {
folly::EventBase& eb = *evb;
auto& atom = *atoms.at(i); auto& atom = *atoms.at(i);
auto ebth = std::thread([&] { eb.loopForever(); }); auto ebth = std::thread([&] { eb.loopForever(); });
eb.waitUntilRunning(); eb.waitUntilRunning();
...@@ -1359,7 +1442,9 @@ TYPED_TEST_P(EventBaseTest, RunInEventBaseThreadAndWait) { ...@@ -1359,7 +1442,9 @@ TYPED_TEST_P(EventBaseTest, RunInEventBaseThreadAndWait) {
} }
TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) { TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
std::thread th(&EventBase::loopForever, &eb); std::thread th(&EventBase::loopForever, &eb);
SCOPE_EXIT { SCOPE_EXIT {
eb.terminateLoopSoon(); eb.terminateLoopSoon();
...@@ -1371,7 +1456,9 @@ TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) { ...@@ -1371,7 +1456,9 @@ TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) {
} }
TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) { TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
std::thread th(&EventBase::loopForever, &eb); std::thread th(&EventBase::loopForever, &eb);
SCOPE_EXIT { SCOPE_EXIT {
eb.terminateLoopSoon(); eb.terminateLoopSoon();
...@@ -1385,7 +1472,9 @@ TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) { ...@@ -1385,7 +1472,9 @@ TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) {
} }
TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadNotLooping) { TYPED_TEST_P(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadNotLooping) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eb = *evbPtr;
auto mutated = false; auto mutated = false;
eb.runImmediatelyOrRunInEventBaseThreadAndWait([&] { mutated = true; }); eb.runImmediatelyOrRunInEventBaseThreadAndWait([&] { mutated = true; });
EXPECT_TRUE(mutated); EXPECT_TRUE(mutated);
...@@ -1427,7 +1516,9 @@ class CountedLoopCallback : public EventBase::LoopCallback { ...@@ -1427,7 +1516,9 @@ class CountedLoopCallback : public EventBase::LoopCallback {
// Test that EventBase::loop() doesn't exit while there are // Test that EventBase::loop() doesn't exit while there are
// still LoopCallbacks remaining to be invoked. // still LoopCallbacks remaining to be invoked.
TYPED_TEST_P(EventBaseTest, RepeatedRunInLoop) { TYPED_TEST_P(EventBaseTest, RepeatedRunInLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eventBase); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eventBase = *evbPtr;
CountedLoopCallback c(&eventBase, 10); CountedLoopCallback c(&eventBase, 10);
eventBase.runInLoop(&c); eventBase.runInLoop(&c);
...@@ -1442,10 +1533,10 @@ TYPED_TEST_P(EventBaseTest, RepeatedRunInLoop) { ...@@ -1442,10 +1533,10 @@ TYPED_TEST_P(EventBaseTest, RepeatedRunInLoop) {
// Test that EventBase::loop() works as expected without time measurements. // Test that EventBase::loop() works as expected without time measurements.
TYPED_TEST_P(EventBaseTest, RunInLoopNoTimeMeasurement) { TYPED_TEST_P(EventBaseTest, RunInLoopNoTimeMeasurement) {
auto backend = TypeParam::getBackend(); auto evbPtr = getEventBase<TypeParam>(
SKIP_IF(!backend) << "Backend not available"; EventBase::Options().setSkipTimeMeasurement(true));
SKIP_IF(!evbPtr) << "Backend not available";
EventBase eventBase(std::move(backend), false); folly::EventBase& eventBase = *evbPtr;
CountedLoopCallback c(&eventBase, 10); CountedLoopCallback c(&eventBase, 10);
eventBase.runInLoop(&c); eventBase.runInLoop(&c);
...@@ -1460,7 +1551,9 @@ TYPED_TEST_P(EventBaseTest, RunInLoopNoTimeMeasurement) { ...@@ -1460,7 +1551,9 @@ TYPED_TEST_P(EventBaseTest, RunInLoopNoTimeMeasurement) {
// Test runInLoop() calls with terminateLoopSoon() // Test runInLoop() calls with terminateLoopSoon()
TYPED_TEST_P(EventBaseTest, RunInLoopStopLoop) { TYPED_TEST_P(EventBaseTest, RunInLoopStopLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eventBase); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
folly::EventBase& eventBase = *evbPtr;
CountedLoopCallback c1(&eventBase, 20); CountedLoopCallback c1(&eventBase, 20);
CountedLoopCallback c2( CountedLoopCallback c2(
...@@ -1488,44 +1581,45 @@ TYPED_TEST_P(EventBaseTest, RunInLoopStopLoop) { ...@@ -1488,44 +1581,45 @@ TYPED_TEST_P(EventBaseTest, RunInLoopStopLoop) {
} }
TYPED_TEST_P(EventBaseTest, messageAvailableException) { TYPED_TEST_P(EventBaseTest, messageAvailableException) {
auto backend = TypeParam::getBackend(); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!backend) << "Backend not available"; SKIP_IF(!evbPtr) << "Backend not available";
auto deadManWalking = [backend = std::move(backend)]() mutable {
EventBase eventBase(std::move(backend)); auto deadManWalking = [evb = std::move(evbPtr)]() mutable {
std::thread t([&] { std::thread t([&] {
// Call this from another thread to force use of NotificationQueue in // Call this from another thread to force use of NotificationQueue in
// runInEventBaseThread // runInEventBaseThread
eventBase.runInEventBaseThread( evb->runInEventBaseThread([]() { throw std::runtime_error("boom"); });
[]() { throw std::runtime_error("boom"); });
}); });
t.join(); t.join();
eventBase.loopForever(); evb->loopForever();
}; };
EXPECT_DEATH(deadManWalking(), ".*"); EXPECT_DEATH(deadManWalking(), ".*");
} }
TYPED_TEST_P(EventBaseTest, TryRunningAfterTerminate) { TYPED_TEST_P(EventBaseTest, TryRunningAfterTerminate) {
auto backend = TypeParam::getBackend(); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!backend) << "Backend not available"; SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& eventBase = *eventBasePtr;
bool ran = false; bool ran = false;
{ CountedLoopCallback c1(
EventBase eventBase(std::move(backend)); &eventBase, 1, std::bind(&EventBase::terminateLoopSoon, &eventBase));
CountedLoopCallback c1( eventBase.runInLoop(&c1);
&eventBase, 1, std::bind(&EventBase::terminateLoopSoon, &eventBase)); eventBase.loopForever();
eventBase.runInLoop(&c1); eventBase.runInEventBaseThread([&]() { ran = true; });
eventBase.loopForever();
eventBase.runInEventBaseThread([&]() { ran = true; }); ASSERT_FALSE(ran);
ASSERT_FALSE(ran); eventBasePtr.reset();
}
// Loop callbacks are triggered on EventBase destruction // Loop callbacks are triggered on EventBase destruction
ASSERT_TRUE(ran); ASSERT_TRUE(ran);
} }
// Test cancelling runInLoop() callbacks // Test cancelling runInLoop() callbacks
TYPED_TEST_P(EventBaseTest, CancelRunInLoop) { TYPED_TEST_P(EventBaseTest, CancelRunInLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eventBase); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& eventBase = *eventBasePtr;
CountedLoopCallback c1(&eventBase, 20); CountedLoopCallback c1(&eventBase, 20);
CountedLoopCallback c2(&eventBase, 20); CountedLoopCallback c2(&eventBase, 20);
...@@ -1646,7 +1740,9 @@ class TerminateTestCallback : public EventBase::LoopCallback, ...@@ -1646,7 +1740,9 @@ class TerminateTestCallback : public EventBase::LoopCallback,
* registered, but a loop callback installed a new fd handler. * registered, but a loop callback installed a new fd handler.
*/ */
TYPED_TEST_P(EventBaseTest, LoopTermination) { TYPED_TEST_P(EventBaseTest, LoopTermination) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eventBase); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& eventBase = *eventBasePtr;
// Open a pipe and close the write end, // Open a pipe and close the write end,
// so the read endpoint will be readable // so the read endpoint will be readable
...@@ -1675,7 +1771,9 @@ TYPED_TEST_P(EventBaseTest, LoopTermination) { ...@@ -1675,7 +1771,9 @@ TYPED_TEST_P(EventBaseTest, LoopTermination) {
TYPED_TEST_P(EventBaseTest, CallbackOrderTest) { TYPED_TEST_P(EventBaseTest, CallbackOrderTest) {
size_t num = 0; size_t num = 0;
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& evb = *eventBasePtr;
evb.runInEventBaseThread([&]() { evb.runInEventBaseThread([&]() {
std::thread t([&]() { std::thread t([&]() {
...@@ -1700,7 +1798,9 @@ TYPED_TEST_P(EventBaseTest, CallbackOrderTest) { ...@@ -1700,7 +1798,9 @@ TYPED_TEST_P(EventBaseTest, CallbackOrderTest) {
TYPED_TEST_P(EventBaseTest, AlwaysEnqueueCallbackOrderTest) { TYPED_TEST_P(EventBaseTest, AlwaysEnqueueCallbackOrderTest) {
size_t num = 0; size_t num = 0;
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& evb = *eventBasePtr;
evb.runInEventBaseThread([&]() { evb.runInEventBaseThread([&]() {
std::thread t([&]() { std::thread t([&]() {
...@@ -1726,7 +1826,9 @@ TYPED_TEST_P(EventBaseTest, AlwaysEnqueueCallbackOrderTest) { ...@@ -1726,7 +1826,9 @@ TYPED_TEST_P(EventBaseTest, AlwaysEnqueueCallbackOrderTest) {
TYPED_TEST_P(EventBaseTest1, InternalExternalCallbackOrderTest) { TYPED_TEST_P(EventBaseTest1, InternalExternalCallbackOrderTest) {
size_t counter = 0; size_t counter = 0;
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& evb = *eventBasePtr;
std::vector<size_t> calls; std::vector<size_t> calls;
...@@ -1801,7 +1903,9 @@ class IdleTimeTimeoutSeries : public AsyncTimeout { ...@@ -1801,7 +1903,9 @@ class IdleTimeTimeoutSeries : public AsyncTimeout {
* caused the loop time to decay. * caused the loop time to decay.
*/ */
TYPED_TEST_P(EventBaseTest, IdleTime) { TYPED_TEST_P(EventBaseTest, IdleTime) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eventBase); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& eventBase = *eventBasePtr;
std::deque<std::size_t> timeouts0(4, 8080); std::deque<std::size_t> timeouts0(4, 8080);
timeouts0.push_front(8000); timeouts0.push_front(8000);
timeouts0.push_back(14000); timeouts0.push_back(14000);
...@@ -1867,7 +1971,9 @@ TYPED_TEST_P(EventBaseTest, ThisLoop) { ...@@ -1867,7 +1971,9 @@ TYPED_TEST_P(EventBaseTest, ThisLoop) {
bool runThisLoop = false; bool runThisLoop = false;
{ {
FOLLY_SKIP_IF_NULLPTR_BACKEND(eb); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& eb = *eventBasePtr;
eb.runInLoop( eb.runInLoop(
[&]() { [&]() {
eb.terminateLoopSoon(); eb.terminateLoopSoon();
...@@ -1888,7 +1994,9 @@ TYPED_TEST_P(EventBaseTest, ThisLoop) { ...@@ -1888,7 +1994,9 @@ TYPED_TEST_P(EventBaseTest, ThisLoop) {
} }
TYPED_TEST_P(EventBaseTest, EventBaseThreadLoop) { TYPED_TEST_P(EventBaseTest, EventBaseThreadLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& base = *eventBasePtr;
bool ran = false; bool ran = false;
base.runInEventBaseThread([&]() { ran = true; }); base.runInEventBaseThread([&]() { ran = true; });
...@@ -1898,7 +2006,9 @@ TYPED_TEST_P(EventBaseTest, EventBaseThreadLoop) { ...@@ -1898,7 +2006,9 @@ TYPED_TEST_P(EventBaseTest, EventBaseThreadLoop) {
} }
TYPED_TEST_P(EventBaseTest, EventBaseThreadName) { TYPED_TEST_P(EventBaseTest, EventBaseThreadName) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& base = *eventBasePtr;
base.setName("foo"); base.setName("foo");
base.loop(); base.loop();
...@@ -1906,7 +2016,9 @@ TYPED_TEST_P(EventBaseTest, EventBaseThreadName) { ...@@ -1906,7 +2016,9 @@ TYPED_TEST_P(EventBaseTest, EventBaseThreadName) {
} }
TYPED_TEST_P(EventBaseTest, RunBeforeLoop) { TYPED_TEST_P(EventBaseTest, RunBeforeLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& base = *eventBasePtr;
CountedLoopCallback cb(&base, 1, [&]() { base.terminateLoopSoon(); }); CountedLoopCallback cb(&base, 1, [&]() { base.terminateLoopSoon(); });
base.runBeforeLoop(&cb); base.runBeforeLoop(&cb);
base.loopForever(); base.loopForever();
...@@ -1914,7 +2026,9 @@ TYPED_TEST_P(EventBaseTest, RunBeforeLoop) { ...@@ -1914,7 +2026,9 @@ TYPED_TEST_P(EventBaseTest, RunBeforeLoop) {
} }
TYPED_TEST_P(EventBaseTest, RunBeforeLoopWait) { TYPED_TEST_P(EventBaseTest, RunBeforeLoopWait) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& base = *eventBasePtr;
CountedLoopCallback cb(&base, 1); CountedLoopCallback cb(&base, 1);
base.tryRunAfterDelay([&]() { base.terminateLoopSoon(); }, 500); base.tryRunAfterDelay([&]() { base.terminateLoopSoon(); }, 500);
base.runBeforeLoop(&cb); base.runBeforeLoop(&cb);
...@@ -1937,7 +2051,9 @@ class PipeHandler : public EventHandler { ...@@ -1937,7 +2051,9 @@ class PipeHandler : public EventHandler {
} // namespace } // namespace
TYPED_TEST_P(EventBaseTest, StopBeforeLoop) { TYPED_TEST_P(EventBaseTest, StopBeforeLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& evb = *eventBasePtr;
// Give the evb something to do. // Give the evb something to do.
int p[2]; int p[2];
...@@ -1963,25 +2079,27 @@ TYPED_TEST_P(EventBaseTest, RunCallbacksOnDestruction) { ...@@ -1963,25 +2079,27 @@ TYPED_TEST_P(EventBaseTest, RunCallbacksOnDestruction) {
bool ran = false; bool ran = false;
{ {
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto eventBasePtr = getEventBase<TypeParam>();
base.runInEventBaseThread([&]() { ran = true; }); SKIP_IF(!eventBasePtr) << "Backend not available";
eventBasePtr->runInEventBaseThread([&]() { ran = true; });
} }
ASSERT_TRUE(ran); ASSERT_TRUE(ran);
} }
TYPED_TEST_P(EventBaseTest, LoopKeepAlive) { TYPED_TEST_P(EventBaseTest, LoopKeepAlive) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
bool done = false; bool done = false;
std::thread t([&, loopKeepAlive = getKeepAliveToken(evb)]() mutable { std::thread t([&, loopKeepAlive = getKeepAliveToken(*evbPtr)]() mutable {
/* sleep override */ std::this_thread::sleep_for( /* sleep override */ std::this_thread::sleep_for(
std::chrono::milliseconds(100)); std::chrono::milliseconds(100));
evb.runInEventBaseThread( evbPtr->runInEventBaseThread(
[&done, loopKeepAlive = std::move(loopKeepAlive)] { done = true; }); [&done, loopKeepAlive = std::move(loopKeepAlive)] { done = true; });
}); });
evb.loop(); evbPtr->loop();
ASSERT_TRUE(done); ASSERT_TRUE(done);
...@@ -1989,21 +2107,22 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAlive) { ...@@ -1989,21 +2107,22 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAlive) {
} }
TYPED_TEST_P(EventBaseTest, LoopKeepAliveInLoop) { TYPED_TEST_P(EventBaseTest, LoopKeepAliveInLoop) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
bool done = false; bool done = false;
std::thread t; std::thread t;
evb.runInEventBaseThread([&] { evbPtr->runInEventBaseThread([&] {
t = std::thread([&, loopKeepAlive = getKeepAliveToken(evb)]() mutable { t = std::thread([&, loopKeepAlive = getKeepAliveToken(*evbPtr)]() mutable {
/* sleep override */ std::this_thread::sleep_for( /* sleep override */ std::this_thread::sleep_for(
std::chrono::milliseconds(100)); std::chrono::milliseconds(100));
evb.runInEventBaseThread( evbPtr->runInEventBaseThread(
[&done, loopKeepAlive = std::move(loopKeepAlive)] { done = true; }); [&done, loopKeepAlive = std::move(loopKeepAlive)] { done = true; });
}); });
}); });
evb.loop(); evbPtr->loop();
ASSERT_TRUE(done); ASSERT_TRUE(done);
...@@ -2011,21 +2130,19 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveInLoop) { ...@@ -2011,21 +2130,19 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveInLoop) {
} }
TYPED_TEST_P(EventBaseTest, LoopKeepAliveWithLoopForever) { TYPED_TEST_P(EventBaseTest, LoopKeepAliveWithLoopForever) {
auto backend = TypeParam::getBackend(); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!backend) << "Backend not available"; SKIP_IF(!evbPtr) << "Backend not available";
std::unique_ptr<EventBase> evb =
std::make_unique<EventBase>(std::move(backend));
bool done = false; bool done = false;
std::thread evThread([&] { std::thread evThread([&] {
evb->loopForever(); evbPtr->loopForever();
evb.reset(); evbPtr.reset();
done = true; done = true;
}); });
{ {
auto* ev = evb.get(); auto* ev = evbPtr.get();
Executor::KeepAlive<EventBase> keepAlive; Executor::KeepAlive<EventBase> keepAlive;
ev->runInEventBaseThreadAndWait( ev->runInEventBaseThreadAndWait(
[&ev, &keepAlive] { keepAlive = getKeepAliveToken(ev); }); [&ev, &keepAlive] { keepAlive = getKeepAliveToken(ev); });
...@@ -2042,23 +2159,21 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveWithLoopForever) { ...@@ -2042,23 +2159,21 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveWithLoopForever) {
} }
TYPED_TEST_P(EventBaseTest, LoopKeepAliveShutdown) { TYPED_TEST_P(EventBaseTest, LoopKeepAliveShutdown) {
auto backend = TypeParam::getBackend(); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!backend) << "Backend not available"; SKIP_IF(!evbPtr) << "Backend not available";
auto evb = std::make_unique<EventBase>(std::move(backend));
bool done = false; bool done = false;
std::thread t([&done, std::thread t([&done,
loopKeepAlive = getKeepAliveToken(evb.get()), loopKeepAlive = getKeepAliveToken(evbPtr.get()),
evbPtr = evb.get()]() mutable { evbPtrRaw = evbPtr.get()]() mutable {
/* sleep override */ std::this_thread::sleep_for( /* sleep override */ std::this_thread::sleep_for(
std::chrono::milliseconds(100)); std::chrono::milliseconds(100));
evbPtr->runInEventBaseThread( evbPtrRaw->runInEventBaseThread(
[&done, loopKeepAlive = std::move(loopKeepAlive)] { done = true; }); [&done, loopKeepAlive = std::move(loopKeepAlive)] { done = true; });
}); });
evb.reset(); evbPtr.reset();
ASSERT_TRUE(done); ASSERT_TRUE(done);
...@@ -2066,9 +2181,8 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveShutdown) { ...@@ -2066,9 +2181,8 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveShutdown) {
} }
TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) { TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) {
auto backend = TypeParam::getBackend(); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!backend) << "Backend not available"; SKIP_IF(!evbPtr) << "Backend not available";
auto evb = std::make_unique<EventBase>(std::move(backend));
static constexpr size_t kNumThreads = 100; static constexpr size_t kNumThreads = 100;
static constexpr size_t kNumTasks = 100; static constexpr size_t kNumTasks = 100;
...@@ -2082,10 +2196,12 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) { ...@@ -2082,10 +2196,12 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) {
} }
for (size_t i = 0; i < kNumThreads; ++i) { for (size_t i = 0; i < kNumThreads; ++i) {
ts.emplace_back([evbPtr = evb.get(), batonPtr = batons[i].get(), &done] { ts.emplace_back([evbPtrRaw = evbPtr.get(),
batonPtr = batons[i].get(),
&done] {
std::vector<Executor::KeepAlive<EventBase>> keepAlives; std::vector<Executor::KeepAlive<EventBase>> keepAlives;
for (size_t j = 0; j < kNumTasks; ++j) { for (size_t j = 0; j < kNumTasks; ++j) {
keepAlives.emplace_back(getKeepAliveToken(evbPtr)); keepAlives.emplace_back(getKeepAliveToken(evbPtrRaw));
} }
batonPtr->post(); batonPtr->post();
...@@ -2093,7 +2209,7 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) { ...@@ -2093,7 +2209,7 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) {
/* sleep override */ std::this_thread::sleep_for(std::chrono::seconds(1)); /* sleep override */ std::this_thread::sleep_for(std::chrono::seconds(1));
for (auto& keepAlive : keepAlives) { for (auto& keepAlive : keepAlives) {
evbPtr->runInEventBaseThread( evbPtrRaw->runInEventBaseThread(
[&done, keepAlive = std::move(keepAlive)]() { ++done; }); [&done, keepAlive = std::move(keepAlive)]() { ++done; });
} }
}); });
...@@ -2103,7 +2219,7 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) { ...@@ -2103,7 +2219,7 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) {
baton->wait(); baton->wait();
} }
evb.reset(); evbPtr.reset();
EXPECT_EQ(kNumThreads * kNumTasks, done); EXPECT_EQ(kNumThreads * kNumTasks, done);
...@@ -2113,14 +2229,17 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) { ...@@ -2113,14 +2229,17 @@ TYPED_TEST_P(EventBaseTest, LoopKeepAliveAtomic) {
} }
TYPED_TEST_P(EventBaseTest, LoopKeepAliveCast) { TYPED_TEST_P(EventBaseTest, LoopKeepAliveCast) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
Executor::KeepAlive<> keepAlive = getKeepAliveToken(evb); SKIP_IF(!evbPtr) << "Backend not available";
Executor::KeepAlive<> keepAlive = getKeepAliveToken(*evbPtr);
} }
TYPED_TEST_P(EventBaseTest1, DrivableExecutorTest) { TYPED_TEST_P(EventBaseTest1, DrivableExecutorTest) {
folly::Promise<bool> p; folly::Promise<bool> p;
auto f = p.getFuture(); auto f = p.getFuture();
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto eventBasePtr = getEventBase<TypeParam>();
SKIP_IF(!eventBasePtr) << "Backend not available";
folly::EventBase& base = *eventBasePtr;
bool finished = false; bool finished = false;
std::thread t([&] { std::thread t([&] {
...@@ -2147,14 +2266,16 @@ TYPED_TEST_P(EventBaseTest1, DrivableExecutorTest) { ...@@ -2147,14 +2266,16 @@ TYPED_TEST_P(EventBaseTest1, DrivableExecutorTest) {
} }
TYPED_TEST_P(EventBaseTest1, IOExecutorTest) { TYPED_TEST_P(EventBaseTest1, IOExecutorTest) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(base); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
// Ensure EventBase manages itself as an IOExecutor. // Ensure EventBase manages itself as an IOExecutor.
EXPECT_EQ(base.getEventBase(), &base); EXPECT_EQ(evbPtr->getEventBase(), evbPtr.get());
} }
TYPED_TEST_P(EventBaseTest1, RequestContextTest) { TYPED_TEST_P(EventBaseTest1, RequestContextTest) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
auto defaultCtx = RequestContext::get(); auto defaultCtx = RequestContext::get();
std::weak_ptr<RequestContext> rctx_weak_ptr; std::weak_ptr<RequestContext> rctx_weak_ptr;
...@@ -2163,8 +2284,8 @@ TYPED_TEST_P(EventBaseTest1, RequestContextTest) { ...@@ -2163,8 +2284,8 @@ TYPED_TEST_P(EventBaseTest1, RequestContextTest) {
rctx_weak_ptr = RequestContext::saveContext(); rctx_weak_ptr = RequestContext::saveContext();
auto context = RequestContext::get(); auto context = RequestContext::get();
EXPECT_NE(defaultCtx, context); EXPECT_NE(defaultCtx, context);
evb.runInLoop([context] { EXPECT_EQ(context, RequestContext::get()); }); evbPtr->runInLoop([context] { EXPECT_EQ(context, RequestContext::get()); });
evb.loop(); evbPtr->loop();
} }
// Ensure that RequestContext created for the scope has been released and // Ensure that RequestContext created for the scope has been released and
...@@ -2175,8 +2296,9 @@ TYPED_TEST_P(EventBaseTest1, RequestContextTest) { ...@@ -2175,8 +2296,9 @@ TYPED_TEST_P(EventBaseTest1, RequestContextTest) {
} }
TYPED_TEST_P(EventBaseTest1, CancelLoopCallbackRequestContextTest) { TYPED_TEST_P(EventBaseTest1, CancelLoopCallbackRequestContextTest) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
CountedLoopCallback c(&evb, 1); SKIP_IF(!evbPtr) << "Backend not available";
CountedLoopCallback c(evbPtr.get(), 1);
auto defaultCtx = RequestContext::get(); auto defaultCtx = RequestContext::get();
EXPECT_EQ(defaultCtx, RequestContext::get()); EXPECT_EQ(defaultCtx, RequestContext::get());
...@@ -2187,7 +2309,7 @@ TYPED_TEST_P(EventBaseTest1, CancelLoopCallbackRequestContextTest) { ...@@ -2187,7 +2309,7 @@ TYPED_TEST_P(EventBaseTest1, CancelLoopCallbackRequestContextTest) {
rctx_weak_ptr = RequestContext::saveContext(); rctx_weak_ptr = RequestContext::saveContext();
auto context = RequestContext::get(); auto context = RequestContext::get();
EXPECT_NE(defaultCtx, context); EXPECT_NE(defaultCtx, context);
evb.runInLoop(&c); evbPtr->runInLoop(&c);
c.cancelLoopCallback(); c.cancelLoopCallback();
} }
...@@ -2199,13 +2321,15 @@ TYPED_TEST_P(EventBaseTest1, CancelLoopCallbackRequestContextTest) { ...@@ -2199,13 +2321,15 @@ TYPED_TEST_P(EventBaseTest1, CancelLoopCallbackRequestContextTest) {
} }
TYPED_TEST_P(EventBaseTest1, TestStarvation) { TYPED_TEST_P(EventBaseTest1, TestStarvation) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
std::promise<void> stopRequested; std::promise<void> stopRequested;
std::promise<void> stopScheduled; std::promise<void> stopScheduled;
bool stopping{false}; bool stopping{false};
std::thread t{[&] { std::thread t{[&] {
stopRequested.get_future().get(); stopRequested.get_future().get();
evb.add([&]() { stopping = true; }); evbPtr->add([&]() { stopping = true; });
stopScheduled.set_value(); stopScheduled.set_value();
}}; }};
...@@ -2221,11 +2345,11 @@ TYPED_TEST_P(EventBaseTest1, TestStarvation) { ...@@ -2221,11 +2345,11 @@ TYPED_TEST_P(EventBaseTest1, TestStarvation) {
stopScheduled.get_future().get(); stopScheduled.get_future().get();
} }
evb.add(fn); evbPtr->add(fn);
}; };
evb.add(fn); evbPtr->add(fn);
evb.loop(); evbPtr->loop();
EXPECT_EQ(1000, num); EXPECT_EQ(1000, num);
t.join(); t.join();
...@@ -2234,8 +2358,9 @@ TYPED_TEST_P(EventBaseTest1, TestStarvation) { ...@@ -2234,8 +2358,9 @@ TYPED_TEST_P(EventBaseTest1, TestStarvation) {
TYPED_TEST_P(EventBaseTest1, RunOnDestructionBasic) { TYPED_TEST_P(EventBaseTest1, RunOnDestructionBasic) {
bool ranOnDestruction = false; bool ranOnDestruction = false;
{ {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
evb.runOnDestruction([&ranOnDestruction] { ranOnDestruction = true; }); SKIP_IF(!evbPtr) << "Backend not available";
evbPtr->runOnDestruction([&ranOnDestruction] { ranOnDestruction = true; });
} }
EXPECT_TRUE(ranOnDestruction); EXPECT_TRUE(ranOnDestruction);
} }
...@@ -2251,8 +2376,9 @@ TYPED_TEST_P(EventBaseTest1, RunOnDestructionCancelled) { ...@@ -2251,8 +2376,9 @@ TYPED_TEST_P(EventBaseTest1, RunOnDestructionCancelled) {
auto cb = std::make_unique<Callback>(); auto cb = std::make_unique<Callback>();
{ {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
evb.runOnDestruction(*cb); SKIP_IF(!evbPtr) << "Backend not available";
evbPtr->runOnDestruction(*cb);
EXPECT_TRUE(cb->cancel()); EXPECT_TRUE(cb->cancel());
} }
EXPECT_FALSE(cb->ranOnDestruction); EXPECT_FALSE(cb->ranOnDestruction);
...@@ -2260,12 +2386,13 @@ TYPED_TEST_P(EventBaseTest1, RunOnDestructionCancelled) { ...@@ -2260,12 +2386,13 @@ TYPED_TEST_P(EventBaseTest1, RunOnDestructionCancelled) {
} }
TYPED_TEST_P(EventBaseTest1, RunOnDestructionAfterHandleDestroyed) { TYPED_TEST_P(EventBaseTest1, RunOnDestructionAfterHandleDestroyed) {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
SKIP_IF(!evbPtr) << "Backend not available";
{ {
bool ranOnDestruction = false; bool ranOnDestruction = false;
auto* cb = new EventBase::FunctionOnDestructionCallback( auto* cb = new EventBase::FunctionOnDestructionCallback(
[&ranOnDestruction] { ranOnDestruction = true; }); [&ranOnDestruction] { ranOnDestruction = true; });
evb.runOnDestruction(*cb); evbPtr->runOnDestruction(*cb);
EXPECT_TRUE(cb->cancel()); EXPECT_TRUE(cb->cancel());
delete cb; delete cb;
} }
...@@ -2274,10 +2401,11 @@ TYPED_TEST_P(EventBaseTest1, RunOnDestructionAfterHandleDestroyed) { ...@@ -2274,10 +2401,11 @@ TYPED_TEST_P(EventBaseTest1, RunOnDestructionAfterHandleDestroyed) {
TYPED_TEST_P(EventBaseTest1, RunOnDestructionAddCallbackWithinCallback) { TYPED_TEST_P(EventBaseTest1, RunOnDestructionAddCallbackWithinCallback) {
size_t callbacksCalled = 0; size_t callbacksCalled = 0;
{ {
FOLLY_SKIP_IF_NULLPTR_BACKEND(evb); auto evbPtr = getEventBase<TypeParam>();
evb.runOnDestruction([&] { SKIP_IF(!evbPtr) << "Backend not available";
evbPtr->runOnDestruction([&] {
++callbacksCalled; ++callbacksCalled;
evb.runOnDestruction([&] { ++callbacksCalled; }); evbPtr->runOnDestruction([&] { ++callbacksCalled; });
}); });
} }
EXPECT_EQ(2, callbacksCalled); EXPECT_EQ(2, callbacksCalled);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment