• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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