diff --git a/libpandabase/CMakeLists.txt b/libpandabase/CMakeLists.txt index 30e47bf94ad71be98adff652b62c90bd35e6fbd7..8ecab08dcdc18bbd0a90a7f32fe6f8a21f15e7da 100644 --- a/libpandabase/CMakeLists.txt +++ b/libpandabase/CMakeLists.txt @@ -226,6 +226,7 @@ set(ARKBASE_TESTS_SOURCES tests/native_bytes_from_mallinfo_test.cpp tests/json_parser_test.cpp tests/alloc_tracker_test.cpp + tests/base_thread_test.cpp ) panda_add_gtest( diff --git a/libpandabase/os/library_loader.h b/libpandabase/os/library_loader.h index e77ced28de0ebc9721d56afd5add8ab69e2e5540..60e06abf52886e5dd363c4c97332aa769d4c639d 100644 --- a/libpandabase/os/library_loader.h +++ b/libpandabase/os/library_loader.h @@ -17,9 +17,9 @@ #define PANDA_LIBPANDABASE_OS_LIBRARY_LOADER_H_ #ifdef PANDA_TARGET_UNIX -#include "os/unix/library_loader.h" -#elif PANDA_TARGET_WINDOWS -#include "os/windows/library_loader.h" +#include +#elif defined PANDA_TARGET_WINDOWS +// No platform-specific includes #else #error "Unsupported platform" #endif @@ -30,8 +30,53 @@ #include namespace panda::os::library_loader { +class LibraryHandle; + Expected Load(std::string_view filename); + Expected ResolveSymbol(const LibraryHandle &handle, std::string_view name); + +void CloseHandle(void *handle); + +class LibraryHandle { +public: + explicit LibraryHandle(void *handle) : handle_(handle) {} + + LibraryHandle(LibraryHandle &&handle) noexcept + { + handle_ = handle.handle_; + handle.handle_ = nullptr; + } + + LibraryHandle &operator=(LibraryHandle &&handle) noexcept + { + handle_ = handle.handle_; + handle.handle_ = nullptr; + return *this; + } + + bool IsValid() const + { + return handle_ != nullptr; + } + + void *GetNativeHandle() const + { + return handle_; + } + + ~LibraryHandle() + { + if (handle_ != nullptr) { + CloseHandle(handle_); + } + } + +private: + void *handle_; + + NO_COPY_SEMANTIC(LibraryHandle); +}; } // namespace panda::os::library_loader #endif // PANDA_LIBPANDABASE_OS_LIBRARY_LOADER_H_ diff --git a/libpandabase/os/mutex.cpp b/libpandabase/os/mutex.cpp index f8cad440c7d8b6884104e67c9c40566d26132db9..d3313528825e4c7f3bc918ae9d51a82b8deebb58 100644 --- a/libpandabase/os/mutex.cpp +++ b/libpandabase/os/mutex.cpp @@ -19,7 +19,7 @@ #include #include -namespace panda::os::unix::memory { +namespace panda::os::memory { const int64_t MILLISECONDS_PER_SEC = 1000; const int64_t NANOSECONDS_PER_MILLISEC = 1000000; const int64_t NANOSECONDS_PER_SEC = 1000000000; @@ -196,4 +196,4 @@ bool ConditionVariable::TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns, bool i FatalIfError("pthread_cond_timedwait", rc); return false; } -} // namespace panda::os::unix::memory +} // namespace panda::os::memory diff --git a/libpandabase/os/mutex.h b/libpandabase/os/mutex.h index 3929d4fd1f8a9eb075e1bab11ac942de260348cf..0a1ffc9052061ad47902349840b426db321784e6 100644 --- a/libpandabase/os/mutex.h +++ b/libpandabase/os/mutex.h @@ -18,17 +18,16 @@ #if defined(PANDA_USE_FUTEX) #include "os/unix/futex/mutex.h" -#elif defined(PANDA_TARGET_UNIX) || defined(PANDA_TARGET_WINDOWS) -#include "os/unix/mutex.h" -#else +#elif !defined(PANDA_TARGET_UNIX) && !defined(PANDA_TARGET_WINDOWS) #error "Unsupported platform" #endif #include "clang.h" #include "macros.h" -namespace panda::os::memory { +#include +namespace panda::os::memory { // Dummy lock which locks nothing // but has the same methods as RWLock and Mutex. // Can be used in Locks Holders. @@ -46,12 +45,87 @@ using RecursiveMutex = panda::os::unix::memory::futex::RecursiveMutex; using RWLock = panda::os::unix::memory::futex::RWLock; using ConditionVariable = panda::os::unix::memory::futex::ConditionVariable; #else -using Mutex = panda::os::unix::memory::Mutex; -using RecursiveMutex = panda::os::unix::memory::RecursiveMutex; -using RWLock = panda::os::unix::memory::RWLock; +class ConditionVariable; + +class CAPABILITY("mutex") Mutex { +public: + explicit Mutex(bool is_init = true); + + ~Mutex(); + + void Lock() ACQUIRE(); + + bool TryLock() TRY_ACQUIRE(true); + + void Unlock() RELEASE(); + +protected: + void Init(pthread_mutexattr_t *attrs); + +private: + pthread_mutex_t mutex_; + + NO_COPY_SEMANTIC(Mutex); + NO_MOVE_SEMANTIC(Mutex); + + friend ConditionVariable; +}; + +class CAPABILITY("mutex") RecursiveMutex : public Mutex { +public: + RecursiveMutex(); + + ~RecursiveMutex() = default; + + NO_COPY_SEMANTIC(RecursiveMutex); + NO_MOVE_SEMANTIC(RecursiveMutex); +}; + +class CAPABILITY("mutex") RWLock { +public: + RWLock(); + + ~RWLock(); + + void ReadLock() ACQUIRE_SHARED(); + + void WriteLock() ACQUIRE(); + + bool TryReadLock() TRY_ACQUIRE_SHARED(true); + + bool TryWriteLock() TRY_ACQUIRE(true); + + void Unlock() RELEASE_GENERIC(); + +private: + pthread_rwlock_t rwlock_; + + NO_COPY_SEMANTIC(RWLock); + NO_MOVE_SEMANTIC(RWLock); +}; + // Some RTOS could not have support for condition variables, so this primitive should be used carefully -using ConditionVariable = panda::os::unix::memory::ConditionVariable; -#endif +class ConditionVariable { +public: + ConditionVariable(); + + ~ConditionVariable(); + + void Signal(); + + void SignalAll(); + + void Wait(Mutex *mutex); + + bool TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns = 0, bool is_absolute = false); + +private: + pthread_cond_t cond_; + + NO_COPY_SEMANTIC(ConditionVariable); + NO_MOVE_SEMANTIC(ConditionVariable); +}; +#endif // PANDA_USE_FUTEX using PandaThreadKey = pthread_key_t; const auto PandaGetspecific = pthread_getspecific; // NOLINT(readability-identifier-naming) @@ -117,7 +191,6 @@ private: NO_COPY_SEMANTIC(WriteLockHolder); NO_MOVE_SEMANTIC(WriteLockHolder); }; - } // namespace panda::os::memory #endif // PANDA_LIBPANDABASE_OS_MUTEX_H_ diff --git a/libpandabase/os/thread.h b/libpandabase/os/thread.h index 3038f7faa94fea701dc006249a73d3e6372d5d83..8ac02dde38227d4b6fce211e2a7750ee626070f4 100644 --- a/libpandabase/os/thread.h +++ b/libpandabase/os/thread.h @@ -23,27 +23,31 @@ #include #include #include +#ifdef PANDA_TARGET_UNIX +#include "os/unix/thread.h" +#elif PANDA_TARGET_WINDOWS +#include "os/windows/thread.h" +#else +#error "Unsupported platform" +#endif namespace panda::os::thread { - using ThreadId = uint32_t; using native_handle_type = std::thread::native_handle_type; ThreadId GetCurrentThreadId(); -int SetPriority(int thread_id, int prio); -int GetPriority(int thread_id); -int SetThreadName(native_handle_type pthread_id, const char *name); +int GetPid(); +int SetThreadName(native_handle_type pthread_handle, const char *name); native_handle_type GetNativeHandle(); void Yield(); void NativeSleep(unsigned int ms); -void ThreadDetach(native_handle_type pthread_id); -void ThreadExit(void *retval); -void ThreadJoin(native_handle_type pthread_id, void **retval); +void ThreadDetach(native_handle_type pthread_handle); +void ThreadExit(void *ret); +void ThreadJoin(native_handle_type pthread_handle, void **ret); // Templated functions need to be defined here to be accessible everywhere namespace internal { - template struct SharedPtrStruct; @@ -103,7 +107,6 @@ static void *ProxyFunc(void *args) CallFunc(*func, args_tuple); return nullptr; } - } // namespace internal template @@ -135,7 +138,6 @@ native_handle_type ThreadStart(Func *func, Args... args) return reinterpret_cast(tid); #endif } - } // namespace panda::os::thread #endif // PANDA_LIBPANDABASE_OS_THREAD_H_ diff --git a/libpandabase/os/unix/library_loader.cpp b/libpandabase/os/unix/library_loader.cpp index 541f1ff4b5809ff3529d73cff6026226b7690cad..01b190748561a1b477c8950310ce83d43366aadb 100644 --- a/libpandabase/os/unix/library_loader.cpp +++ b/libpandabase/os/unix/library_loader.cpp @@ -39,4 +39,10 @@ Expected ResolveSymbol(const LibraryHandle &handle, std::string_v return msg != nullptr ? Unexpected(Error(msg)) : Unexpected(Error("no error message")); } +void CloseHandle(void *handle) +{ + if (handle != nullptr) { + dlclose(handle); + } +} } // namespace panda::os::library_loader diff --git a/libpandabase/os/unix/mutex.h b/libpandabase/os/unix/mutex.h deleted file mode 100644 index 3369424d3c26a85fe6db48ad21167df0d3a24ed3..0000000000000000000000000000000000000000 --- a/libpandabase/os/unix/mutex.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. - * 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 PANDA_LIBPANDABASE_OS_UNIX_MUTEX_H_ -#define PANDA_LIBPANDABASE_OS_UNIX_MUTEX_H_ - -#include "clang.h" -#include "macros.h" - -#include - -namespace panda::os::unix::memory { - -class ConditionVariable; - -class CAPABILITY("mutex") Mutex { -public: - explicit Mutex(bool is_init = true); - - ~Mutex(); - - void Lock() ACQUIRE(); - - bool TryLock() TRY_ACQUIRE(true); - - void Unlock() RELEASE(); - -protected: - void Init(pthread_mutexattr_t *attrs); - -private: - pthread_mutex_t mutex_; - - NO_COPY_SEMANTIC(Mutex); - NO_MOVE_SEMANTIC(Mutex); - - friend ConditionVariable; -}; - -class CAPABILITY("mutex") RecursiveMutex : public Mutex { -public: - RecursiveMutex(); - - ~RecursiveMutex() = default; - - NO_COPY_SEMANTIC(RecursiveMutex); - NO_MOVE_SEMANTIC(RecursiveMutex); -}; - -class CAPABILITY("mutex") RWLock { -public: - RWLock(); - - ~RWLock(); - - void ReadLock() ACQUIRE_SHARED(); - - void WriteLock() ACQUIRE(); - - bool TryReadLock() TRY_ACQUIRE_SHARED(true); - - bool TryWriteLock() TRY_ACQUIRE(true); - - void Unlock() RELEASE_GENERIC(); - -private: - pthread_rwlock_t rwlock_; - - NO_COPY_SEMANTIC(RWLock); - NO_MOVE_SEMANTIC(RWLock); -}; - -class ConditionVariable { -public: - ConditionVariable(); - - ~ConditionVariable(); - - void Signal(); - - void SignalAll(); - - void Wait(Mutex *mutex); - - bool TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns = 0, bool is_absolute = false); - -private: - pthread_cond_t cond_; - - NO_COPY_SEMANTIC(ConditionVariable); - NO_MOVE_SEMANTIC(ConditionVariable); -}; - -} // namespace panda::os::unix::memory - -#endif // PANDA_LIBPANDABASE_OS_UNIX_MUTEX_H_ diff --git a/libpandabase/os/unix/thread.cpp b/libpandabase/os/unix/thread.cpp index 28d5f1929f7fdc9ab1d27f1a30e9f88bfb823ce0..c54c72720228e7cdd7dc233fab41aed1db7c18e9 100644 --- a/libpandabase/os/unix/thread.cpp +++ b/libpandabase/os/unix/thread.cpp @@ -15,11 +15,17 @@ #include "os/thread.h" +#include "utils/span.h" + +#include #include +#include "os/failure_retry.h" #ifdef PANDA_TARGET_UNIX +#include #include #include #endif +#include #include namespace panda::os::thread { @@ -38,8 +44,15 @@ ThreadId GetCurrentThreadId() #endif } +int GetPid() +{ + return getpid(); +} + int SetPriority(int thread_id, int prio) { + // The priority can be set within range [-20, 19], and 19 is the lowest priority. + // The return value is 0 if the function succeeds, and -1 if it fails. return setpriority(PRIO_PROCESS, thread_id, prio); } @@ -48,13 +61,13 @@ int GetPriority(int thread_id) return getpriority(PRIO_PROCESS, thread_id); } -int SetThreadName(native_handle_type pthread_id, const char *name) +int SetThreadName(native_handle_type pthread_handle, const char *name) { - ASSERT(pthread_id != 0); + ASSERT(pthread_handle != 0); #if defined(PANDA_TARGET_MACOS) return pthread_setname_np(name); #else - return pthread_setname_np(pthread_id, name); + return pthread_setname_np(pthread_handle, name); #endif } @@ -73,18 +86,18 @@ void NativeSleep(unsigned int ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } -void ThreadDetach(native_handle_type pthread_id) +void ThreadDetach(native_handle_type pthread_handle) { - pthread_detach(pthread_id); + pthread_detach(pthread_handle); } -void ThreadExit(void *retval) +void ThreadExit(void *ret) { - pthread_exit(retval); + pthread_exit(ret); } -void ThreadJoin(native_handle_type pthread_id, void **retval) +void ThreadJoin(native_handle_type pthread_handle, void **ret) { - pthread_join(pthread_id, retval); + pthread_join(pthread_handle, ret); } } // namespace panda::os::thread diff --git a/libpandabase/os/unix/library_loader.h b/libpandabase/os/unix/thread.h similarity index 31% rename from libpandabase/os/unix/library_loader.h rename to libpandabase/os/unix/thread.h index a20f17d7737c977728936e795b85d57e82de8872..f56cfb246731b13acfdce6e6d5314877d7b111bd 100644 --- a/libpandabase/os/unix/library_loader.h +++ b/libpandabase/os/unix/thread.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2022 Huawei Device Co., Ltd. * 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 @@ -13,59 +13,12 @@ * limitations under the License. */ -#ifndef PANDA_LIBPANDABASE_OS_UNIX_LIBRARY_LOADER_H_ -#define PANDA_LIBPANDABASE_OS_UNIX_LIBRARY_LOADER_H_ +#ifndef PANDA_LIBPANDABASE_OS_UNIX_THREAD_H_ +#define PANDA_LIBPANDABASE_OS_UNIX_THREAD_H_ -#include "macros.h" +namespace panda::os::thread { +int GetPriority(int thread_id); +int SetPriority(int thread_id, int prio); +} // namespace panda::os::thread -#include - -namespace panda::os::unix::library_loader { - -class LibraryHandle { -public: - explicit LibraryHandle(void *handle) : handle_(handle) {} - - LibraryHandle(LibraryHandle &&handle) noexcept - { - handle_ = handle.handle_; - handle.handle_ = nullptr; - } - - LibraryHandle &operator=(LibraryHandle &&handle) noexcept - { - handle_ = handle.handle_; - handle.handle_ = nullptr; - return *this; - } - - bool IsValid() const - { - return handle_ != nullptr; - } - - void *GetNativeHandle() const - { - return handle_; - } - - ~LibraryHandle() - { - if (handle_ != nullptr) { - dlclose(handle_); - } - } - -private: - void *handle_; - - NO_COPY_SEMANTIC(LibraryHandle); -}; - -} // namespace panda::os::unix::library_loader - -namespace panda::os::library_loader { -using LibraryHandle = panda::os::unix::library_loader::LibraryHandle; -} // namespace panda::os::library_loader - -#endif // PANDA_LIBPANDABASE_OS_UNIX_LIBRARY_LOADER_H_ +#endif // PANDA_LIBPANDABASE_OS_UNIX_THREAD_H_ diff --git a/libpandabase/os/windows/error.cpp b/libpandabase/os/windows/error.cpp index b3ee1c51a4aafdf05a42581070e96ef8657e5d12..d3dae6e9b8f47c4e843791fc997a8cfe75ba5653 100644 --- a/libpandabase/os/windows/error.cpp +++ b/libpandabase/os/windows/error.cpp @@ -14,6 +14,7 @@ */ #include "os/error.h" +#include namespace panda::os { diff --git a/libpandabase/os/windows/library_loader.cpp b/libpandabase/os/windows/library_loader.cpp index 24449ecd351e7fb72226a60f063f5656d03e91f9..f2a7ecd286ee20cff68f7f3d62acf03f830da6e9 100644 --- a/libpandabase/os/windows/library_loader.cpp +++ b/libpandabase/os/windows/library_loader.cpp @@ -39,13 +39,11 @@ Expected ResolveSymbol(const LibraryHandle &handle, std::string_v return Unexpected(Error(std::string("Failed to resolve symbol ") + name.data() + std::string(", error code ") + std::to_string(GetLastError()))); } -} // namespace panda::os::library_loader -namespace panda::os::windows::library_loader { -LibraryHandle::~LibraryHandle() +void CloseHandle(void *handle) { - if (handle_ != nullptr) { - FreeLibrary(reinterpret_cast(handle_)); + if (handle != nullptr) { + FreeLibrary(reinterpret_cast(handle)); } } -} // namespace panda::os::windows::library_loader +} // namespace panda::os::library_loader diff --git a/libpandabase/os/windows/mem_hooks.cpp b/libpandabase/os/windows/mem_hooks.cpp index 741f7a8959990021f061a31841cbc9af8ef03603..41cfd43c8d32da6da0dfd7d79dd607242ce7f2d3 100644 --- a/libpandabase/os/windows/mem_hooks.cpp +++ b/libpandabase/os/windows/mem_hooks.cpp @@ -75,8 +75,8 @@ int PandaHooks::PandaAllocHook(int alloctype, [[maybe_unused]] void *data, std:: first = false; } - const char* alloctype_name = GetAllocTypeName(alloctype); - const char* blocktype_name = GetBlockTypeName(blocktype); + const char *alloctype_name = GetAllocTypeName(alloctype); + const char *blocktype_name = GetBlockTypeName(blocktype); std::cout << std::left << std::setfill(' ') << std::setw(ALIGN_SIZE) << alloctype_name; std::cout << std::left << std::setfill(' ') << std::setw(ALIGN_SIZE) << blocktype_name; diff --git a/libpandabase/os/windows/thread.cpp b/libpandabase/os/windows/thread.cpp index 1dca1e55597cf4b0608d208a1fd6704945e7dc9d..97eedde370685ebbaf90bfc84787f5d7ecd5d97d 100644 --- a/libpandabase/os/windows/thread.cpp +++ b/libpandabase/os/windows/thread.cpp @@ -14,31 +14,59 @@ */ #include "os/thread.h" +#include "utils/logger.h" -#include +#include +#include #include +#include namespace panda::os::thread { - ThreadId GetCurrentThreadId() { - return static_cast(std::hash()(std::this_thread::get_id())); + // The function is provided by mingw + return ::GetCurrentThreadId(); +} + +int GetPid() +{ + return _getpid(); +} + +int SetPriority(DWORD thread_id, int prio) +{ + // The priority can be set within range [-2, 2], and -2 is the lowest priority. + HANDLE thread = OpenThread(THREAD_SET_INFORMATION, false, thread_id); + if (thread == NULL) { + LOG(FATAL, COMMON) << "OpenThread failed, error code " << GetLastError(); + } + auto ret = SetThreadPriority(thread, prio); + CloseHandle(thread); + // The return value is nonzero if the function succeeds, and zero if it fails. + return ret; } -int SetPriority([[maybe_unused]] int thread_id, int prio) +int GetPriority(DWORD thread_id) { - return SetThreadPriority(GetCurrentThread(), prio); + HANDLE thread = OpenThread(THREAD_QUERY_INFORMATION, false, thread_id); + if (thread == NULL) { + LOG(FATAL, COMMON) << "OpenThread failed, error code " << GetLastError(); + } + auto ret = GetThreadPriority(thread); + CloseHandle(thread); + return ret; } -int GetPriority([[maybe_unused]] int thread_id) +int SetThreadName(native_handle_type pthread_handle, const char *name) { - return GetThreadPriority(GetCurrentThread()); + ASSERT(pthread_handle != 0); + pthread_t thread = reinterpret_cast(pthread_handle); + return pthread_setname_np(thread, name); } -int SetThreadName([[maybe_unused]] native_handle_type pthread_id, const char *name) +native_handle_type GetNativeHandle() { - ASSERT(pthread_id != 0); - return pthread_setname_np(pthread_self(), name); + return reinterpret_cast(pthread_self()); } void Yield() @@ -51,9 +79,18 @@ void NativeSleep(unsigned int ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } -void ThreadJoin(native_handle_type pthread_id, void **retval) +void ThreadDetach(native_handle_type pthread_handle) { - pthread_join(reinterpret_cast(pthread_id), retval); + pthread_detach(reinterpret_cast(pthread_handle)); } +void ThreadExit(void *ret) +{ + pthread_exit(ret); +} + +void ThreadJoin(native_handle_type pthread_handle, void **ret) +{ + pthread_join(reinterpret_cast(pthread_handle), ret); +} } // namespace panda::os::thread diff --git a/libpandabase/os/windows/library_loader.h b/libpandabase/os/windows/thread.h similarity index 36% rename from libpandabase/os/windows/library_loader.h rename to libpandabase/os/windows/thread.h index 8d8efabb4e97bd8d353e453a6417e84faab295ee..e6435c3c02aa34bef8f1be4b8cc1db650d200f4a 100644 --- a/libpandabase/os/windows/library_loader.h +++ b/libpandabase/os/windows/thread.h @@ -13,50 +13,14 @@ * limitations under the License. */ -#ifndef PANDA_LIBPANDABASE_OS_WINDOWS_LIBRARY_LOADER_H_ -#define PANDA_LIBPANDABASE_OS_WINDOWS_LIBRARY_LOADER_H_ +#ifndef PANDA_LIBPANDABASE_OS_WINDOWS_THREAD_H_ +#define PANDA_LIBPANDABASE_OS_WINDOWS_THREAD_H_ -#include "macros.h" +namespace panda::os::thread { +using DWORD = unsigned long; -namespace panda::os::windows::library_loader { -class LibraryHandle { -public: - explicit LibraryHandle(void *handle) : handle_(handle) {} +int GetPriority(DWORD thread_id); +int SetPriority(DWORD thread_id, int prio); +} // namespace panda::os::thread - LibraryHandle(LibraryHandle &&handle) noexcept - { - handle_ = handle.handle_; - handle.handle_ = nullptr; - } - - LibraryHandle &operator=(LibraryHandle &&handle) noexcept - { - handle_ = handle.handle_; - handle.handle_ = nullptr; - return *this; - } - - bool IsValid() const - { - return handle_ != nullptr; - } - - void *GetNativeHandle() const - { - return handle_; - } - - ~LibraryHandle(); - -private: - void *handle_; - - NO_COPY_SEMANTIC(LibraryHandle); -}; -} // namespace panda::os::windows::library_loader - -namespace panda::os::library_loader { -using LibraryHandle = panda::os::windows::library_loader::LibraryHandle; -} // namespace panda::os::library_loader - -#endif // PANDA_LIBPANDABASE_OS_WINDOWS_LIBRARY_LOADER_H_ +#endif // PANDA_LIBPANDABASE_OS_WINDOWS_THREAD_H_ diff --git a/libpandabase/tests/base_thread_test.cpp b/libpandabase/tests/base_thread_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c34103605870d9ca7d33e69fc2841566bd1dc70 --- /dev/null +++ b/libpandabase/tests/base_thread_test.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "gtest/gtest.h" +#include "os/thread.h" + +namespace panda::os::thread { +class ThreadTest : public testing::Test {}; + +uint32_t thread_id = 0; +bool updated = false; +bool operated = false; +std::mutex mu; +std::condition_variable cv; + +#ifdef PANDA_TARGET_UNIX +// On linux, the priority can be set within range [-20, 19], and 19 is the lowest priority. +constexpr int LOWER_PRIOIRITY = 1; +constexpr int LOWEST_PRIORITY = 19; +#elif PANDA_TARGET_WINDOWS +// On Windows, the priority can be set within range [-2, 2], and -2 is the lowest priority. +constexpr int LOWER_PRIOIRITY = -1; +constexpr int LOWEST_PRIORITY = -2; +#endif + +void ThreadFunc() +{ + thread_id = GetCurrentThreadId(); + { + std::lock_guard lk(mu); + updated = true; + } + cv.notify_one(); + { + // wait for the main thread to Set/GetPriority + std::unique_lock lk(mu); + cv.wait(lk, [] { return operated; }); + } +} + +TEST_F(ThreadTest, SetCurrentThreadPriorityTest) +{ + // Since setting higher priority needs "sudo" right, we only test lower one here. + auto ret1 = SetPriority(GetCurrentThreadId(), LOWER_PRIOIRITY); + auto prio1 = GetPriority(GetCurrentThreadId()); + ASSERT_EQ(prio1, LOWER_PRIOIRITY); + + auto ret2 = SetPriority(GetCurrentThreadId(), LOWEST_PRIORITY); + auto prio2 = GetPriority(GetCurrentThreadId()); + ASSERT_EQ(prio2, LOWEST_PRIORITY); + +#ifdef PANDA_TARGET_UNIX + ASSERT_EQ(ret1, 0); + ASSERT_EQ(ret2, 0); +#elif PANDA_TARGET_WINDOWS + ASSERT_NE(ret1, 0); + ASSERT_NE(ret2, 0); +#endif +} + +TEST_F(ThreadTest, SetOtherThreadPriorityTest) +{ + auto parent_pid = GetCurrentThreadId(); + auto parent_prio_before = GetPriority(parent_pid); + + auto new_thread = ThreadStart(ThreadFunc); + // wait for the new_thread to update thread_id + std::unique_lock lk(mu); + cv.wait(lk, [] { return updated; }); + auto child_pid = thread_id; + + auto child_prio_before = GetPriority(child_pid); + auto ret = SetPriority(child_pid, LOWEST_PRIORITY); + + auto child_prio_after = GetPriority(child_pid); + auto parent_prio_after = GetPriority(parent_pid); + + operated = true; + lk.unlock(); + cv.notify_one(); + void *res; + ThreadJoin(new_thread, &res); + + ASSERT_EQ(parent_prio_before, parent_prio_after); +#ifdef PANDA_TARGET_UNIX + ASSERT_EQ(ret, 0); + ASSERT(child_prio_before <= child_prio_after); +#elif PANDA_TARGET_WINDOWS + ASSERT_NE(ret, 0); + ASSERT(child_prio_after <= child_prio_before); +#endif +} +} // namespace panda::os::thread diff --git a/libpandabase/tests/hash_test.cpp b/libpandabase/tests/hash_test.cpp index e67c1bfba6a79b76d34e2b1f967378540755da93..b5f45be2086dbea17205ac8b021a40ac351fb11b 100644 --- a/libpandabase/tests/hash_test.cpp +++ b/libpandabase/tests/hash_test.cpp @@ -120,7 +120,7 @@ void HashTest::EndOfPageStringHashTest() const void *mem = panda::os::mem::MapRWAnonymousRaw(ALLOC_SIZE); ASAN_UNPOISON_MEMORY_REGION(mem, ALLOC_SIZE); panda::os::mem::MakeMemWithProtFlag( - reinterpret_cast(reinterpret_cast(mem) + PAGE_SIZE), PAGE_SIZE, PROT_NONE); + reinterpret_cast(reinterpret_cast(mem) + PAGE_SIZE), PAGE_SIZE, os::mem::MMAP_PROT_NONE); char *string = reinterpret_cast((reinterpret_cast(mem) + PAGE_SIZE) - sizeof(char) * string_size); string[0] = 'O'; diff --git a/runtime/thread.cpp b/runtime/thread.cpp index 294356b1ab64ea03891f63cdb6805cc3ba6de8e7..683f330fd6e39247942c0de7e92766603dd8ea1e 100644 --- a/runtime/thread.cpp +++ b/runtime/thread.cpp @@ -36,7 +36,11 @@ using TaggedType = coretypes::TaggedType; bool ManagedThread::is_initialized = false; mem::TLAB *ManagedThread::zero_tlab = nullptr; +#ifdef PANDA_TARGET_UNIX static const int MIN_PRIORITY = 19; +#elif PANDA_TARGET_WINDOWS +static const int MIN_PRIORITY = -2; +#endif MTManagedThread::ThreadId MTManagedThread::GetInternalId() { @@ -454,7 +458,11 @@ void ManagedThread::SetThreadPriority(int32_t prio) { ThreadId tid = GetId(); int res = os::thread::SetPriority(tid, prio); +#ifdef PANDA_TARGET_UNIX if (res == 0) { +#elif PANDA_TARGET_WINDOWS + if (res != 0) { +#endif LOG(DEBUG, RUNTIME) << "Successfully changed priority for thread " << tid << " to " << prio; } else { LOG(DEBUG, RUNTIME) << "Cannot change priority for thread " << tid << " to " << prio;