[Threading] Android thread naming and other cleanup
This commit is contained in:
parent
aca23c08cf
commit
63ff758049
|
@ -35,16 +35,20 @@ void Initialize(const ANativeActivity* activity) {
|
||||||
AConfiguration_delete(configuration);
|
AConfiguration_delete(configuration);
|
||||||
|
|
||||||
if (api_level_ >= 26) {
|
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
|
// https://chromium.googlesource.com/chromium/src/+/master/third_party/ashmem/ashmem-dev.c#201
|
||||||
void* libandroid = dlopen("libandroid.so", RTLD_NOW);
|
void* libandroid = dlopen("libandroid.so", RTLD_NOW);
|
||||||
assert_not_null(libandroid);
|
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 = \
|
api_functions_.api_##api.name = \
|
||||||
reinterpret_cast<decltype(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);
|
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
|
#undef XE_PLATFORM_ANDROID_LOAD_API_FUNCTION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
// avoided!
|
// avoided!
|
||||||
|
|
||||||
#include <android/native_activity.h>
|
#include <android/native_activity.h>
|
||||||
|
#include <pthread.h>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
@ -32,7 +33,10 @@ int32_t api_level();
|
||||||
// Android API functions added after the minimum supported API version.
|
// Android API functions added after the minimum supported API version.
|
||||||
struct ApiFunctions {
|
struct ApiFunctions {
|
||||||
struct {
|
struct {
|
||||||
|
// libandroid
|
||||||
int (*ASharedMemory_create)(const char* name, size_t size);
|
int (*ASharedMemory_create)(const char* name, size_t size);
|
||||||
|
// libc
|
||||||
|
int (*pthread_getname_np)(pthread_t pthread, char* buf, size_t n);
|
||||||
} api_26;
|
} api_26;
|
||||||
};
|
};
|
||||||
const ApiFunctions& api_functions();
|
const ApiFunctions& api_functions();
|
||||||
|
|
|
@ -95,9 +95,6 @@ void set_current_thread_id(uint32_t id);
|
||||||
|
|
||||||
// Sets the current thread name.
|
// Sets the current thread name.
|
||||||
void set_name(const std::string_view 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.
|
// Yields the current thread to the scheduler. Maybe.
|
||||||
void MaybeYield();
|
void MaybeYield();
|
||||||
|
|
|
@ -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
|
|
|
@ -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(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 MaybeYield() { pthread_yield_np(); }
|
||||||
|
|
||||||
void Sleep(std::chrono::microseconds duration) {
|
void Sleep(std::chrono::microseconds duration) {
|
||||||
|
|
|
@ -21,11 +21,15 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if XE_PLATFORM_ANDROID
|
#if XE_PLATFORM_ANDROID
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
|
||||||
|
#include "xenia/base/platform_android.h"
|
||||||
|
#include "xenia/base/string_util.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -92,13 +96,6 @@ uint32_t current_thread_system_id() {
|
||||||
return static_cast<uint32_t>(syscall(SYS_gettid));
|
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() {
|
void MaybeYield() {
|
||||||
#if XE_PLATFORM_ANDROID
|
#if XE_PLATFORM_ANDROID
|
||||||
sched_yield();
|
sched_yield();
|
||||||
|
@ -498,7 +495,11 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
signaled_(false),
|
signaled_(false),
|
||||||
exit_code_(0),
|
exit_code_(0),
|
||||||
state_(State::kUninitialized),
|
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,
|
bool Initialize(Thread::CreationParameters params,
|
||||||
ThreadStartData* start_data) {
|
ThreadStartData* start_data) {
|
||||||
start_data->create_suspended = params.create_suspended;
|
start_data->create_suspended = params.create_suspended;
|
||||||
|
@ -534,7 +535,11 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
: thread_(thread),
|
: thread_(thread),
|
||||||
signaled_(false),
|
signaled_(false),
|
||||||
exit_code_(0),
|
exit_code_(0),
|
||||||
state_(State::kRunning) {}
|
state_(State::kRunning) {
|
||||||
|
#if XE_PLATFORM_ANDROID
|
||||||
|
android_pre_api_26_name_[0] = '\0';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~PosixCondition() {
|
virtual ~PosixCondition() {
|
||||||
if (thread_ && !signaled_) {
|
if (thread_ && !signaled_) {
|
||||||
|
@ -561,9 +566,25 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
auto result = std::array<char, 17>{'\0'};
|
auto result = std::array<char, 17>{'\0'};
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||||
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
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();
|
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());
|
return std::string(result.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,11 +592,24 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||||
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
||||||
threading::set_name(static_cast<std::thread::native_handle_type>(thread_),
|
pthread_setname_np(thread_, std::string(name).c_str());
|
||||||
name);
|
#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_); }
|
uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
|
||||||
|
|
||||||
uint64_t affinity_mask() {
|
uint64_t affinity_mask() {
|
||||||
|
@ -647,8 +681,13 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
user_callback_ = std::move(callback);
|
user_callback_ = std::move(callback);
|
||||||
sigval value{};
|
sigval value{};
|
||||||
value.sival_ptr = this;
|
value.sival_ptr = this;
|
||||||
|
#if XE_PLATFORM_ANDROID
|
||||||
|
sigqueue(pthread_gettid_np(thread_),
|
||||||
|
GetSystemSignal(SignalType::kThreadUserCallback), value);
|
||||||
|
#else
|
||||||
pthread_sigqueue(thread_, GetSystemSignal(SignalType::kThreadUserCallback),
|
pthread_sigqueue(thread_, GetSystemSignal(SignalType::kThreadUserCallback),
|
||||||
value);
|
value);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallUserCallback() {
|
void CallUserCallback() {
|
||||||
|
@ -751,6 +790,12 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
mutable std::mutex callback_mutex_;
|
mutable std::mutex callback_mutex_;
|
||||||
mutable std::condition_variable state_signal_;
|
mutable std::condition_variable state_signal_;
|
||||||
std::function<void()> user_callback_;
|
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 {
|
class PosixWaitHandle {
|
||||||
|
@ -770,7 +815,7 @@ class PosixConditionHandle : public T, public PosixWaitHandle {
|
||||||
PosixConditionHandle(uint32_t initial_count, uint32_t maximum_count);
|
PosixConditionHandle(uint32_t initial_count, uint32_t maximum_count);
|
||||||
~PosixConditionHandle() override = default;
|
~PosixConditionHandle() override = default;
|
||||||
|
|
||||||
PosixConditionBase& condition() override { return handle_; }
|
PosixCondition<T>& condition() override { return handle_; }
|
||||||
void* native_handle() const override { return handle_.native_handle(); }
|
void* native_handle() const override { return handle_.native_handle(); }
|
||||||
|
|
||||||
protected:
|
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*/) {
|
static void signal_handler(int signal, siginfo_t* info, void* /*context*/) {
|
||||||
switch (GetSystemSignalType(signal)) {
|
switch (GetSystemSignalType(signal)) {
|
||||||
case SignalType::kHighResolutionTimer: {
|
case SignalType::kHighResolutionTimer: {
|
||||||
|
|
|
@ -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");
|
auto kernel = GetModuleHandleW(L"kernel32.dll");
|
||||||
if (kernel) {
|
if (kernel) {
|
||||||
auto func =
|
auto func =
|
||||||
|
|
Loading…
Reference in New Issue