1 /* 2 * Copyright (c) 2021 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 26 namespace panda::os::thread { 27 28 using ThreadId = uint32_t; 29 using native_handle_type = std::thread::native_handle_type; 30 31 ThreadId GetCurrentThreadId(); 32 int SetPriority(int thread_id, int prio); 33 int GetPriority(int thread_id); 34 int SetThreadName(native_handle_type pthread_id, const char *name); 35 native_handle_type GetNativeHandle(); 36 void Yield(); 37 void NativeSleep(unsigned int ms); 38 void ThreadDetach(native_handle_type pthread_id); 39 void ThreadExit(void *retval); 40 void ThreadJoin(native_handle_type pthread_id, void **retval); 41 42 // Templated functions need to be defined here to be accessible everywhere 43 44 namespace internal { 45 46 template <typename T> 47 struct SharedPtrStruct; 48 49 template <typename T> 50 // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_NO_USE_SHAREDPTR) 51 using SharedPtrToSharedPtrStruct = std::shared_ptr<SharedPtrStruct<T>>; 52 53 template <typename T> 54 struct SharedPtrStruct { 55 SharedPtrToSharedPtrStruct<T> this_ptr; // NOLINT(misc-non-private-member-variables-in-classes) 56 T data; // NOLINT(misc-non-private-member-variables-in-classes) SharedPtrStructSharedPtrStruct57 SharedPtrStruct(SharedPtrToSharedPtrStruct<T> ptr_in, T data_in) 58 : this_ptr(std::move(ptr_in)), data(std::move(data_in)) 59 { 60 } 61 }; 62 63 template <size_t... Is> 64 struct Seq { 65 }; 66 67 template <size_t N, size_t... Is> 68 struct GenArgSeq : GenArgSeq<N - 1, N - 1, Is...> { 69 }; 70 71 template <size_t... Is> 72 struct GenArgSeq<1, Is...> : Seq<Is...> { 73 }; 74 75 template <class Func, typename Tuple, size_t... I> 76 static void CallFunc(Func &func, Tuple &args, Seq<I...> /* unused */) 77 { 78 func(std::get<I>(args)...); 79 } 80 81 template <class Func, typename Tuple, size_t N> 82 static void CallFunc(Func &func, Tuple &args) 83 { 84 CallFunc(func, args, GenArgSeq<N>()); 85 } 86 87 template <typename Func, typename Tuple, size_t N> 88 static void *ProxyFunc(void *args) 89 { 90 // Parse pointer and move args to local tuple. 91 // We need this pointer to be destroyed by the time function starts to avoid memleak on thread termination. 92 Tuple args_tuple; 93 { 94 auto args_ptr = static_cast<SharedPtrStruct<Tuple> *>(args); 95 SharedPtrToSharedPtrStruct<Tuple> local; 96 // This breaks shared pointer loop 97 local.swap(args_ptr->this_ptr); 98 // This moves tuple data to local variable 99 args_tuple = args_ptr->data; 100 } 101 Func *func = std::get<0>(args_tuple); 102 CallFunc<Func, Tuple, N>(*func, args_tuple); 103 return nullptr; 104 } 105 106 } // namespace internal 107 108 template <typename Func, typename... Args> 109 native_handle_type ThreadStart(Func *func, Args... args) 110 { 111 native_handle_type tid; 112 auto args_tuple = std::make_tuple(func, std::move(args)...); 113 internal::SharedPtrStruct<decltype(args_tuple)> *ptr = nullptr; 114 { 115 // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_NO_USE_SHAREDPTR) 116 auto shared_ptr = std::make_shared<internal::SharedPtrStruct<decltype(args_tuple)>>(nullptr, args_tuple); 117 // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_NO_USE_SHAREDPTR) 118 ptr = shared_ptr.get(); 119 // Make recursive ref to prevent shared pointer from being destroyed until child thread acquires it. 120 // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_NO_USE_SHAREDPTR) 121 ptr->this_ptr = shared_ptr; 122 // Leave scope to make sure that local shared_ptr is destroyed before thread creation. 123 } 124 pthread_create(&tid, nullptr, 125 &internal::ProxyFunc<Func, decltype(args_tuple), std::tuple_size<decltype(args_tuple)>::value>, 126 static_cast<void *>(ptr)); 127 return tid; 128 } 129 130 } // namespace panda::os::thread 131 132 #endif // PANDA_LIBPANDABASE_OS_THREAD_H_ 133