From 32f8f84e8e0ebf0f006f591c0ac24337c9f1916b Mon Sep 17 00:00:00 2001 From: FirstName LastName Date: Fri, 19 Jan 2024 23:30:33 +0000 Subject: [PATCH] Introduce pthread_mutex APIs. - Add support for pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock and pthread_mutex_trylock. b/302335657 Change-Id: I8774ddb8ad466b7342e045402b170a719f2e1a81 --- starboard/build/config/modular/BUILD.gn | 5 + starboard/elf_loader/exported_symbols.cc | 11 ++ starboard/nplb/BUILD.gn | 4 + .../posix_mutex_acquire_test.cc | 96 +++++++++++++++ .../posix_mutex_acquire_try_test.cc | 81 +++++++++++++ .../posix_mutex_create_test.cc | 65 +++++++++++ .../posix_mutex_destroy_test.cc | 35 ++++++ starboard/shared/modular/BUILD.gn | 2 + .../shared/modular/posix_pthread_wrappers.cc | 109 ++++++++++++++++++ .../shared/modular/posix_pthread_wrappers.h | 53 +++++++++ .../shared/win32/posix_emu/include/pthread.h | 46 ++++++++ starboard/shared/win32/posix_emu/pthread.cc | 53 +++++++++ .../stub/platform_configuration/BUILD.gn | 2 + starboard/win/shared/BUILD.gn | 1 + .../abseil-cpp/absl/base/internal/sysinfo.cc | 10 ++ third_party/musl/BUILD.gn | 1 + third_party/musl/include/pthread.h | 9 ++ third_party/musl/include/sys/types.h | 3 + .../musl/src/starboard/pthread/pthread.c | 61 ++++++++++ .../musl/src/starboard/pthread/pthread.h | 91 +++++++++++++++ 20 files changed, 738 insertions(+) create mode 100644 starboard/nplb/posix_compliance/posix_mutex_acquire_test.cc create mode 100644 starboard/nplb/posix_compliance/posix_mutex_acquire_try_test.cc create mode 100644 starboard/nplb/posix_compliance/posix_mutex_create_test.cc create mode 100644 starboard/nplb/posix_compliance/posix_mutex_destroy_test.cc create mode 100644 starboard/shared/modular/posix_pthread_wrappers.cc create mode 100644 starboard/shared/modular/posix_pthread_wrappers.h create mode 100644 starboard/shared/win32/posix_emu/include/pthread.h create mode 100644 starboard/shared/win32/posix_emu/pthread.cc create mode 100644 third_party/musl/src/starboard/pthread/pthread.c create mode 100644 third_party/musl/src/starboard/pthread/pthread.h diff --git a/starboard/build/config/modular/BUILD.gn b/starboard/build/config/modular/BUILD.gn index b8a864db52ed..1bbbd5f6dc4a 100644 --- a/starboard/build/config/modular/BUILD.gn +++ b/starboard/build/config/modular/BUILD.gn @@ -185,6 +185,11 @@ config("modular") { "-Wl,--wrap=time", "-Wl,--wrap=gmtime_r", "-Wl,--wrap=mmap", + "-Wl,--wrap=pthread_mutex_destroy", + "-Wl,--wrap=pthread_mutex_init", + "-Wl,--wrap=pthread_mutex_lock", + "-Wl,--wrap=pthread_mutex_unlock", + "-Wl,--wrap=pthread_mutex_trylock", ] } } diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index c1b85d100f07..dd46c6c567ee 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -46,6 +46,7 @@ #include "starboard/player.h" #if SB_API_VERSION >= 16 #include "starboard/shared/modular/posix_mmap_wrappers.h" +#include "starboard/shared/modular/posix_pthread_wrappers.h" #include "starboard/shared/modular/posix_time_wrappers.h" #endif // SB_API_VERSION >= 16 @@ -435,6 +436,16 @@ ExportedSymbols::ExportedSymbols() { map_["time"] = reinterpret_cast(&__wrap_time); map_["gmtime_r"] = reinterpret_cast(&__wrap_gmtime_r); map_["mmap"] = reinterpret_cast(&__wrap_mmap); + map_["pthread_mutex_destroy"] = + reinterpret_cast(&__wrap_pthread_mutex_destroy); + map_["pthread_mutex_init"] = + reinterpret_cast(&__wrap_pthread_mutex_init); + map_["pthread_mutex_lock"] = + reinterpret_cast(&__wrap_pthread_mutex_lock); + map_["pthread_mutex_unlock"] = + reinterpret_cast(&__wrap_pthread_mutex_unlock); + map_["pthread_mutex_trylock"] = + reinterpret_cast(&__wrap_pthread_mutex_trylock); REGISTER_SYMBOL(sprintf); REGISTER_SYMBOL(snprintf); diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn index 26460f62d9d9..0b95d0cc071b 100644 --- a/starboard/nplb/BUILD.gn +++ b/starboard/nplb/BUILD.gn @@ -137,6 +137,10 @@ target(gtest_target_type, "nplb") { "posix_compliance/posix_arpa_inet_test.cc", "posix_compliance/posix_directory_create_test.cc", "posix_compliance/posix_memory_map_test.cc", + "posix_compliance/posix_mutex_acquire_test.cc", + "posix_compliance/posix_mutex_acquire_try_test.cc", + "posix_compliance/posix_mutex_create_test.cc", + "posix_compliance/posix_mutex_destroy_test.cc", "posix_compliance/posix_string_compare_no_case_n_test.cc", "posix_compliance/posix_string_compare_no_case_test.cc", "posix_compliance/posix_string_format_test.cc", diff --git a/starboard/nplb/posix_compliance/posix_mutex_acquire_test.cc b/starboard/nplb/posix_compliance/posix_mutex_acquire_test.cc new file mode 100644 index 000000000000..753c18792a68 --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_mutex_acquire_test.cc @@ -0,0 +1,96 @@ +// Copyright 2015 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. + +#if SB_API_VERSION >= 16 + +#include + +#include "starboard/configuration.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +struct TestContext { + TestContext() : count(0) {} + pthread_mutex_t mutex; + int count; +}; + +const int kLoops = 10000; + +void* EntryPoint(void* parameter) { + TestContext* context = static_cast(parameter); + + for (int i = 0; i < kLoops; ++i) { + pthread_mutex_lock(&context->mutex); + context->count++; + pthread_mutex_unlock(&context->mutex); + } + + return NULL; +} + +// This test just tries to acquire a mutex repeatedly while other threads are +// doing the same. +TEST(PosixMutexAcquireTest, SunnyDayContended) { + TestContext context; + EXPECT_EQ(pthread_mutex_init(&context.mutex, NULL), 0); + const int kThreads = 4; + SbThread threads[kThreads]; + for (int i = 0; i < kThreads; ++i) { + threads[i] = SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, + true, NULL, EntryPoint, &context); + } + + for (int i = 0; i < kLoops; ++i) { + for (int j = 0; j < kThreads; ++j) { + EXPECT_EQ(pthread_mutex_lock(&context.mutex), 0); + int k = context.count; + k = k - 1; + context.count = k; + EXPECT_EQ(pthread_mutex_unlock(&context.mutex), 0); + } + } + + // Join other threads and clean up. + for (int i = 0; i < kThreads; ++i) { + EXPECT_TRUE(SbThreadJoin(threads[i], NULL)); + } + EXPECT_EQ(pthread_mutex_destroy(&context.mutex), 0); + EXPECT_EQ(0, context.count); +} + +TEST(PosixMutexAcquireTest, SunnyDayUncontended) { + pthread_mutex_t mutex; + EXPECT_EQ(pthread_mutex_init(&mutex, NULL), 0); + + EXPECT_EQ(pthread_mutex_lock(&mutex), 0); + EXPECT_EQ(pthread_mutex_unlock(&mutex), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +TEST(PosixMutexAcquireTest, SunnyDayStaticallyInitialized) { + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + EXPECT_EQ(pthread_mutex_lock(&mutex), 0); + EXPECT_EQ(pthread_mutex_unlock(&mutex), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_mutex_acquire_try_test.cc b/starboard/nplb/posix_compliance/posix_mutex_acquire_try_test.cc new file mode 100644 index 000000000000..640827b1ef96 --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_mutex_acquire_try_test.cc @@ -0,0 +1,81 @@ +// Copyright 2015 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. + +#if SB_API_VERSION >= 16 + +#include + +#include "starboard/configuration.h" +#include "testing/gtest/include/gtest/gtest.h" + +#include "starboard/nplb/thread_helpers.h" +#include "starboard/thread.h" + +namespace starboard { +namespace nplb { +namespace { + +struct TestContext { + explicit TestContext(pthread_mutex_t* mutex) + : was_locked_(false), mutex_(mutex) {} + bool was_locked_; + pthread_mutex_t* mutex_; +}; + +void* EntryPoint(void* parameter) { + TestContext* context = static_cast(parameter); + context->was_locked_ = (pthread_mutex_trylock(context->mutex_) == 0); + return NULL; +} + +TEST(PosixMutexAcquireTryTest, SunnyDayUncontended) { + pthread_mutex_t mutex; + EXPECT_EQ(pthread_mutex_init(&mutex, NULL), 0); + + EXPECT_EQ(pthread_mutex_trylock(&mutex), 0); + EXPECT_EQ(pthread_mutex_unlock(&mutex), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +TEST(PosixMutexAcquireTest, SunnyDayAutoInit) { + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + EXPECT_EQ(pthread_mutex_trylock(&mutex), 0); + EXPECT_EQ(pthread_mutex_unlock(&mutex), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +TEST(PosixMutexAcquireTryTest, RainyDayReentrant) { + pthread_mutex_t mutex; + EXPECT_EQ(pthread_mutex_init(&mutex, NULL), 0); + + EXPECT_EQ(pthread_mutex_trylock(&mutex), 0); + + TestContext context(&mutex); + // TODO: Migrate to pthread_create when available. + SbThread thread = + SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, true, + nplb::kThreadName, &EntryPoint, &context); + + EXPECT_TRUE(SbThreadIsValid(thread)); + EXPECT_TRUE(SbThreadJoin(thread, NULL)); + EXPECT_FALSE(context.was_locked_); + EXPECT_EQ(pthread_mutex_unlock(&mutex), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_mutex_create_test.cc b/starboard/nplb/posix_compliance/posix_mutex_create_test.cc new file mode 100644 index 000000000000..484cac55215e --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_mutex_create_test.cc @@ -0,0 +1,65 @@ +// Copyright 2015 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. + +#if SB_API_VERSION >= 16 + +#include + +#include "starboard/configuration.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +const int kALot = 128 * 1024; +const int kABunch = 2 * 1024; + +TEST(PosixMutexCreateTest, SunnyDay) { + pthread_mutex_t mutex; + EXPECT_EQ(pthread_mutex_init(&mutex, NULL), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +TEST(PosixMutexCreateTest, SunnyDayAutoInit) { + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + EXPECT_EQ(pthread_mutex_init(&mutex, NULL), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +TEST(PosixMutexCreateTest, SunnyDayALot) { + for (int i = 0; i < kALot; ++i) { + pthread_mutex_t mutex; + EXPECT_EQ(pthread_mutex_init(&mutex, NULL), 0); + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); + } +} + +TEST(PosixMutexCreateTest, SunnyDayABunchAtOnce) { + pthread_mutex_t mutexes[kABunch]; + for (int i = 0; i < kABunch; ++i) { + EXPECT_EQ(pthread_mutex_init(&mutexes[i], NULL), 0); + } + + for (int i = 0; i < kABunch; ++i) { + EXPECT_EQ(pthread_mutex_destroy(&mutexes[i]), 0); + } +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_mutex_destroy_test.cc b/starboard/nplb/posix_compliance/posix_mutex_destroy_test.cc new file mode 100644 index 000000000000..be2864ea59ff --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_mutex_destroy_test.cc @@ -0,0 +1,35 @@ +// Copyright 2015 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. + +#if SB_API_VERSION >= 16 + +#include + +#include "starboard/configuration.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +TEST(PosixMutexDestroyTest, SunnyDayAutoInit) { + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + EXPECT_EQ(pthread_mutex_destroy(&mutex), 0); +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/shared/modular/BUILD.gn b/starboard/shared/modular/BUILD.gn index 9362852b883f..e1ce81661ae6 100644 --- a/starboard/shared/modular/BUILD.gn +++ b/starboard/shared/modular/BUILD.gn @@ -18,6 +18,8 @@ source_set("posix_wrappers") { sources = [ "posix_mmap_wrappers.cc", "posix_mmap_wrappers.h", + "posix_pthread_wrappers.cc", + "posix_pthread_wrappers.h", "posix_time_wrappers.cc", "posix_time_wrappers.h", ] diff --git a/starboard/shared/modular/posix_pthread_wrappers.cc b/starboard/shared/modular/posix_pthread_wrappers.cc new file mode 100644 index 000000000000..517ea18074d3 --- /dev/null +++ b/starboard/shared/modular/posix_pthread_wrappers.cc @@ -0,0 +1,109 @@ +// 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 "starboard/shared/modular/posix_pthread_wrappers.h" + +#include + +#include "starboard/shared/pthread/is_success.h" +#include "starboard/shared/starboard/lazy_initialization_internal.h" + +using starboard::shared::starboard::EnsureInitialized; +using starboard::shared::starboard::IsInitialized; +using starboard::shared::starboard::SetInitialized; + +typedef struct PosixMutexPrivate { + InitializedState initialized_state; + pthread_mutex_t mutex; +} PosixMutexPrivate; + +typedef struct PosixMutexAttrPrivate { + InitializedState initialized_state; + pthread_mutexattr_t mutex_attr; +} PosixMutexAttrPrivate; + +#define INTERNAL_MUTEX(mutex_var) \ + reinterpret_cast((mutex_var)->mutex_buffer) +#define PTHREAD_INTERNAL_MUTEX(mutex_var) \ + &(reinterpret_cast((mutex_var)->mutex_buffer)->mutex) +#define PTHREAD_INTERNAL_MUTEX_ATTR(mutex_var) \ + &(reinterpret_cast((mutex_var)->mutex_buffer) \ + ->mutex_attr) + +int __wrap_pthread_mutex_destroy(musl_pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + + if (!IsInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state))) { + // If the mutex is not initialized there is nothing to destroy. + return 0; + } + + return pthread_mutex_destroy(PTHREAD_INTERNAL_MUTEX(mutex)); +} + +int __wrap_pthread_mutex_init(musl_pthread_mutex_t* mutex, + const musl_pthread_mutexattr_t* mutex_attr) { + if (!mutex) { + return EINVAL; + } + + *PTHREAD_INTERNAL_MUTEX(mutex) = PTHREAD_MUTEX_INITIALIZER; + SetInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state)); + + const pthread_mutexattr_t* tmp = nullptr; + if (mutex_attr) { + tmp = PTHREAD_INTERNAL_MUTEX_ATTR(mutex_attr); + } + return pthread_mutex_init(PTHREAD_INTERNAL_MUTEX(mutex), tmp); +} + +int __wrap_pthread_mutex_lock(musl_pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + + if (!EnsureInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state))) { + *PTHREAD_INTERNAL_MUTEX(mutex) = PTHREAD_MUTEX_INITIALIZER; + SetInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state)); + } + + return pthread_mutex_lock(PTHREAD_INTERNAL_MUTEX(mutex)); +} + +int __wrap_pthread_mutex_unlock(musl_pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + + if (!IsInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state))) { + // If the mutex is not initialized there is nothing to release. + return EINVAL; + } + return pthread_mutex_unlock(PTHREAD_INTERNAL_MUTEX(mutex)); +} + +int __wrap_pthread_mutex_trylock(musl_pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + + if (!EnsureInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state))) { + *PTHREAD_INTERNAL_MUTEX(mutex) = PTHREAD_MUTEX_INITIALIZER; + SetInitialized(&(INTERNAL_MUTEX(mutex)->initialized_state)); + } + + return pthread_mutex_trylock(PTHREAD_INTERNAL_MUTEX(mutex)); +} diff --git a/starboard/shared/modular/posix_pthread_wrappers.h b/starboard/shared/modular/posix_pthread_wrappers.h new file mode 100644 index 000000000000..49c906d20e4b --- /dev/null +++ b/starboard/shared/modular/posix_pthread_wrappers.h @@ -0,0 +1,53 @@ +// 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_SHARED_MODULAR_POSIX_PTHREAD_WRAPPERS_H_ +#define STARBOARD_SHARED_MODULAR_POSIX_PTHREAD_WRAPPERS_H_ + +#include + +#include "starboard/configuration.h" +#include "starboard/export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Max size of the native mutex type. +#define MUSL_MUTEX_MAX_SIZE 80 + +typedef union musl_pthread_mutex_t { + uint8_t mutex_buffer[MUSL_MUTEX_MAX_SIZE]; + void* ptr; +} musl_pthread_mutex_t; + +#define MUSL_MUTEX_ATTR_MAX_SIZE 40 +typedef union musl_pthread_mutexattr_t { + uint8_t mutex_buffer[MUSL_MUTEX_ATTR_MAX_SIZE]; + void* ptr; +} musl_pthread_mutexattr_t; + +SB_EXPORT int __wrap_pthread_mutex_destroy(musl_pthread_mutex_t* mutex); +SB_EXPORT int __wrap_pthread_mutex_init( + musl_pthread_mutex_t* mutex, + const musl_pthread_mutexattr_t* mutex_attr); +SB_EXPORT int __wrap_pthread_mutex_lock(musl_pthread_mutex_t* mutex); +SB_EXPORT int __wrap_pthread_mutex_unlock(musl_pthread_mutex_t* mutex); +SB_EXPORT int __wrap_pthread_mutex_trylock(musl_pthread_mutex_t* mutex); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // STARBOARD_SHARED_MODULAR_POSIX_PTHREAD_WRAPPERS_H_ diff --git a/starboard/shared/win32/posix_emu/include/pthread.h b/starboard/shared/win32/posix_emu/include/pthread.h new file mode 100644 index 000000000000..06ff17159ec5 --- /dev/null +++ b/starboard/shared/win32/posix_emu/include/pthread.h @@ -0,0 +1,46 @@ +// 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_SHARED_WIN32_POSIX_EMU_INCLUDE_PTHREAD_H_ +#define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_PTHREAD_H_ + +#include + +#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT + +#ifdef __cplusplus +extern "C" { +#endif + +typedef SRWLOCK pthread_mutex_t; +typedef unsigned int pthread_mutexattr_t; +typedef DWORD pthread_key_t; + +int pthread_mutex_destroy(pthread_mutex_t* mutex); +int pthread_mutex_init(pthread_mutex_t* mutex, + const pthread_mutexattr_t* mutex_attr); +int pthread_mutex_lock(pthread_mutex_t* mutex); +int pthread_mutex_unlock(pthread_mutex_t* mutex); +int pthread_mutex_trylock(pthread_mutex_t* mutex); + +int pthread_key_create(pthread_key_t* key, void (*)(void* dtor)); +int pthread_key_delete(pthread_key_t key); +void* pthread_getspecific(pthread_key_t key); +int pthread_setspecific(pthread_key_t key, const void* value); + +#ifdef __cplusplus +} +#endif + +#endif // STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_PTHREAD_H_ diff --git a/starboard/shared/win32/posix_emu/pthread.cc b/starboard/shared/win32/posix_emu/pthread.cc new file mode 100644 index 000000000000..541d210b8e86 --- /dev/null +++ b/starboard/shared/win32/posix_emu/pthread.cc @@ -0,0 +1,53 @@ +// 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 + +int pthread_mutex_destroy(pthread_mutex_t* mutex) { + return 0; +} + +int pthread_mutex_init(pthread_mutex_t* mutex, + const pthread_mutexattr_t* mutex_attr) { + if (!mutex) { + return EINVAL; + } + InitializeSRWLock(mutex); + return 0; +} + +int pthread_mutex_lock(pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + AcquireSRWLockExclusive(mutex); + return 0; +} + +int pthread_mutex_unlock(pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + ReleaseSRWLockExclusive(mutex); + return 0; +} + +int pthread_mutex_trylock(pthread_mutex_t* mutex) { + if (!mutex) { + return EINVAL; + } + bool result = TryAcquireSRWLockExclusive(mutex); + return result ? 0 : EBUSY; +} diff --git a/starboard/stub/platform_configuration/BUILD.gn b/starboard/stub/platform_configuration/BUILD.gn index e1d5a11664e2..d3804a6280e1 100644 --- a/starboard/stub/platform_configuration/BUILD.gn +++ b/starboard/stub/platform_configuration/BUILD.gn @@ -19,6 +19,8 @@ config("platform_configuration") { cflags_cc = [ "-std=gnu++17" ] ldflags = [ "-static-libstdc++" ] + libs = [ "pthread" ] + if (is_debug) { cflags += [ "-O0" ] configs += [ "//build/config/compiler:rtti" ] diff --git a/starboard/win/shared/BUILD.gn b/starboard/win/shared/BUILD.gn index 9ea285f763ef..6d8e4a4f7571 100644 --- a/starboard/win/shared/BUILD.gn +++ b/starboard/win/shared/BUILD.gn @@ -235,6 +235,7 @@ static_library("starboard_platform") { "//starboard/shared/win32/once.cc", "//starboard/shared/win32/posix_emu/mman.cc", "//starboard/shared/win32/posix_emu/posix_memalign.cc", + "//starboard/shared/win32/posix_emu/pthread.cc", "//starboard/shared/win32/posix_emu/stat.cc", "//starboard/shared/win32/posix_emu/time.cc", "//starboard/shared/win32/set_non_blocking_internal.cc", diff --git a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc index 8429fb90e40d..7cf161eef5aa 100644 --- a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc +++ b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc @@ -418,7 +418,17 @@ pid_t GetTID() { // Fallback implementation of GetTID using pthread_getspecific. ABSL_CONST_INIT static once_flag tid_once; + +// ABSL tries to enforce a constant initializer for +// this variable. However for Starboard we have a more complex +// type definition of pthread_key_t for portability reasons and +// it doesn't have a constant initializer. +#if defined(STARBOARD) +static pthread_key_t tid_key; +#else ABSL_CONST_INIT static pthread_key_t tid_key; +#endif + ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock( absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); diff --git a/third_party/musl/BUILD.gn b/third_party/musl/BUILD.gn index c83da2c3e691..b8d88188ba1e 100644 --- a/third_party/musl/BUILD.gn +++ b/third_party/musl/BUILD.gn @@ -385,6 +385,7 @@ static_library("c_internal") { "src/starboard/malloc/malloc.c", "src/starboard/malloc/posix_memalign.c", "src/starboard/mman/mman.c", + "src/starboard/pthread/pthread.c", "src/starboard/stdio/fflush.c", "src/starboard/stdio/fputc.c", "src/starboard/stdio/stderr.c", diff --git a/third_party/musl/include/pthread.h b/third_party/musl/include/pthread.h index 89fd9ff7c12f..2703585ad634 100644 --- a/third_party/musl/include/pthread.h +++ b/third_party/musl/include/pthread.h @@ -1,5 +1,12 @@ #ifndef _PTHREAD_H #define _PTHREAD_H + +#if defined(STARBOARD) + +#include "third_party/musl/src/starboard/pthread/pthread.h" + +#else + #ifdef __cplusplus extern "C" { #endif @@ -241,4 +248,6 @@ __REDIR(pthread_timedjoin_np, __pthread_timedjoin_np_time64); #ifdef __cplusplus } #endif + +#endif // defined(STARBOARD) #endif diff --git a/third_party/musl/include/sys/types.h b/third_party/musl/include/sys/types.h index 3363374fd3d6..e786500137b6 100644 --- a/third_party/musl/include/sys/types.h +++ b/third_party/musl/include/sys/types.h @@ -30,6 +30,7 @@ extern "C" { #define __NEED_suseconds_t #define __NEED_blksize_t +#if !defined(STARBOARD) #define __NEED_pthread_t #define __NEED_pthread_attr_t #define __NEED_pthread_mutexattr_t @@ -43,6 +44,8 @@ extern "C" { #define __NEED_pthread_spinlock_t #define __NEED_pthread_key_t #define __NEED_pthread_once_t +#endif // !defined(STARBOARD) + #define __NEED_useconds_t #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) diff --git a/third_party/musl/src/starboard/pthread/pthread.c b/third_party/musl/src/starboard/pthread/pthread.c new file mode 100644 index 000000000000..3cc65c026c99 --- /dev/null +++ b/third_party/musl/src/starboard/pthread/pthread.c @@ -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 "third_party/musl/src/starboard/pthread/pthread.h" + +#include + +#if SB_API_VERSION < 16 + +#include "starboard/mutex.h" + +int pthread_mutex_init(pthread_mutex_t *__restrict mutext, const pthread_mutexattr_t *__restrict) { + if (SbMutexCreate((SbMutex*)mutext->mutex_buffer)) { + return 0; + } + return EINVAL; +} + +int pthread_mutex_lock(pthread_mutex_t* mutex) { + SbMutexResult result = SbMutexAcquire((SbMutex*)mutex->mutex_buffer); + if (result == kSbMutexAcquired) { + return 0; + } + return EINVAL; +} + +int pthread_mutex_unlock(pthread_mutex_t* mutex) { + if (SbMutexRelease((SbMutex*)mutex->mutex_buffer)) { + return 0; + } + return EINVAL; + +} + +int pthread_mutex_trylock(pthread_mutex_t* mutex) { + if (SbMutexAcquireTry((SbMutex*)mutex->mutex_buffer)) { + return 0; + } + return EINVAL; +} + +int pthread_mutex_destroy(pthread_mutex_t* mutex) { + if (SbMutexDestroy((SbMutex*)mutex->mutex_buffer)) { + return 0; + } + return EINVAL; + +} + +#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 new file mode 100644 index 000000000000..0f524c5a95d7 --- /dev/null +++ b/third_party/musl/src/starboard/pthread/pthread.h @@ -0,0 +1,91 @@ +// 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 THIRD_PARTY_MUSL_SRC_STARBOARD_PTHREAD_H_ +#define THIRD_PARTY_MUSL_SRC_STARBOARD_PTHREAD_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +#define PTHREAD_MUTEX_INITIALIZER \ + {} +#else +#define PTHREAD_MUTEX_INITIALIZER \ + { 0 } +#endif + +// Max size of the native mutex type. +#define MUSL_PTHREAD_MUTEX_MAX_SIZE 80 + +// An opaque handle to a native mutex type with reserved memory +// bufferaligned at void pointer type. +typedef union pthread_mutex_t { + // Reserved memory in which the implementation should map its + // native mutex type. + uint8_t mutex_buffer[MUSL_PTHREAD_MUTEX_MAX_SIZE]; + + // Guarantees alignment of the type to a void pointer. + void* ptr; +} pthread_mutex_t; + + +// Max size of the native mutex attribute type. +#define MUSL_PTHREAD_MUTEX_ATTR_MAX_SIZE 40 + +// An opaque handle to a native mutex attribute type with reserved memory +// bufferaligned at void pointer type. +typedef union pthread_mutexattr_t { + // Reserved memory in which the implementation should map its + // native mutex attribute type. + uint8_t mutex_buffer[MUSL_PTHREAD_MUTEX_ATTR_MAX_SIZE]; + + // Guarantees alignment of the type to a void pointer. + void* ptr; +} pthread_mutexattr_t; + + +// Max size of the native key type. +#define MUSL_PTHREAD_KEY_MAX_SIZE 40 + +// An opaque handle to a native key type with reserved memory +// bufferaligned at void pointer type. +typedef union pthread_key_t { + // Reserved memory in which the implementation should map its + // native key type. + uint8_t pthread_key_t[MUSL_PTHREAD_KEY_MAX_SIZE]; + + // Guarantees alignment of the type to a void pointer. + void* ptr; +} pthread_key_t; + +int pthread_mutex_destroy(pthread_mutex_t* mutex); +int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* mutex_attr); +int pthread_mutex_lock(pthread_mutex_t* mutex); +int pthread_mutex_unlock(pthread_mutex_t* mutex); +int pthread_mutex_trylock(pthread_mutex_t* mutex); + +int pthread_key_create(pthread_key_t* key, void (*)(void* dtor)); +int pthread_key_delete(pthread_key_t key); +void *pthread_getspecific(pthread_key_t key); +int pthread_setspecific(pthread_key_t key, const void* value); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // THIRD_PARTY_MUSL_SRC_STARBOARD_PTHREAD_H_