Commit 4f6b9926 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Sara Golemon

Lift thrift/lib/cpp/test/TNotificationQueueTest.

Summary: [Folly] Lift thrift/lib/cpp/test/TNotificationQueueTest.

`NotificationQueue` is already moved into folly; move its accompanying test suite as well.

Reviewed By: @simpkins

Differential Revision: D2207104
parent 4a0bffd8
...@@ -201,6 +201,7 @@ nobase_follyinclude_HEADERS = \ ...@@ -201,6 +201,7 @@ nobase_follyinclude_HEADERS = \
io/async/HHWheelTimer.h \ io/async/HHWheelTimer.h \
io/async/Request.h \ io/async/Request.h \
io/async/SSLContext.h \ io/async/SSLContext.h \
io/async/ScopedEventBaseThread.h \
io/async/TimeoutManager.h \ io/async/TimeoutManager.h \
io/async/test/AsyncSSLSocketTest.h \ io/async/test/AsyncSSLSocketTest.h \
io/async/test/BlockingSocket.h \ io/async/test/BlockingSocket.h \
...@@ -385,6 +386,7 @@ libfolly_la_SOURCES = \ ...@@ -385,6 +386,7 @@ libfolly_la_SOURCES = \
io/async/EventBaseManager.cpp \ io/async/EventBaseManager.cpp \
io/async/EventHandler.cpp \ io/async/EventHandler.cpp \
io/async/SSLContext.cpp \ io/async/SSLContext.cpp \
io/async/ScopedEventBaseThread.cpp \
io/async/HHWheelTimer.cpp \ io/async/HHWheelTimer.cpp \
io/async/test/TimeUtil.cpp \ io/async/test/TimeUtil.cpp \
json.cpp \ json.cpp \
......
...@@ -120,7 +120,7 @@ class NotificationQueue { ...@@ -120,7 +120,7 @@ class NotificationQueue {
* @returns true if the queue was drained, false otherwise. In practice, * @returns true if the queue was drained, false otherwise. In practice,
* this will only fail if someone else is already draining the queue. * this will only fail if someone else is already draining the queue.
*/ */
bool consumeUntilDrained() noexcept; bool consumeUntilDrained(size_t* numConsumed = nullptr) noexcept;
/** /**
* Get the NotificationQueue that this consumer is currently consuming * Get the NotificationQueue that this consumer is currently consuming
...@@ -165,7 +165,7 @@ class NotificationQueue { ...@@ -165,7 +165,7 @@ class NotificationQueue {
* *
* (1) Well, maybe. See logic/comments around "wasEmpty" in implementation. * (1) Well, maybe. See logic/comments around "wasEmpty" in implementation.
*/ */
void consumeMessages(bool isDrain) noexcept; void consumeMessages(bool isDrain, size_t* numConsumed = nullptr) noexcept;
void setActive(bool active, bool shouldLock = false) { void setActive(bool active, bool shouldLock = false) {
if (!queue_) { if (!queue_) {
...@@ -595,11 +595,16 @@ void NotificationQueue<MessageT>::Consumer::handlerReady(uint16_t events) ...@@ -595,11 +595,16 @@ void NotificationQueue<MessageT>::Consumer::handlerReady(uint16_t events)
template<typename MessageT> template<typename MessageT>
void NotificationQueue<MessageT>::Consumer::consumeMessages( void NotificationQueue<MessageT>::Consumer::consumeMessages(
bool isDrain) noexcept { bool isDrain, size_t* numConsumed) noexcept {
uint32_t numProcessed = 0; uint32_t numProcessed = 0;
bool firstRun = true; bool firstRun = true;
setActive(true); setActive(true);
SCOPE_EXIT { setActive(false, /* shouldLock = */ true); }; SCOPE_EXIT { setActive(false, /* shouldLock = */ true); };
SCOPE_EXIT {
if (numConsumed != nullptr) {
*numConsumed = numProcessed;
}
};
while (true) { while (true) {
// Try to decrement the eventfd. // Try to decrement the eventfd.
// //
...@@ -760,7 +765,8 @@ void NotificationQueue<MessageT>::Consumer::stopConsuming() { ...@@ -760,7 +765,8 @@ void NotificationQueue<MessageT>::Consumer::stopConsuming() {
} }
template<typename MessageT> template<typename MessageT>
bool NotificationQueue<MessageT>::Consumer::consumeUntilDrained() noexcept { bool NotificationQueue<MessageT>::Consumer::consumeUntilDrained(
size_t* numConsumed) noexcept {
{ {
folly::SpinLockGuard g(queue_->spinlock_); folly::SpinLockGuard g(queue_->spinlock_);
if (queue_->draining_) { if (queue_->draining_) {
...@@ -768,7 +774,7 @@ bool NotificationQueue<MessageT>::Consumer::consumeUntilDrained() noexcept { ...@@ -768,7 +774,7 @@ bool NotificationQueue<MessageT>::Consumer::consumeUntilDrained() noexcept {
} }
queue_->draining_ = true; queue_->draining_ = true;
} }
consumeMessages(true); consumeMessages(true, numConsumed);
{ {
folly::SpinLockGuard g(queue_->spinlock_); folly::SpinLockGuard g(queue_->spinlock_);
queue_->draining_ = false; queue_->draining_ = false;
......
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/io/async/ScopedEventBaseThread.h>
#include <thread>
#include <folly/Memory.h>
using namespace std;
namespace folly {
ScopedEventBaseThread::ScopedEventBaseThread(bool autostart) {
if (autostart) {
start();
}
}
ScopedEventBaseThread::~ScopedEventBaseThread() {
stop();
}
ScopedEventBaseThread::ScopedEventBaseThread(
ScopedEventBaseThread&& other) noexcept = default;
ScopedEventBaseThread& ScopedEventBaseThread::operator=(
ScopedEventBaseThread&& other) noexcept = default;
void ScopedEventBaseThread::start() {
if (running()) {
return;
}
eventBase_ = make_unique<EventBase>();
thread_ = make_unique<thread>(&EventBase::loopForever, &*eventBase_);
eventBase_->waitUntilRunning();
}
void ScopedEventBaseThread::stop() {
if (!running()) {
return;
}
eventBase_->terminateLoopSoon();
thread_->join();
eventBase_ = nullptr;
thread_ = nullptr;
}
bool ScopedEventBaseThread::running() {
CHECK(bool(eventBase_) == bool(thread_));
return eventBase_ && thread_;
}
}
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include <folly/io/async/EventBase.h>
namespace std {
class thread;
}
namespace folly {
/**
* A helper class to start a new thread running a TEventBase loop.
*
* The new thread will be started by the ScopedEventBaseThread constructor.
* When the ScopedEventBaseThread object is destroyed, the thread will be
* stopped.
*/
class ScopedEventBaseThread {
public:
explicit ScopedEventBaseThread(bool autostart = true);
~ScopedEventBaseThread();
ScopedEventBaseThread(ScopedEventBaseThread&& other) noexcept;
ScopedEventBaseThread &operator=(ScopedEventBaseThread&& other) noexcept;
/**
* Get a pointer to the TEventBase driving this thread.
*/
EventBase* getEventBase() const {
return eventBase_.get();
}
void start();
void stop();
bool running();
private:
ScopedEventBaseThread(const ScopedEventBaseThread& other) = delete;
ScopedEventBaseThread& operator=(const ScopedEventBaseThread& other) = delete;
std::unique_ptr<EventBase> eventBase_;
std::unique_ptr<std::thread> thread_;
};
}
This diff is collapsed.
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/io/async/ScopedEventBaseThread.h>
#include <chrono>
#include <folly/Baton.h>
#include <gtest/gtest.h>
using namespace std;
using namespace std::chrono;
using namespace folly;
class ScopedEventBaseThreadTest : public testing::Test {};
TEST_F(ScopedEventBaseThreadTest, example) {
ScopedEventBaseThread sebt;
Baton<> done;
sebt.getEventBase()->runInEventBaseThread([&] { done.post(); });
done.timed_wait(steady_clock::now() + milliseconds(100));
}
TEST_F(ScopedEventBaseThreadTest, start_stop) {
ScopedEventBaseThread sebt(false);
for (size_t i = 0; i < 4; ++i) {
EXPECT_EQ(nullptr, sebt.getEventBase());
sebt.start();
EXPECT_NE(nullptr, sebt.getEventBase());
Baton<> done;
sebt.getEventBase()->runInEventBaseThread([&] { done.post(); });
done.timed_wait(steady_clock::now() + milliseconds(100));
EXPECT_NE(nullptr, sebt.getEventBase());
sebt.stop();
EXPECT_EQ(nullptr, sebt.getEventBase());
}
}
TEST_F(ScopedEventBaseThreadTest, move) {
auto sebt0 = ScopedEventBaseThread();
auto sebt1 = std::move(sebt0);
auto sebt2 = std::move(sebt1);
EXPECT_EQ(nullptr, sebt0.getEventBase());
EXPECT_EQ(nullptr, sebt1.getEventBase());
EXPECT_NE(nullptr, sebt2.getEventBase());
Baton<> done;
sebt2.getEventBase()->runInEventBaseThread([&] { done.post(); });
done.timed_wait(steady_clock::now() + milliseconds(100));
}
TEST_F(ScopedEventBaseThreadTest, self_move) {
ScopedEventBaseThread sebt;
sebt = std::move(sebt);
EXPECT_NE(nullptr, sebt.getEventBase());
Baton<> done;
sebt.getEventBase()->runInEventBaseThread([&] { done.post(); });
done.timed_wait(steady_clock::now() + milliseconds(100));
}
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