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