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