Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add threadid to AsyncStackRootHolder #644

Merged
merged 14 commits into from
Dec 4, 2024
6 changes: 2 additions & 4 deletions include/unifex/tracing/async_stack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ struct AsyncStackRoot;
struct AsyncStackFrame;
namespace detail {
class ScopedAsyncStackRoot;
}
} // namespace detail

// Get access to the current thread's top-most AsyncStackRoot.
//
Expand Down Expand Up @@ -321,9 +321,7 @@ struct frame_ptr {
return frame_ptr{p};
}

explicit operator void*() const noexcept {
return p_;
}
explicit operator void*() const noexcept { return p_; }

private:
void* p_;
Expand Down
112 changes: 69 additions & 43 deletions source/async_stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
#include <mutex>

#if !defined(UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD)
#if defined(__linux__)
# define UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD 1
#else
# if defined(__linux__)
# define UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD 1
# else
// defaults to using vector to store AsyncStackRoots instead of a pthread key
# define UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD 0
#endif
# define UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD 0
# endif
#endif

#if UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
Expand All @@ -41,9 +41,14 @@ extern "C" {
// Initialise to some value that will be interpreted as an invalid key.
inline pthread_key_t folly_async_stack_root_tls_key = 0xFFFF'FFFFu;
}
#else
# include <vector>
#endif //UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
#else
# include <vector>
# if defined(_WIN32)
# include <windows.h>
# elif defined(__linux__)
# include <unistd.h>
# endif // defined(_WIN32)
#endif // UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD

namespace unifex {

Expand All @@ -58,34 +63,49 @@ struct AsyncStackRootHolderList {
asyncStackRootHolders_.reserve(50);
}

void add(void* holder) {
std::lock_guard<std::mutex> lock(mutex_);
asyncStackRootHolders_.push_back(holder);
}
void add(void* holder) {
std::lock_guard<std::mutex> lock(mutex_);
asyncStackRootHolders_.push_back(holder);
}

void remove(void* holder) {
std::lock_guard<std::mutex> lock(mutex_);
auto it = std::find(asyncStackRootHolders_.begin(), asyncStackRootHolders_.end(), holder);
if (it != asyncStackRootHolders_.end()) {
std::swap(*it, asyncStackRootHolders_.back());
asyncStackRootHolders_.pop_back();
void remove(void* holder) {
std::lock_guard<std::mutex> lock(mutex_);
auto it = std::find(
asyncStackRootHolders_.begin(), asyncStackRootHolders_.end(), holder);
if (it != asyncStackRootHolders_.end()) {
std::swap(*it, asyncStackRootHolders_.back());
asyncStackRootHolders_.pop_back();
}
}
}

std::vector<void*> getAsyncStackRoots() {
if (!mutex_.try_lock()) {
// assume we crashed holding the lock and give up
return {};
std::vector<void*> getAsyncStackRoots() {
if (!mutex_.try_lock()) {
// assume we crashed holding the lock and give up
return {};
}
std::lock_guard<std::mutex> lock(mutex_, std::adopt_lock);
return asyncStackRootHolders_;
}
std::lock_guard<std::mutex> lock(mutex_, std::adopt_lock);
return asyncStackRootHolders_;
}
};

extern "C" {
auto* kUnifexAsyncStackRootHolderList = new AsyncStackRootHolderList();
auto* kUnifexAsyncStackRootHolderList = new AsyncStackRootHolderList();
}

namespace utils {
static std::uint64_t get_os_thread_id() {
# if defined(__APPLE__)
std::uint64_t tid;
pthread_threadid_np(nullptr, &tid);
return tid;
# elif defined(_WIN32)
return std::uint64_t(GetCurrentThreadId());
# else
return std::uint64_t(gettid());
# endif
}
#endif // UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD == 0
} // namespace utils
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since get_os_thread_id is static and inside the unifex namespace, I don't think you don't need the utils namespace.

#endif // UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD == 0

namespace {

Expand All @@ -108,23 +128,26 @@ static void ensureAsyncRootTlsKeyIsInitialised() noexcept {
#endif

struct AsyncStackRootHolder {

AsyncStackRootHolder() noexcept {
#if UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
ensureAsyncRootTlsKeyIsInitialised();
[[maybe_unused]] const int result =
pthread_setspecific(folly_async_stack_root_tls_key, this);
UNIFEX_ASSERT(result == 0);
#else
kUnifexAsyncStackRootHolderList->add(this);
#endif
#if UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
ensureAsyncRootTlsKeyIsInitialised();
[[maybe_unused]] const int result =
pthread_setspecific(folly_async_stack_root_tls_key, this);
UNIFEX_ASSERT(result == 0);
#else
kUnifexAsyncStackRootHolderList->add(this);
threadId = unifex::utils::get_os_thread_id();
#endif
}

#if !UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
~AsyncStackRootHolder() noexcept {
kUnifexAsyncStackRootHolderList->remove(this);
}
#endif
#if !UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
~AsyncStackRootHolder() noexcept {
kUnifexAsyncStackRootHolderList->remove(this);
}

std::uint64_t get_thread_id() const noexcept { return threadId; }

#endif

AsyncStackRoot* get() const noexcept {
return value.load(std::memory_order_relaxed);
Expand All @@ -139,6 +162,9 @@ struct AsyncStackRootHolder {
}

std::atomic<AsyncStackRoot*> value{nullptr};
#if !UNIFEX_ASYNC_STACK_ROOT_USE_PTHREAD
std::uint64_t threadId = 0;
#endif
};

static thread_local AsyncStackRootHolder currentThreadAsyncStackRoot;
Expand Down Expand Up @@ -220,6 +246,6 @@ UNIFEX_NO_INLINE void resumeCoroutineWithNewAsyncStackRoot(
h.resume();
}

#endif // FOLLY_HAS_COROUTINES
#endif // !UNIFEX_NO_COROUTINES

} // namespace unifex
Loading