diff --git a/starboard/android/shared/platform_configuration/BUILD.gn b/starboard/android/shared/platform_configuration/BUILD.gn index 35671e87429..ccc6d13dd91 100644 --- a/starboard/android/shared/platform_configuration/BUILD.gn +++ b/starboard/android/shared/platform_configuration/BUILD.gn @@ -19,6 +19,12 @@ config("platform_configuration") { cflags = [] defines = [] + + include_dirs = [ + # POSIX emulation headers + "//starboard/android/shared/posix_emu/include", + ] + ldflags = [ # The NDK default "ld" is actually the gold linker for all architectures # except arm64 (aarch64) where it"s the bfd linker. Don"t use either of diff --git a/starboard/android/shared/posix_emu/include/pthread.h b/starboard/android/shared/posix_emu/include/pthread.h new file mode 100644 index 00000000000..1c10db2da10 --- /dev/null +++ b/starboard/android/shared/posix_emu/include/pthread.h @@ -0,0 +1,24 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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. + +#ifndef STARBOARD_ANDROID_SHARED_POSIX_EMU_INCLUDE_PTHREAD_H_ +#define STARBOARD_ANDROID_SHARED_POSIX_EMU_INCLUDE_PTHREAD_H_ + +#include_next + +#if __ANDROID_API__ < 26 +int pthread_getname_np(pthread_t thread, char* name, size_t len); +#endif // __ANDROID_API__ < 26 + +#endif // STARBOARD_ANDROID_SHARED_POSIX_EMU_INCLUDE_PTHREAD_H_ diff --git a/starboard/android/shared/posix_emu/pthread.cc b/starboard/android/shared/posix_emu/pthread.cc new file mode 100644 index 00000000000..633b11e5e44 --- /dev/null +++ b/starboard/android/shared/posix_emu/pthread.cc @@ -0,0 +1,33 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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 + +#include +#include +#include +#include + +#if __ANDROID_API__ < 26 +// The API doesn exist before API Level 26 and we currently target 24 +// If this is the current thread we can obtain the name using `prctl`. +int pthread_getname_np(pthread_t thread, char* name, size_t len) { + // The PR_GET_NAME expects a buffer of size 16 bytes. + if (pthread_equal(pthread_self(), thread) && len >= 16) { + prctl(PR_GET_NAME, name, 0L, 0L, 0L); + return 0; + } + return -1; +} +#endif // __ANDROID_API__ < 26 diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index fb36d3d2c3f..450f77bb706 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -510,10 +510,12 @@ ExportedSymbols::ExportedSymbols() { reinterpret_cast(&__abi_wrap_pthread_detach); map_["pthread_equal"] = reinterpret_cast(&__abi_wrap_pthread_equal); - map_["pthread_join"] = - reinterpret_cast(&__abi_wrap_pthread_join); + map_["pthread_getname_np"] = + reinterpret_cast(&__abi_wrap_pthread_getname_np); map_["pthread_getspecific"] = reinterpret_cast(&__abi_wrap_pthread_getspecific); + map_["pthread_join"] = + reinterpret_cast(&__abi_wrap_pthread_join); map_["pthread_key_create"] = reinterpret_cast(&__abi_wrap_pthread_key_create); map_["pthread_key_delete"] = @@ -534,6 +536,8 @@ ExportedSymbols::ExportedSymbols() { reinterpret_cast(&__abi_wrap_pthread_self); map_["pthread_setspecific"] = reinterpret_cast(&__abi_wrap_pthread_setspecific); + map_["pthread_setname_np"] = + reinterpret_cast(&__abi_wrap_pthread_setname_np); map_["stat"] = reinterpret_cast(&__abi_wrap_stat); map_["time"] = reinterpret_cast(&__abi_wrap_time); map_["accept"] = reinterpret_cast(&__abi_wrap_accept); diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn index 04ceafbe07c..346ee856415 100644 --- a/starboard/nplb/BUILD.gn +++ b/starboard/nplb/BUILD.gn @@ -175,10 +175,12 @@ target(gtest_target_type, "nplb") { "posix_compliance/posix_thread_create_test.cc", "posix_compliance/posix_thread_detach_test.cc", "posix_compliance/posix_thread_get_current_test.cc", + "posix_compliance/posix_thread_get_name_test.cc", "posix_compliance/posix_thread_helpers.cc", "posix_compliance/posix_thread_is_equal_test.cc", "posix_compliance/posix_thread_join_test.cc", "posix_compliance/posix_thread_local_value_test.cc", + "posix_compliance/posix_thread_set_name_test.cc", "posix_compliance/posix_thread_sleep_test.cc", "posix_compliance/posix_thread_yield_test.cc", "posix_compliance/posix_time_test.cc", diff --git a/starboard/nplb/posix_compliance/posix_thread_get_name_test.cc b/starboard/nplb/posix_compliance/posix_thread_get_name_test.cc new file mode 100644 index 00000000000..5093ca4fb5f --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_thread_get_name_test.cc @@ -0,0 +1,47 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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 + +#include "starboard/nplb/thread_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +void* GetThreadNameEntryPoint(void* context) { + pthread_setname_np(pthread_self(), kThreadName); + + char name[4096] = {0}; + pthread_getname_np(pthread_self(), name, SB_ARRAY_SIZE_INT(name)); + std::string* result = static_cast(context); + *result = name; + return NULL; +} + +TEST(PosixThreadGetNameTest, SunnyDay) { + std::string result; + + pthread_t thread; + EXPECT_EQ(pthread_create(&thread, NULL, GetThreadNameEntryPoint, &result), 0); + + EXPECT_TRUE(thread != 0); + EXPECT_EQ(pthread_join(thread, NULL), 0); + EXPECT_EQ(kThreadName, result); +} + +} // namespace +} // namespace nplb +} // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_thread_set_name_test.cc b/starboard/nplb/posix_compliance/posix_thread_set_name_test.cc new file mode 100644 index 00000000000..6019a4da78b --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_thread_set_name_test.cc @@ -0,0 +1,60 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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 + +#include "starboard/nplb/thread_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +struct Context { + std::string got_name1; + std::string name_to_set; + std::string got_name2; +}; + +// Gets the thread's name and sets it in the context. +void* SetThreadNameEntryPoint(void* context) { + char name[4096] = {0}; + Context* real_context = static_cast(context); + + pthread_getname_np(pthread_self(), name, SB_ARRAY_SIZE_INT(name)); + real_context->got_name1 = name; + + pthread_setname_np(pthread_self(), real_context->name_to_set.c_str()); + + pthread_getname_np(pthread_self(), name, SB_ARRAY_SIZE_INT(name)); + real_context->got_name2 = name; + + return NULL; +} + +TEST(PosixThreadSetNameTest, SunnyDay) { + Context context; + context.name_to_set = kAltThreadName; + pthread_t thread; + EXPECT_EQ(pthread_create(&thread, NULL, SetThreadNameEntryPoint, &context), + 0); + EXPECT_TRUE(thread != 0); + EXPECT_EQ(pthread_join(thread, NULL), 0); + EXPECT_NE(kAltThreadName, context.got_name1); + EXPECT_EQ(kAltThreadName, context.got_name2); +} + +} // namespace +} // namespace nplb +} // namespace starboard diff --git a/starboard/shared/modular/cobalt_layer_posix_pthread_abi_wrappers.cc b/starboard/shared/modular/cobalt_layer_posix_pthread_abi_wrappers.cc index 1d317c986f1..d33634ffa13 100644 --- a/starboard/shared/modular/cobalt_layer_posix_pthread_abi_wrappers.cc +++ b/starboard/shared/modular/cobalt_layer_posix_pthread_abi_wrappers.cc @@ -185,6 +185,17 @@ int __abi_wrap_pthread_setspecific(pthread_key_t key, const void* value); int pthread_setspecific(pthread_key_t key, const void* value) { return __abi_wrap_pthread_setspecific(key, value); } + +int __abi_wrap_pthread_setname_np(pthread_t thread, const char* name); + +int pthread_setname_np(pthread_t thread, const char* name) { + return __abi_wrap_pthread_setname_np(thread, name); } +int __abi_wrap_pthread_getname_np(pthread_t thread, char* name, size_t len); + +int pthread_getname_np(pthread_t thread, char* name, size_t len) { + return __abi_wrap_pthread_getname_np(thread, name, len); +} +} #endif // SB_API_VERSION >= 16 diff --git a/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.cc b/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.cc index 24599c4b232..1a4df37e361 100644 --- a/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.cc +++ b/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.cc @@ -370,3 +370,13 @@ int __abi_wrap_pthread_setspecific(musl_pthread_key_t key, const void* value) { return pthread_setspecific( reinterpret_cast(key)->key, value); } + +int __abi_wrap_pthread_setname_np(musl_pthread_t thread, const char* name) { + return pthread_setname_np(reinterpret_cast(thread), name); +} + +int __abi_wrap_pthread_getname_np(musl_pthread_t thread, + char* name, + size_t len) { + return pthread_getname_np(reinterpret_cast(thread), name, len); +} diff --git a/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h b/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h index 175cc497a44..be73b119a2c 100644 --- a/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h +++ b/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h @@ -112,6 +112,12 @@ SB_EXPORT void* __abi_wrap_pthread_getspecific(musl_pthread_key_t key); SB_EXPORT int __abi_wrap_pthread_setspecific(musl_pthread_key_t key, const void* value); +SB_EXPORT int __abi_wrap_pthread_setname_np(musl_pthread_t thread, + const char* name); +SB_EXPORT int __abi_wrap_pthread_getname_np(musl_pthread_t thread, + char* name, + size_t len); + #ifdef __cplusplus } // extern "C" #endif diff --git a/starboard/shared/win32/posix_emu/include/pthread.h b/starboard/shared/win32/posix_emu/include/pthread.h index 36ef23e50cc..46546c0bb61 100644 --- a/starboard/shared/win32/posix_emu/include/pthread.h +++ b/starboard/shared/win32/posix_emu/include/pthread.h @@ -74,6 +74,8 @@ int pthread_detach(pthread_t thread); pthread_t pthread_self(); int pthread_equal(pthread_t t1, pthread_t t2); +int pthread_setname_np(pthread_t thread, const char* name); +int pthread_getname_np(pthread_t thread, char* name, size_t len); #ifdef __cplusplus } #endif diff --git a/starboard/shared/win32/posix_emu/pthread.cc b/starboard/shared/win32/posix_emu/pthread.cc index aed69bf05a0..8f507d9c1ba 100644 --- a/starboard/shared/win32/posix_emu/pthread.cc +++ b/starboard/shared/win32/posix_emu/pthread.cc @@ -18,10 +18,13 @@ #include #include "starboard/common/log.h" +#include "starboard/common/string.h" #include "starboard/common/time.h" #include "starboard/shared/win32/thread_local_internal.h" #include "starboard/shared/win32/thread_private.h" +#include "starboard/shared/win32/wchar_utils.h" +using starboard::shared::win32::CStringToWString; using starboard::shared::win32::GetCurrentSbThreadPrivate; using starboard::shared::win32::GetThreadSubsystemSingleton; using starboard::shared::win32::SbThreadPrivate; @@ -314,4 +317,24 @@ int pthread_setspecific(pthread_key_t key, const void* value) { return TlsInternalSetValue(tls_index, const_cast(value)) ? 0 : -1; } +int pthread_setname_np(pthread_t thread, const char* name) { + SbThreadPrivate* thread_private = static_cast(thread); + std::wstring wname = CStringToWString(name); + + HRESULT hr = SetThreadDescription(thread_private->handle_, wname.c_str()); + if (FAILED(hr)) { + return -1; + } + // We store the thread name in our own TLS context as well as telling + // the OS because it's much easier to retrieve from our own TLS context. + thread_private->name_ = name; + + return 0; +} + +int pthread_getname_np(pthread_t thread, char* name, size_t len) { + SbThreadPrivate* thread_private = static_cast(thread); + starboard::strlcpy(name, thread_private->name_.c_str(), len); + return 0; +} } // extern "C" diff --git a/starboard/tools/api_leak_detector/api_leak_detector.py b/starboard/tools/api_leak_detector/api_leak_detector.py index 430e797dcf2..083cd41d6d6 100755 --- a/starboard/tools/api_leak_detector/api_leak_detector.py +++ b/starboard/tools/api_leak_detector/api_leak_detector.py @@ -146,6 +146,8 @@ 'pthread_key_create', 'pthread_key_delete', 'pthread_setspecific', + 'pthread_setname_np', + 'pthread_getname_np', 'usleep', ] diff --git a/third_party/musl/src/starboard/pthread/pthread.c b/third_party/musl/src/starboard/pthread/pthread.c index 95459824e13..04e350ec463 100644 --- a/third_party/musl/src/starboard/pthread/pthread.c +++ b/third_party/musl/src/starboard/pthread/pthread.c @@ -195,4 +195,24 @@ int pthread_setspecific(pthread_key_t key, const void* value) { return SbThreadSetLocalValue((SbThreadLocalKey)key, value)? 0: -1; } +int pthread_setname_np(pthread_t thread, const char* name) { + // Starboard 14/15 can only set thread name for the current thread + if (SbThreadGetCurrent() != thread) { + SB_DCHECK(false); + return -1; + } + SbThreadSetName(name); + return 0; +} + +int pthread_getname_np(pthread_t thread, char* name, size_t len) { + // Starboard 14/15 can only get the thread name for the current thread + if (SbThreadGetCurrent() != thread) { + SB_DCHECK(false); + return -1; + } + SbThreadGetName(name, len); + return 0; +} + #endif // SB_API_VERSION < 16 diff --git a/third_party/musl/src/starboard/pthread/pthread.h b/third_party/musl/src/starboard/pthread/pthread.h index 777adfebad7..60acecf66c6 100644 --- a/third_party/musl/src/starboard/pthread/pthread.h +++ b/third_party/musl/src/starboard/pthread/pthread.h @@ -173,6 +173,9 @@ int pthread_detach(pthread_t thread); pthread_t pthread_self(); int pthread_equal(pthread_t t1, pthread_t t2); +int pthread_setname_np(pthread_t thread, const char* name); +int pthread_getname_np(pthread_t thread, char* name, size_t len); + #ifdef __cplusplus } // extern "C" #endif