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