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