[Threading] Android thread naming and other cleanup

This commit is contained in:
Triang3l 2020-11-22 20:03:45 +03:00
parent aca23c08cf
commit 63ff758049
8 changed files with 80 additions and 42 deletions

View File

@ -35,16 +35,20 @@ void Initialize(const ANativeActivity* activity) {
AConfiguration_delete(configuration);
if (api_level_ >= 26) {
// Leaked intentionally, already loaded into the address space.
// Leaked intentionally as these will be usable anywhere, already loaded
// into the address space as the application is linked against them.
// https://chromium.googlesource.com/chromium/src/+/master/third_party/ashmem/ashmem-dev.c#201
void* libandroid = dlopen("libandroid.so", RTLD_NOW);
assert_not_null(libandroid);
#define XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(name, api) \
void* libc = dlopen("libc.so", RTLD_NOW);
assert_not_null(libc);
#define XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(lib, name, api) \
api_functions_.api_##api.name = \
reinterpret_cast<decltype(api_functions_.api_##api.name)>( \
dlsym(libandroid, #name)); \
dlsym(lib, #name)); \
assert_not_null(api_functions_.api_##api.name);
XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(ASharedMemory_create, 26);
XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(libandroid, ASharedMemory_create, 26);
XE_PLATFORM_ANDROID_LOAD_API_FUNCTION(libc, pthread_getname_np, 26);
#undef XE_PLATFORM_ANDROID_LOAD_API_FUNCTION
}

View File

@ -15,6 +15,7 @@
// avoided!
#include <android/native_activity.h>
#include <pthread.h>
#include <cstddef>
#include <cstdint>
@ -32,7 +33,10 @@ int32_t api_level();
// Android API functions added after the minimum supported API version.
struct ApiFunctions {
struct {
// libandroid
int (*ASharedMemory_create)(const char* name, size_t size);
// libc
int (*pthread_getname_np)(pthread_t pthread, char* buf, size_t n);
} api_26;
};
const ApiFunctions& api_functions();

View File

@ -95,9 +95,6 @@ void set_current_thread_id(uint32_t id);
// Sets the current thread name.
void set_name(const std::string_view name);
// Sets the target thread name.
void set_name(std::thread::native_handle_type handle,
const std::string_view name);
// Yields the current thread to the scheduler. Maybe.
void MaybeYield();

View File

@ -1,17 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/threading.h"
#include <pthread.h>
#include <time.h>
namespace xe {
namespace threading {} // namespace threading
} // namespace xe

View File

@ -26,10 +26,6 @@ uint32_t current_thread_id() {
void set_name(const std::string& name) { pthread_setname_np(name.c_str()); }
void set_name(std::thread::native_handle_type handle, const std::string& name) {
// ?
}
void MaybeYield() { pthread_yield_np(); }
void Sleep(std::chrono::microseconds duration) {

View File

@ -21,11 +21,15 @@
#include <sys/types.h>
#include <unistd.h>
#include <array>
#include <cstring>
#include <ctime>
#include <memory>
#if XE_PLATFORM_ANDROID
#include <sched.h>
#include "xenia/base/platform_android.h"
#include "xenia/base/string_util.h"
#endif
namespace xe {
@ -92,13 +96,6 @@ uint32_t current_thread_system_id() {
return static_cast<uint32_t>(syscall(SYS_gettid));
}
void set_name(std::thread::native_handle_type handle,
const std::string_view name) {
pthread_setname_np(handle, std::string(name).c_str());
}
void set_name(const std::string_view name) { set_name(pthread_self(), name); }
void MaybeYield() {
#if XE_PLATFORM_ANDROID
sched_yield();
@ -498,7 +495,11 @@ class PosixCondition<Thread> : public PosixConditionBase {
signaled_(false),
exit_code_(0),
state_(State::kUninitialized),
suspend_count_(0) {}
suspend_count_(0) {
#if XE_PLATFORM_ANDROID
android_pre_api_26_name_[0] = '\0';
#endif
}
bool Initialize(Thread::CreationParameters params,
ThreadStartData* start_data) {
start_data->create_suspended = params.create_suspended;
@ -534,7 +535,11 @@ class PosixCondition<Thread> : public PosixConditionBase {
: thread_(thread),
signaled_(false),
exit_code_(0),
state_(State::kRunning) {}
state_(State::kRunning) {
#if XE_PLATFORM_ANDROID
android_pre_api_26_name_[0] = '\0';
#endif
}
virtual ~PosixCondition() {
if (thread_ && !signaled_) {
@ -561,9 +566,25 @@ class PosixCondition<Thread> : public PosixConditionBase {
auto result = std::array<char, 17>{'\0'};
std::unique_lock<std::mutex> lock(state_mutex_);
if (state_ != State::kUninitialized && state_ != State::kFinished) {
if (pthread_getname_np(thread_, result.data(), result.size() - 1) != 0)
#if XE_PLATFORM_ANDROID
// pthread_getname_np was added in API 26 - below that, store the name in
// this object, which may be only modified through Xenia threading, but
// should be enough in most cases.
if (xe::platform::android::api_level() >= 26) {
if (xe::platform::android::api_functions().api_26.pthread_getname_np(
thread_, result.data(), result.size() - 1) != 0) {
assert_always();
}
} else {
std::lock_guard<std::mutex> lock(android_pre_api_26_name_mutex_);
std::strcpy(result.data(), android_pre_api_26_name_);
}
#else
if (pthread_getname_np(thread_, result.data(), result.size() - 1) != 0) {
assert_always();
}
#endif
}
return std::string(result.data());
}
@ -571,11 +592,24 @@ class PosixCondition<Thread> : public PosixConditionBase {
WaitStarted();
std::unique_lock<std::mutex> lock(state_mutex_);
if (state_ != State::kUninitialized && state_ != State::kFinished) {
threading::set_name(static_cast<std::thread::native_handle_type>(thread_),
name);
pthread_setname_np(thread_, std::string(name).c_str());
#if XE_PLATFORM_ANDROID
SetAndroidPreApi26Name(name);
#endif
}
}
#if XE_PLATFORM_ANDROID
void SetAndroidPreApi26Name(const std::string_view name) {
if (xe::platform::android::api_level() >= 26) {
return;
}
std::lock_guard<std::mutex> lock(android_pre_api_26_name_mutex_);
xe::string_util::copy_truncating(android_pre_api_26_name_, name,
xe::countof(android_pre_api_26_name_));
}
#endif
uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
uint64_t affinity_mask() {
@ -647,8 +681,13 @@ class PosixCondition<Thread> : public PosixConditionBase {
user_callback_ = std::move(callback);
sigval value{};
value.sival_ptr = this;
#if XE_PLATFORM_ANDROID
sigqueue(pthread_gettid_np(thread_),
GetSystemSignal(SignalType::kThreadUserCallback), value);
#else
pthread_sigqueue(thread_, GetSystemSignal(SignalType::kThreadUserCallback),
value);
#endif
}
void CallUserCallback() {
@ -751,6 +790,12 @@ class PosixCondition<Thread> : public PosixConditionBase {
mutable std::mutex callback_mutex_;
mutable std::condition_variable state_signal_;
std::function<void()> user_callback_;
#if XE_PLATFORM_ANDROID
// Name accessible via name() on Android before API 26 which added
// pthread_getname_np.
mutable std::mutex android_pre_api_26_name_mutex_;
char android_pre_api_26_name_[16];
#endif
};
class PosixWaitHandle {
@ -770,7 +815,7 @@ class PosixConditionHandle : public T, public PosixWaitHandle {
PosixConditionHandle(uint32_t initial_count, uint32_t maximum_count);
~PosixConditionHandle() override = default;
PosixConditionBase& condition() override { return handle_; }
PosixCondition<T>& condition() override { return handle_; }
void* native_handle() const override { return handle_.native_handle(); }
protected:
@ -1079,6 +1124,15 @@ void Thread::Exit(int exit_code) {
}
}
void set_name(const std::string_view name) {
pthread_setname_np(pthread_self(), std::string(name).c_str());
#if XE_PLATFORM_ANDROID
if (xe::platform::android::api_level() < 26 && current_thread_) {
current_thread_->condition().SetAndroidPreApi26Name(name);
}
#endif
}
static void signal_handler(int signal, siginfo_t* info, void* /*context*/) {
switch (GetSystemSignalType(signal)) {
case SignalType::kHighResolutionTimer: {

View File

@ -57,7 +57,7 @@ void raise_thread_name_exception(HANDLE thread, const std::string& name) {
}
}
void set_name(HANDLE thread, const std::string_view name) {
static void set_name(HANDLE thread, const std::string_view name) {
auto kernel = GetModuleHandleW(L"kernel32.dll");
if (kernel) {
auto func =