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 ThreadJoin(NativeHandleType pthreadHandle, void **ret); 56 PANDA_PUBLIC_API void ThreadSendSignal(NativeHandleType pthreadHandle, int sig); 57 58 WEAK_FOR_LTO_END 59 60 // Templated functions need to be defined here to be accessible everywhere 61 62 namespace internal { 63 64 template <typename T> 65 struct SharedPtrStruct; 66 67 template <typename T> 68 using SharedPtrToSharedPtrStruct = std::shared_ptr<SharedPtrStruct<T>>; 69 70 template <typename T> 71 struct SharedPtrStruct { 72 SharedPtrToSharedPtrStruct<T> thisPtr; // NOLINT(misc-non-private-member-variables-in-classes) 73 T data; // NOLINT(misc-non-private-member-variables-in-classes) SharedPtrStructSharedPtrStruct74 SharedPtrStruct(SharedPtrToSharedPtrStruct<T> ptrIn, T dataIn) : thisPtr(std::move(ptrIn)), data(std::move(dataIn)) 75 { 76 } 77 }; 78 79 template <size_t... IS> 80 struct Seq { 81 }; 82 83 template <size_t N, size_t... IS> 84 struct GenArgSeq : GenArgSeq<N - 1, N - 1, IS...> { 85 }; 86 87 template <size_t... IS> 88 struct GenArgSeq<1, IS...> : Seq<IS...> { 89 }; 90 91 template <class Func, typename Tuple, size_t... I> 92 static void CallFunc(Func &func, Tuple &args, Seq<I...> /* unused */) 93 { 94 func(std::get<I>(args)...); 95 } 96 97 template <class Func, typename Tuple, size_t N> 98 static void CallFunc(Func &func, Tuple &args) 99 { 100 CallFunc(func, args, GenArgSeq<N>()); 101 } 102 103 template <typename Func, typename Tuple, size_t N> 104 static void *ProxyFunc(void *args) 105 { 106 // Parse pointer and move args to local tuple. 107 // We need this pointer to be destroyed by the time function starts to avoid memleak on thread termination 108 Tuple argsTuple; 109 { 110 auto argsPtr = static_cast<SharedPtrStruct<Tuple> *>(args); 111 SharedPtrToSharedPtrStruct<Tuple> local; 112 // This breaks shared pointer loop 113 local.swap(argsPtr->thisPtr); 114 // This moves tuple data to local variable 115 argsTuple = argsPtr->data; 116 } 117 Func *func = std::get<0>(argsTuple); 118 CallFunc<Func, Tuple, N>(*func, argsTuple); 119 return nullptr; 120 } 121 122 } // namespace internal 123 124 template <typename Func, typename... Args> 125 NativeHandleType ThreadStart(Func *func, Args... args) 126 { 127 #ifdef PANDA_TARGET_UNIX 128 NativeHandleType tid; 129 #else 130 pthread_t tid; 131 #endif 132 auto argsTuple = std::make_tuple(func, std::move(args)...); 133 internal::SharedPtrStruct<decltype(argsTuple)> *ptr = nullptr; 134 { 135 auto sharedPtr = std::make_shared<internal::SharedPtrStruct<decltype(argsTuple)>>(nullptr, argsTuple); 136 ptr = sharedPtr.get(); 137 // Make recursive ref to prevent from shared pointer being destroyed until child thread acquires it. 138 ptr->thisPtr = sharedPtr; 139 // Leave scope to make sure that local shared_ptr was destroyed before thread creation 140 } 141 pthread_create(&tid, nullptr, 142 &internal::ProxyFunc<Func, decltype(argsTuple), std::tuple_size<decltype(argsTuple)>::value>, 143 static_cast<void *>(ptr)); 144 #ifdef PANDA_TARGET_UNIX 145 return tid; 146 #else 147 return reinterpret_cast<NativeHandleType>(tid); 148 #endif 149 } 150 151 WEAK_FOR_LTO_START 152 PANDA_PUBLIC_API int ThreadGetStackInfo(NativeHandleType thread, void **stackAddr, size_t *stackSize, 153 size_t *guardSize); 154 WEAK_FOR_LTO_END 155 156 inline bool IsSetPriorityError(int res) 157 { 158 #ifdef PANDA_TARGET_UNIX 159 return res != 0; 160 #elif defined(PANDA_TARGET_WINDOWS) 161 return res == 0; 162 #endif 163 } 164 } // namespace ark::os::thread 165 166 #endif // PANDA_LIBPANDABASE_OS_THREAD_H_ 167