mirror of
https://gitee.com/openharmony/ark_runtime_core
synced 2025-02-21 06:01:58 +00:00
Refactor mutex, library loader and complement Windows thread API
Signed-off-by: huangyu <huangyu76@huawei.com> Change-Id: I662463d239f6d050ef6908de70e0e98cf85bf2a6
This commit is contained in:
parent
633c83d2b0
commit
f76f983336
@ -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(
|
||||
|
@ -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 <dlfcn.h>
|
||||
#elif defined PANDA_TARGET_WINDOWS
|
||||
// No platform-specific includes
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
@ -30,8 +30,53 @@
|
||||
#include <string_view>
|
||||
|
||||
namespace panda::os::library_loader {
|
||||
class LibraryHandle;
|
||||
|
||||
Expected<LibraryHandle, Error> Load(std::string_view filename);
|
||||
|
||||
Expected<void *, Error> 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_
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
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
|
||||
|
@ -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 <pthread.h>
|
||||
|
||||
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_
|
||||
|
@ -23,27 +23,31 @@
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <pthread.h>
|
||||
#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 <typename T>
|
||||
struct SharedPtrStruct;
|
||||
|
||||
@ -103,7 +107,6 @@ static void *ProxyFunc(void *args)
|
||||
CallFunc<Func, Tuple, N>(*func, args_tuple);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Func, typename... Args>
|
||||
@ -135,7 +138,6 @@ native_handle_type ThreadStart(Func *func, Args... args)
|
||||
return reinterpret_cast<native_handle_type>(tid);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace panda::os::thread
|
||||
|
||||
#endif // PANDA_LIBPANDABASE_OS_THREAD_H_
|
||||
|
@ -39,4 +39,10 @@ Expected<void *, Error> 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
|
||||
|
@ -1,71 +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_LIBRARY_LOADER_H_
|
||||
#define PANDA_LIBPANDABASE_OS_UNIX_LIBRARY_LOADER_H_
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
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_
|
@ -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 <pthread.h>
|
||||
|
||||
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_
|
@ -15,11 +15,17 @@
|
||||
|
||||
#include "os/thread.h"
|
||||
|
||||
#include "utils/span.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include "os/failure_retry.h"
|
||||
#ifdef PANDA_TARGET_UNIX
|
||||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <securec.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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
|
||||
|
24
libpandabase/os/unix/thread.h
Normal file
24
libpandabase/os/unix/thread.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_LIBPANDABASE_OS_UNIX_THREAD_H_
|
||||
#define PANDA_LIBPANDABASE_OS_UNIX_THREAD_H_
|
||||
|
||||
namespace panda::os::thread {
|
||||
int GetPriority(int thread_id);
|
||||
int SetPriority(int thread_id, int prio);
|
||||
} // namespace panda::os::thread
|
||||
|
||||
#endif // PANDA_LIBPANDABASE_OS_UNIX_THREAD_H_
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "os/error.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace panda::os {
|
||||
|
||||
|
@ -39,13 +39,11 @@ Expected<void *, Error> 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<HMODULE>(handle_));
|
||||
if (handle != nullptr) {
|
||||
FreeLibrary(reinterpret_cast<HMODULE>(handle));
|
||||
}
|
||||
}
|
||||
} // namespace panda::os::windows::library_loader
|
||||
} // namespace panda::os::library_loader
|
||||
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_LIBPANDABASE_OS_WINDOWS_LIBRARY_LOADER_H_
|
||||
#define PANDA_LIBPANDABASE_OS_WINDOWS_LIBRARY_LOADER_H_
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::os::windows::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();
|
||||
|
||||
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_
|
@ -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;
|
||||
|
@ -14,31 +14,59 @@
|
||||
*/
|
||||
|
||||
#include "os/thread.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <thread>
|
||||
#include <errhandlingapi.h>
|
||||
#include <handleapi.h>
|
||||
#include <processthreadsapi.h>
|
||||
#include <thread>
|
||||
|
||||
namespace panda::os::thread {
|
||||
|
||||
ThreadId GetCurrentThreadId()
|
||||
{
|
||||
return static_cast<ThreadId>(std::hash<std::thread::id>()(std::this_thread::get_id()));
|
||||
// The function is provided by mingw
|
||||
return ::GetCurrentThreadId();
|
||||
}
|
||||
|
||||
int SetPriority([[maybe_unused]] int thread_id, int prio)
|
||||
int GetPid()
|
||||
{
|
||||
return SetThreadPriority(GetCurrentThread(), prio);
|
||||
return _getpid();
|
||||
}
|
||||
|
||||
int GetPriority([[maybe_unused]] int thread_id)
|
||||
int SetPriority(DWORD thread_id, int prio)
|
||||
{
|
||||
return GetThreadPriority(GetCurrentThread());
|
||||
// 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 SetThreadName([[maybe_unused]] native_handle_type pthread_id, const char *name)
|
||||
int GetPriority(DWORD thread_id)
|
||||
{
|
||||
ASSERT(pthread_id != 0);
|
||||
return pthread_setname_np(pthread_self(), name);
|
||||
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 SetThreadName(native_handle_type pthread_handle, const char *name)
|
||||
{
|
||||
ASSERT(pthread_handle != 0);
|
||||
pthread_t thread = reinterpret_cast<pthread_t>(pthread_handle);
|
||||
return pthread_setname_np(thread, name);
|
||||
}
|
||||
|
||||
native_handle_type GetNativeHandle()
|
||||
{
|
||||
return reinterpret_cast<native_handle_type>(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_t>(pthread_id), retval);
|
||||
pthread_detach(reinterpret_cast<pthread_t>(pthread_handle));
|
||||
}
|
||||
|
||||
void ThreadExit(void *ret)
|
||||
{
|
||||
pthread_exit(ret);
|
||||
}
|
||||
|
||||
void ThreadJoin(native_handle_type pthread_handle, void **ret)
|
||||
{
|
||||
pthread_join(reinterpret_cast<pthread_t>(pthread_handle), ret);
|
||||
}
|
||||
} // namespace panda::os::thread
|
||||
|
26
libpandabase/os/windows/thread.h
Normal file
26
libpandabase/os/windows/thread.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_LIBPANDABASE_OS_WINDOWS_THREAD_H_
|
||||
#define PANDA_LIBPANDABASE_OS_WINDOWS_THREAD_H_
|
||||
|
||||
namespace panda::os::thread {
|
||||
using DWORD = unsigned long;
|
||||
|
||||
int GetPriority(DWORD thread_id);
|
||||
int SetPriority(DWORD thread_id, int prio);
|
||||
} // namespace panda::os::thread
|
||||
|
||||
#endif // PANDA_LIBPANDABASE_OS_WINDOWS_THREAD_H_
|
106
libpandabase/tests/base_thread_test.cpp
Normal file
106
libpandabase/tests/base_thread_test.cpp
Normal file
@ -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 <condition_variable>
|
||||
#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
|
@ -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<void *>(reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE), PAGE_SIZE, PROT_NONE);
|
||||
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE), PAGE_SIZE, os::mem::MMAP_PROT_NONE);
|
||||
char *string =
|
||||
reinterpret_cast<char *>((reinterpret_cast<uintptr_t>(mem) + PAGE_SIZE) - sizeof(char) * string_size);
|
||||
string[0] = 'O';
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user