Commit 0a2b61fd authored by Martin Martin's avatar Martin Martin Committed by Facebook Github Bot 0

Clang-format in preparation for other change

Summary: Clang-format in preparation for other change

Reviewed By: andriigrynenko

Differential Revision: D3241297

fb-gh-sync-id: b7b26812e9e61c291d5c7bdb523df8f28f2d9b4f
fbshipit-source-id: b7b26812e9e61c291d5c7bdb523df8f28f2d9b4f
parent 78b48f15
...@@ -18,18 +18,16 @@ ...@@ -18,18 +18,16 @@
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
template <typename T> template <typename T>
TaskIterator<T>::TaskIterator(TaskIterator&& other) noexcept TaskIterator<T>::TaskIterator(TaskIterator&& other) noexcept
: context_(std::move(other.context_)), : context_(std::move(other.context_)), id_(other.id_) {}
id_(other.id_) {
}
template <typename T> template <typename T>
TaskIterator<T>::TaskIterator(std::shared_ptr<Context> context) TaskIterator<T>::TaskIterator(std::shared_ptr<Context> context)
: context_(std::move(context)), : context_(std::move(context)), id_(-1) {
id_(-1) {
assert(context_); assert(context_);
} }
...@@ -82,11 +80,10 @@ inline void TaskIterator<T>::reserve(size_t n) { ...@@ -82,11 +80,10 @@ inline void TaskIterator<T>::reserve(size_t n) {
size_t tasksLeft = context_->totalTasks - context_->results.size(); size_t tasksLeft = context_->totalTasks - context_->results.size();
n = std::min(n, tasksLeft); n = std::min(n, tasksLeft);
await( await([this, n](Promise<void> promise) {
[this, n](Promise<void> promise) { context_->tasksToFulfillPromise = n;
context_->tasksToFulfillPromise = n; context_->promise.assign(std::move(promise));
context_->promise.assign(std::move(promise)); });
});
} }
template <typename T> template <typename T>
...@@ -97,10 +94,10 @@ inline size_t TaskIterator<T>::getTaskID() const { ...@@ -97,10 +94,10 @@ inline size_t TaskIterator<T>::getTaskID() const {
template <class InputIterator> template <class InputIterator>
TaskIterator<typename std::result_of< TaskIterator<typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type> typename std::iterator_traits<InputIterator>::value_type()>::type>
addTasks(InputIterator first, InputIterator last) { addTasks(InputIterator first, InputIterator last) {
typedef typename std::result_of< typedef typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type typename std::iterator_traits<InputIterator>::value_type()>::type
ResultType; ResultType;
typedef TaskIterator<ResultType> IteratorType; typedef TaskIterator<ResultType> IteratorType;
...@@ -113,19 +110,17 @@ addTasks(InputIterator first, InputIterator last) { ...@@ -113,19 +110,17 @@ addTasks(InputIterator first, InputIterator last) {
#pragma clang diagnostic push // ignore generalized lambda capture warning #pragma clang diagnostic push // ignore generalized lambda capture warning
#pragma clang diagnostic ignored "-Wc++1y-extensions" #pragma clang diagnostic ignored "-Wc++1y-extensions"
#endif #endif
addTask( addTask([ i, context, f = std::move(*first) ]() {
[i, context, f = std::move(*first)]() { context->results.emplace_back(i, folly::makeTryWith(std::move(f)));
context->results.emplace_back(i, folly::makeTryWith(std::move(f)));
// Check for awaiting iterator.
// Check for awaiting iterator. if (context->promise.hasValue()) {
if (context->promise.hasValue()) { if (--context->tasksToFulfillPromise == 0) {
if (--context->tasksToFulfillPromise == 0) { context->promise->setValue();
context->promise->setValue(); context->promise.clear();
context->promise.clear();
}
} }
} }
); });
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
...@@ -133,5 +128,5 @@ addTasks(InputIterator first, InputIterator last) { ...@@ -133,5 +128,5 @@ addTasks(InputIterator first, InputIterator last) {
return IteratorType(std::move(context)); return IteratorType(std::move(context));
} }
}
}} }
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
#include <folly/experimental/fibers/Promise.h> #include <folly/experimental/fibers/Promise.h>
#include <folly/futures/Try.h> #include <folly/futures/Try.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
template <typename T> template <typename T>
class TaskIterator; class TaskIterator;
...@@ -39,10 +40,9 @@ class TaskIterator; ...@@ -39,10 +40,9 @@ class TaskIterator;
* @return movable, non-copyable iterator * @return movable, non-copyable iterator
*/ */
template <class InputIterator> template <class InputIterator>
TaskIterator< TaskIterator<typename std::result_of<
typename std::result_of< typename std::iterator_traits<InputIterator>::value_type()>::
typename std::iterator_traits<InputIterator>::value_type()>::type> type> inline addTasks(InputIterator first, InputIterator last);
inline addTasks(InputIterator first, InputIterator last);
template <typename T> template <typename T>
class TaskIterator { class TaskIterator {
...@@ -99,9 +99,8 @@ class TaskIterator { ...@@ -99,9 +99,8 @@ class TaskIterator {
private: private:
template <class InputIterator> template <class InputIterator>
friend TaskIterator< friend TaskIterator<typename std::result_of<
typename std::result_of< typename std::iterator_traits<InputIterator>::value_type()>::type>
typename std::iterator_traits<InputIterator>::value_type()>::type>
addTasks(InputIterator first, InputIterator last); addTasks(InputIterator first, InputIterator last);
struct Context { struct Context {
...@@ -119,7 +118,7 @@ class TaskIterator { ...@@ -119,7 +118,7 @@ class TaskIterator {
folly::Try<T> awaitNextResult(); folly::Try<T> awaitNextResult();
}; };
}
}} }
#include <folly/experimental/fibers/AddTasks-inl.h> #include <folly/experimental/fibers/AddTasks-inl.h>
...@@ -16,14 +16,16 @@ ...@@ -16,14 +16,16 @@
#include <folly/experimental/fibers/Fiber.h> #include <folly/experimental/fibers/Fiber.h>
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
inline Baton::Baton() : Baton(NO_WAITER) { inline Baton::Baton() : Baton(NO_WAITER) {
assert(Baton(NO_WAITER).futex_.futex == static_cast<uint32_t>(NO_WAITER)); assert(Baton(NO_WAITER).futex_.futex == static_cast<uint32_t>(NO_WAITER));
assert(Baton(POSTED).futex_.futex == static_cast<uint32_t>(POSTED)); assert(Baton(POSTED).futex_.futex == static_cast<uint32_t>(POSTED));
assert(Baton(TIMEOUT).futex_.futex == static_cast<uint32_t>(TIMEOUT)); assert(Baton(TIMEOUT).futex_.futex == static_cast<uint32_t>(TIMEOUT));
assert(Baton(THREAD_WAITING).futex_.futex == assert(
static_cast<uint32_t>(THREAD_WAITING)); Baton(THREAD_WAITING).futex_.futex ==
static_cast<uint32_t>(THREAD_WAITING));
assert(futex_.futex.is_lock_free()); assert(futex_.futex.is_lock_free());
assert(waitingFiber_.is_lock_free()); assert(waitingFiber_.is_lock_free());
...@@ -54,9 +56,8 @@ void Baton::waitFiber(FiberManager& fm, F&& mainContextFunc) { ...@@ -54,9 +56,8 @@ void Baton::waitFiber(FiberManager& fm, F&& mainContextFunc) {
} else { } else {
throw std::logic_error("Some Fiber is already waiting on this Baton."); throw std::logic_error("Some Fiber is already waiting on this Baton.");
} }
} while(!waitingFiber.compare_exchange_weak( } while (!waitingFiber.compare_exchange_weak(
baton_fiber, baton_fiber, reinterpret_cast<intptr_t>(&fiber)));
reinterpret_cast<intptr_t>(&fiber)));
mainContextFunc(); mainContextFunc();
}; };
...@@ -66,8 +67,9 @@ void Baton::waitFiber(FiberManager& fm, F&& mainContextFunc) { ...@@ -66,8 +67,9 @@ void Baton::waitFiber(FiberManager& fm, F&& mainContextFunc) {
} }
template <typename F> template <typename F>
bool Baton::timed_wait(TimeoutController::Duration timeout, bool Baton::timed_wait(
F&& mainContextFunc) { TimeoutController::Duration timeout,
F&& mainContextFunc) {
auto fm = FiberManager::getFiberManagerUnsafe(); auto fm = FiberManager::getFiberManagerUnsafe();
if (!fm || !fm->activeFiber_) { if (!fm || !fm->activeFiber_) {
...@@ -82,8 +84,8 @@ bool Baton::timed_wait(TimeoutController::Duration timeout, ...@@ -82,8 +84,8 @@ bool Baton::timed_wait(TimeoutController::Duration timeout,
canceled = true; canceled = true;
}; };
auto id = fm->timeoutManager_->registerTimeout( auto id =
std::ref(timeoutFunc), timeout); fm->timeoutManager_->registerTimeout(std::ref(timeoutFunc), timeout);
waitFiber(*fm, std::move(mainContextFunc)); waitFiber(*fm, std::move(mainContextFunc));
...@@ -96,8 +98,8 @@ bool Baton::timed_wait(TimeoutController::Duration timeout, ...@@ -96,8 +98,8 @@ bool Baton::timed_wait(TimeoutController::Duration timeout,
return posted; return posted;
} }
template<typename C, typename D> template <typename C, typename D>
bool Baton::timed_wait(const std::chrono::time_point<C,D>& timeout) { bool Baton::timed_wait(const std::chrono::time_point<C, D>& timeout) {
auto now = C::now(); auto now = C::now();
if (LIKELY(now <= timeout)) { if (LIKELY(now <= timeout)) {
...@@ -107,6 +109,5 @@ bool Baton::timed_wait(const std::chrono::time_point<C,D>& timeout) { ...@@ -107,6 +109,5 @@ bool Baton::timed_wait(const std::chrono::time_point<C,D>& timeout) {
return timed_wait(TimeoutController::Duration(0)); return timed_wait(TimeoutController::Duration(0));
} }
} }
}
}
}}
...@@ -21,10 +21,11 @@ ...@@ -21,10 +21,11 @@
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
#include <folly/portability/Asm.h> #include <folly/portability/Asm.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
void Baton::wait() { void Baton::wait() {
wait([](){}); wait([]() {});
} }
void Baton::wait(TimeoutHandler& timeoutHandler) { void Baton::wait(TimeoutHandler& timeoutHandler) {
...@@ -41,7 +42,7 @@ void Baton::wait(TimeoutHandler& timeoutHandler) { ...@@ -41,7 +42,7 @@ void Baton::wait(TimeoutHandler& timeoutHandler) {
} }
bool Baton::timed_wait(TimeoutController::Duration timeout) { bool Baton::timed_wait(TimeoutController::Duration timeout) {
return timed_wait(timeout, [](){}); return timed_wait(timeout, []() {});
} }
void Baton::waitThread() { void Baton::waitThread() {
...@@ -52,8 +53,9 @@ void Baton::waitThread() { ...@@ -52,8 +53,9 @@ void Baton::waitThread() {
auto fiber = waitingFiber_.load(); auto fiber = waitingFiber_.load();
if (LIKELY(fiber == NO_WAITER && if (LIKELY(
waitingFiber_.compare_exchange_strong(fiber, THREAD_WAITING))) { fiber == NO_WAITER &&
waitingFiber_.compare_exchange_strong(fiber, THREAD_WAITING))) {
do { do {
folly::detail::MemoryIdler::futexWait(futex_.futex, THREAD_WAITING); folly::detail::MemoryIdler::futexWait(futex_.futex, THREAD_WAITING);
fiber = waitingFiber_.load(std::memory_order_relaxed); fiber = waitingFiber_.load(std::memory_order_relaxed);
...@@ -75,7 +77,8 @@ void Baton::waitThread() { ...@@ -75,7 +77,8 @@ void Baton::waitThread() {
} }
bool Baton::spinWaitForEarlyPost() { bool Baton::spinWaitForEarlyPost() {
static_assert(PreBlockAttempts > 0, static_assert(
PreBlockAttempts > 0,
"isn't this assert clearer than an uninitialized variable warning?"); "isn't this assert clearer than an uninitialized variable warning?");
for (int i = 0; i < PreBlockAttempts; ++i) { for (int i = 0; i < PreBlockAttempts; ++i) {
if (try_wait()) { if (try_wait()) {
...@@ -100,12 +103,13 @@ bool Baton::timedWaitThread(TimeoutController::Duration timeout) { ...@@ -100,12 +103,13 @@ bool Baton::timedWaitThread(TimeoutController::Duration timeout) {
auto fiber = waitingFiber_.load(); auto fiber = waitingFiber_.load();
if (LIKELY(fiber == NO_WAITER && if (LIKELY(
waitingFiber_.compare_exchange_strong(fiber, THREAD_WAITING))) { fiber == NO_WAITER &&
waitingFiber_.compare_exchange_strong(fiber, THREAD_WAITING))) {
auto deadline = TimeoutController::Clock::now() + timeout; auto deadline = TimeoutController::Clock::now() + timeout;
do { do {
const auto wait_rv = const auto wait_rv =
futex_.futex.futexWaitUntil(THREAD_WAITING, deadline); futex_.futex.futexWaitUntil(THREAD_WAITING, deadline);
if (wait_rv == folly::detail::FutexResult::TIMEDOUT) { if (wait_rv == folly::detail::FutexResult::TIMEDOUT) {
return false; return false;
} }
...@@ -167,7 +171,8 @@ void Baton::postThread() { ...@@ -167,7 +171,8 @@ void Baton::postThread() {
} }
void Baton::reset() { void Baton::reset() {
waitingFiber_.store(NO_WAITER, std::memory_order_relaxed);; waitingFiber_.store(NO_WAITER, std::memory_order_relaxed);
;
} }
void Baton::TimeoutHandler::scheduleTimeout( void Baton::TimeoutHandler::scheduleTimeout(
...@@ -177,8 +182,8 @@ void Baton::TimeoutHandler::scheduleTimeout( ...@@ -177,8 +182,8 @@ void Baton::TimeoutHandler::scheduleTimeout(
assert(timeoutPtr_ == 0); assert(timeoutPtr_ == 0);
if (timeout.count() > 0) { if (timeout.count() > 0) {
timeoutPtr_ = fiberManager_->timeoutManager_->registerTimeout( timeoutPtr_ =
timeoutFunc_, timeout); fiberManager_->timeoutManager_->registerTimeout(timeoutFunc_, timeout);
} }
} }
...@@ -187,5 +192,5 @@ void Baton::TimeoutHandler::cancelTimeout() { ...@@ -187,5 +192,5 @@ void Baton::TimeoutHandler::cancelTimeout() {
fiberManager_->timeoutManager_->cancel(timeoutPtr_); fiberManager_->timeoutManager_->cancel(timeoutPtr_);
} }
} }
}
}} }
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
#include <folly/detail/Futex.h> #include <folly/detail/Futex.h>
#include <folly/experimental/fibers/TimeoutController.h> #include <folly/experimental/fibers/TimeoutController.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class Fiber; class Fiber;
class FiberManager; class FiberManager;
...@@ -66,8 +67,8 @@ class Baton { ...@@ -66,8 +67,8 @@ class Baton {
* This is here only not break tao/locks. Please don't use it, because it is * This is here only not break tao/locks. Please don't use it, because it is
* inefficient when used on Fibers. * inefficient when used on Fibers.
*/ */
template<typename C, typename D = typename C::duration> template <typename C, typename D = typename C::duration>
bool timed_wait(const std::chrono::time_point<C,D>& timeout); bool timed_wait(const std::chrono::time_point<C, D>& timeout);
/** /**
* Puts active fiber to sleep. Returns when post is called. * Puts active fiber to sleep. Returns when post is called.
...@@ -153,7 +154,7 @@ class Baton { ...@@ -153,7 +154,7 @@ class Baton {
PreBlockAttempts = 300, PreBlockAttempts = 300,
}; };
explicit Baton(intptr_t state) : waitingFiber_(state) {}; explicit Baton(intptr_t state) : waitingFiber_(state){};
void postHelper(intptr_t new_value); void postHelper(intptr_t new_value);
void postThread(); void postThread();
...@@ -184,7 +185,7 @@ class Baton { ...@@ -184,7 +185,7 @@ class Baton {
} futex_; } futex_;
}; };
}; };
}
}} }
#include <folly/experimental/fibers/Baton-inl.h> #include <folly/experimental/fibers/Baton-inl.h>
...@@ -21,16 +21,19 @@ ...@@ -21,16 +21,19 @@
/** /**
* Wrappers for different versions of boost::context library * Wrappers for different versions of boost::context library
* API reference for different versions * API reference for different versions
* Boost 1.51: http://www.boost.org/doc/libs/1_51_0/libs/context/doc/html/context/context/boost_fcontext.html * Boost 1.51:
* Boost 1.52: http://www.boost.org/doc/libs/1_52_0/libs/context/doc/html/context/context/boost_fcontext.html * http://www.boost.org/doc/libs/1_51_0/libs/context/doc/html/context/context/boost_fcontext.html
* Boost 1.56: http://www.boost.org/doc/libs/1_56_0/libs/context/doc/html/context/context/boost_fcontext.html * Boost 1.52:
* http://www.boost.org/doc/libs/1_52_0/libs/context/doc/html/context/context/boost_fcontext.html
* Boost 1.56:
* http://www.boost.org/doc/libs/1_56_0/libs/context/doc/html/context/context/boost_fcontext.html
*/ */
namespace folly { namespace fibers { namespace folly {
namespace fibers {
struct FContext { struct FContext {
public: public:
#if BOOST_VERSION >= 105200 #if BOOST_VERSION >= 105200
using ContextStruct = boost::context::fcontext_t; using ContextStruct = boost::context::fcontext_t;
#else #else
...@@ -57,17 +60,16 @@ struct FContext { ...@@ -57,17 +60,16 @@ struct FContext {
ContextStruct context_; ContextStruct context_;
#endif #endif
friend intptr_t jumpContext(FContext* oldC, FContext::ContextStruct* newC, friend intptr_t
intptr_t p); jumpContext(FContext* oldC, FContext::ContextStruct* newC, intptr_t p);
friend intptr_t jumpContext(FContext::ContextStruct* oldC, FContext* newC, friend intptr_t
intptr_t p); jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p);
friend FContext makeContext(void* stackLimit, size_t stackSize, friend FContext
void(*fn)(intptr_t)); makeContext(void* stackLimit, size_t stackSize, void (*fn)(intptr_t));
}; };
inline intptr_t jumpContext(FContext* oldC, FContext::ContextStruct* newC, inline intptr_t
intptr_t p) { jumpContext(FContext* oldC, FContext::ContextStruct* newC, intptr_t p) {
#if BOOST_VERSION >= 105600 #if BOOST_VERSION >= 105600
return boost::context::jump_fcontext(&oldC->context_, *newC, p); return boost::context::jump_fcontext(&oldC->context_, *newC, p);
#elif BOOST_VERSION >= 105200 #elif BOOST_VERSION >= 105200
...@@ -75,22 +77,19 @@ inline intptr_t jumpContext(FContext* oldC, FContext::ContextStruct* newC, ...@@ -75,22 +77,19 @@ inline intptr_t jumpContext(FContext* oldC, FContext::ContextStruct* newC,
#else #else
return jump_fcontext(&oldC->context_, newC, p); return jump_fcontext(&oldC->context_, newC, p);
#endif #endif
} }
inline intptr_t jumpContext(FContext::ContextStruct* oldC, FContext* newC, inline intptr_t
intptr_t p) { jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p) {
#if BOOST_VERSION >= 105200 #if BOOST_VERSION >= 105200
return boost::context::jump_fcontext(oldC, newC->context_, p); return boost::context::jump_fcontext(oldC, newC->context_, p);
#else #else
return jump_fcontext(oldC, &newC->context_, p); return jump_fcontext(oldC, &newC->context_, p);
#endif #endif
} }
inline FContext makeContext(void* stackLimit, size_t stackSize, inline FContext
void(*fn)(intptr_t)) { makeContext(void* stackLimit, size_t stackSize, void (*fn)(intptr_t)) {
FContext res; FContext res;
res.stackLimit_ = stackLimit; res.stackLimit_ = stackLimit;
res.stackBase_ = static_cast<unsigned char*>(stackLimit) + stackSize; res.stackBase_ = static_cast<unsigned char*>(stackLimit) + stackSize;
...@@ -105,5 +104,5 @@ inline FContext makeContext(void* stackLimit, size_t stackSize, ...@@ -105,5 +104,5 @@ inline FContext makeContext(void* stackLimit, size_t stackSize,
return res; return res;
} }
}
}} // folly::fibers } // folly::fibers
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
#include <folly/experimental/fibers/EventBaseLoopController.h> #include <folly/experimental/fibers/EventBaseLoopController.h>
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
inline EventBaseLoopController::EventBaseLoopController() inline EventBaseLoopController::EventBaseLoopController()
: callback_(*this), aliveWeak_(destructionCallback_.getWeak()) {} : callback_(*this), aliveWeak_(destructionCallback_.getWeak()) {}
...@@ -27,8 +28,7 @@ inline EventBaseLoopController::~EventBaseLoopController() { ...@@ -27,8 +28,7 @@ inline EventBaseLoopController::~EventBaseLoopController() {
} }
inline void EventBaseLoopController::attachEventBase( inline void EventBaseLoopController::attachEventBase(
folly::EventBase& eventBase) { folly::EventBase& eventBase) {
if (eventBase_ != nullptr) { if (eventBase_ != nullptr) {
LOG(ERROR) << "Attempt to reattach EventBase to LoopController"; LOG(ERROR) << "Attempt to reattach EventBase to LoopController";
} }
...@@ -87,16 +87,19 @@ inline void EventBaseLoopController::scheduleThreadSafe( ...@@ -87,16 +87,19 @@ inline void EventBaseLoopController::scheduleThreadSafe(
} }
} }
inline void EventBaseLoopController::timedSchedule(std::function<void()> func, inline void EventBaseLoopController::timedSchedule(
TimePoint time) { std::function<void()> func,
TimePoint time) {
assert(eventBaseAttached_); assert(eventBaseAttached_);
// We want upper bound for the cast, thus we just add 1 // We want upper bound for the cast, thus we just add 1
auto delay_ms = std::chrono::duration_cast< auto delay_ms =
std::chrono::milliseconds>(time - Clock::now()).count() + 1; std::chrono::duration_cast<std::chrono::milliseconds>(time - Clock::now())
.count() +
1;
// If clock is not monotonic // If clock is not monotonic
delay_ms = std::max<decltype(delay_ms)>(delay_ms, 0L); delay_ms = std::max<decltype(delay_ms)>(delay_ms, 0L);
eventBase_->tryRunAfterDelay(func, delay_ms); eventBase_->tryRunAfterDelay(func, delay_ms);
} }
}
}} // folly::fibers } // folly::fibers
...@@ -15,16 +15,17 @@ ...@@ -15,16 +15,17 @@
*/ */
#pragma once #pragma once
#include <memory>
#include <atomic>
#include <folly/experimental/fibers/LoopController.h> #include <folly/experimental/fibers/LoopController.h>
#include <folly/io/async/EventBase.h> #include <folly/io/async/EventBase.h>
#include <atomic>
#include <memory>
namespace folly { namespace folly {
class EventBase; class EventBase;
} }
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class FiberManager; class FiberManager;
...@@ -48,7 +49,9 @@ class EventBaseLoopController : public LoopController { ...@@ -48,7 +49,9 @@ class EventBaseLoopController : public LoopController {
explicit ControllerCallback(EventBaseLoopController& controller) explicit ControllerCallback(EventBaseLoopController& controller)
: controller_(controller) {} : controller_(controller) {}
void runLoopCallback() noexcept override { controller_.runLoop(); } void runLoopCallback() noexcept override {
controller_.runLoop();
}
private: private:
EventBaseLoopController& controller_; EventBaseLoopController& controller_;
...@@ -57,11 +60,17 @@ class EventBaseLoopController : public LoopController { ...@@ -57,11 +60,17 @@ class EventBaseLoopController : public LoopController {
class DestructionCallback : public folly::EventBase::LoopCallback { class DestructionCallback : public folly::EventBase::LoopCallback {
public: public:
DestructionCallback() : alive_(new int(42)) {} DestructionCallback() : alive_(new int(42)) {}
~DestructionCallback() { reset(); } ~DestructionCallback() {
reset();
}
void runLoopCallback() noexcept override { reset(); } void runLoopCallback() noexcept override {
reset();
}
std::weak_ptr<void> getWeak() { return {alive_}; } std::weak_ptr<void> getWeak() {
return {alive_};
}
private: private:
void reset() { void reset() {
...@@ -96,7 +105,7 @@ class EventBaseLoopController : public LoopController { ...@@ -96,7 +105,7 @@ class EventBaseLoopController : public LoopController {
friend class FiberManager; friend class FiberManager;
}; };
}
}} // folly::fibers } // folly::fibers
#include "EventBaseLoopController-inl.h" #include "EventBaseLoopController-inl.h"
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
#include <cassert> #include <cassert>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
template <typename F> template <typename F>
void Fiber::setFunction(F&& func) { void Fiber::setFunction(F&& func) {
...@@ -27,8 +28,7 @@ void Fiber::setFunction(F&& func) { ...@@ -27,8 +28,7 @@ void Fiber::setFunction(F&& func) {
} }
template <typename F, typename G> template <typename F, typename G>
void Fiber::setFunctionFinally(F&& resultFunc, void Fiber::setFunctionFinally(F&& resultFunc, G&& finallyFunc) {
G&& finallyFunc) {
assert(state_ == INVALID); assert(state_ == INVALID);
resultFunc_ = std::forward<F>(resultFunc); resultFunc_ = std::forward<F>(resultFunc);
finallyFunc_ = std::forward<G>(finallyFunc); finallyFunc_ = std::forward<G>(finallyFunc);
...@@ -68,9 +68,9 @@ void Fiber::LocalData::dataBufferDestructor(void* ptr) { ...@@ -68,9 +68,9 @@ void Fiber::LocalData::dataBufferDestructor(void* ptr) {
} }
template <typename T> template <typename T>
void Fiber::LocalData::dataHeapDestructor(void *ptr) { void Fiber::LocalData::dataHeapDestructor(void* ptr) {
reinterpret_cast<T*>(ptr)->~T(); reinterpret_cast<T*>(ptr)->~T();
freeHeapBuffer(ptr); freeHeapBuffer(ptr);
} }
}
}} // folly::fibers } // folly::fibers
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#include <glog/logging.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
#include <glog/logging.h>
#include <folly/Likely.h> #include <folly/Likely.h>
#include <folly/Portability.h> #include <folly/Portability.h>
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
#include <folly/portability/SysSyscall.h> #include <folly/portability/SysSyscall.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
namespace { namespace {
static const uint64_t kMagic8Bytes = 0xfaceb00cfaceb00c; static const uint64_t kMagic8Bytes = 0xfaceb00cfaceb00c;
...@@ -50,16 +51,12 @@ static size_t nonMagicInBytes(const FContext& context) { ...@@ -50,16 +51,12 @@ static size_t nonMagicInBytes(const FContext& context) {
uint64_t* end = static_cast<uint64_t*>(context.stackBase()); uint64_t* end = static_cast<uint64_t*>(context.stackBase());
auto firstNonMagic = std::find_if( auto firstNonMagic = std::find_if(
begin, end, begin, end, [](uint64_t val) { return val != kMagic8Bytes; });
[](uint64_t val) {
return val != kMagic8Bytes;
}
);
return (end - firstNonMagic) * sizeof(uint64_t); return (end - firstNonMagic) * sizeof(uint64_t);
} }
} // anonymous namespace } // anonymous namespace
void Fiber::setData(intptr_t data) { void Fiber::setData(intptr_t data) {
DCHECK_EQ(state_, AWAITING); DCHECK_EQ(state_, AWAITING);
...@@ -78,9 +75,7 @@ void Fiber::setData(intptr_t data) { ...@@ -78,9 +75,7 @@ void Fiber::setData(intptr_t data) {
} }
} }
Fiber::Fiber(FiberManager& fiberManager) : Fiber::Fiber(FiberManager& fiberManager) : fiberManager_(fiberManager) {
fiberManager_(fiberManager) {
auto size = fiberManager_.options_.stackSize; auto size = fiberManager_.options_.stackSize;
auto limit = fiberManager_.stackAllocator_.allocate(size); auto limit = fiberManager_.stackAllocator_.allocate(size);
...@@ -98,9 +93,10 @@ void Fiber::init(bool recordStackUsed) { ...@@ -98,9 +93,10 @@ void Fiber::init(bool recordStackUsed) {
auto limit = fcontext_.stackLimit(); auto limit = fcontext_.stackLimit();
auto base = fcontext_.stackBase(); auto base = fcontext_.stackBase();
std::fill(static_cast<uint64_t*>(limit), std::fill(
static_cast<uint64_t*>(base), static_cast<uint64_t*>(limit),
kMagic8Bytes); static_cast<uint64_t*>(base),
kMagic8Bytes);
// newer versions of boost allocate context on fiber stack, // newer versions of boost allocate context on fiber stack,
// need to create a new one // need to create a new one
...@@ -116,17 +112,17 @@ void Fiber::init(bool recordStackUsed) { ...@@ -116,17 +112,17 @@ void Fiber::init(bool recordStackUsed) {
Fiber::~Fiber() { Fiber::~Fiber() {
fiberManager_.stackAllocator_.deallocate( fiberManager_.stackAllocator_.deallocate(
static_cast<unsigned char*>(fcontext_.stackLimit()), static_cast<unsigned char*>(fcontext_.stackLimit()),
fiberManager_.options_.stackSize); fiberManager_.options_.stackSize);
} }
void Fiber::recordStackPosition() { void Fiber::recordStackPosition() {
int stackDummy; int stackDummy;
auto currentPosition = static_cast<size_t>( auto currentPosition = static_cast<size_t>(
static_cast<unsigned char*>(fcontext_.stackBase()) - static_cast<unsigned char*>(fcontext_.stackBase()) -
static_cast<unsigned char*>(static_cast<void*>(&stackDummy))); static_cast<unsigned char*>(static_cast<void*>(&stackDummy)));
fiberManager_.stackHighWatermark_ = fiberManager_.stackHighWatermark_ =
std::max(fiberManager_.stackHighWatermark_, currentPosition); std::max(fiberManager_.stackHighWatermark_, currentPosition);
VLOG(4) << "Stack usage: " << currentPosition; VLOG(4) << "Stack usage: " << currentPosition;
} }
...@@ -152,17 +148,18 @@ void Fiber::fiberFunc() { ...@@ -152,17 +148,18 @@ void Fiber::fiberFunc() {
func_(); func_();
} }
} catch (...) { } catch (...) {
fiberManager_.exceptionCallback_(std::current_exception(), fiberManager_.exceptionCallback_(
"running Fiber func_/resultFunc_"); std::current_exception(), "running Fiber func_/resultFunc_");
} }
if (UNLIKELY(recordStackUsed_)) { if (UNLIKELY(recordStackUsed_)) {
fiberManager_.stackHighWatermark_ = fiberManager_.stackHighWatermark_ = std::max(
std::max(fiberManager_.stackHighWatermark_, fiberManager_.stackHighWatermark_, nonMagicInBytes(fcontext_));
nonMagicInBytes(fcontext_));
VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_; VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_;
CHECK(fiberManager_.stackHighWatermark_ < CHECK(
fiberManager_.options_.stackSize - 64) << "Fiber stack overflow"; fiberManager_.stackHighWatermark_ <
fiberManager_.options_.stackSize - 64)
<< "Fiber stack overflow";
} }
state_ = INVALID; state_ = INVALID;
...@@ -243,5 +240,5 @@ void* Fiber::LocalData::allocateHeapBuffer(size_t size) { ...@@ -243,5 +240,5 @@ void* Fiber::LocalData::allocateHeapBuffer(size_t size) {
void Fiber::LocalData::freeHeapBuffer(void* buffer) { void Fiber::LocalData::freeHeapBuffer(void* buffer) {
delete[] reinterpret_cast<char*>(buffer); delete[] reinterpret_cast<char*>(buffer);
} }
}
}} }
...@@ -28,7 +28,8 @@ ...@@ -28,7 +28,8 @@
#include <boost/context/all.hpp> #include <boost/context/all.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class Baton; class Baton;
class FiberManager; class FiberManager;
...@@ -63,26 +64,26 @@ class Fiber { ...@@ -63,26 +64,26 @@ class Fiber {
*/ */
std::pair<void*, size_t> getStack() const { std::pair<void*, size_t> getStack() const {
void* const stack = void* const stack =
std::min<void*>(fcontext_.stackLimit(), fcontext_.stackBase()); std::min<void*>(fcontext_.stackLimit(), fcontext_.stackBase());
const size_t size = std::abs<intptr_t>( const size_t size = std::abs<intptr_t>(
reinterpret_cast<intptr_t>(fcontext_.stackBase()) - reinterpret_cast<intptr_t>(fcontext_.stackBase()) -
reinterpret_cast<intptr_t>(fcontext_.stackLimit())); reinterpret_cast<intptr_t>(fcontext_.stackLimit()));
return { stack, size }; return {stack, size};
} }
private: private:
enum State { enum State {
INVALID, /**< Does't have task function */ INVALID, /**< Does't have task function */
NOT_STARTED, /**< Has task function, not started */ NOT_STARTED, /**< Has task function, not started */
READY_TO_RUN, /**< Was started, blocked, then unblocked */ READY_TO_RUN, /**< Was started, blocked, then unblocked */
RUNNING, /**< Is running right now */ RUNNING, /**< Is running right now */
AWAITING, /**< Is currently blocked */ AWAITING, /**< Is currently blocked */
AWAITING_IMMEDIATE, /**< Was preempted to run an immediate function, AWAITING_IMMEDIATE, /**< Was preempted to run an immediate function,
and will be resumed right away */ and will be resumed right away */
YIELDED, /**< The fiber yielded execution voluntarily */ YIELDED, /**< The fiber yielded execution voluntarily */
}; };
State state_{INVALID}; /**< current Fiber state */ State state_{INVALID}; /**< current Fiber state */
friend class Baton; friend class Baton;
friend class FiberManager; friend class FiberManager;
...@@ -116,11 +117,11 @@ class Fiber { ...@@ -116,11 +117,11 @@ class Fiber {
*/ */
void recordStackPosition(); void recordStackPosition();
FiberManager& fiberManager_; /**< Associated FiberManager */ FiberManager& fiberManager_; /**< Associated FiberManager */
FContext fcontext_; /**< current task execution context */ FContext fcontext_; /**< current task execution context */
intptr_t data_; /**< Used to keep some data with the Fiber */ intptr_t data_; /**< Used to keep some data with the Fiber */
std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */ std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */
folly::Function<void()> func_; /**< task function */ folly::Function<void()> func_; /**< task function */
bool recordStackUsed_{false}; bool recordStackUsed_{false};
bool stackFilledWithMagic_{false}; bool stackFilledWithMagic_{false};
...@@ -154,7 +155,7 @@ class Fiber { ...@@ -154,7 +155,7 @@ class Fiber {
void reset(); void reset();
//private: // private:
template <typename T> template <typename T>
FOLLY_NOINLINE T& getSlow(); FOLLY_NOINLINE T& getSlow();
...@@ -185,7 +186,7 @@ class Fiber { ...@@ -185,7 +186,7 @@ class Fiber {
folly::IntrusiveListHook globalListHook_; /**< list hook for global list */ folly::IntrusiveListHook globalListHook_; /**< list hook for global list */
pid_t threadId_{0}; pid_t threadId_{0};
}; };
}
}} }
#include <folly/experimental/fibers/Fiber-inl.h> #include <folly/experimental/fibers/Fiber-inl.h>
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
#include <folly/futures/Promise.h> #include <folly/futures/Promise.h>
#include <folly/futures/Try.h> #include <folly/futures/Try.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
namespace { namespace {
...@@ -47,7 +48,7 @@ inline FiberManager::Options preprocessOptions(FiberManager::Options opts) { ...@@ -47,7 +48,7 @@ inline FiberManager::Options preprocessOptions(FiberManager::Options opts) {
return opts; return opts;
} }
} // anonymous } // anonymous
inline void FiberManager::ensureLoopScheduled() { inline void FiberManager::ensureLoopScheduled() {
if (isLoopScheduled_) { if (isLoopScheduled_) {
...@@ -86,8 +87,9 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) { ...@@ -86,8 +87,9 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
assert(activeFiber_ == nullptr); assert(activeFiber_ == nullptr);
}; };
assert(fiber->state_ == Fiber::NOT_STARTED || assert(
fiber->state_ == Fiber::READY_TO_RUN); fiber->state_ == Fiber::NOT_STARTED ||
fiber->state_ == Fiber::READY_TO_RUN);
currentFiber_ = fiber; currentFiber_ = fiber;
fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_)); fiber->rcontext_ = RequestContext::setContext(std::move(fiber->rcontext_));
if (observer_) { if (observer_) {
...@@ -185,31 +187,27 @@ inline bool FiberManager::loopUntilNoReady() { ...@@ -185,31 +187,27 @@ inline bool FiberManager::loopUntilNoReady() {
runReadyFiber(&fiber); runReadyFiber(&fiber);
} }
remoteReadyQueue_.sweep( remoteReadyQueue_.sweep([this, &hadRemoteFiber](Fiber* fiber) {
[this, &hadRemoteFiber] (Fiber* fiber) { runReadyFiber(fiber);
runReadyFiber(fiber); hadRemoteFiber = true;
hadRemoteFiber = true; });
remoteTaskQueue_.sweep([this, &hadRemoteFiber](RemoteTask* taskPtr) {
std::unique_ptr<RemoteTask> task(taskPtr);
auto fiber = getFiber();
if (task->localData) {
fiber->localData_ = *task->localData;
} }
); fiber->rcontext_ = std::move(task->rcontext);
remoteTaskQueue_.sweep(
[this, &hadRemoteFiber] (RemoteTask* taskPtr) {
std::unique_ptr<RemoteTask> task(taskPtr);
auto fiber = getFiber();
if (task->localData) {
fiber->localData_ = *task->localData;
}
fiber->rcontext_ = std::move(task->rcontext);
fiber->setFunction(std::move(task->func)); fiber->setFunction(std::move(task->func));
fiber->data_ = reinterpret_cast<intptr_t>(fiber); fiber->data_ = reinterpret_cast<intptr_t>(fiber);
if (observer_) { if (observer_) {
observer_->runnable(reinterpret_cast<uintptr_t>(fiber)); observer_->runnable(reinterpret_cast<uintptr_t>(fiber));
}
runReadyFiber(fiber);
hadRemoteFiber = true;
} }
); runReadyFiber(fiber);
hadRemoteFiber = true;
});
} }
if (observer_) { if (observer_) {
...@@ -229,19 +227,18 @@ struct FiberManager::AddTaskHelper { ...@@ -229,19 +227,18 @@ struct FiberManager::AddTaskHelper {
class Func; class Func;
static constexpr bool allocateInBuffer = static constexpr bool allocateInBuffer =
sizeof(Func) <= Fiber::kUserBufferSize; sizeof(Func) <= Fiber::kUserBufferSize;
class Func { class Func {
public: public:
Func(F&& func, FiberManager& fm) : Func(F&& func, FiberManager& fm) : func_(std::forward<F>(func)), fm_(fm) {}
func_(std::forward<F>(func)), fm_(fm) {}
void operator()() { void operator()() {
try { try {
func_(); func_();
} catch (...) { } catch (...) {
fm_.exceptionCallback_(std::current_exception(), fm_.exceptionCallback_(
"running Func functor"); std::current_exception(), "running Func functor");
} }
if (allocateInBuffer) { if (allocateInBuffer) {
this->~Func(); this->~Func();
...@@ -289,10 +286,11 @@ auto FiberManager::addTaskFuture(F&& func) ...@@ -289,10 +286,11 @@ auto FiberManager::addTaskFuture(F&& func)
using T = typename std::result_of<F()>::type; using T = typename std::result_of<F()>::type;
folly::Promise<T> p; folly::Promise<T> p;
auto f = p.getFuture(); auto f = p.getFuture();
addTaskFinally([func = std::forward<F>(func)]() mutable { return func(); }, addTaskFinally(
[p = std::move(p)](folly::Try<T> && t) mutable { [func = std::forward<F>(func)]() mutable { return func(); },
p.setTry(std::move(t)); [p = std::move(p)](folly::Try<T> && t) mutable {
}); p.setTry(std::move(t));
});
return f; return f;
} }
...@@ -300,16 +298,16 @@ template <typename F> ...@@ -300,16 +298,16 @@ template <typename F>
void FiberManager::addTaskRemote(F&& func) { void FiberManager::addTaskRemote(F&& func) {
auto task = [&]() { auto task = [&]() {
auto currentFm = getFiberManagerUnsafe(); auto currentFm = getFiberManagerUnsafe();
if (currentFm && if (currentFm && currentFm->currentFiber_ &&
currentFm->currentFiber_ &&
currentFm->localType_ == localType_) { currentFm->localType_ == localType_) {
return folly::make_unique<RemoteTask>( return folly::make_unique<RemoteTask>(
std::forward<F>(func), currentFm->currentFiber_->localData_); std::forward<F>(func), currentFm->currentFiber_->localData_);
} }
return folly::make_unique<RemoteTask>(std::forward<F>(func)); return folly::make_unique<RemoteTask>(std::forward<F>(func));
}(); }();
auto insertHead = auto insertHead = [&]() {
[&]() { return remoteTaskQueue_.insertHead(task.release()); }; return remoteTaskQueue_.insertHead(task.release());
};
loopController_->scheduleThreadSafe(std::ref(insertHead)); loopController_->scheduleThreadSafe(std::ref(insertHead));
} }
...@@ -327,9 +325,13 @@ auto FiberManager::addTaskRemoteFuture(F&& func) ...@@ -327,9 +325,13 @@ auto FiberManager::addTaskRemoteFuture(F&& func)
} }
template <typename X> template <typename X>
struct IsRvalueRefTry { static const bool value = false; }; struct IsRvalueRefTry {
static const bool value = false;
};
template <typename T> template <typename T>
struct IsRvalueRefTry<folly::Try<T>&&> { static const bool value = true; }; struct IsRvalueRefTry<folly::Try<T>&&> {
static const bool value = true;
};
// We need this to be in a struct, not inlined in addTaskFinally, because clang // We need this to be in a struct, not inlined in addTaskFinally, because clang
// crashes otherwise. // crashes otherwise.
...@@ -348,8 +350,8 @@ struct FiberManager::AddTaskFinallyHelper { ...@@ -348,8 +350,8 @@ struct FiberManager::AddTaskFinallyHelper {
try { try {
finally_(std::move(*result_)); finally_(std::move(*result_));
} catch (...) { } catch (...) {
fm_.exceptionCallback_(std::current_exception(), fm_.exceptionCallback_(
"running Finally functor"); std::current_exception(), "running Finally functor");
} }
if (allocateInBuffer) { if (allocateInBuffer) {
...@@ -396,16 +398,14 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) { ...@@ -396,16 +398,14 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) {
typedef typename std::result_of<F()>::type Result; typedef typename std::result_of<F()>::type Result;
static_assert( static_assert(
IsRvalueRefTry<typename FirstArgOf<G>::type>::value, IsRvalueRefTry<typename FirstArgOf<G>::type>::value,
"finally(arg): arg must be Try<T>&&"); "finally(arg): arg must be Try<T>&&");
static_assert( static_assert(
std::is_convertible< std::is_convertible<
Result, Result,
typename std::remove_reference< typename std::remove_reference<
typename FirstArgOf<G>::type typename FirstArgOf<G>::type>::type::element_type>::value,
>::type::element_type "finally(Try<T>&&): T must be convertible from func()'s return type");
>::value,
"finally(Try<T>&&): T must be convertible from func()'s return type");
auto fiber = getFiber(); auto fiber = getFiber();
initLocalData(*fiber); initLocalData(*fiber);
...@@ -416,10 +416,9 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) { ...@@ -416,10 +416,9 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) {
Helper; Helper;
if (Helper::allocateInBuffer) { if (Helper::allocateInBuffer) {
auto funcLoc = static_cast<typename Helper::Func*>( auto funcLoc = static_cast<typename Helper::Func*>(fiber->getUserBuffer());
fiber->getUserBuffer()); auto finallyLoc =
auto finallyLoc = static_cast<typename Helper::Finally*>( static_cast<typename Helper::Finally*>(static_cast<void*>(funcLoc + 1));
static_cast<void*>(funcLoc + 1));
new (finallyLoc) typename Helper::Finally(std::forward<G>(finally), *this); new (finallyLoc) typename Helper::Finally(std::forward<G>(finally), *this);
new (funcLoc) typename Helper::Func(std::forward<F>(func), *finallyLoc); new (funcLoc) typename Helper::Func(std::forward<F>(func), *finallyLoc);
...@@ -444,8 +443,7 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) { ...@@ -444,8 +443,7 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) {
} }
template <typename F> template <typename F>
typename std::result_of<F()>::type typename std::result_of<F()>::type FiberManager::runInMainContext(F&& func) {
FiberManager::runInMainContext(F&& func) {
if (UNLIKELY(activeFiber_ == nullptr)) { if (UNLIKELY(activeFiber_ == nullptr)) {
return func(); return func();
} }
...@@ -512,18 +510,18 @@ inline void FiberManager::initLocalData(Fiber& fiber) { ...@@ -512,18 +510,18 @@ inline void FiberManager::initLocalData(Fiber& fiber) {
template <typename LocalT> template <typename LocalT>
FiberManager::FiberManager( FiberManager::FiberManager(
LocalType<LocalT>, LocalType<LocalT>,
std::unique_ptr<LoopController> loopController__, std::unique_ptr<LoopController> loopController__,
Options options) : Options options)
loopController_(std::move(loopController__)), : loopController_(std::move(loopController__)),
stackAllocator_(options.useGuardPages), stackAllocator_(options.useGuardPages),
options_(preprocessOptions(std::move(options))), options_(preprocessOptions(std::move(options))),
exceptionCallback_([](std::exception_ptr eptr, std::string context) { exceptionCallback_([](std::exception_ptr eptr, std::string context) {
try { try {
std::rethrow_exception(eptr); std::rethrow_exception(eptr);
} catch (const std::exception& e) { } catch (const std::exception& e) {
LOG(DFATAL) << "Exception " << typeid(e).name() LOG(DFATAL) << "Exception " << typeid(e).name() << " with message '"
<< " with message '" << e.what() << "' was thrown in " << e.what() << "' was thrown in "
<< "FiberManager with context '" << context << "'"; << "FiberManager with context '" << context << "'";
throw; throw;
} catch (...) { } catch (...) {
...@@ -532,25 +530,24 @@ FiberManager::FiberManager( ...@@ -532,25 +530,24 @@ FiberManager::FiberManager(
throw; throw;
} }
}), }),
timeoutManager_(std::make_shared<TimeoutController>(*loopController_)), timeoutManager_(std::make_shared<TimeoutController>(*loopController_)),
fibersPoolResizer_(*this), fibersPoolResizer_(*this),
localType_(typeid(LocalT)) { localType_(typeid(LocalT)) {
loopController_->setFiberManager(this); loopController_->setFiberManager(this);
} }
template <typename F> template <typename F>
typename FirstArgOf<F>::type::value_type typename FirstArgOf<F>::type::value_type inline await(F&& func) {
inline await(F&& func) {
typedef typename FirstArgOf<F>::type::value_type Result; typedef typename FirstArgOf<F>::type::value_type Result;
folly::Try<Result> result; folly::Try<Result> result;
Baton baton; Baton baton;
baton.wait([&func, &result, &baton]() mutable { baton.wait([&func, &result, &baton]() mutable {
func(Promise<Result>(result, baton)); func(Promise<Result>(result, baton));
}); });
return folly::moveFromTry(result); return folly::moveFromTry(result);
} }
}
}} }
...@@ -40,24 +40,28 @@ static void __asan_exit_fiber_weak() ...@@ -40,24 +40,28 @@ static void __asan_exit_fiber_weak()
typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t); typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t);
typedef void (*AsanExitFiberFuncPtr)(); typedef void (*AsanExitFiberFuncPtr)();
namespace folly { namespace fibers { namespace folly {
namespace fibers {
static AsanEnterFiberFuncPtr getEnterFiberFunc(); static AsanEnterFiberFuncPtr getEnterFiberFunc();
static AsanExitFiberFuncPtr getExitFiberFunc(); static AsanExitFiberFuncPtr getExitFiberFunc();
}
}} }
#endif #endif
namespace folly { namespace fibers { namespace folly {
namespace fibers {
FOLLY_TLS FiberManager* FiberManager::currentFiberManager_ = nullptr; FOLLY_TLS FiberManager* FiberManager::currentFiberManager_ = nullptr;
FiberManager::FiberManager(std::unique_ptr<LoopController> loopController, FiberManager::FiberManager(
Options options) : std::unique_ptr<LoopController> loopController,
FiberManager(LocalType<void>(), Options options)
std::move(loopController), : FiberManager(
std::move(options)) {} LocalType<void>(),
std::move(loopController),
std::move(options)) {}
FiberManager::~FiberManager() { FiberManager::~FiberManager() {
if (isLoopScheduled_) { if (isLoopScheduled_) {
...@@ -65,9 +69,7 @@ FiberManager::~FiberManager() { ...@@ -65,9 +69,7 @@ FiberManager::~FiberManager() {
} }
while (!fibersPool_.empty()) { while (!fibersPool_.empty()) {
fibersPool_.pop_front_and_dispose([] (Fiber* fiber) { fibersPool_.pop_front_and_dispose([](Fiber* fiber) { delete fiber; });
delete fiber;
});
} }
assert(readyFibers_.empty()); assert(readyFibers_.empty());
assert(fibersActive_ == 0); assert(fibersActive_ == 0);
...@@ -82,9 +84,8 @@ const LoopController& FiberManager::loopController() const { ...@@ -82,9 +84,8 @@ const LoopController& FiberManager::loopController() const {
} }
bool FiberManager::hasTasks() const { bool FiberManager::hasTasks() const {
return fibersActive_ > 0 || return fibersActive_ > 0 || !remoteReadyQueue_.empty() ||
!remoteReadyQueue_.empty() || !remoteTaskQueue_.empty();
!remoteTaskQueue_.empty();
} }
Fiber* FiberManager::getFiber() { Fiber* FiberManager::getFiber() {
...@@ -110,7 +111,7 @@ Fiber* FiberManager::getFiber() { ...@@ -110,7 +111,7 @@ Fiber* FiberManager::getFiber() {
} }
++fiberId_; ++fiberId_;
bool recordStack = (options_.recordStackEvery != 0) && bool recordStack = (options_.recordStackEvery != 0) &&
(fiberId_ % options_.recordStackEvery == 0); (fiberId_ % options_.recordStackEvery == 0);
return fiber; return fiber;
} }
...@@ -166,7 +167,7 @@ void FiberManager::FibersPoolResizer::operator()() { ...@@ -166,7 +167,7 @@ void FiberManager::FibersPoolResizer::operator()() {
fiberManager_.timeoutManager_->registerTimeout( fiberManager_.timeoutManager_->registerTimeout(
*this, *this,
std::chrono::milliseconds( std::chrono::milliseconds(
fiberManager_.options_.fibersPoolResizePeriodMs)); fiberManager_.options_.fibersPoolResizePeriodMs));
} }
#ifdef FOLLY_SANITIZE_ADDRESS #ifdef FOLLY_SANITIZE_ADDRESS
...@@ -235,4 +236,5 @@ static AsanExitFiberFuncPtr getExitFiberFunc() { ...@@ -235,4 +236,5 @@ static AsanExitFiberFuncPtr getExitFiberFunc() {
} }
#endif // FOLLY_SANITIZE_ADDRESS #endif // FOLLY_SANITIZE_ADDRESS
}} }
}
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <thread> #include <thread>
#include <typeindex>
#include <type_traits> #include <type_traits>
#include <typeindex>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
...@@ -51,8 +51,7 @@ class LoopController; ...@@ -51,8 +51,7 @@ class LoopController;
class TimeoutController; class TimeoutController;
template <typename T> template <typename T>
class LocalType { class LocalType {};
};
class InlineFunctionRunner { class InlineFunctionRunner {
public: public:
...@@ -128,8 +127,9 @@ class FiberManager : public ::folly::Executor { ...@@ -128,8 +127,9 @@ class FiberManager : public ::folly::Executor {
* @param loopController * @param loopController
* @param options FiberManager options * @param options FiberManager options
*/ */
explicit FiberManager(std::unique_ptr<LoopController> loopController, explicit FiberManager(
Options options = Options()); std::unique_ptr<LoopController> loopController,
Options options = Options());
/** /**
* Initializes, but doesn't start FiberManager loop * Initializes, but doesn't start FiberManager loop
...@@ -140,10 +140,10 @@ class FiberManager : public ::folly::Executor { ...@@ -140,10 +140,10 @@ class FiberManager : public ::folly::Executor {
* Locals of other types will be considered thread-locals. * Locals of other types will be considered thread-locals.
*/ */
template <typename LocalT> template <typename LocalT>
FiberManager(LocalType<LocalT>, FiberManager(
std::unique_ptr<LoopController> loopController, LocalType<LocalT>,
Options options = Options()); std::unique_ptr<LoopController> loopController,
Options options = Options());
~FiberManager(); ~FiberManager();
...@@ -237,8 +237,7 @@ class FiberManager : public ::folly::Executor { ...@@ -237,8 +237,7 @@ class FiberManager : public ::folly::Executor {
* @return value returned by func(). * @return value returned by func().
*/ */
template <typename F> template <typename F>
typename std::result_of<F()>::type typename std::result_of<F()>::type runInMainContext(F&& func);
runInMainContext(F&& func);
/** /**
* Returns a refference to a fiber-local context for given Fiber. Should be * Returns a refference to a fiber-local context for given Fiber. Should be
...@@ -323,14 +322,13 @@ class FiberManager : public ::folly::Executor { ...@@ -323,14 +322,13 @@ class FiberManager : public ::folly::Executor {
struct RemoteTask { struct RemoteTask {
template <typename F> template <typename F>
explicit RemoteTask(F&& f) : explicit RemoteTask(F&& f)
func(std::forward<F>(f)), : func(std::forward<F>(f)), rcontext(RequestContext::saveContext()) {}
rcontext(RequestContext::saveContext()) {}
template <typename F> template <typename F>
RemoteTask(F&& f, const Fiber::LocalData& localData_) : RemoteTask(F&& f, const Fiber::LocalData& localData_)
func(std::forward<F>(f)), : func(std::forward<F>(f)),
localData(folly::make_unique<Fiber::LocalData>(localData_)), localData(folly::make_unique<Fiber::LocalData>(localData_)),
rcontext(RequestContext::saveContext()) {} rcontext(RequestContext::saveContext()) {}
folly::Function<void()> func; folly::Function<void()> func;
std::unique_ptr<Fiber::LocalData> localData; std::unique_ptr<Fiber::LocalData> localData;
std::shared_ptr<RequestContext> rcontext; std::shared_ptr<RequestContext> rcontext;
...@@ -351,17 +349,17 @@ class FiberManager : public ::folly::Executor { ...@@ -351,17 +349,17 @@ class FiberManager : public ::folly::Executor {
*/ */
Fiber* currentFiber_{nullptr}; Fiber* currentFiber_{nullptr};
FiberTailQueue readyFibers_; /**< queue of fibers ready to be executed */ FiberTailQueue readyFibers_; /**< queue of fibers ready to be executed */
FiberTailQueue yieldedFibers_; /**< queue of fibers which have yielded FiberTailQueue yieldedFibers_; /**< queue of fibers which have yielded
execution */ execution */
FiberTailQueue fibersPool_; /**< pool of unitialized Fiber objects */ FiberTailQueue fibersPool_; /**< pool of unitialized Fiber objects */
GlobalFiberTailQueue allFibers_; /**< list of all Fiber objects owned */ GlobalFiberTailQueue allFibers_; /**< list of all Fiber objects owned */
size_t fibersAllocated_{0}; /**< total number of fibers allocated */ size_t fibersAllocated_{0}; /**< total number of fibers allocated */
size_t fibersPoolSize_{0}; /**< total number of fibers in the free pool */ size_t fibersPoolSize_{0}; /**< total number of fibers in the free pool */
size_t fibersActive_{0}; /**< number of running or blocked fibers */ size_t fibersActive_{0}; /**< number of running or blocked fibers */
size_t fiberId_{0}; /**< id of last fiber used */ size_t fiberId_{0}; /**< id of last fiber used */
/** /**
* Maximum number of active fibers in the last period lasting * Maximum number of active fibers in the last period lasting
...@@ -369,7 +367,7 @@ class FiberManager : public ::folly::Executor { ...@@ -369,7 +367,7 @@ class FiberManager : public ::folly::Executor {
*/ */
size_t maxFibersActiveLastPeriod_{0}; size_t maxFibersActiveLastPeriod_{0};
FContext::ContextStruct mainContext_; /**< stores loop function context */ FContext::ContextStruct mainContext_; /**< stores loop function context */
std::unique_ptr<LoopController> loopController_; std::unique_ptr<LoopController> loopController_;
bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */ bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */
...@@ -386,7 +384,7 @@ class FiberManager : public ::folly::Executor { ...@@ -386,7 +384,7 @@ class FiberManager : public ::folly::Executor {
*/ */
GuardPageAllocator stackAllocator_; GuardPageAllocator stackAllocator_;
const Options options_; /**< FiberManager options */ const Options options_; /**< FiberManager options */
/** /**
* Largest observed individual Fiber stack usage in bytes. * Largest observed individual Fiber stack usage in bytes.
...@@ -439,9 +437,9 @@ class FiberManager : public ::folly::Executor { ...@@ -439,9 +437,9 @@ class FiberManager : public ::folly::Executor {
std::shared_ptr<TimeoutController> timeoutManager_; std::shared_ptr<TimeoutController> timeoutManager_;
struct FibersPoolResizer { struct FibersPoolResizer {
explicit FibersPoolResizer(FiberManager& fm) : explicit FibersPoolResizer(FiberManager& fm) : fiberManager_(fm) {}
fiberManager_(fm) {}
void operator()(); void operator()();
private: private:
FiberManager& fiberManager_; FiberManager& fiberManager_;
}; };
...@@ -503,7 +501,7 @@ inline void addTask(F&& func) { ...@@ -503,7 +501,7 @@ inline void addTask(F&& func) {
template <typename F, typename G> template <typename F, typename G>
inline void addTaskFinally(F&& func, G&& finally) { inline void addTaskFinally(F&& func, G&& finally) {
return FiberManager::getFiberManager().addTaskFinally( return FiberManager::getFiberManager().addTaskFinally(
std::forward<F>(func), std::forward<G>(finally)); std::forward<F>(func), std::forward<G>(finally));
} }
/** /**
...@@ -514,8 +512,7 @@ inline void addTaskFinally(F&& func, G&& finally) { ...@@ -514,8 +512,7 @@ inline void addTaskFinally(F&& func, G&& finally) {
* @return data which was used to fulfill the promise. * @return data which was used to fulfill the promise.
*/ */
template <typename F> template <typename F>
typename FirstArgOf<F>::type::value_type typename FirstArgOf<F>::type::value_type inline await(F&& func);
inline await(F&& func);
/** /**
* If called from a fiber, immediately switches to the FiberManager's context * If called from a fiber, immediately switches to the FiberManager's context
...@@ -525,8 +522,7 @@ inline await(F&& func); ...@@ -525,8 +522,7 @@ inline await(F&& func);
* @return value returned by func(). * @return value returned by func().
*/ */
template <typename F> template <typename F>
typename std::result_of<F()>::type typename std::result_of<F()>::type inline runInMainContext(F&& func) {
inline runInMainContext(F&& func) {
auto fm = FiberManager::getFiberManagerUnsafe(); auto fm = FiberManager::getFiberManagerUnsafe();
if (UNLIKELY(fm == nullptr)) { if (UNLIKELY(fm == nullptr)) {
return func(); return func();
...@@ -558,7 +554,7 @@ inline void yield() { ...@@ -558,7 +554,7 @@ inline void yield() {
std::this_thread::yield(); std::this_thread::yield();
} }
} }
}
}} }
#include "FiberManager-inl.h" #include "FiberManager-inl.h"
...@@ -18,10 +18,11 @@ ...@@ -18,10 +18,11 @@
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <folly/ThreadLocal.h>
#include <folly/Synchronized.h> #include <folly/Synchronized.h>
#include <folly/ThreadLocal.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
namespace { namespace {
...@@ -109,12 +110,14 @@ class ThreadLocalCache { ...@@ -109,12 +110,14 @@ class ThreadLocalCache {
ThreadLocalCache() {} ThreadLocalCache() {}
struct ThreadLocalCacheTag {}; struct ThreadLocalCacheTag {};
using ThreadThreadLocalCache = ThreadLocal<ThreadLocalCache, ThreadLocalCacheTag>; using ThreadThreadLocalCache =
ThreadLocal<ThreadLocalCache, ThreadLocalCacheTag>;
// Leak this intentionally. During shutdown, we may call getFiberManager, // Leak this intentionally. During shutdown, we may call getFiberManager,
// and want access to the fiber managers during that time. // and want access to the fiber managers during that time.
static ThreadThreadLocalCache& instance() { static ThreadThreadLocalCache& instance() {
static auto ret = new ThreadThreadLocalCache([]() { return new ThreadLocalCache(); }); static auto ret =
new ThreadThreadLocalCache([]() { return new ThreadLocalCache(); });
return *ret; return *ret;
} }
...@@ -177,9 +180,10 @@ void EventBaseOnDestructionCallback::runLoopCallback() noexcept { ...@@ -177,9 +180,10 @@ void EventBaseOnDestructionCallback::runLoopCallback() noexcept {
} // namespace } // namespace
FiberManager& getFiberManager(EventBase& evb, FiberManager& getFiberManager(
const FiberManager::Options& opts) { EventBase& evb,
const FiberManager::Options& opts) {
return ThreadLocalCache::get(evb, opts); return ThreadLocalCache::get(evb, opts);
} }
}
}} }
...@@ -15,13 +15,14 @@ ...@@ -15,13 +15,14 @@
*/ */
#pragma once #pragma once
#include <folly/experimental/fibers/FiberManager.h>
#include <folly/experimental/fibers/EventBaseLoopController.h> #include <folly/experimental/fibers/EventBaseLoopController.h>
#include <folly/experimental/fibers/FiberManager.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
FiberManager& getFiberManager( FiberManager& getFiberManager(
folly::EventBase& evb, folly::EventBase& evb,
const FiberManager::Options& opts = FiberManager::Options()); const FiberManager::Options& opts = FiberManager::Options());
}
}} }
...@@ -15,26 +15,27 @@ ...@@ -15,26 +15,27 @@
*/ */
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
namespace { namespace {
template <class F, class G> template <class F, class G>
typename std::enable_if< typename std::enable_if<
!std::is_same<typename std::result_of<F()>::type, void>::value, void>::type !std::is_same<typename std::result_of<F()>::type, void>::value,
inline callFuncs(F&& f, G&& g, size_t id) { void>::type inline callFuncs(F&& f, G&& g, size_t id) {
g(id, f()); g(id, f());
} }
template <class F, class G> template <class F, class G>
typename std::enable_if< typename std::enable_if<
std::is_same<typename std::result_of<F()>::type, void>::value, void>::type std::is_same<typename std::result_of<F()>::type, void>::value,
inline callFuncs(F&& f, G&& g, size_t id) { void>::type inline callFuncs(F&& f, G&& g, size_t id) {
f(); f();
g(id); g(id);
} }
} // anonymous namespace } // anonymous namespace
template <class InputIterator, class F> template <class InputIterator, class F>
inline void forEach(InputIterator first, InputIterator last, F&& f) { inline void forEach(InputIterator first, InputIterator last, F&& f) {
...@@ -52,20 +53,25 @@ inline void forEach(InputIterator first, InputIterator last, F&& f) { ...@@ -52,20 +53,25 @@ inline void forEach(InputIterator first, InputIterator last, F&& f) {
#pragma clang diagnostic push // ignore generalized lambda capture warning #pragma clang diagnostic push // ignore generalized lambda capture warning
#pragma clang diagnostic ignored "-Wc++1y-extensions" #pragma clang diagnostic ignored "-Wc++1y-extensions"
#endif #endif
auto taskFunc = auto taskFunc = [&tasksTodo, &e, &f, &baton](size_t id, FuncType&& func) {
[&tasksTodo, &e, &f, &baton] (size_t id, FuncType&& func) { return [
return [id, &tasksTodo, &e, &f, &baton, id,
func_ = std::forward<FuncType>(func)]() mutable { &tasksTodo,
try { &e,
callFuncs(std::forward<FuncType>(func_), f, id); &f,
} catch (...) { &baton,
e = std::current_exception(); func_ = std::forward<FuncType>(func)
} ]() mutable {
if (--tasksTodo == 0) { try {
baton.post(); callFuncs(std::forward<FuncType>(func_), f, id);
} } catch (...) {
}; e = std::current_exception();
}
if (--tasksTodo == 0) {
baton.post();
}
}; };
};
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
...@@ -84,5 +90,5 @@ inline void forEach(InputIterator first, InputIterator last, F&& f) { ...@@ -84,5 +90,5 @@ inline void forEach(InputIterator first, InputIterator last, F&& f) {
std::rethrow_exception(e); std::rethrow_exception(e);
} }
} }
}
}} // folly::fibers } // folly::fibers
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
*/ */
#pragma once #pragma once
namespace folly { namespace fibers { namespace folly {
namespace fibers {
/** /**
* Schedules several tasks and blocks until all of them are completed. * Schedules several tasks and blocks until all of them are completed.
...@@ -37,7 +38,7 @@ namespace folly { namespace fibers { ...@@ -37,7 +38,7 @@ namespace folly { namespace fibers {
*/ */
template <class InputIterator, class F> template <class InputIterator, class F>
inline void forEach(InputIterator first, InputIterator last, F&& f); inline void forEach(InputIterator first, InputIterator last, F&& f);
}
}} // folly::fibers } // folly::fibers
#include <folly/experimental/fibers/ForEach-inl.h> #include <folly/experimental/fibers/ForEach-inl.h>
...@@ -19,8 +19,9 @@ ...@@ -19,8 +19,9 @@
#include <folly/experimental/fibers/Baton.h> #include <folly/experimental/fibers/Baton.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
typedef Baton GenericBaton; typedef Baton GenericBaton;
}
}} }
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
#include <glog/logging.h> #include <glog/logging.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
/** /**
* Each stack with a guard page creates two memory mappings. * Each stack with a guard page creates two memory mappings.
...@@ -52,12 +53,14 @@ constexpr size_t kMaxInUse = 100; ...@@ -52,12 +53,14 @@ constexpr size_t kMaxInUse = 100;
*/ */
class StackCache { class StackCache {
public: public:
explicit StackCache(size_t stackSize) explicit StackCache(size_t stackSize) : allocSize_(allocSize(stackSize)) {
: allocSize_(allocSize(stackSize)) { auto p = ::mmap(
auto p = ::mmap(nullptr, allocSize_ * kNumGuarded, nullptr,
PROT_READ | PROT_WRITE, allocSize_ * kNumGuarded,
MAP_PRIVATE | MAP_ANONYMOUS, PROT_READ | PROT_WRITE,
-1, 0); MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
PCHECK(p != (void*)(-1)); PCHECK(p != (void*)(-1));
storage_ = reinterpret_cast<unsigned char*>(p); storage_ = reinterpret_cast<unsigned char*>(p);
...@@ -140,7 +143,7 @@ class StackCache { ...@@ -140,7 +143,7 @@ class StackCache {
/* Returns a multiple of pagesize() enough to store size + one guard page */ /* Returns a multiple of pagesize() enough to store size + one guard page */
static size_t allocSize(size_t size) { static size_t allocSize(size_t size) {
return pagesize() * ((size + pagesize() - 1)/pagesize() + 1); return pagesize() * ((size + pagesize() - 1) / pagesize() + 1);
} }
}; };
...@@ -187,8 +190,7 @@ class CacheManager { ...@@ -187,8 +190,7 @@ class CacheManager {
class StackCacheEntry { class StackCacheEntry {
public: public:
explicit StackCacheEntry(size_t stackSize) explicit StackCacheEntry(size_t stackSize)
: stackCache_(folly::make_unique<StackCache>(stackSize)) { : stackCache_(folly::make_unique<StackCache>(stackSize)) {}
}
StackCache& cache() const noexcept { StackCache& cache() const noexcept {
return *stackCache_; return *stackCache_;
...@@ -203,8 +205,7 @@ class StackCacheEntry { ...@@ -203,8 +205,7 @@ class StackCacheEntry {
}; };
GuardPageAllocator::GuardPageAllocator(bool useGuardPages) GuardPageAllocator::GuardPageAllocator(bool useGuardPages)
: useGuardPages_(useGuardPages) { : useGuardPages_(useGuardPages) {}
}
GuardPageAllocator::~GuardPageAllocator() = default; GuardPageAllocator::~GuardPageAllocator() = default;
...@@ -227,5 +228,5 @@ void GuardPageAllocator::deallocate(unsigned char* limit, size_t size) { ...@@ -227,5 +228,5 @@ void GuardPageAllocator::deallocate(unsigned char* limit, size_t size) {
fallbackAllocator_.deallocate(limit, size); fallbackAllocator_.deallocate(limit, size);
} }
} }
}
}} // folly::fibers } // folly::fibers
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
#include <memory> #include <memory>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class StackCacheEntry; class StackCacheEntry;
...@@ -51,5 +52,5 @@ class GuardPageAllocator { ...@@ -51,5 +52,5 @@ class GuardPageAllocator {
std::allocator<unsigned char> fallbackAllocator_; std::allocator<unsigned char> fallbackAllocator_;
bool useGuardPages_{true}; bool useGuardPages_{true};
}; };
}
}} // folly::fibers } // folly::fibers
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
#include <chrono> #include <chrono>
#include <functional> #include <functional>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class FiberManager; class FiberManager;
...@@ -57,5 +58,5 @@ class LoopController { ...@@ -57,5 +58,5 @@ class LoopController {
*/ */
virtual void timedSchedule(std::function<void()> func, TimePoint time) = 0; virtual void timedSchedule(std::function<void()> func, TimePoint time) = 0;
}; };
}
}} // folly::fibers } // folly::fibers
...@@ -15,16 +15,16 @@ ...@@ -15,16 +15,16 @@
*/ */
#include <folly/experimental/fibers/Baton.h> #include <folly/experimental/fibers/Baton.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
template <class T> template <class T>
Promise<T>::Promise(folly::Try<T>& value, Baton& baton) : Promise<T>::Promise(folly::Try<T>& value, Baton& baton)
value_(&value), baton_(&baton) : value_(&value), baton_(&baton) {}
{}
template <class T> template <class T>
Promise<T>::Promise(Promise&& other) noexcept : Promise<T>::Promise(Promise&& other) noexcept
value_(other.value_), baton_(other.baton_) { : value_(other.value_), baton_(other.baton_) {
other.value_ = nullptr; other.value_ = nullptr;
other.baton_ = nullptr; other.baton_ = nullptr;
} }
...@@ -70,16 +70,14 @@ void Promise<T>::setTry(folly::Try<T>&& t) { ...@@ -70,16 +70,14 @@ void Promise<T>::setTry(folly::Try<T>&& t) {
template <class T> template <class T>
template <class M> template <class M>
void Promise<T>::setValue(M&& v) { void Promise<T>::setValue(M&& v) {
static_assert(!std::is_same<T, void>::value, static_assert(!std::is_same<T, void>::value, "Use setValue() instead");
"Use setValue() instead");
setTry(folly::Try<T>(std::forward<M>(v))); setTry(folly::Try<T>(std::forward<M>(v)));
} }
template <class T> template <class T>
void Promise<T>::setValue() { void Promise<T>::setValue() {
static_assert(std::is_same<T, void>::value, static_assert(std::is_same<T, void>::value, "Use setValue(value) instead");
"Use setValue(value) instead");
setTry(folly::Try<void>()); setTry(folly::Try<void>());
} }
...@@ -89,5 +87,5 @@ template <class F> ...@@ -89,5 +87,5 @@ template <class F>
void Promise<T>::setWith(F&& func) { void Promise<T>::setWith(F&& func) {
setTry(makeTryWith(std::forward<F>(func))); setTry(makeTryWith(std::forward<F>(func)));
} }
}
}} }
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
#include <folly/experimental/fibers/traits.h> #include <folly/experimental/fibers/traits.h>
#include <folly/futures/Try.h> #include <folly/futures/Try.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class Baton; class Baton;
template <typename F> template <typename F>
typename FirstArgOf<F>::type::value_type typename FirstArgOf<F>::type::value_type inline await(F&& func);
inline await(F&& func);
template <typename T> template <typename T>
class Promise { class Promise {
...@@ -84,17 +84,17 @@ class Promise { ...@@ -84,17 +84,17 @@ class Promise {
template <class F> template <class F>
typename std::enable_if< typename std::enable_if<
std::is_convertible<typename std::result_of<F()>::type, T>::value && std::is_convertible<typename std::result_of<F()>::type, T>::value &&
!std::is_same<T, void>::value>::type !std::is_same<T, void>::value>::type
fulfilHelper(F&& func); fulfilHelper(F&& func);
template <class F> template <class F>
typename std::enable_if< typename std::enable_if<
std::is_same<typename std::result_of<F()>::type, void>::value && std::is_same<typename std::result_of<F()>::type, void>::value &&
std::is_same<T, void>::value>::type std::is_same<T, void>::value>::type
fulfilHelper(F&& func); fulfilHelper(F&& func);
}; };
}
}} }
#include <folly/experimental/fibers/Promise-inl.h> #include <folly/experimental/fibers/Promise-inl.h>
...@@ -19,16 +19,14 @@ ...@@ -19,16 +19,14 @@
#include <folly/experimental/fibers/LoopController.h> #include <folly/experimental/fibers/LoopController.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class FiberManager; class FiberManager;
class SimpleLoopController : public LoopController { class SimpleLoopController : public LoopController {
public: public:
SimpleLoopController() SimpleLoopController() : fm_(nullptr), stopRequested_(false) {}
: fm_(nullptr),
stopRequested_(false) {
}
/** /**
* Run FiberManager loop; if no ready task are present, * Run FiberManager loop; if no ready task are present,
...@@ -45,7 +43,7 @@ class SimpleLoopController : public LoopController { ...@@ -45,7 +43,7 @@ class SimpleLoopController : public LoopController {
auto time = Clock::now(); auto time = Clock::now();
for (size_t i=0; i<scheduledFuncs_.size(); ++i) { for (size_t i = 0; i < scheduledFuncs_.size(); ++i) {
if (scheduledFuncs_[i].first <= time) { if (scheduledFuncs_[i].first <= time) {
scheduledFuncs_[i].second(); scheduledFuncs_[i].second();
swap(scheduledFuncs_[i], scheduledFuncs_.back()); swap(scheduledFuncs_[i], scheduledFuncs_.back());
...@@ -106,5 +104,5 @@ class SimpleLoopController : public LoopController { ...@@ -106,5 +104,5 @@ class SimpleLoopController : public LoopController {
friend class FiberManager; friend class FiberManager;
}; };
}
}} // folly::fibers } // folly::fibers
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
*/ */
#pragma once #pragma once
namespace folly {
namespace folly { namespace fibers { namespace fibers {
// //
// TimedMutex implementation // TimedMutex implementation
...@@ -113,8 +113,9 @@ void TimedRWMutex<BatonType>::read_lock() { ...@@ -113,8 +113,9 @@ void TimedRWMutex<BatonType>::read_lock() {
assert(state_ == State::READ_LOCKED); assert(state_ == State::READ_LOCKED);
return; return;
} }
assert((state_ == State::UNLOCKED && readers_ == 0) || assert(
(state_ == State::READ_LOCKED && readers_ > 0)); (state_ == State::UNLOCKED && readers_ == 0) ||
(state_ == State::READ_LOCKED && readers_ > 0));
assert(read_waiters_.empty()); assert(read_waiters_.empty());
state_ = State::READ_LOCKED; state_ = State::READ_LOCKED;
readers_ += 1; readers_ += 1;
...@@ -147,8 +148,9 @@ bool TimedRWMutex<BatonType>::timed_read_lock( ...@@ -147,8 +148,9 @@ bool TimedRWMutex<BatonType>::timed_read_lock(
} }
return true; return true;
} }
assert((state_ == State::UNLOCKED && readers_ == 0) || assert(
(state_ == State::READ_LOCKED && readers_ > 0)); (state_ == State::UNLOCKED && readers_ == 0) ||
(state_ == State::READ_LOCKED && readers_ > 0));
assert(read_waiters_.empty()); assert(read_waiters_.empty());
state_ = State::READ_LOCKED; state_ = State::READ_LOCKED;
readers_ += 1; readers_ += 1;
...@@ -160,8 +162,9 @@ template <typename BatonType> ...@@ -160,8 +162,9 @@ template <typename BatonType>
bool TimedRWMutex<BatonType>::try_read_lock() { bool TimedRWMutex<BatonType>::try_read_lock() {
pthread_spin_lock(&lock_); pthread_spin_lock(&lock_);
if (state_ != State::WRITE_LOCKED) { if (state_ != State::WRITE_LOCKED) {
assert((state_ == State::UNLOCKED && readers_ == 0) || assert(
(state_ == State::READ_LOCKED && readers_ > 0)); (state_ == State::UNLOCKED && readers_ == 0) ||
(state_ == State::READ_LOCKED && readers_ > 0));
assert(read_waiters_.empty()); assert(read_waiters_.empty());
state_ = State::READ_LOCKED; state_ = State::READ_LOCKED;
readers_ += 1; readers_ += 1;
...@@ -237,15 +240,17 @@ template <typename BatonType> ...@@ -237,15 +240,17 @@ template <typename BatonType>
void TimedRWMutex<BatonType>::unlock() { void TimedRWMutex<BatonType>::unlock() {
pthread_spin_lock(&lock_); pthread_spin_lock(&lock_);
assert(state_ != State::UNLOCKED); assert(state_ != State::UNLOCKED);
assert((state_ == State::READ_LOCKED && readers_ > 0) || assert(
(state_ == State::WRITE_LOCKED && readers_ == 0)); (state_ == State::READ_LOCKED && readers_ > 0) ||
(state_ == State::WRITE_LOCKED && readers_ == 0));
if (state_ == State::READ_LOCKED) { if (state_ == State::READ_LOCKED) {
readers_ -= 1; readers_ -= 1;
} }
if (!read_waiters_.empty()) { if (!read_waiters_.empty()) {
assert(state_ == State::WRITE_LOCKED && readers_ == 0 && assert(
"read waiters can only accumulate while write locked"); state_ == State::WRITE_LOCKED && readers_ == 0 &&
"read waiters can only accumulate while write locked");
state_ = State::READ_LOCKED; state_ = State::READ_LOCKED;
readers_ = read_waiters_.size(); readers_ = read_waiters_.size();
...@@ -291,5 +296,5 @@ void TimedRWMutex<BatonType>::downgrade() { ...@@ -291,5 +296,5 @@ void TimedRWMutex<BatonType>::downgrade() {
} }
pthread_spin_unlock(&lock_); pthread_spin_unlock(&lock_);
} }
}
}} }
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#include <folly/experimental/fibers/GenericBaton.h> #include <folly/experimental/fibers/GenericBaton.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
/** /**
* @class TimedMutex * @class TimedMutex
...@@ -49,8 +50,7 @@ class TimedMutex { ...@@ -49,8 +50,7 @@ class TimedMutex {
// //
// @return true if the mutex was locked, false otherwise // @return true if the mutex was locked, false otherwise
template <typename Rep, typename Period> template <typename Rep, typename Period>
bool timed_lock( bool timed_lock(const std::chrono::duration<Rep, Period>& duration);
const std::chrono::duration<Rep, Period>& duration);
// Try to obtain lock without blocking the thread or fiber // Try to obtain lock without blocking the thread or fiber
bool try_lock(); bool try_lock();
...@@ -68,18 +68,19 @@ class TimedMutex { ...@@ -68,18 +68,19 @@ class TimedMutex {
MutexWaiterHookType hook; MutexWaiterHookType hook;
}; };
typedef boost::intrusive::member_hook<MutexWaiter, typedef boost::intrusive::
MutexWaiterHookType, member_hook<MutexWaiter, MutexWaiterHookType, &MutexWaiter::hook>
&MutexWaiter::hook> MutexWaiterHook; MutexWaiterHook;
typedef boost::intrusive::list<MutexWaiter, typedef boost::intrusive::list<
MutexWaiterHook, MutexWaiter,
boost::intrusive::constant_time_size<true>> MutexWaiterHook,
MutexWaiterList; boost::intrusive::constant_time_size<true>>
MutexWaiterList;
pthread_spinlock_t lock_; //< lock to protect waiter list pthread_spinlock_t lock_; //< lock to protect waiter list
bool locked_ = false; //< is this locked by some thread? bool locked_ = false; //< is this locked by some thread?
MutexWaiterList waiters_; //< list of waiters MutexWaiterList waiters_; //< list of waiters
}; };
/** /**
...@@ -136,7 +137,9 @@ class TimedRWMutex { ...@@ -136,7 +137,9 @@ class TimedRWMutex {
bool try_write_lock(); bool try_write_lock();
// Wrapper for write_lock() for compatibility with Mutex // Wrapper for write_lock() for compatibility with Mutex
void lock() { write_lock(); } void lock() {
write_lock();
}
// Realease the lock. The thread / fiber will wake up all readers if there are // Realease the lock. The thread / fiber will wake up all readers if there are
// any. If there are waiting writers then only one of them will be woken up. // any. If there are waiting writers then only one of them will be woken up.
...@@ -149,8 +152,7 @@ class TimedRWMutex { ...@@ -149,8 +152,7 @@ class TimedRWMutex {
class ReadHolder { class ReadHolder {
public: public:
explicit ReadHolder(TimedRWMutex& lock) explicit ReadHolder(TimedRWMutex& lock) : lock_(&lock) {
: lock_(&lock) {
lock_->read_lock(); lock_->read_lock();
} }
...@@ -213,28 +215,29 @@ class TimedRWMutex { ...@@ -213,28 +215,29 @@ class TimedRWMutex {
MutexWaiterHookType hook; MutexWaiterHookType hook;
}; };
typedef boost::intrusive::member_hook<MutexWaiter, typedef boost::intrusive::
MutexWaiterHookType, member_hook<MutexWaiter, MutexWaiterHookType, &MutexWaiter::hook>
&MutexWaiter::hook> MutexWaiterHook; MutexWaiterHook;
typedef boost::intrusive::list<MutexWaiter, typedef boost::intrusive::list<
MutexWaiterHook, MutexWaiter,
boost::intrusive::constant_time_size<true>> MutexWaiterHook,
MutexWaiterList; boost::intrusive::constant_time_size<true>>
MutexWaiterList;
pthread_spinlock_t lock_; //< lock protecting the internal state pthread_spinlock_t lock_; //< lock protecting the internal state
// (state_, read_waiters_, etc.) // (state_, read_waiters_, etc.)
State state_ = State::UNLOCKED; State state_ = State::UNLOCKED;
uint32_t readers_ = 0; //< Number of readers who have the lock uint32_t readers_ = 0; //< Number of readers who have the lock
MutexWaiterList write_waiters_; //< List of thread / fibers waiting for MutexWaiterList write_waiters_; //< List of thread / fibers waiting for
// exclusive access // exclusive access
MutexWaiterList read_waiters_; //< List of thread / fibers waiting for MutexWaiterList read_waiters_; //< List of thread / fibers waiting for
// shared access // shared access
}; };
}
}} }
#include "TimedMutex-inl.h" #include "TimedMutex-inl.h"
...@@ -16,14 +16,15 @@ ...@@ -16,14 +16,15 @@
#include "TimeoutController.h" #include "TimeoutController.h"
#include <folly/Memory.h> #include <folly/Memory.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
TimeoutController::TimeoutController(LoopController& loopController) : TimeoutController::TimeoutController(LoopController& loopController)
nextTimeout_(TimePoint::max()), : nextTimeout_(TimePoint::max()), loopController_(loopController) {}
loopController_(loopController) {}
intptr_t TimeoutController::registerTimeout(std::function<void()> f, intptr_t TimeoutController::registerTimeout(
Duration duration) { std::function<void()> f,
Duration duration) {
auto& list = [&]() -> TimeoutHandleList& { auto& list = [&]() -> TimeoutHandleList& {
for (auto& bucket : timeoutHandleBuckets_) { for (auto& bucket : timeoutHandleBuckets_) {
if (bucket.first == duration) { if (bucket.first == duration) {
...@@ -31,8 +32,8 @@ intptr_t TimeoutController::registerTimeout(std::function<void()> f, ...@@ -31,8 +32,8 @@ intptr_t TimeoutController::registerTimeout(std::function<void()> f,
} }
} }
timeoutHandleBuckets_.emplace_back(duration, timeoutHandleBuckets_.emplace_back(
folly::make_unique<TimeoutHandleList>()); duration, folly::make_unique<TimeoutHandleList>());
return *timeoutHandleBuckets_.back().second; return *timeoutHandleBuckets_.back().second;
}(); }();
...@@ -84,11 +85,13 @@ void TimeoutController::scheduleRun() { ...@@ -84,11 +85,13 @@ void TimeoutController::scheduleRun() {
auto time = nextTimeout_; auto time = nextTimeout_;
std::weak_ptr<TimeoutController> timeoutControllerWeak = shared_from_this(); std::weak_ptr<TimeoutController> timeoutControllerWeak = shared_from_this();
loopController_.timedSchedule([timeoutControllerWeak, time]() { loopController_.timedSchedule(
if (auto timeoutController = timeoutControllerWeak.lock()) { [timeoutControllerWeak, time]() {
timeoutController->runTimeouts(time); if (auto timeoutController = timeoutControllerWeak.lock()) {
} timeoutController->runTimeouts(time);
}, time); }
},
time);
} }
void TimeoutController::cancel(intptr_t p) { void TimeoutController::cancel(intptr_t p) {
...@@ -101,5 +104,5 @@ void TimeoutController::cancel(intptr_t p) { ...@@ -101,5 +104,5 @@ void TimeoutController::cancel(intptr_t p) {
list.pop(); list.pop();
} }
} }
}
}} }
...@@ -26,10 +26,11 @@ ...@@ -26,10 +26,11 @@
#include <folly/experimental/fibers/LoopController.h> #include <folly/experimental/fibers/LoopController.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
class TimeoutController : class TimeoutController
public std::enable_shared_from_this<TimeoutController> { : public std::enable_shared_from_this<TimeoutController> {
public: public:
typedef std::chrono::steady_clock Clock; typedef std::chrono::steady_clock Clock;
typedef std::chrono::time_point<Clock> TimePoint; typedef std::chrono::time_point<Clock> TimePoint;
...@@ -50,10 +51,11 @@ class TimeoutController : ...@@ -50,10 +51,11 @@ class TimeoutController :
typedef std::unique_ptr<TimeoutHandleList> TimeoutHandleListPtr; typedef std::unique_ptr<TimeoutHandleList> TimeoutHandleListPtr;
struct TimeoutHandle { struct TimeoutHandle {
TimeoutHandle(std::function<void()> func_, TimeoutHandle(
TimePoint timeout_, std::function<void()> func_,
TimeoutHandleList& list_) : TimePoint timeout_,
func(std::move(func_)), timeout(timeout_), list(list_) {} TimeoutHandleList& list_)
: func(std::move(func_)), timeout(timeout_), list(list_) {}
std::function<void()> func; std::function<void()> func;
bool canceled{false}; bool canceled{false};
...@@ -65,5 +67,5 @@ class TimeoutController : ...@@ -65,5 +67,5 @@ class TimeoutController :
TimePoint nextTimeout_; TimePoint nextTimeout_;
LoopController& loopController_; LoopController& loopController_;
}; };
}
}} }
...@@ -18,24 +18,22 @@ ...@@ -18,24 +18,22 @@
#include <folly/experimental/fibers/FiberManager.h> #include <folly/experimental/fibers/FiberManager.h>
#include <folly/experimental/fibers/ForEach.h> #include <folly/experimental/fibers/ForEach.h>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
template <class InputIterator> template <class InputIterator>
typename std::vector< typename std::vector<typename std::enable_if<
typename std::enable_if<
!std::is_same< !std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, void>::value,
typename std::pair< typename std::pair<
size_t, size_t,
typename std::result_of< typename std::result_of<typename std::iterator_traits<
typename std::iterator_traits<InputIterator>::value_type()>::type> InputIterator>::value_type()>::type>>::type>
>::type
>
collectN(InputIterator first, InputIterator last, size_t n) { collectN(InputIterator first, InputIterator last, size_t n) {
typedef typename std::result_of< typedef typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type Result; typename std::iterator_traits<InputIterator>::value_type()>::type Result;
assert(n > 0); assert(n > 0);
assert(std::distance(first, last) >= 0); assert(std::distance(first, last) >= 0);
assert(n <= static_cast<size_t>(std::distance(first, last))); assert(n <= static_cast<size_t>(std::distance(first, last)));
...@@ -52,37 +50,35 @@ collectN(InputIterator first, InputIterator last, size_t n) { ...@@ -52,37 +50,35 @@ collectN(InputIterator first, InputIterator last, size_t n) {
}; };
auto context = std::make_shared<Context>(n); auto context = std::make_shared<Context>(n);
await( await([first, last, context](Promise<void> promise) mutable {
[first, last, context](Promise<void> promise) mutable { context->promise = std::move(promise);
context->promise = std::move(promise); for (size_t i = 0; first != last; ++i, ++first) {
for (size_t i = 0; first != last; ++i, ++first) {
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic push // ignore generalized lambda capture warning #pragma clang diagnostic push // ignore generalized lambda capture warning
#pragma clang diagnostic ignored "-Wc++1y-extensions" #pragma clang diagnostic ignored "-Wc++1y-extensions"
#endif #endif
addTask( addTask([ i, context, f = std::move(*first) ]() {
[i, context, f = std::move(*first)]() { try {
try { auto result = f();
auto result = f(); if (context->tasksTodo == 0) {
if (context->tasksTodo == 0) { return;
return; }
} context->results.emplace_back(i, std::move(result));
context->results.emplace_back(i, std::move(result)); } catch (...) {
} catch (...) { if (context->tasksTodo == 0) {
if (context->tasksTodo == 0) { return;
return; }
} context->e = std::current_exception();
context->e = std::current_exception(); }
} if (--context->tasksTodo == 0) {
if (--context->tasksTodo == 0) { context->promise->setValue();
context->promise->setValue(); }
} });
});
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
} }
}); });
if (context->e != std::exception_ptr()) { if (context->e != std::exception_ptr()) {
std::rethrow_exception(context->e); std::rethrow_exception(context->e);
...@@ -93,10 +89,11 @@ collectN(InputIterator first, InputIterator last, size_t n) { ...@@ -93,10 +89,11 @@ collectN(InputIterator first, InputIterator last, size_t n) {
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
std::is_same< std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, std::vector<size_t>>::type void>::value,
std::vector<size_t>>::type
collectN(InputIterator first, InputIterator last, size_t n) { collectN(InputIterator first, InputIterator last, size_t n) {
assert(n > 0); assert(n > 0);
assert(std::distance(first, last) >= 0); assert(std::distance(first, last) >= 0);
...@@ -114,37 +111,35 @@ collectN(InputIterator first, InputIterator last, size_t n) { ...@@ -114,37 +111,35 @@ collectN(InputIterator first, InputIterator last, size_t n) {
}; };
auto context = std::make_shared<Context>(n); auto context = std::make_shared<Context>(n);
await( await([first, last, context](Promise<void> promise) mutable {
[first, last, context](Promise<void> promise) mutable { context->promise = std::move(promise);
context->promise = std::move(promise); for (size_t i = 0; first != last; ++i, ++first) {
for (size_t i = 0; first != last; ++i, ++first) {
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic push // ignore generalized lambda capture warning #pragma clang diagnostic push // ignore generalized lambda capture warning
#pragma clang diagnostic ignored "-Wc++1y-extensions" #pragma clang diagnostic ignored "-Wc++1y-extensions"
#endif #endif
addTask( addTask([ i, context, f = std::move(*first) ]() {
[i, context, f = std::move(*first)]() { try {
try { f();
f(); if (context->tasksTodo == 0) {
if (context->tasksTodo == 0) { return;
return; }
} context->taskIndices.push_back(i);
context->taskIndices.push_back(i); } catch (...) {
} catch (...) { if (context->tasksTodo == 0) {
if (context->tasksTodo == 0) { return;
return; }
} context->e = std::current_exception();
context->e = std::current_exception(); }
} if (--context->tasksTodo == 0) {
if (--context->tasksTodo == 0) { context->promise->setValue();
context->promise->setValue(); }
} });
});
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
} }
}); });
if (context->e != std::exception_ptr()) { if (context->e != std::exception_ptr()) {
std::rethrow_exception(context->e); std::rethrow_exception(context->e);
...@@ -155,26 +150,25 @@ collectN(InputIterator first, InputIterator last, size_t n) { ...@@ -155,26 +150,25 @@ collectN(InputIterator first, InputIterator last, size_t n) {
template <class InputIterator> template <class InputIterator>
typename std::vector< typename std::vector<
typename std::enable_if< typename std::enable_if<
!std::is_same< !std::is_same<
typename std::result_of< typename std::result_of<typename std::iterator_traits<
typename std::iterator_traits<InputIterator>::value_type()>::type, void InputIterator>::value_type()>::type,
>::value, void>::value,
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type>::type> typename std::iterator_traits<InputIterator>::value_type()>::type>::
inline collectAll(InputIterator first, InputIterator last) { type> inline collectAll(InputIterator first, InputIterator last) {
typedef typename std::result_of< typedef typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type Result; typename std::iterator_traits<InputIterator>::value_type()>::type Result;
size_t n = std::distance(first, last); size_t n = std::distance(first, last);
std::vector<Result> results; std::vector<Result> results;
std::vector<size_t> order(n); std::vector<size_t> order(n);
results.reserve(n); results.reserve(n);
forEach(first, last, forEach(first, last, [&results, &order](size_t id, Result result) {
[&results, &order] (size_t id, Result result) { order[id] = results.size();
order[id] = results.size(); results.emplace_back(std::move(result));
results.emplace_back(std::move(result)); });
});
assert(results.size() == n); assert(results.size() == n);
std::vector<Result> orderedResults; std::vector<Result> orderedResults;
...@@ -189,26 +183,25 @@ inline collectAll(InputIterator first, InputIterator last) { ...@@ -189,26 +183,25 @@ inline collectAll(InputIterator first, InputIterator last) {
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
std::is_same< std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, void>::type void>::value,
inline collectAll(InputIterator first, InputIterator last) { void>::type inline collectAll(InputIterator first, InputIterator last) {
forEach(first, last, [](size_t /* id */) {}); forEach(first, last, [](size_t /* id */) {});
} }
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
!std::is_same< !std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, void>::value,
typename std::pair< typename std::pair<
size_t, size_t,
typename std::result_of< typename std::result_of<typename std::iterator_traits<
typename std::iterator_traits<InputIterator>::value_type()>::type> InputIterator>::value_type()>::type>>::
>::type type inline collectAny(InputIterator first, InputIterator last) {
inline collectAny(InputIterator first, InputIterator last) {
auto result = collectN(first, last, 1); auto result = collectN(first, last, 1);
assert(result.size() == 1); assert(result.size() == 1);
return std::move(result[0]); return std::move(result[0]);
...@@ -216,14 +209,14 @@ inline collectAny(InputIterator first, InputIterator last) { ...@@ -216,14 +209,14 @@ inline collectAny(InputIterator first, InputIterator last) {
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
std::is_same< std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, size_t>::type void>::value,
inline collectAny(InputIterator first, InputIterator last) { size_t>::type inline collectAny(InputIterator first, InputIterator last) {
auto result = collectN(first, last, 1); auto result = collectN(first, last, 1);
assert(result.size() == 1); assert(result.size() == 1);
return std::move(result[0]); return std::move(result[0]);
} }
}
}} }
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
*/ */
#pragma once #pragma once
namespace folly { namespace fibers { namespace folly {
namespace fibers {
/** /**
* Schedules several tasks and blocks until n of these tasks are completed. * Schedules several tasks and blocks until n of these tasks are completed.
...@@ -31,18 +32,16 @@ namespace folly { namespace fibers { ...@@ -31,18 +32,16 @@ namespace folly { namespace fibers {
*/ */
template <class InputIterator> template <class InputIterator>
typename std::vector< typename std::vector<
typename std::enable_if< typename std::enable_if<
!std::is_same< !std::is_same<
typename std::result_of< typename std::result_of<typename std::iterator_traits<
typename std::iterator_traits<InputIterator>::value_type()>::type, InputIterator>::value_type()>::type,
void>::value, void>::value,
typename std::pair< typename std::pair<
size_t, size_t,
typename std::result_of< typename std::result_of<typename std::iterator_traits<
typename std::iterator_traits<InputIterator>::value_type()>::type> InputIterator>::value_type()>::type>>::
>::type type> inline collectN(InputIterator first, InputIterator last, size_t n);
>
inline collectN(InputIterator first, InputIterator last, size_t n);
/** /**
* collectN specialization for functions returning void * collectN specialization for functions returning void
...@@ -55,11 +54,12 @@ inline collectN(InputIterator first, InputIterator last, size_t n); ...@@ -55,11 +54,12 @@ inline collectN(InputIterator first, InputIterator last, size_t n);
*/ */
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
std::is_same< std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, std::vector<size_t>>::type void>::value,
inline collectN(InputIterator first, InputIterator last, size_t n); std::vector<size_t>>::
type inline collectN(InputIterator first, InputIterator last, size_t n);
/** /**
* Schedules several tasks and blocks until all of these tasks are completed. * Schedules several tasks and blocks until all of these tasks are completed.
...@@ -73,16 +73,14 @@ inline collectN(InputIterator first, InputIterator last, size_t n); ...@@ -73,16 +73,14 @@ inline collectN(InputIterator first, InputIterator last, size_t n);
* @return vector of values returned by tasks * @return vector of values returned by tasks
*/ */
template <class InputIterator> template <class InputIterator>
typename std::vector< typename std::vector<typename std::enable_if<
typename std::enable_if<
!std::is_same< !std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, typename std::iterator_traits<InputIterator>::value_type()>::type,
void>::value, void>::value,
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type>::type typename std::iterator_traits<InputIterator>::value_type()>::
> type>::type> inline collectAll(InputIterator first, InputIterator last);
inline collectAll(InputIterator first, InputIterator last);
/** /**
* collectAll specialization for functions returning void * collectAll specialization for functions returning void
...@@ -92,11 +90,11 @@ inline collectAll(InputIterator first, InputIterator last); ...@@ -92,11 +90,11 @@ inline collectAll(InputIterator first, InputIterator last);
*/ */
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
std::is_same< std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, void>::type void>::value,
inline collectAll(InputIterator first, InputIterator last); void>::type inline collectAll(InputIterator first, InputIterator last);
/** /**
* Schedules several tasks and blocks until one of them is completed. * Schedules several tasks and blocks until one of them is completed.
...@@ -110,16 +108,15 @@ inline collectAll(InputIterator first, InputIterator last); ...@@ -110,16 +108,15 @@ inline collectAll(InputIterator first, InputIterator last);
*/ */
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
!std::is_same< !std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, void>::value,
typename std::pair< typename std::pair<
size_t, size_t,
typename std::result_of< typename std::result_of<typename std::iterator_traits<
typename std::iterator_traits<InputIterator>::value_type()>::type> InputIterator>::value_type()>::type>>::
>::type type inline collectAny(InputIterator first, InputIterator last);
inline collectAny(InputIterator first, InputIterator last);
/** /**
* WhenAny specialization for functions returning void. * WhenAny specialization for functions returning void.
...@@ -131,12 +128,12 @@ inline collectAny(InputIterator first, InputIterator last); ...@@ -131,12 +128,12 @@ inline collectAny(InputIterator first, InputIterator last);
*/ */
template <class InputIterator> template <class InputIterator>
typename std::enable_if< typename std::enable_if<
std::is_same< std::is_same<
typename std::result_of< typename std::result_of<
typename std::iterator_traits<InputIterator>::value_type()>::type, void typename std::iterator_traits<InputIterator>::value_type()>::type,
>::value, size_t>::type void>::value,
inline collectAny(InputIterator first, InputIterator last); size_t>::type inline collectAny(InputIterator first, InputIterator last);
}
}} }
#include <folly/experimental/fibers/WhenN-inl.h> #include <folly/experimental/fibers/WhenN-inl.h>
...@@ -25,18 +25,17 @@ using namespace folly::fibers; ...@@ -25,18 +25,17 @@ using namespace folly::fibers;
struct Application { struct Application {
public: public:
Application () Application()
: fiberManager(folly::make_unique<SimpleLoopController>()), : fiberManager(folly::make_unique<SimpleLoopController>()),
toSend(20), toSend(20),
maxOutstanding(5) { maxOutstanding(5) {}
}
void loop() { void loop() {
if (pendingRequests.size() == maxOutstanding || toSend == 0) { if (pendingRequests.size() == maxOutstanding || toSend == 0) {
if (pendingRequests.empty()) { if (pendingRequests.empty()) {
return; return;
} }
intptr_t value = rand()%1000; intptr_t value = rand() % 1000;
std::cout << "Completing request with data = " << value << std::endl; std::cout << "Completing request with data = " << value << std::endl;
pendingRequests.front().setValue(value); pendingRequests.front().setValue(value);
...@@ -47,27 +46,25 @@ struct Application { ...@@ -47,27 +46,25 @@ struct Application {
std::cout << "Adding new request with id = " << id << std::endl; std::cout << "Adding new request with id = " << id << std::endl;
fiberManager.addTask([this, id]() { fiberManager.addTask([this, id]() {
std::cout << "Executing fiber with id = " << id << std::endl; std::cout << "Executing fiber with id = " << id << std::endl;
auto result1 = await( auto result1 = await([this](Promise<int> fiber) {
[this](Promise<int> fiber) { pendingRequests.push(std::move(fiber));
pendingRequests.push(std::move(fiber)); });
});
std::cout << "Fiber id = " << id std::cout << "Fiber id = " << id << " got result1 = " << result1
<< " got result1 = " << result1 << std::endl; << std::endl;
auto result2 = await auto result2 = await([this](Promise<int> fiber) {
([this](Promise<int> fiber) { pendingRequests.push(std::move(fiber));
pendingRequests.push(std::move(fiber)); });
}); std::cout << "Fiber id = " << id << " got result2 = " << result2
std::cout << "Fiber id = " << id << std::endl;
<< " got result2 = " << result2 << std::endl; });
});
if (--toSend == 0) { if (--toSend == 0) {
auto& loopController = auto& loopController =
dynamic_cast<SimpleLoopController&>(fiberManager.loopController()); dynamic_cast<SimpleLoopController&>(fiberManager.loopController());
loopController.stop(); loopController.stop();
} }
} }
...@@ -83,12 +80,10 @@ struct Application { ...@@ -83,12 +80,10 @@ struct Application {
int main() { int main() {
Application app; Application app;
auto loop = [&app]() { auto loop = [&app]() { app.loop(); };
app.loop();
};
auto& loopController = auto& loopController =
dynamic_cast<SimpleLoopController&>(app.fiberManager.loopController()); dynamic_cast<SimpleLoopController&>(app.fiberManager.loopController());
loopController.loop(std::move(loop)); loopController.loop(std::move(loop));
......
...@@ -18,8 +18,10 @@ ...@@ -18,8 +18,10 @@
#include <folly/Benchmark.h> #include <folly/Benchmark.h>
// for backward compatibility with gflags // for backward compatibility with gflags
namespace gflags { } namespace gflags {}
namespace google { using namespace gflags; } namespace google {
using namespace gflags;
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
......
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
#include <boost/type_traits.hpp> #include <boost/type_traits.hpp>
namespace folly { namespace fibers { namespace folly {
namespace fibers {
/** /**
* For any functor F taking >= 1 argument, * For any functor F taking >= 1 argument,
...@@ -38,7 +39,7 @@ namespace detail { ...@@ -38,7 +39,7 @@ namespace detail {
* If F is a pointer-to-member, will contain a typedef type * If F is a pointer-to-member, will contain a typedef type
* with the type of F's first parameter * with the type of F's first parameter
*/ */
template<typename> template <typename>
struct ExtractFirstMemfn; struct ExtractFirstMemfn;
template <typename Ret, typename T, typename First, typename... Args> template <typename Ret, typename T, typename First, typename... Args>
...@@ -51,20 +52,20 @@ struct ExtractFirstMemfn<Ret (T::*)(First, Args...) const> { ...@@ -51,20 +52,20 @@ struct ExtractFirstMemfn<Ret (T::*)(First, Args...) const> {
typedef First type; typedef First type;
}; };
} // detail } // detail
/** Default - use boost */ /** Default - use boost */
template <typename F, typename Enable = void> template <typename F, typename Enable = void>
struct FirstArgOf { struct FirstArgOf {
typedef typename boost::function_traits< typedef typename boost::function_traits<
typename std::remove_pointer<F>::type>::arg1_type type; typename std::remove_pointer<F>::type>::arg1_type type;
}; };
/** Specialization for function objects */ /** Specialization for function objects */
template <typename F> template <typename F>
struct FirstArgOf<F, typename std::enable_if<std::is_class<F>::value>::type> { struct FirstArgOf<F, typename std::enable_if<std::is_class<F>::value>::type> {
typedef typename detail::ExtractFirstMemfn< typedef
decltype(&F::operator())>::type type; typename detail::ExtractFirstMemfn<decltype(&F::operator())>::type type;
}; };
}
}} // folly::fibers } // folly::fibers
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