Commit 0978159b authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Viswanath Sivakumar

Add FiberManager local type

Summary: This adds local type for each FiberManager. Only local of given type can be created on fibers of this FiberManager. Locals of other types will be just treated as regualar thread-locals.

Test Plan: unit test

Reviewed By: bwatling@fb.com

Subscribers: folly-diffs@, yfeldblum, chalfant

FB internal diff: D1969739

Signature: t1:1969739:1428345931:aff5deb526c179158e5881b29330ff3f6698149a
parent 42caa0b1
......@@ -44,6 +44,20 @@ template <class T, AtomicLinkedListHook<T> T::* HookMember>
class AtomicLinkedList {
public:
AtomicLinkedList() {}
AtomicLinkedList(const AtomicLinkedList&) = delete;
AtomicLinkedList& operator=(const AtomicLinkedList&) = delete;
AtomicLinkedList(AtomicLinkedList&& other) noexcept {
auto tmp = other.head_.load();
other.head_ = head_.load();
head_ = tmp;
}
AtomicLinkedList& operator=(AtomicLinkedList&& other) noexcept {
auto tmp = other.head_.load();
other.head_ = head_.load();
head_ = tmp;
return *this;
}
/**
* Note: list must be empty on destruction.
......
......@@ -174,9 +174,7 @@ void FiberManager::addTask(F&& func) {
typedef AddTaskHelper<F> Helper;
auto fiber = getFiber();
if (currentFiber_) {
fiber->localData_ = currentFiber_->localData_;
}
initLocalData(*fiber);
if (Helper::allocateInBuffer) {
auto funcLoc = static_cast<typename Helper::Func*>(fiber->getUserBuffer());
......@@ -199,7 +197,9 @@ 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_);
......@@ -297,9 +297,7 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) {
"finally(Try<T>&&): T must be convertible from func()'s return type");
auto fiber = getFiber();
if (currentFiber_) {
fiber->localData_ = currentFiber_->localData_;
}
initLocalData(*fiber);
typedef AddTaskFinallyHelper<F,G> Helper;
......@@ -383,7 +381,7 @@ inline bool FiberManager::hasActiveFiber() const {
template <typename T>
T& FiberManager::local() {
if (currentFiber_) {
if (std::type_index(typeid(T)) == localType_ && currentFiber_) {
return currentFiber_->localData_.get<T>();
}
return localThread<T>();
......@@ -395,6 +393,22 @@ T& FiberManager::localThread() {
return t;
}
inline void FiberManager::initLocalData(Fiber& fiber) {
auto fm = getFiberManagerUnsafe();
if (fm && fm->currentFiber_ && fm->localType_ == localType_) {
fiber.localData_ = fm->currentFiber_->localData_;
}
}
template <typename LocalT>
FiberManager FiberManager::create(
std::unique_ptr<LoopController> loopController,
Options options) {
FiberManager fm(std::move(loopController), std::move(options));
fm.localType_ = typeid(LocalT);
return fm;
}
template <typename F>
typename FirstArgOf<F>::type::value_type
inline await(F&& func) {
......
......@@ -48,7 +48,8 @@ FiberManager::FiberManager(std::unique_ptr<LoopController> loopController,
throw;
}
}),
timeoutManager_(std::make_shared<TimeoutController>(*loopController_)) {
timeoutManager_(std::make_shared<TimeoutController>(*loopController_)),
localType_(typeid(void)) {
loopController_->setFiberManager(this);
}
......
......@@ -18,6 +18,7 @@
#include <functional>
#include <memory>
#include <queue>
#include <typeindex>
#include <unordered_set>
#include <vector>
......@@ -91,14 +92,33 @@ class FiberManager {
typedef std::function<void(std::exception_ptr, std::string)>
ExceptionCallback;
FiberManager(const FiberManager&) = delete;
FiberManager& operator=(const FiberManager&) = delete;
FiberManager(FiberManager&&) = default;
FiberManager& operator=(FiberManager&&) = default;
/**
* Initializes, but doesn't start FiberManager loop
*
* @param loopController
* @param options FiberManager options
*/
explicit FiberManager(std::unique_ptr<LoopController> loopController,
Options options = Options());
/**
* Initializes, but doesn't start FiberManager loop
*
* @param loopController
* @param options FiberManager options
* @tparam LocalT only local of this type may be stored on fibers.
* Locals of other types will be considered thread-locals.
*/
template <typename LocalT>
static FiberManager create(std::unique_ptr<LoopController> loopController,
Options options = Options());
~FiberManager();
/**
......@@ -300,6 +320,11 @@ class FiberManager {
*/
Fiber* getFiber();
/**
* Sets local data for given fiber if all conditions are met.
*/
void initLocalData(Fiber& fiber);
/**
* Function passed to the await call.
*/
......@@ -319,6 +344,11 @@ class FiberManager {
std::shared_ptr<TimeoutController> timeoutManager_;
/**
* Only local of this type will be available for fibers.
*/
std::type_index localType_;
void runReadyFiber(Fiber* fiber);
void remoteReadyInsert(Fiber* fiber);
};
......
......@@ -1217,7 +1217,8 @@ TEST(FiberManager, remoteHasReadyTasks) {
template <typename Data>
void testFiberLocal() {
FiberManager fm(folly::make_unique<SimpleLoopController>());
auto fm =
FiberManager::create<Data>(folly::make_unique<SimpleLoopController>());
fm.addTask([]() {
EXPECT_EQ(42, local<Data>().value);
......
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