logging: add an assert for the FLAG_INHERIT bit
[folly.git] / folly / fibers / Fiber.cpp
index 20af545569d35e0e102bad782f512e7a41f19c58..afc05200a878ee6b34ef491eb87721b29724eae4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,8 +15,6 @@
  */
 #include "Fiber.h"
 
-#include <unistd.h>
-
 #include <glog/logging.h>
 #include <algorithm>
 #include <cstring>
@@ -24,9 +22,9 @@
 
 #include <folly/Likely.h>
 #include <folly/Portability.h>
-#include <folly/fibers/BoostContextCompatibility.h>
-#include <folly/fibers/FiberManager.h>
+#include <folly/fibers/FiberManagerInternal.h>
 #include <folly/portability/SysSyscall.h>
+#include <folly/portability/Unistd.h>
 
 namespace folly {
 namespace fibers {
@@ -39,9 +37,11 @@ std::thread::id localThreadId() {
 }
 
 /* Size of the region from p + nBytes down to the last non-magic value */
-static size_t nonMagicInBytes(const FContext& context) {
-  uint64_t* begin = static_cast<uint64_t*>(context.stackLimit());
-  uint64_t* end = static_cast<uint64_t*>(context.stackBase());
+static size_t nonMagicInBytes(unsigned char* stackLimit, size_t stackSize) {
+  CHECK_EQ(reinterpret_cast<intptr_t>(stackLimit) % sizeof(uint64_t), 0u);
+  CHECK_EQ(stackSize % sizeof(uint64_t), 0u);
+  uint64_t* begin = reinterpret_cast<uint64_t*>(stackLimit);
+  uint64_t* end = reinterpret_cast<uint64_t*>(stackLimit + stackSize);
 
   auto firstNonMagic = std::find_if(
       begin, end, [](uint64_t val) { return val != kMagic8Bytes; });
@@ -49,11 +49,10 @@ static size_t nonMagicInBytes(const FContext& context) {
   return (end - firstNonMagic) * sizeof(uint64_t);
 }
 
-} // anonymous namespace
+} // namespace
 
-void Fiber::setData(intptr_t data) {
+void Fiber::resume() {
   DCHECK_EQ(state_, AWAITING);
-  data_ = data;
   state_ = READY_TO_RUN;
 
   if (fiberManager_.observer_) {
@@ -68,12 +67,11 @@ void Fiber::setData(intptr_t data) {
   }
 }
 
-Fiber::Fiber(FiberManager& fiberManager) : fiberManager_(fiberManager) {
-  auto size = fiberManager_.options_.stackSize;
-  auto limit = fiberManager_.stackAllocator_.allocate(size);
-
-  fcontext_ = makeContext(limit, size, &Fiber::fiberFuncHelper);
-
+Fiber::Fiber(FiberManager& fiberManager)
+    : fiberManager_(fiberManager),
+      fiberStackSize_(fiberManager_.options_.stackSize),
+      fiberStackLimit_(fiberManager_.stackAllocator_.allocate(fiberStackSize_)),
+      fiberImpl_([this] { fiberFunc(); }, fiberStackLimit_, fiberStackSize_) {
   fiberManager_.allFibers_.push_back(*this);
 }
 
@@ -83,20 +81,20 @@ void Fiber::init(bool recordStackUsed) {
 #ifndef FOLLY_SANITIZE_ADDRESS
   recordStackUsed_ = recordStackUsed;
   if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) {
-    auto limit = fcontext_.stackLimit();
-    auto base = fcontext_.stackBase();
-
+    CHECK_EQ(
+        reinterpret_cast<intptr_t>(fiberStackLimit_) % sizeof(uint64_t), 0u);
+    CHECK_EQ(fiberStackSize_ % sizeof(uint64_t), 0u);
     std::fill(
-        static_cast<uint64_t*>(limit),
-        static_cast<uint64_t*>(base),
+        reinterpret_cast<uint64_t*>(fiberStackLimit_),
+        reinterpret_cast<uint64_t*>(fiberStackLimit_ + fiberStackSize_),
         kMagic8Bytes);
 
+    stackFilledWithMagic_ = true;
+
     // newer versions of boost allocate context on fiber stack,
     // need to create a new one
-    auto size = fiberManager_.options_.stackSize;
-    fcontext_ = makeContext(limit, size, &Fiber::fiberFuncHelper);
-
-    stackFilledWithMagic_ = true;
+    fiberImpl_ =
+        FiberImpl([this] { fiberFunc(); }, fiberStackLimit_, fiberStackSize_);
   }
 #else
   (void)recordStackUsed;
@@ -105,28 +103,30 @@ void Fiber::init(bool recordStackUsed) {
 
 Fiber::~Fiber() {
 #ifdef FOLLY_SANITIZE_ADDRESS
+  if (asanFakeStack_ != nullptr) {
+    fiberManager_.freeFakeStack(asanFakeStack_);
+  }
   fiberManager_.unpoisonFiberStack(this);
 #endif
-  fiberManager_.stackAllocator_.deallocate(
-      static_cast<unsigned char*>(fcontext_.stackLimit()),
-      fiberManager_.options_.stackSize);
+  fiberManager_.stackAllocator_.deallocate(fiberStackLimit_, fiberStackSize_);
 }
 
 void Fiber::recordStackPosition() {
   int stackDummy;
   auto currentPosition = static_cast<size_t>(
-      static_cast<unsigned char*>(fcontext_.stackBase()) -
+      fiberStackLimit_ + fiberStackSize_ -
       static_cast<unsigned char*>(static_cast<void*>(&stackDummy)));
   fiberManager_.stackHighWatermark_ =
       std::max(fiberManager_.stackHighWatermark_, currentPosition);
   VLOG(4) << "Stack usage: " << currentPosition;
 }
 
-void Fiber::fiberFuncHelper(intptr_t fiber) {
-  reinterpret_cast<Fiber*>(fiber)->fiberFunc();
-}
+[[noreturn]] void Fiber::fiberFunc() {
+#ifdef FOLLY_SANITIZE_ADDRESS
+  fiberManager_.registerFinishSwitchStackWithAsan(
+      nullptr, &asanMainStackBase_, &asanMainStackSize_);
+#endif
 
-void Fiber::fiberFunc() {
   while (true) {
     DCHECK_EQ(state_, NOT_STARTED);
 
@@ -150,7 +150,8 @@ void Fiber::fiberFunc() {
 
     if (UNLIKELY(recordStackUsed_)) {
       fiberManager_.stackHighWatermark_ = std::max(
-          fiberManager_.stackHighWatermark_, nonMagicInBytes(fcontext_));
+          fiberManager_.stackHighWatermark_,
+          nonMagicInBytes(fiberStackLimit_, fiberStackSize_));
       VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_;
       CHECK(
           fiberManager_.stackHighWatermark_ <
@@ -160,15 +161,11 @@ void Fiber::fiberFunc() {
 
     state_ = INVALID;
 
-    auto context = fiberManager_.deactivateFiber(this);
-
-    DCHECK_EQ(reinterpret_cast<Fiber*>(context), this);
+    fiberManager_.deactivateFiber(this);
   }
 }
 
-intptr_t Fiber::preempt(State state) {
-  intptr_t ret;
-
+void Fiber::preempt(State state) {
   auto preemptImpl = [&]() mutable {
     DCHECK_EQ(fiberManager_.activeFiber_, this);
     DCHECK_EQ(state_, RUNNING);
@@ -178,7 +175,7 @@ intptr_t Fiber::preempt(State state) {
 
     recordStackPosition();
 
-    ret = fiberManager_.deactivateFiber(this);
+    fiberManager_.deactivateFiber(this);
 
     DCHECK_EQ(fiberManager_.activeFiber_, this);
     DCHECK_EQ(state_, READY_TO_RUN);
@@ -190,8 +187,10 @@ intptr_t Fiber::preempt(State state) {
   } else {
     preemptImpl();
   }
+}
 
-  return ret;
+Fiber::LocalData::~LocalData() {
+  reset();
 }
 
 Fiber::LocalData::LocalData(const LocalData& other) : data_(nullptr) {
@@ -236,5 +235,5 @@ void* Fiber::LocalData::allocateHeapBuffer(size_t size) {
 void Fiber::LocalData::freeHeapBuffer(void* buffer) {
   delete[] reinterpret_cast<char*>(buffer);
 }
-}
-}
+} // namespace fibers
+} // namespace folly