1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 
17 #pragma once
18 
19 #include <atomic>
20 #include <cassert>
21 #include <cstdint>
22 
23 #include <folly/CPortability.h>
24 #include <folly/CppAttributes.h>
25 #include <folly/Portability.h>
26 #include <folly/experimental/coro/Coroutine.h>
27 
28 namespace folly {
29 
30 // Gets the instruction pointer of the return-address of the current function.
31 //
32 // Generally a function that uses this macro should be declared FOLLY_NOINLINE
33 // to prevent this returning surprising results in cases where the function
34 // is inlined.
35 #if FOLLY_HAS_BUILTIN(__builtin_return_address)
36 #define FOLLY_ASYNC_STACK_RETURN_ADDRESS() __builtin_return_address(0)
37 #else
38 #define FOLLY_ASYNC_STACK_RETURN_ADDRESS() static_cast<void*>(nullptr)
39 #endif
40 
41 // Gets pointer to the current function invocation's stack-frame.
42 //
43 // Generally a function that uses this macro should be declared FOLLY_NOINLINE
44 // to prevent this returning surprising results in cases where the function
45 // is inlined.
46 #if FOLLY_HAS_BUILTIN(__builtin_frame_address)
47 #define FOLLY_ASYNC_STACK_FRAME_POINTER() __builtin_frame_address(0)
48 #else
49 #define FOLLY_ASYNC_STACK_FRAME_POINTER() static_cast<void*>(nullptr)
50 #endif
51 
52 // This header defines data-structures used to represent an async stack-trace.
53 //
54 // These data-structures are intended for use by coroutines (and possibly other
55 // representations of async operations) to allow the current program to record
56 // an async-stack as a linked-list of async-stack-frames in a similar way to
57 // how a normal thread represents the stack as a linked-list of stack frames.
58 //
59 // From a high-level, just looking at the AsyncStackRoot/AsyncStackFrame
60 // data-structures, each thread maintains a linked-list of active AsyncStack
61 // chains that looks a bit like this.
62 //
63 //  Stack Register
64 //      |
65 //      V
66 //  Stack Frame   currentStackRoot (TLS)
67 //      |               |
68 //      V               V
69 //  Stack Frame <- AsyncStackRoot  -> AsyncStackFrame -> AsyncStackFrame -> ...
70 //      |               |
71 //      V               |
72 //  Stack Frame         |
73 //      :               |
74 //      V               V
75 //  Stack Frame <- AsyncStackRoot  -> AsyncStackFrame -> AsyncStackFrame -> ...
76 //      |               |
77 //      V               X
78 //  Stack Frame
79 //      :
80 //      V
81 //
82 // Whenever a thread enters an event loop or is about to execute some
83 // asynchronus callback/continuation the current thread registers an
84 // AsyncStackRoot and records the stack-frame of the normal thread
85 // stack that corresponds to that call so that each AsyncStackRoot
86 // can be later interleaved with a normal thread stack-trace at
87 // the appropriate location.
88 //
89 // Each AsyncStackRoot contains a pointer to the currently active
90 // AsyncStackFrame (if any). This AsyncStackFrame forms the head
91 // of a linked-list of AsyncStackFrame objects that represent the
92 // async stack-trace. Each non-head AsyncStackFrame is a suspended
93 // asynchronous operation, which is typically suspended waiting for
94 // the previous operation to complete.
95 //
96 //
97 // The following diagram shows in more detail how each of the fields
98 // in these data-structures relate to each other and how the
99 // async-stack interleaves with the normal thread-stack.
100 //
101 //      Current Thread Stack
102 //      ====================
103 // +------------------------------------+ <--- current top of stack
104 // | Normal Stack Frame                 |
105 // | - stack-base-pointer  ---.         |
106 // | - return-address         |         |          Thread Local Storage
107 // |                          |         |          ====================
108 // +--------------------------V---------+
109 // |         ...                        |     +-------------------------+
110 // |                          :         |     | - currentStackRoot  -.  |
111 // |                          :         |     |                      |  |
112 // +--------------------------V---------+     +----------------------|--+
113 // | Normal Stack Frame                 |                            |
114 // | - stack-base-pointer  ---.         |                            |
115 // | - return-address         |      .-------------------------------`
116 // |                          |      |  |
117 // +--------------------------V------|--+
118 // | Active Async Operation          |  |
119 // | (Callback or Coroutine)         |  |            Heap Allocated
120 // | - stack-base-pointer  ---.      |  |            ==============
121 // | - return-address         |      |  |
122 // | - pointer to async state | --------------> +-------------------------+
123 // |   (e.g. coro frame or    |      |  |       | Coroutine Frame         |
124 // |    future core)          |      |  |       | +---------------------+ |
125 // |                          |      |  |       | | Promise             | |
126 // +--------------------------V------|--+       | | +-----------------+ | |
127 // |   Event  / Callback             |  |   .------>| AsyncStackFrame | | |
128 // |   Loop     Callsite             |  |   |   | | | - parentFrame  --------.
129 // | - stack-base-pointer  ---.      |  |   |   | | | - instructionPtr| | |  |
130 // | - return-address         |      |  |   |   | | | - stackRoot -.  | | |  |
131 // |                          |      |  |   |   | | +--------------|--+ | |  |
132 // |  +--------------------+  |      |  |   |   | | ...            |    | |  |
133 // |  | AsyncStackRoot     |<--------`  |   |   | +----------------|----+ |  |
134 // |  | - topFrame   -----------------------`   | ...              |      |  |
135 // |  | - stackFramePtr -. |<---------------,   +------------------|------+  |
136 // |  | - nextRoot --.   | |  |         |   |                      |         |
137 // |  +--------------|---|-+  |         |   '----------------------`         |
138 // +-----------------|---V----V---------+       +-------------------------+  |
139 // |         ...     |                  |       | Coroutine Frame         |  |
140 // |                 |        :         |       |                         |  |
141 // |                 |        :         |       |  +-------------------+  |  |
142 // +-----------------|--------V---------+       |  | AsyncStackFrame   |<----`
143 // | Async Operation |                  |       |  | - parentFrame   --------.
144 // | (Callback/Coro) |                  |       |  | - instructionPtr  |  |  |
145 // |                 |        :         |       |  | - stackRoot       |  |  |
146 // |                 |        :         |       |  +-------------------+  |  |
147 // +-----------------|--------V---------+       +-------------------------+  |
148 // |  Event Loop /   |                  |                                    :
149 // |  Callback Call  |                  |                                    :
150 // | - frame-pointer | -------.         |                                    V
151 // | - return-address|        |         |
152 // |                 |        |         |      Another chain of potentially
153 // |  +--------------V-----+  |         |      unrelated AsyncStackFrame
154 // |  | AsyncStackRoot     |  |         |       +---------------------+
155 // |  | - topFrame  ---------------- - - - - >  | AsyncStackFrame     |
156 // |  | - stackFramePtr -. |  |         |       | - parentFrame -.    |
157 // |  | - nextRoot -.    | |  |         |       +----------------|----+
158 // |  +-------------|----|-+  |         |                        :
159 // |                |    |    |         |                        V
160 // +----------------|----V----V---------+
161 // |         ...    :                   |
162 // |                V                   |
163 // |                                    |
164 // +------------------------------------+
165 //
166 //
167 // This data-structure can be inspected from within the current process
168 // if desired, but is also intended to allow tools such as debuggers or
169 // profilers that are inspecting the memory of this process remotely.
170 
171 struct AsyncStackRoot;
172 struct AsyncStackFrame;
173 namespace detail {
174 class ScopedAsyncStackRoot;
175 }
176 
177 // Get access to the current thread's top-most AsyncStackRoot.
178 //
179 // Returns nullptr if there is no active AsyncStackRoot.
180 FOLLY_NODISCARD AsyncStackRoot* tryGetCurrentAsyncStackRoot() noexcept;
181 
182 // Get access to the current thread's top-most AsyncStackRoot.
183 //
184 // Assumes that there is a current AsyncStackRoot.
185 FOLLY_NODISCARD AsyncStackRoot& getCurrentAsyncStackRoot() noexcept;
186 
187 // Exchange the current thread's active AsyncStackRoot with the
188 // specified AsyncStackRoot pointer, returning the old AsyncStackRoot
189 // pointer.
190 //
191 // This is intended to be used to update the thread-local pointer
192 // when context-switching fiber stacks.
193 FOLLY_NODISCARD AsyncStackRoot* exchangeCurrentAsyncStackRoot(
194     AsyncStackRoot* newRoot) noexcept;
195 
196 // Perform some consistency checks on the specified AsyncStackFrame,
197 // assuming that it is the currently active AsyncStackFrame.
198 void checkAsyncStackFrameIsActive(const folly::AsyncStackFrame& frame) noexcept;
199 
200 // Activate the specified AsyncStackFrame on the specified AsyncStackRoot,
201 // setting it as the current 'topFrame'.
202 //
203 // The AsyncStackRoot must be the current thread's top-most AsyncStackRoot
204 // and it must not currently have an active 'topFrame'.
205 //
206 // This is typically called immediately prior to executing a callback that
207 // resumes the async operation represented by 'frame'.
208 void activateAsyncStackFrame(
209     folly::AsyncStackRoot& root, folly::AsyncStackFrame& frame) noexcept;
210 
211 // Deactivate the specified AsyncStackFrame, clearing the current 'topFrame'.
212 //
213 // Typically called when the current async operation completes or is suspended
214 // and execution is about to return from the callback to the executor's event
215 // loop.
216 void deactivateAsyncStackFrame(folly::AsyncStackFrame& frame) noexcept;
217 
218 // Push the 'callee' frame onto the current thread's async stack, deactivating
219 // the 'caller' frame and setting up the 'caller' to be the parent-frame of
220 // the 'callee'.
221 //
222 // The 'caller' frame must be the current thread's active frame.
223 //
224 // After this call, the 'callee' frame will be the current thread's active
225 // frame.
226 //
227 // This is typically used when one async operation is about to transfer
228 // execution to a child async operation. e.g. via a coroutine symmetric
229 // transfer.
230 void pushAsyncStackFrameCallerCallee(
231     folly::AsyncStackFrame& callerFrame,
232     folly::AsyncStackFrame& calleeFrame) noexcept;
233 
234 // Pop the 'callee' frame off the stack, restoring the parent frame as the
235 // current frame.
236 //
237 // This is typically used when the current async operation completes and
238 // you are about to call/resume the caller. e.g. performing a symmetric
239 // transfer to the calling coroutine in final_suspend().
240 //
241 // If calleeFrame.getParentFrame() is null then this method is equivalent
242 // to deactivateAsyncStackFrame(), leaving no active AsyncStackFrame on
243 // the current AsyncStackRoot.
244 void popAsyncStackFrameCallee(folly::AsyncStackFrame& calleeFrame) noexcept;
245 
246 // Get a pointer to a special frame that can be used as the root-frame
247 // for a chain of AsyncStackFrame that does not chain onto a normal
248 // call-stack.
249 //
250 // The caller should never modify this frame as it will be shared across
251 // many frames and threads. The implication of this restriction is that
252 // you should also never activate this frame.
253 AsyncStackFrame& getDetachedRootAsyncStackFrame() noexcept;
254 
255 // Given an initial AsyncStackFrame, this will write `addresses` with
256 // the return addresses of the frames in this async stack trace, up to
257 // `maxAddresses` written.
258 // This assumes `addresses` has `maxAddresses` allocated space available.
259 // Returns the number of frames written.
260 size_t getAsyncStackTraceFromInitialFrame(
261     folly::AsyncStackFrame* initialFrame,
262     std::uintptr_t* addresses,
263     size_t maxAddresses);
264 
265 #if FOLLY_HAS_COROUTINES
266 
267 // Resume the specified coroutine after installing a new AsyncStackRoot
268 // on the current thread and setting the specified AsyncStackFrame as
269 // the current async frame.
270 FOLLY_NOINLINE void resumeCoroutineWithNewAsyncStackRoot(
271     coro::coroutine_handle<> h, AsyncStackFrame& frame) noexcept;
272 
273 // Resume the specified coroutine after installing a new AsyncStackRoot
274 // on the current thread and setting the coroutine's associated
275 // AsyncStackFrame, obtained by calling promise.getAsyncFrame(), as the
276 // current async frame.
277 template <typename Promise>
278 void resumeCoroutineWithNewAsyncStackRoot(
279     coro::coroutine_handle<Promise> h) noexcept;
280 
281 #endif // FOLLY_HAS_COROUTINES
282 
283 // An async stack frame contains information about a particular
284 // invocation of an asynchronous operation.
285 //
286 // For example, asynchronous operations implemented using coroutines
287 // would have each coroutine-frame contain an instance of AsyncStackFrame
288 // to record async-stack trace information for that coroutine invocation.
289 struct AsyncStackFrame {
290  public:
291   AsyncStackFrame() = default;
292 
293   // The parent frame is the frame of the async operation that is logically
294   // the caller of this frame.
295   AsyncStackFrame* getParentFrame() noexcept;
296   const AsyncStackFrame* getParentFrame() const noexcept;
297   void setParentFrame(AsyncStackFrame& frame) noexcept;
298 
299   // Get access to the current stack-root.
300   //
301   // This is only valid for either the root or leaf AsyncStackFrame
302   // in a chain of frames.
303   //
304   // In the case of an active leaf-frame it is used as a cache to
305   // avoid accessing the thread-local when pushing/popping frames.
306   // In the case of the root frame (which has a null parent frame)
307   // it points to an AsyncStackRoot that contains information about
308   // the normal-stack caller.
309   AsyncStackRoot* getStackRoot() noexcept;
310 
311   // The return address is generallty the address of the code in the
312   // caller that will be executed when the operation owning the current
313   // frame completes.
314   void setReturnAddress(void* p = FOLLY_ASYNC_STACK_RETURN_ADDRESS()) noexcept;
315   void* getReturnAddress() const noexcept;
316 
317  private:
318   friend AsyncStackRoot;
319 
320   friend AsyncStackFrame& getDetachedRootAsyncStackFrame() noexcept;
321   friend void activateAsyncStackFrame(
322       folly::AsyncStackRoot&, folly::AsyncStackFrame&) noexcept;
323   friend void deactivateAsyncStackFrame(folly::AsyncStackFrame&) noexcept;
324   friend void pushAsyncStackFrameCallerCallee(
325       folly::AsyncStackFrame&, folly::AsyncStackFrame&) noexcept;
326   friend void checkAsyncStackFrameIsActive(
327       const folly::AsyncStackFrame&) noexcept;
328   friend void popAsyncStackFrameCallee(folly::AsyncStackFrame&) noexcept;
329 
330   // Pointer to the async caller's stack-frame info.
331   //
332   // This forms a linked-list of frames that make up a stack.
333   // The list is terminated by a null pointer which indicates
334   // the top of the async stack - either because the operation
335   // is detached or because the next frame is a thread that is
336   // blocked waiting for the async stack to complete.
337   AsyncStackFrame* parentFrame = nullptr;
338 
339   // Instruction pointer of the caller of this frame.
340   // This will typically be either the address of the continuation
341   // of this asynchronous operation, or the address of the code
342   // that launched this asynchronous operation. May be null
343   // if the address is not known.
344   //
345   // Typically initialised with the result of a call to
346   // FOLLY_ASYNC_STACK_RETURN_ADDRESS().
347   void* instructionPointer = nullptr;
348 
349   // Pointer to the stack-root for the current thread.
350   // Cache this in each async-stack frame so we don't have to
351   // read from a thread-local to get the pointer.
352   //
353   // This pointer is only valid for the top-most stack frame.
354   // When a frame is pushed or popped it should be copied to
355   // the next frame, etc.
356   //
357   // The exception is for the bottom-most frame (ie. where
358   // parentFrame == null). In this case, if stackRoot is non-null
359   // then it points to a root that is currently blocked on some
360   // thread waiting for the async work to complete. In this case
361   // you can find the information about the stack-frame for that
362   // thread in the AsyncStackRoot and can use it to continue
363   // walking the stack-frames.
364   AsyncStackRoot* stackRoot = nullptr;
365 };
366 
367 // A stack-root represents the context of an event loop
368 // that is running some asynchronous work. The current async
369 // operation that is being executed by the event loop (if any)
370 // is pointed to by the 'topFrame'.
371 //
372 // If the current event loop is running nested inside some other
373 // event loop context then the 'nextRoot' points to the AsyncStackRoot
374 // context for the next event loop up the stack on the current thread.
375 //
376 // The 'stackFramePtr' holds a pointer to the normal stack-frame
377 // that is currently executing this event loop. This allows
378 // reconciliation of the parts between a normal stack-trace and
379 // the start of the async-stack trace.
380 //
381 // The current thread's top-most context (the head of the linked
382 // list of contexts) is obtained by calling getCurrentAsyncStackRoot().
383 struct AsyncStackRoot {
384  public:
385   // Sets the top-frame to be 'frame' and also updates the cached
386   // 'frame.stackRoot' to be 'this'.
387   //
388   // The current stack root must not currently have any active
389   // frame.
390   void setTopFrame(AsyncStackFrame& frame) noexcept;
391   AsyncStackFrame* getTopFrame() const noexcept;
392 
393   // Initialises this stack root with information about the context
394   // in which the stack-root was declared. This records information
395   // about where the async-stack-trace should be spliced into the
396   // normal stack-trace.
397   void setStackFrameContext(
398       void* framePtr = FOLLY_ASYNC_STACK_FRAME_POINTER(),
399       void* ip = FOLLY_ASYNC_STACK_RETURN_ADDRESS()) noexcept;
400   void* getStackFramePointer() const noexcept;
401   void* getReturnAddress() const noexcept;
402 
403   const AsyncStackRoot* getNextRoot() const noexcept;
404   void setNextRoot(AsyncStackRoot* next) noexcept;
405 
406  private:
407   friend class detail::ScopedAsyncStackRoot;
408   friend void activateAsyncStackFrame(
409       folly::AsyncStackRoot&, folly::AsyncStackFrame&) noexcept;
410   friend void deactivateAsyncStackFrame(folly::AsyncStackFrame&) noexcept;
411   friend void pushAsyncStackFrameCallerCallee(
412       folly::AsyncStackFrame&, folly::AsyncStackFrame&) noexcept;
413   friend void checkAsyncStackFrameIsActive(
414       const folly::AsyncStackFrame&) noexcept;
415   friend void popAsyncStackFrameCallee(folly::AsyncStackFrame&) noexcept;
416 
417   // Pointer to the currently-active AsyncStackFrame for this event
418   // loop or callback invocation. May be null if this event loop is
419   // not currently executing any async operations.
420   //
421   // This is atomic primarily to enforce visibility of writes to the
422   // AsyncStackFrame that occur before the topFrame in other processes,
423   // such as profilers/debuggers that may be running concurrently
424   // with the current thread.
425   std::atomic<AsyncStackFrame*> topFrame{nullptr};
426 
427   // Pointer to the next event loop context lower on the current
428   // thread's stack.
429   // This is nullptr if this is not a nested call to an event loop.
430   AsyncStackRoot* nextRoot = nullptr;
431 
432   // Pointer to the stack-frame and return-address of the function
433   // call that registered this AsyncStackRoot on the current thread.
434   // This is generally the stack-frame responsible for executing async
435   // callbacks (typically an event-loop).
436   // Anything prior to this frame on the stack in the current thread
437   // is potentially unrelated to the call-chain of the current async-stack.
438   //
439   // Typically initialised with FOLLY_ASYNC_STACK_FRAME_POINTER() or
440   // setStackFrameContext().
441   void* stackFramePtr = nullptr;
442 
443   // Typically initialise with FOLLY_ASYNC_STACK_RETURN_ADDRESS() or
444   // setStackFrameContext().
445   void* returnAddress = nullptr;
446 };
447 
448 namespace detail {
449 
450 class ScopedAsyncStackRoot {
451  public:
452   explicit ScopedAsyncStackRoot(
453       void* framePointer = FOLLY_ASYNC_STACK_FRAME_POINTER(),
454       void* returnAddress = FOLLY_ASYNC_STACK_RETURN_ADDRESS()) noexcept;
455   ~ScopedAsyncStackRoot();
456 
activateFrame(AsyncStackFrame & frame)457   void activateFrame(AsyncStackFrame& frame) noexcept {
458     folly::activateAsyncStackFrame(root_, frame);
459   }
460 
461  private:
462   AsyncStackRoot root_;
463 };
464 
465 } // namespace detail
466 } // namespace folly
467 
468 #include <folly/tracing/AsyncStack-inl.h>
469