proxygen
Fiber.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/fibers/Fiber.h>
17 
18 #include <glog/logging.h>
19 #include <algorithm>
20 #include <cstring>
21 #include <stdexcept>
22 
23 #include <folly/Likely.h>
24 #include <folly/Portability.h>
28 
29 namespace folly {
30 namespace fibers {
31 
32 namespace {
33 static const uint64_t kMagic8Bytes = 0xfaceb00cfaceb00c;
34 
35 std::thread::id localThreadId() {
36  return std::this_thread::get_id();
37 }
38 
39 /* Size of the region from p + nBytes down to the last non-magic value */
40 static size_t nonMagicInBytes(unsigned char* stackLimit, size_t stackSize) {
41  CHECK_EQ(reinterpret_cast<intptr_t>(stackLimit) % sizeof(uint64_t), 0u);
42  CHECK_EQ(stackSize % sizeof(uint64_t), 0u);
43  uint64_t* begin = reinterpret_cast<uint64_t*>(stackLimit);
44  uint64_t* end = reinterpret_cast<uint64_t*>(stackLimit + stackSize);
45 
46  auto firstNonMagic = std::find_if(
47  begin, end, [](uint64_t val) { return val != kMagic8Bytes; });
48 
49  return (end - firstNonMagic) * sizeof(uint64_t);
50 }
51 
52 } // namespace
53 
54 void Fiber::resume() {
55  DCHECK_EQ(state_, AWAITING);
57 
59  fiberManager_.observer_->runnable(reinterpret_cast<uintptr_t>(this));
60  }
61 
62  if (LIKELY(threadId_ == localThreadId())) {
63  fiberManager_.readyFibers_.push_back(*this);
65  } else {
67  }
68 }
69 
70 Fiber::Fiber(FiberManager& fiberManager)
71  : fiberManager_(fiberManager),
72  fiberStackSize_(fiberManager_.options_.stackSize),
73  fiberStackLimit_(fiberManager_.stackAllocator_.allocate(fiberStackSize_)),
75  fiberManager_.allFibers_.push_back(*this);
76 }
77 
78 void Fiber::init(bool recordStackUsed) {
79 // It is necessary to disable the logic for ASAN because we change
80 // the fiber's stack.
81 #ifndef FOLLY_SANITIZE_ADDRESS
82  recordStackUsed_ = recordStackUsed;
84  CHECK_EQ(
85  reinterpret_cast<intptr_t>(fiberStackLimit_) % sizeof(uint64_t), 0u);
86  CHECK_EQ(fiberStackSize_ % sizeof(uint64_t), 0u);
87  std::fill(
88  reinterpret_cast<uint64_t*>(fiberStackLimit_),
89  reinterpret_cast<uint64_t*>(fiberStackLimit_ + fiberStackSize_),
90  kMagic8Bytes);
91 
92  stackFilledWithMagic_ = true;
93 
94  // newer versions of boost allocate context on fiber stack,
95  // need to create a new one
96  fiberImpl_ =
98  }
99 #else
100  (void)recordStackUsed;
101 #endif
102 }
103 
105 #ifdef FOLLY_SANITIZE_ADDRESS
106  if (asanFakeStack_ != nullptr) {
107  fiberManager_.freeFakeStack(asanFakeStack_);
108  }
109  fiberManager_.unpoisonFiberStack(this);
110 #endif
112 }
113 
115  // For ASAN builds, functions may run on fake stack.
116  // So we cannot get meaningful stack position.
117 #ifndef FOLLY_SANITIZE_ADDRESS
118  int stackDummy;
119  auto currentPosition = static_cast<size_t>(
121  static_cast<unsigned char*>(static_cast<void*>(&stackDummy)));
123  std::max(fiberManager_.stackHighWatermark_, currentPosition);
124  VLOG(4) << "Stack usage: " << currentPosition;
125 #endif
126 }
127 
128 [[noreturn]] void Fiber::fiberFunc() {
129 #ifdef FOLLY_SANITIZE_ADDRESS
130  fiberManager_.registerFinishSwitchStackWithAsan(
131  nullptr, &asanMainStackBase_, &asanMainStackSize_);
132 #endif
133 
134  while (true) {
135  DCHECK_EQ(state_, NOT_STARTED);
136 
137  threadId_ = localThreadId();
138  state_ = RUNNING;
139 
140  try {
141  if (resultFunc_) {
142  DCHECK(finallyFunc_);
143  DCHECK(!func_);
144 
145  resultFunc_();
146  } else {
147  DCHECK(func_);
148  func_();
149  }
150  } catch (...) {
152  std::current_exception(), "running Fiber func_/resultFunc_");
153  }
154 
155  if (UNLIKELY(recordStackUsed_)) {
158  nonMagicInBytes(fiberStackLimit_, fiberStackSize_));
159  VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_;
160  CHECK(
163  << "Fiber stack overflow";
164  }
165 
166  state_ = INVALID;
167 
169  }
170 }
171 
173  auto preemptImpl = [&]() mutable {
174  DCHECK_EQ(fiberManager_.activeFiber_, this);
175  DCHECK_EQ(state_, RUNNING);
176  DCHECK_NE(state, RUNNING);
177  DCHECK(!std::current_exception());
178 
179  state_ = state;
180 
182 
184 
185  DCHECK_EQ(fiberManager_.activeFiber_, this);
186  DCHECK_EQ(state_, READY_TO_RUN);
187  state_ = RUNNING;
188  };
189 
191  fiberManager_.preemptRunner_->run(std::ref(preemptImpl));
192  } else {
193  preemptImpl();
194  }
195 }
196 
198  reset();
199 }
200 
202  *this = other;
203 }
204 
206  reset();
207  if (!other.data_) {
208  return *this;
209  }
210 
211  dataSize_ = other.dataSize_;
212  dataType_ = other.dataType_;
215 
216  if (dataSize_ <= kBufferSize) {
217  data_ = &buffer_;
218  } else {
220  }
221 
223 
224  return *this;
225 }
226 
228  if (!data_) {
229  return;
230  }
231 
233  data_ = nullptr;
234 }
235 
237  return new char[size];
238 }
239 
241  delete[] reinterpret_cast<char*>(buffer);
242 }
243 } // namespace fibers
244 } // namespace folly
std::vector< uint8_t > buffer(kBufferSize+16)
static void freeHeapBuffer(void *buffer)
Definition: Fiber.cpp:240
FiberImpl fiberImpl_
Definition: Fiber.h:112
void(* dataDestructor_)(void *)
Definition: Fiber.h:168
LogLevel max
Definition: LogLevel.cpp:31
void deallocate(unsigned char *limit, size_t size)
unsigned char * fiberStackLimit_
Definition: Fiber.h:111
size_t fiberStackSize_
Definition: Fiber.h:110
#define LIKELY(x)
Definition: Likely.h:47
std::aligned_storage< kBufferSize >::type buffer_
Definition: Fiber.h:164
const std::type_info * dataType_
Definition: Fiber.h:167
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
double val
Definition: String.cpp:273
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
bool stackFilledWithMagic_
Definition: Fiber.h:116
virtual void run(folly::Function< void()> func)=0
static void * allocateHeapBuffer(size_t size)
Definition: Fiber.cpp:236
#define nullptr
Definition: http_parser.c:41
folly::Function< void()> resultFunc_
Definition: Fiber.h:128
virtual void runnable(uintptr_t id) noexcept=0
Fiber(const Fiber &)=delete
static constexpr size_t kBufferSize
Definition: Fiber.h:163
Single-threaded task execution engine.
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
InlineFunctionRunner * preemptRunner_
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
void recordStackPosition()
Definition: Fiber.cpp:114
void remoteReadyInsert(Fiber *fiber)
void preempt(State state)
Definition: Fiber.cpp:172
void init(bool recordStackUsed)
Definition: Fiber.cpp:78
FiberManager & fiberManager_
Definition: Fiber.h:109
folly::Function< void()> func_
Definition: Fiber.h:114
folly::Function< void()> finallyFunc_
Definition: Fiber.h:129
std::thread::id threadId_
Definition: Fiber.h:178
bool recordStackUsed_
Definition: Fiber.h:115
void(* dataCopyConstructor_)(void *, const void *)
Definition: Fiber.h:169
#define UNLIKELY(x)
Definition: Likely.h:48
LocalData & operator=(const LocalData &other)
Definition: Fiber.cpp:205
StringPiece data_
state
Definition: http_parser.c:272