/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBPANDABASE_OS_THREAD_H #define LIBPANDABASE_OS_THREAD_H #include "os/error.h" #include "utils/expected.h" #include #include #include #include #ifdef PANDA_TARGET_UNIX #include "platforms/unix/libpandabase/thread.h" #elif defined PANDA_TARGET_WINDOWS #include "platforms/windows/libpandabase/thread.h" #else #error "Unsupported platform" #endif namespace panda::os::thread { using ThreadId = uint32_t; using native_handle_type = std::thread::native_handle_type; WEAK_FOR_LTO_START ThreadId GetCurrentThreadId(); int GetPid(); int SetThreadName(native_handle_type pthread_handle, const char *name); native_handle_type GetNativeHandle(); void NativeSleep(unsigned int ms); void ThreadDetach(native_handle_type pthread_handle); void ThreadExit(void *ret); void ThreadJoin(native_handle_type pthread_handle, void **ret); void ThreadSendSignal(native_handle_type pthread_handle, int sig); void ThreadYield(); WEAK_FOR_LTO_END // Templated functions need to be defined here to be accessible everywhere namespace internal { template struct SharedPtrStruct; template using SharedPtrToSharedPtrStruct = std::shared_ptr>; template struct SharedPtrStruct { SharedPtrToSharedPtrStruct this_ptr; // NOLINT(misc-non-private-member-variables-in-classes) T data; // NOLINT(misc-non-private-member-variables-in-classes) SharedPtrStruct(SharedPtrToSharedPtrStruct ptr_in, T data_in) : this_ptr(std::move(ptr_in)), data(std::move(data_in)) { } }; template struct Seq { }; template struct GenArgSeq : GenArgSeq { }; template struct GenArgSeq<1, Is...> : Seq { }; template static void CallFunc(Func &func, Tuple &args, Seq /* unused */) { func(std::get(args)...); } template static void CallFunc(Func &func, Tuple &args) { CallFunc(func, args, GenArgSeq()); } template static void *ProxyFunc(void *args) { // Parse pointer and move args to local tuple. // We need this pointer to be destroyed by the time function starts to avoid memleak on thread termination Tuple args_tuple; { auto args_ptr = static_cast *>(args); SharedPtrToSharedPtrStruct local; // This breaks shared pointer loop local.swap(args_ptr->this_ptr); // This moves tuple data to local variable args_tuple = args_ptr->data; } Func *func = std::get<0>(args_tuple); CallFunc(*func, args_tuple); return nullptr; } } // namespace internal template native_handle_type ThreadStart(Func *func, Args... args) { #ifdef PANDA_TARGET_UNIX native_handle_type tid; #else pthread_t tid; #endif auto args_tuple = std::make_tuple(func, std::move(args)...); internal::SharedPtrStruct *ptr = nullptr; { auto shared_ptr = std::make_shared>(nullptr, args_tuple); ptr = shared_ptr.get(); // Make recursive ref to prevent from shared pointer being destroyed until child thread acquires it. ptr->this_ptr = shared_ptr; // Leave scope to make sure that local shared_ptr was destroyed before thread creation } pthread_create(&tid, nullptr, &internal::ProxyFunc::value>, static_cast(ptr)); #ifdef PANDA_TARGET_UNIX return tid; #else return reinterpret_cast(tid); #endif } WEAK_FOR_LTO_START int ThreadGetStackInfo(native_handle_type thread, void **stack_addr, size_t *stack_size, size_t *guard_size); WEAK_FOR_LTO_END inline bool IsSetPriorityError(int res) { #ifdef PANDA_TARGET_UNIX return res != 0; #elif defined(PANDA_TARGET_WINDOWS) return res == 0; #endif } } // namespace panda::os::thread #endif // LIBPANDABASE_OS_THREAD_H