#pragma once #include #include #include #include #include #include #include #if defined(__linux__) #include #endif // Linux's static TLS image is larger than the default pthread stack in this standalone build. // Give only host-owned generation workers enough stack for that TLS plus normal call frames. #if defined(__linux__) class FStandaloneWorkerThread { public: static constexpr std::size_t StackSizeBytes=32u*1024u*1024u; FStandaloneWorkerThread()=default; template explicit FStandaloneWorkerThread(F&& function) { using FTask=std::decay_t; auto task=std::make_unique(std::forward(function)); pthread_attr_t attributes; int result=pthread_attr_init(&attributes); if(result!=0)throw std::system_error(result,std::generic_category(),"pthread_attr_init"); result=pthread_attr_setstacksize(&attributes,StackSizeBytes); if(result==0) { result=pthread_create(&thread_,&attributes,&RunTask,task.get()); if(result==0)task.release(); } const int destroyResult=pthread_attr_destroy(&attributes); if(result!=0)throw std::system_error(result,std::generic_category(),"pthread_create"); if(destroyResult!=0) { (void)pthread_join(thread_,nullptr); throw std::system_error(destroyResult,std::generic_category(),"pthread_attr_destroy"); } joinable_=true; } FStandaloneWorkerThread(const FStandaloneWorkerThread&)=delete; FStandaloneWorkerThread& operator=(const FStandaloneWorkerThread&)=delete; FStandaloneWorkerThread(FStandaloneWorkerThread&& other) noexcept :thread_(other.thread_),joinable_(std::exchange(other.joinable_,false)) {} FStandaloneWorkerThread& operator=(FStandaloneWorkerThread&& other) noexcept { if(this!=&other) { if(joinable_)(void)pthread_join(thread_,nullptr); thread_=other.thread_; joinable_=std::exchange(other.joinable_,false); } return *this; } ~FStandaloneWorkerThread() { if(joinable_)(void)pthread_join(thread_,nullptr); } bool joinable()const noexcept{return joinable_;} void join() { if(!joinable_)throw std::system_error(std::make_error_code(std::errc::invalid_argument)); const int result=pthread_join(thread_,nullptr); if(result!=0)throw std::system_error(result,std::generic_category(),"pthread_join"); joinable_=false; } private: template static void* RunTask(void* raw) { std::unique_ptr task(static_cast(raw)); (*task)(); return nullptr; } pthread_t thread_{}; bool joinable_=false; }; #else using FStandaloneWorkerThread=std::thread; #endif