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 namespace folly {
20 
checkAsyncStackFrameIsActive(FOLLY_MAYBE_UNUSED const folly::AsyncStackFrame & frame)21 inline void checkAsyncStackFrameIsActive(
22     FOLLY_MAYBE_UNUSED const folly::AsyncStackFrame& frame) noexcept {
23   (void)frame;
24   assert(frame.stackRoot != nullptr);
25   assert(tryGetCurrentAsyncStackRoot() == frame.stackRoot);
26   assert(frame.stackRoot->topFrame.load(std::memory_order_relaxed) == &frame);
27 }
28 
activateAsyncStackFrame(folly::AsyncStackRoot & root,folly::AsyncStackFrame & frame)29 inline void activateAsyncStackFrame(
30     folly::AsyncStackRoot& root, folly::AsyncStackFrame& frame) noexcept {
31   assert(tryGetCurrentAsyncStackRoot() == &root);
32   root.setTopFrame(frame);
33 }
34 
deactivateAsyncStackFrame(folly::AsyncStackFrame & frame)35 inline void deactivateAsyncStackFrame(folly::AsyncStackFrame& frame) noexcept {
36   checkAsyncStackFrameIsActive(frame);
37   frame.stackRoot->topFrame.store(nullptr, std::memory_order_relaxed);
38   frame.stackRoot = nullptr;
39 }
40 
pushAsyncStackFrameCallerCallee(folly::AsyncStackFrame & callerFrame,folly::AsyncStackFrame & calleeFrame)41 inline void pushAsyncStackFrameCallerCallee(
42     folly::AsyncStackFrame& callerFrame,
43     folly::AsyncStackFrame& calleeFrame) noexcept {
44   checkAsyncStackFrameIsActive(callerFrame);
45   calleeFrame.stackRoot = callerFrame.stackRoot;
46   calleeFrame.parentFrame = &callerFrame;
47   calleeFrame.stackRoot->topFrame.store(
48       &calleeFrame, std::memory_order_release);
49 
50   // Clearing out non-top-frame's stackRoot is not strictly necessary
51   // but it may help with debugging.
52   callerFrame.stackRoot = nullptr;
53 }
54 
popAsyncStackFrameCallee(folly::AsyncStackFrame & calleeFrame)55 inline void popAsyncStackFrameCallee(
56     folly::AsyncStackFrame& calleeFrame) noexcept {
57   checkAsyncStackFrameIsActive(calleeFrame);
58   auto* callerFrame = calleeFrame.parentFrame;
59   auto* stackRoot = calleeFrame.stackRoot;
60   if (callerFrame != nullptr) {
61     callerFrame->stackRoot = stackRoot;
62   }
63   stackRoot->topFrame.store(callerFrame, std::memory_order_release);
64 
65   // Clearing out non-top-frame's stackRoot is not strictly necessary
66   // but it may help with debugging.
67   calleeFrame.stackRoot = nullptr;
68 }
69 
getAsyncStackTraceFromInitialFrame(folly::AsyncStackFrame * initialFrame,std::uintptr_t * addresses,size_t maxAddresses)70 inline size_t getAsyncStackTraceFromInitialFrame(
71     folly::AsyncStackFrame* initialFrame,
72     std::uintptr_t* addresses,
73     size_t maxAddresses) {
74   size_t numFrames = 0;
75   for (auto* frame = initialFrame; frame != nullptr && numFrames < maxAddresses;
76        frame = frame->getParentFrame()) {
77     addresses[numFrames++] =
78         reinterpret_cast<std::uintptr_t>(frame->getReturnAddress());
79   }
80   return numFrames;
81 }
82 
83 #if FOLLY_HAS_COROUTINES
84 
85 template <typename Promise>
resumeCoroutineWithNewAsyncStackRoot(coro::coroutine_handle<Promise> h)86 void resumeCoroutineWithNewAsyncStackRoot(
87     coro::coroutine_handle<Promise> h) noexcept {
88   resumeCoroutineWithNewAsyncStackRoot(h, h.promise().getAsyncFrame());
89 }
90 
91 #endif
92 
getParentFrame()93 inline AsyncStackFrame* AsyncStackFrame::getParentFrame() noexcept {
94   return parentFrame;
95 }
96 
getParentFrame()97 inline const AsyncStackFrame* AsyncStackFrame::getParentFrame() const noexcept {
98   return parentFrame;
99 }
100 
setParentFrame(AsyncStackFrame & frame)101 inline void AsyncStackFrame::setParentFrame(AsyncStackFrame& frame) noexcept {
102   parentFrame = &frame;
103 }
104 
getStackRoot()105 inline AsyncStackRoot* AsyncStackFrame::getStackRoot() noexcept {
106   return stackRoot;
107 }
108 
setReturnAddress(void * p)109 inline void AsyncStackFrame::setReturnAddress(void* p) noexcept {
110   instructionPointer = p;
111 }
112 
getReturnAddress()113 inline void* AsyncStackFrame::getReturnAddress() const noexcept {
114   return instructionPointer;
115 }
116 
setTopFrame(AsyncStackFrame & frame)117 inline void AsyncStackRoot::setTopFrame(AsyncStackFrame& frame) noexcept {
118   assert(this->topFrame.load(std::memory_order_relaxed) == nullptr);
119   assert(frame.stackRoot == nullptr);
120   frame.stackRoot = this;
121   this->topFrame.store(&frame, std::memory_order_release);
122 }
123 
getTopFrame()124 inline AsyncStackFrame* AsyncStackRoot::getTopFrame() const noexcept {
125   return topFrame.load(std::memory_order_relaxed);
126 }
127 
setStackFrameContext(void * framePtr,void * ip)128 inline void AsyncStackRoot::setStackFrameContext(
129     void* framePtr, void* ip) noexcept {
130   stackFramePtr = framePtr;
131   returnAddress = ip;
132 }
133 
getStackFramePointer()134 inline void* AsyncStackRoot::getStackFramePointer() const noexcept {
135   return stackFramePtr;
136 }
137 
getReturnAddress()138 inline void* AsyncStackRoot::getReturnAddress() const noexcept {
139   return returnAddress;
140 }
141 
getNextRoot()142 inline const AsyncStackRoot* AsyncStackRoot::getNextRoot() const noexcept {
143   return nextRoot;
144 }
145 
setNextRoot(AsyncStackRoot * next)146 inline void AsyncStackRoot::setNextRoot(AsyncStackRoot* next) noexcept {
147   nextRoot = next;
148 }
149 
150 } // namespace folly
151