unioil-loyalty-rn-app/ios/Pods/Flipper-Folly/folly/tracing/AsyncStack.cpp

184 lines
5.0 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/tracing/AsyncStack.h>
#include <atomic>
#include <cassert>
#include <mutex>
#include <glog/logging.h>
#include <folly/BenchmarkUtil.h>
#include <folly/Likely.h>
#if defined(__linux__)
#define FOLLY_ASYNC_STACK_ROOT_USE_PTHREAD 1
#else
#define FOLLY_ASYNC_STACK_ROOT_USE_PTHREAD 0
#endif
#if FOLLY_ASYNC_STACK_ROOT_USE_PTHREAD
#include <folly/portability/PThread.h>
// Use a global TLS key variable to make it easier for profilers/debuggers
// to lookup the current thread's AsyncStackRoot by walking the pthread
// TLS structures.
extern "C" {
// Current pthread implementation has valid keys in range 0 .. 1023.
// Initialise to some value that will be interpreted as an invalid key.
pthread_key_t folly_async_stack_root_tls_key = 0xFFFF'FFFFu;
}
#endif // FOLLY_ASYNC_STACK_ROOT_USE_PTHREAD
namespace folly {
namespace {
#if FOLLY_ASYNC_STACK_ROOT_USE_PTHREAD
static pthread_once_t initialiseTlsKeyFlag = PTHREAD_ONCE_INIT;
static void ensureAsyncRootTlsKeyIsInitialised() noexcept {
(void)pthread_once(&initialiseTlsKeyFlag, []() noexcept {
int result = pthread_key_create(&folly_async_stack_root_tls_key, nullptr);
if (UNLIKELY(result != 0)) {
LOG(FATAL)
<< "Failed to initialise folly_async_stack_root_tls_key: (error:"
<< result << ")";
std::terminate();
}
VLOG(2) << "Initialising folly_async_stack_root_tls_key at address "
<< (void*)(&folly_async_stack_root_tls_key)
<< " with pthread_key_t " << folly_async_stack_root_tls_key;
});
}
#endif
struct AsyncStackRootHolder {
#if FOLLY_ASYNC_STACK_ROOT_USE_PTHREAD
AsyncStackRootHolder() noexcept {
ensureAsyncRootTlsKeyIsInitialised();
const int result =
pthread_setspecific(folly_async_stack_root_tls_key, this);
if (FOLLY_UNLIKELY(result != 0)) {
LOG(FATAL) << "Failed to set current thread's AsyncStackRoot";
std::terminate();
}
}
#endif
AsyncStackRoot* get() const noexcept {
return value.load(std::memory_order_relaxed);
}
void set(AsyncStackRoot* root) noexcept {
value.store(root, std::memory_order_release);
}
void set_relaxed(AsyncStackRoot* root) noexcept {
value.store(root, std::memory_order_relaxed);
}
std::atomic<AsyncStackRoot*> value{nullptr};
};
static thread_local AsyncStackRootHolder currentThreadAsyncStackRoot;
} // namespace
AsyncStackRoot* tryGetCurrentAsyncStackRoot() noexcept {
return currentThreadAsyncStackRoot.get();
}
AsyncStackRoot* exchangeCurrentAsyncStackRoot(
AsyncStackRoot* newRoot) noexcept {
auto* oldStackRoot = currentThreadAsyncStackRoot.get();
currentThreadAsyncStackRoot.set(newRoot);
return oldStackRoot;
}
namespace detail {
ScopedAsyncStackRoot::ScopedAsyncStackRoot(
void* framePointer, void* returnAddress) noexcept {
root_.setStackFrameContext(framePointer, returnAddress);
root_.nextRoot = currentThreadAsyncStackRoot.get();
currentThreadAsyncStackRoot.set(&root_);
}
ScopedAsyncStackRoot::~ScopedAsyncStackRoot() {
assert(currentThreadAsyncStackRoot.get() == &root_);
assert(root_.topFrame.load(std::memory_order_relaxed) == nullptr);
currentThreadAsyncStackRoot.set_relaxed(root_.nextRoot);
}
} // namespace detail
} // namespace folly
namespace folly {
FOLLY_NOINLINE static void* get_return_address() noexcept {
return FOLLY_ASYNC_STACK_RETURN_ADDRESS();
}
// This function is a special function that returns an address
// that can be used as a return-address and that will resolve
// debug-info to itself.
FOLLY_NOINLINE static void* detached_task() noexcept {
void* p = get_return_address();
// Add this after the call to prevent the compiler from
// turning the call to get_return_address() into a tailcall.
folly::doNotOptimizeAway(p);
return p;
}
AsyncStackRoot& getCurrentAsyncStackRoot() noexcept {
auto* root = tryGetCurrentAsyncStackRoot();
assert(root != nullptr);
return *root;
}
static AsyncStackFrame makeDetachedRootFrame() noexcept {
AsyncStackFrame frame;
frame.setReturnAddress(detached_task());
return frame;
}
static AsyncStackFrame detachedRootFrame = makeDetachedRootFrame();
AsyncStackFrame& getDetachedRootAsyncStackFrame() noexcept {
return detachedRootFrame;
}
#if FOLLY_HAS_COROUTINES
FOLLY_NOINLINE void resumeCoroutineWithNewAsyncStackRoot(
coro::coroutine_handle<> h, folly::AsyncStackFrame& frame) noexcept {
detail::ScopedAsyncStackRoot root;
root.activateFrame(frame);
h.resume();
}
#endif // FOLLY_HAS_COROUTINES
} // namespace folly