• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 LIBPANDABASE_OS_THREAD_H
17 #define 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 panda::os::thread {
35 
36 using ThreadId = uint32_t;
37 using native_handle_type = std::thread::native_handle_type;
38 
39 WEAK_FOR_LTO_START
40 
41 ThreadId GetCurrentThreadId();
42 int GetPid();
43 int SetThreadName(native_handle_type pthread_handle, const char *name);
44 native_handle_type GetNativeHandle();
45 void NativeSleep(unsigned int ms);
46 void ThreadDetach(native_handle_type pthread_handle);
47 void ThreadExit(void *ret);
48 void ThreadJoin(native_handle_type pthread_handle, void **ret);
49 void ThreadSendSignal(native_handle_type pthread_handle, int sig);
50 void ThreadYield();
51 
52 WEAK_FOR_LTO_END
53 
54 // Templated functions need to be defined here to be accessible everywhere
55 
56 namespace internal {
57 
58 template <typename T>
59 struct SharedPtrStruct;
60 
61 template <typename T>
62 using SharedPtrToSharedPtrStruct = std::shared_ptr<SharedPtrStruct<T>>;
63 
64 template <typename T>
65 struct SharedPtrStruct {
66     SharedPtrToSharedPtrStruct<T> this_ptr;  // NOLINT(misc-non-private-member-variables-in-classes)
67     T data;                                  // NOLINT(misc-non-private-member-variables-in-classes)
SharedPtrStructSharedPtrStruct68     SharedPtrStruct(SharedPtrToSharedPtrStruct<T> ptr_in, T data_in)
69         : this_ptr(std::move(ptr_in)), data(std::move(data_in))
70     {
71     }
72 };
73 
74 template <size_t... Is>
75 struct Seq {
76 };
77 
78 template <size_t N, size_t... Is>
79 struct GenArgSeq : GenArgSeq<N - 1, N - 1, Is...> {
80 };
81 
82 template <size_t... Is>
83 struct GenArgSeq<1, Is...> : Seq<Is...> {
84 };
85 
86 template <class Func, typename Tuple, size_t... I>
87 static void CallFunc(Func &func, Tuple &args, Seq<I...> /* unused */)
88 {
89     func(std::get<I>(args)...);
90 }
91 
92 template <class Func, typename Tuple, size_t N>
93 static void CallFunc(Func &func, Tuple &args)
94 {
95     CallFunc(func, args, GenArgSeq<N>());
96 }
97 
98 template <typename Func, typename Tuple, size_t N>
99 static void *ProxyFunc(void *args)
100 {
101     // Parse pointer and move args to local tuple.
102     // We need this pointer to be destroyed by the time function starts to avoid memleak on thread  termination
103     Tuple args_tuple;
104     {
105         auto args_ptr = static_cast<SharedPtrStruct<Tuple> *>(args);
106         SharedPtrToSharedPtrStruct<Tuple> local;
107         // This breaks shared pointer loop
108         local.swap(args_ptr->this_ptr);
109         // This moves tuple data to local variable
110         args_tuple = args_ptr->data;
111     }
112     Func *func = std::get<0>(args_tuple);
113     CallFunc<Func, Tuple, N>(*func, args_tuple);
114     return nullptr;
115 }
116 
117 }  // namespace internal
118 
119 template <typename Func, typename... Args>
120 native_handle_type ThreadStart(Func *func, Args... args)
121 {
122 #ifdef PANDA_TARGET_UNIX
123     native_handle_type tid;
124 #else
125     pthread_t tid;
126 #endif
127     auto args_tuple = std::make_tuple(func, std::move(args)...);
128     internal::SharedPtrStruct<decltype(args_tuple)> *ptr = nullptr;
129     {
130         auto shared_ptr = std::make_shared<internal::SharedPtrStruct<decltype(args_tuple)>>(nullptr, args_tuple);
131         ptr = shared_ptr.get();
132         // Make recursive ref to prevent from shared pointer being destroyed until child thread acquires it.
133         ptr->this_ptr = shared_ptr;
134         // Leave scope to make sure that local shared_ptr was destroyed before thread creation
135     }
136     pthread_create(&tid, nullptr,
137                    &internal::ProxyFunc<Func, decltype(args_tuple), std::tuple_size<decltype(args_tuple)>::value>,
138                    static_cast<void *>(ptr));
139 #ifdef PANDA_TARGET_UNIX
140     return tid;
141 #else
142     return reinterpret_cast<native_handle_type>(tid);
143 #endif
144 }
145 
146 WEAK_FOR_LTO_START
147 int ThreadGetStackInfo(native_handle_type thread, void **stack_addr, size_t *stack_size, size_t *guard_size);
148 WEAK_FOR_LTO_END
149 
150 inline bool IsSetPriorityError(int res)
151 {
152 #ifdef PANDA_TARGET_UNIX
153     return res != 0;
154 #elif defined(PANDA_TARGET_WINDOWS)
155     return res == 0;
156 #endif
157 }
158 }  // namespace panda::os::thread
159 
160 #endif  // LIBPANDABASE_OS_THREAD_H
161