diff --git a/starboard/CHANGELOG.md b/starboard/CHANGELOG.md index 3cc260f67f09..3a80327124f3 100644 --- a/starboard/CHANGELOG.md +++ b/starboard/CHANGELOG.md @@ -9,6 +9,11 @@ since the version previous to it. ## Version 16 +### Added support for pthread create attributes. +The standard pthread APIs `pthread_attr_init`, `pthread_attr_destroy`, +`pthread_attr_getdetachstate`, `pthread_attr_getstacksize`, +`pthread_attr_setdetachstate`, `pthread_attr_setstacksize` were added. + ### Deprecated the `SbThreadSetName` and `SbThreadGetName` APIs. Replaced the `SbThreadSetName`/`SbThreadGetName` with the POSIX `pthread_setname_np`/`pthread_getname_np`. diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index abcce34c92b2..50409aa63a89 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -505,6 +505,19 @@ ExportedSymbols::ExportedSymbols() { map_["gmtime_r"] = reinterpret_cast(&__abi_wrap_gmtime_r); map_["lseek"] = reinterpret_cast(&__abi_wrap_lseek); map_["mmap"] = reinterpret_cast(&__abi_wrap_mmap); + + map_["pthread_attr_init"] = + reinterpret_cast(&__abi_wrap_pthread_attr_init); + map_["pthread_attr_destroy"] = + reinterpret_cast(&__abi_wrap_pthread_attr_destroy); + map_["pthread_attr_getdetachstate"] = + reinterpret_cast(&__abi_wrap_pthread_attr_getdetachstate); + map_["pthread_attr_getstacksize"] = + reinterpret_cast(&__abi_wrap_pthread_attr_getstacksize); + map_["pthread_attr_setdetachstate"] = + reinterpret_cast(&__abi_wrap_pthread_attr_setdetachstate); + map_["pthread_attr_setstacksize"] = + reinterpret_cast(&__abi_wrap_pthread_attr_setstacksize); map_["pthread_cond_broadcast"] = reinterpret_cast(&__abi_wrap_pthread_cond_broadcast); map_["pthread_cond_destroy"] = diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn index e303c8bde456..cacbc58fa25d 100644 --- a/starboard/nplb/BUILD.gn +++ b/starboard/nplb/BUILD.gn @@ -175,6 +175,7 @@ target(gtest_target_type, "nplb") { "posix_compliance/posix_string_compare_no_case_test.cc", "posix_compliance/posix_string_format_test.cc", "posix_compliance/posix_string_format_wide_test.cc", + "posix_compliance/posix_thread_attr_test.cc", "posix_compliance/posix_thread_create_test.cc", "posix_compliance/posix_thread_detach_test.cc", "posix_compliance/posix_thread_get_current_test.cc", diff --git a/starboard/nplb/posix_compliance/posix_thread_attr_test.cc b/starboard/nplb/posix_compliance/posix_thread_attr_test.cc new file mode 100644 index 000000000000..7d9e64bae3c9 --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_thread_attr_test.cc @@ -0,0 +1,61 @@ +// 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 "testing/gtest/include/gtest/gtest.h" +namespace starboard { +namespace nplb { +namespace { + +constexpr int kStackSize = 4 * 1024 * 1024; + +TEST(PosixThreadAttrTest, InitAttr) { + pthread_attr_t attr; + EXPECT_EQ(pthread_attr_init(&attr), 0); + EXPECT_EQ(pthread_attr_destroy(&attr), 0); +} + +TEST(PosixThreadAttrTest, DetachAttr) { + pthread_attr_t attr; + EXPECT_EQ(pthread_attr_init(&attr), 0); + int detach_state = PTHREAD_CREATE_JOINABLE; + + EXPECT_EQ(pthread_attr_getdetachstate(&attr, &detach_state), 0); + EXPECT_EQ(detach_state, PTHREAD_CREATE_JOINABLE); + + EXPECT_EQ(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED), 0); + + EXPECT_EQ(pthread_attr_getdetachstate(&attr, &detach_state), 0); + EXPECT_EQ(detach_state, PTHREAD_CREATE_DETACHED); + + EXPECT_EQ(pthread_attr_destroy(&attr), 0); +} + +TEST(PosixThreadAttrTest, StackSizeAttr) { + pthread_attr_t attr; + EXPECT_EQ(pthread_attr_init(&attr), 0); + size_t stack_size = 0; + + EXPECT_EQ(pthread_attr_setstacksize(&attr, kStackSize), 0); + + EXPECT_EQ(pthread_attr_getstacksize(&attr, &stack_size), 0); + EXPECT_EQ(stack_size, kStackSize); + + EXPECT_EQ(pthread_attr_destroy(&attr), 0); +} + +} // 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 d33634ffa132..1ed7920cd03f 100644 --- a/starboard/shared/modular/cobalt_layer_posix_pthread_abi_wrappers.cc +++ b/starboard/shared/modular/cobalt_layer_posix_pthread_abi_wrappers.cc @@ -197,5 +197,45 @@ 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); } + +int __abi_wrap_pthread_attr_destroy(pthread_attr_t* attr); + +int pthread_attr_destroy(pthread_attr_t* attr) { + return __abi_wrap_pthread_attr_destroy(attr); +} + +int __abi_wrap_pthread_attr_init(pthread_attr_t* attr); + +int pthread_attr_init(pthread_attr_t* attr) { + return __abi_wrap_pthread_attr_init(attr); +} + +int __abi_wrap_pthread_attr_getstacksize(const pthread_attr_t* attr, + size_t* stack_size); + +int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size) { + return __abi_wrap_pthread_attr_getstacksize(attr, stack_size); +} + +int __abi_wrap_pthread_attr_setstacksize(pthread_attr_t* attr, + size_t stack_size); + +int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) { + return __abi_wrap_pthread_attr_setstacksize(attr, stack_size); +} + +int __abi_wrap_pthread_attr_getdetachstate(const pthread_attr_t* att, + int* detachs_state); + +int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detach_state) { + return __abi_wrap_pthread_attr_getdetachstate(attr, detach_state); +} + +int __abi_wrap_pthread_attr_setdetachstate(pthread_attr_t* attr, + int detach_state); + +int pthread_attr_setdetachstate(pthread_attr_t* attr, int detach_state) { + return __abi_wrap_pthread_attr_setdetachstate(attr, detach_state); +} } #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 1a4df37e3611..93dcd62299f9 100644 --- a/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.cc +++ b/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.cc @@ -380,3 +380,37 @@ int __abi_wrap_pthread_getname_np(musl_pthread_t thread, size_t len) { return pthread_getname_np(reinterpret_cast(thread), name, len); } + +int __abi_wrap_pthread_attr_init(musl_pthread_attr_t* attr) { + return pthread_attr_init(PTHREAD_INTERNAL_ATTR(attr)); +} + +int __abi_wrap_pthread_attr_destroy(musl_pthread_attr_t* attr) { + return pthread_attr_destroy(PTHREAD_INTERNAL_ATTR(attr)); +} + +int __abi_wrap_pthread_attr_getstacksize(const musl_pthread_attr_t* attr, + size_t* stack_size) { + return pthread_attr_getstacksize(CONST_PTHREAD_INTERNAL_ATTR(attr), + stack_size); +} + +int __abi_wrap_pthread_attr_setstacksize(musl_pthread_attr_t* attr, + size_t stack_size) { + return pthread_attr_setstacksize(PTHREAD_INTERNAL_ATTR(attr), stack_size); +} + +int __abi_wrap_pthread_attr_getdetachstate(const musl_pthread_attr_t* attr, + int* detach_state) { + return pthread_attr_getdetachstate(CONST_PTHREAD_INTERNAL_ATTR(attr), + detach_state); +} + +int __abi_wrap_pthread_attr_setdetachstate(musl_pthread_attr_t* attr, + int detach_state) { + int d = PTHREAD_CREATE_JOINABLE; + if (detach_state == MUSL_PTHREAD_CREATE_DETACHED) { + d = PTHREAD_CREATE_DETACHED; + } + return pthread_attr_setdetachstate(PTHREAD_INTERNAL_ATTR(attr), d); +} 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 be73b119a2cd..3a618a683bf1 100644 --- a/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h +++ b/starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h @@ -25,6 +25,9 @@ extern "C" { #endif +#define MUSL_PTHREAD_CREATE_JOINABLE 0 +#define MUSL_PTHREAD_CREATE_DETACHED 1 + // Max size of the native mutex type. #define MUSL_MUTEX_MAX_SIZE 80 @@ -118,6 +121,21 @@ SB_EXPORT int __abi_wrap_pthread_getname_np(musl_pthread_t thread, char* name, size_t len); +SB_EXPORT int __abi_wrap_pthread_attr_init(musl_pthread_attr_t* attr); +SB_EXPORT int __abi_wrap_pthread_attr_destroy(musl_pthread_attr_t* attr); + +SB_EXPORT int __abi_wrap_pthread_attr_getstacksize( + const musl_pthread_attr_t* attr, + size_t* stack_size); +SB_EXPORT int __abi_wrap_pthread_attr_setstacksize(musl_pthread_attr_t* attr, + size_t stack_size); + +SB_EXPORT int __abi_wrap_pthread_attr_getdetachstate( + const musl_pthread_attr_t* attr, + int* detach_state); +SB_EXPORT int __abi_wrap_pthread_attr_setdetachstate(musl_pthread_attr_t* attr, + int detach_state); + #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 ea0743946b45..6ccbb95216d1 100644 --- a/starboard/shared/win32/posix_emu/include/pthread.h +++ b/starboard/shared/win32/posix_emu/include/pthread.h @@ -30,6 +30,9 @@ #define PTHREAD_COND_INITIALIZER _INITIALIZER #define PTHREAD_ONCE_INIT _INITIALIZER +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + #ifdef __cplusplus extern "C" { #endif @@ -94,6 +97,16 @@ 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); + +int pthread_attr_init(pthread_attr_t* attr); +int pthread_attr_destroy(pthread_attr_t* attr); + +int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size); +int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size); + +int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detach_state); +int pthread_attr_setdetachstate(pthread_attr_t* attr, int detach_state); + #ifdef __cplusplus } #endif diff --git a/starboard/shared/win32/posix_emu/pthread.cc b/starboard/shared/win32/posix_emu/pthread.cc index 84cf21f1cb35..1edf68517832 100644 --- a/starboard/shared/win32/posix_emu/pthread.cc +++ b/starboard/shared/win32/posix_emu/pthread.cc @@ -42,6 +42,11 @@ void ResetWinError(); int RunThreadLocalDestructors(ThreadSubsystemSingleton* singleton); int CountTlsObjectsRemaining(ThreadSubsystemSingleton* singleton); +typedef struct pthread_attr_impl_t { + size_t stack_size; + int detach_state; +} pthread_attr_impl_t; + extern "C" { int pthread_mutex_destroy(pthread_mutex_t* mutex) { @@ -225,13 +230,20 @@ int pthread_create(pthread_t* thread, info->entry_point_ = start_routine; info->user_context_ = arg; + info->thread_private_.wait_for_join_ = true; + if (reinterpret_cast(*attr)->detach_state == + PTHREAD_CREATE_DETACHED) { + info->thread_private_.wait_for_join_ = false; + } // Create the thread suspended, and then resume once ThreadCreateInfo::handle_ // has been set, so that it's always valid in the ThreadCreateInfo // destructor. - uintptr_t handle = - _beginthreadex(NULL, 0, ThreadTrampoline, info, CREATE_SUSPENDED, NULL); + unsigned int stack_size = + reinterpret_cast(*attr)->stack_size; + uintptr_t handle = _beginthreadex(NULL, stack_size, ThreadTrampoline, info, + CREATE_SUSPENDED, NULL); SB_DCHECK(handle); info->thread_private_.handle_ = reinterpret_cast(handle); ResetWinError(); @@ -351,4 +363,38 @@ int pthread_getname_np(pthread_t thread, char* name, size_t len) { starboard::strlcpy(name, thread_private->name_.c_str(), len); return 0; } + +int pthread_attr_init(pthread_attr_t* attr) { + *attr = calloc(sizeof(pthread_attr_impl_t), 1); + if (*attr) { + return 0; + } + return -1; +} + +int pthread_attr_destroy(pthread_attr_t* attr) { + free(*attr); + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size) { + *stack_size = reinterpret_cast(*attr)->stack_size; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) { + reinterpret_cast(*attr)->stack_size = stack_size; + return 0; +} + +int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detach_state) { + *detach_state = reinterpret_cast(*attr)->detach_state; + return 0; +} + +int pthread_attr_setdetachstate(pthread_attr_t* attr, int detach_state) { + reinterpret_cast(*attr)->detach_state = detach_state; + 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 ec9e0dc4ddf8..231903bc4365 100755 --- a/starboard/tools/api_leak_detector/api_leak_detector.py +++ b/starboard/tools/api_leak_detector/api_leak_detector.py @@ -124,6 +124,12 @@ 'read', 'sched_yield', 'stat', + 'pthread_attr_init', + 'pthread_attr_destroy', + 'pthread_attr_getdetachstate', + 'pthread_attr_getstacksize', + 'pthread_attr_setdetachstate', + 'pthread_attr_setstacksize', 'pthread_cond_broadcast', 'pthread_cond_destroy', 'pthread_cond_init', diff --git a/third_party/musl/src/starboard/pthread/pthread.c b/third_party/musl/src/starboard/pthread/pthread.c index 04e350ec4636..369ed1075984 100644 --- a/third_party/musl/src/starboard/pthread/pthread.c +++ b/third_party/musl/src/starboard/pthread/pthread.c @@ -24,6 +24,11 @@ #include "starboard/once.h" #include "starboard/time.h" +typedef struct pthread_attr_impl_t { + size_t stack_size; + int detach_state; +} pthread_attr_impl_t; + int pthread_mutex_init(pthread_mutex_t* mutext, const pthread_mutexattr_t*) { if (SbMutexCreate((SbMutex*)mutext->mutex_buffer)) { return 0; @@ -146,9 +151,19 @@ int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg) { + int stack_size = 0; + bool joinable = true; + if (attr != NULL) { + stack_size = ((pthread_attr_impl_t*)(attr->attr_buffer))->stack_size; + if ((((pthread_attr_impl_t*)(attr->attr_buffer))->detach_state == + PTHREAD_CREATE_DETACHED)) { + joinable = false; + } + } + SbThread starboard_thread = - SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, true, NULL, - start_routine, arg); + SbThreadCreate(stack_size, kSbThreadNoPriority, kSbThreadNoAffinity, + joinable, NULL, start_routine, arg); if (SbThreadIsValid(thread)) { *thread = starboard_thread; return 0; @@ -192,7 +207,7 @@ void* pthread_getspecific(pthread_key_t key) { } int pthread_setspecific(pthread_key_t key, const void* value) { - return SbThreadSetLocalValue((SbThreadLocalKey)key, value)? 0: -1; + return SbThreadSetLocalValue((SbThreadLocalKey)key, value) ? 0 : -1; } int pthread_setname_np(pthread_t thread, const char* name) { @@ -211,7 +226,36 @@ int pthread_getname_np(pthread_t thread, char* name, size_t len) { SB_DCHECK(false); return -1; } - SbThreadGetName(name, len); + SbThreadGetName(name, len); + return 0; +} + +int pthread_attr_init(pthread_attr_t* attr) { + memset(attr, 0, sizeof(pthread_attr_t)); + return 0; +} + +int pthread_attr_destroy(pthread_attr_t* attr) { + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size) { + *stack_size = ((pthread_attr_impl_t*)(attr->attr_buffer))->stack_size; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size) { + ((pthread_attr_impl_t*)(attr->attr_buffer))->stack_size = stack_size; + return 0; +} + +int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detach_state) { + *detach_state = ((pthread_attr_impl_t*)(attr->attr_buffer))->detach_state; + return 0; +} + +int pthread_attr_setdetachstate(pthread_attr_t* attr, int detach_state) { + ((pthread_attr_impl_t*)(attr->attr_buffer))->detach_state = detach_state; return 0; } diff --git a/third_party/musl/src/starboard/pthread/pthread.h b/third_party/musl/src/starboard/pthread/pthread.h index 559bff63fab0..e456d5742322 100644 --- a/third_party/musl/src/starboard/pthread/pthread.h +++ b/third_party/musl/src/starboard/pthread/pthread.h @@ -18,6 +18,9 @@ #include #include +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + #ifdef __cplusplus extern "C" { #endif @@ -176,6 +179,15 @@ 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); +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_init(pthread_attr_t *attr); + +int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stack_size); +int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stack_size); + +int pthread_attr_getdetachstate(const pthread_attr_t* att, int* detach_state); +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detach_state); + #ifdef __cplusplus } // extern "C" #endif