1 /* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_LIBPANDABASE_OS_THREAD_H_ 17 #define PANDA_LIBPANDABASE_OS_THREAD_H_ 18 19 #include "os/error.h" 20 #include "utils/expected.h" 21 22 #include <cstdint> 23 #include <memory> 24 #include <thread> 25 #include <pthread.h> 26 #ifdef PANDA_TARGET_UNIX 27 #include "platforms/unix/libpandabase/thread.h" 28 #elif defined PANDA_TARGET_WINDOWS 29 #include "platforms/windows/libpandabase/thread.h" 30 #else 31 #error "Unsupported platform" 32 #endif 33 34 namespace ark::os::thread { 35 36 using ThreadId = uint32_t; 37 using NativeHandleType = std::thread::native_handle_type; 38 39 WEAK_FOR_LTO_START 40 41 PANDA_PUBLIC_API ThreadId GetCurrentThreadId(); 42 PANDA_PUBLIC_API int GetPid(); 43 PANDA_PUBLIC_API int GetPPid(); 44 PANDA_PUBLIC_API int GetUid(); 45 PANDA_PUBLIC_API int GetEuid(); 46 PANDA_PUBLIC_API uint32_t GetGid(); 47 PANDA_PUBLIC_API uint32_t GetEgid(); 48 PANDA_PUBLIC_API std::vector<uint32_t> GetGroups(); 49 PANDA_PUBLIC_API int SetThreadName(NativeHandleType pthreadHandle, const char *name); 50 PANDA_PUBLIC_API NativeHandleType GetNativeHandle(); 51 PANDA_PUBLIC_API void Yield(); 52 PANDA_PUBLIC_API void NativeSleep(unsigned int ms); 53 PANDA_PUBLIC_API void NativeSleepUS(std::chrono::microseconds us); 54 PANDA_PUBLIC_API void ThreadDetach(NativeHandleType pthreadHandle); 55 PANDA_PUBLIC_API void ThreadExit(void *ret); 56 PANDA_PUBLIC_API void ThreadJoin(NativeHandleType pthreadHandle, void **ret); 57 PANDA_PUBLIC_API void ThreadSendSignal(NativeHandleType pthreadHandle, int sig); 58 59 WEAK_FOR_LTO_END 60 61 // Templated functions need to be defined here to be accessible everywhere 62 63 namespace internal { 64 65 template <typename T> 66 struct SharedPtrStruct; 67 68 template <typename T> 69 using SharedPtrToSharedPtrStruct = std::shared_ptr<SharedPtrStruct<T>>; 70 71 template <typename T> 72 struct SharedPtrStruct { 73 SharedPtrToSharedPtrStruct<T> thisPtr; // NOLINT(misc-non-private-member-variables-in-classes) 74 T data; // NOLINT(misc-non-private-member-variables-in-classes) SharedPtrStructSharedPtrStruct75 SharedPtrStruct(SharedPtrToSharedPtrStruct<T> ptrIn, T dataIn) : thisPtr(std::move(ptrIn)), data(std::move(dataIn)) 76 { 77 } 78 }; 79 80 template <size_t... IS> 81 struct Seq { 82 }; 83 84 template <size_t N, size_t... IS> 85 struct GenArgSeq : GenArgSeq<N - 1, N - 1, IS...> { 86 }; 87 88 template <size_t... IS> 89 struct GenArgSeq<1, IS...> : Seq<IS...> { 90 }; 91 92 template <class Func, typename Tuple, size_t... I> 93 static void CallFunc(Func &func, Tuple &args, Seq<I...> /* unused */) 94 { 95 func(std::get<I>(args)...); 96 } 97 98 template <class Func, typename Tuple, size_t N> 99 static void CallFunc(Func &func, Tuple &args) 100 { 101 CallFunc(func, args, GenArgSeq<N>()); 102 } 103 104 template <typename Func, typename Tuple, size_t N> 105 static void *ProxyFunc(void *args) 106 { 107 // Parse pointer and move args to local tuple. 108 // We need this pointer to be destroyed by the time function starts to avoid memleak on thread termination 109 Tuple argsTuple; 110 { 111 auto argsPtr = static_cast<SharedPtrStruct<Tuple> *>(args); 112 SharedPtrToSharedPtrStruct<Tuple> local; 113 // This breaks shared pointer loop 114 local.swap(argsPtr->thisPtr); 115 // This moves tuple data to local variable 116 argsTuple = argsPtr->data; 117 } 118 Func *func = std::get<0>(argsTuple); 119 CallFunc<Func, Tuple, N>(*func, argsTuple); 120 return nullptr; 121 } 122 123 } // namespace internal 124 125 template <typename Func, typename... Args> 126 NativeHandleType ThreadStart(Func *func, Args... args) 127 { 128 #ifdef PANDA_TARGET_UNIX 129 NativeHandleType tid; 130 #else 131 pthread_t tid; 132 #endif 133 auto argsTuple = std::make_tuple(func, std::move(args)...); 134 internal::SharedPtrStruct<decltype(argsTuple)> *ptr = nullptr; 135 { 136 auto sharedPtr = std::make_shared<internal::SharedPtrStruct<decltype(argsTuple)>>(nullptr, argsTuple); 137 ptr = sharedPtr.get(); 138 // Make recursive ref to prevent from shared pointer being destroyed until child thread acquires it. 139 ptr->thisPtr = sharedPtr; 140 // Leave scope to make sure that local shared_ptr was destroyed before thread creation 141 } 142 pthread_create(&tid, nullptr, 143 &internal::ProxyFunc<Func, decltype(argsTuple), std::tuple_size<decltype(argsTuple)>::value>, 144 static_cast<void *>(ptr)); 145 #ifdef PANDA_TARGET_UNIX 146 return tid; 147 #else 148 return reinterpret_cast<NativeHandleType>(tid); 149 #endif 150 } 151 152 WEAK_FOR_LTO_START 153 PANDA_PUBLIC_API int ThreadGetStackInfo(NativeHandleType thread, void **stackAddr, size_t *stackSize, 154 size_t *guardSize); 155 WEAK_FOR_LTO_END 156 157 inline bool IsSetPriorityError(int res) 158 { 159 #ifdef PANDA_TARGET_UNIX 160 return res != 0; 161 #elif defined(PANDA_TARGET_WINDOWS) 162 return res == 0; 163 #endif 164 } 165 } // namespace ark::os::thread 166 167 #endif // PANDA_LIBPANDABASE_OS_THREAD_H_ 168