#pragma once /// This code should not be used directly unless you really understand what you do. /// If you need threads, use thread pool functionality in <util/thread/factory.h> /// @see SystemThreadFactory() #include <util/generic/ptr.h> #include <util/generic/string.h> #include "defaults.h" #include "progname.h" bool SetHighestThreadPriority(); bool SetLowestThreadPriority(); class TThread { template <typename Callable> struct TCallableParams; struct TPrivateCtor {}; public: using TThreadProc = void* (*)(void*); using TId = size_t; struct TParams { TThreadProc Proc; void* Data; size_t StackSize; void* StackPointer; // See comments for `SetCurrentThreadName` TString Name = GetProgramName(); inline TParams() : Proc(nullptr) , Data(nullptr) , StackSize(0) , StackPointer(nullptr) { } inline TParams(TThreadProc proc, void* data) : Proc(proc) , Data(data) , StackSize(0) , StackPointer(nullptr) { } inline TParams(TThreadProc proc, void* data, size_t stackSize) : Proc(proc) , Data(data) , StackSize(stackSize) , StackPointer(nullptr) { } inline TParams& SetName(const TString& name) noexcept { Name = name; return *this; } inline TParams& SetStackSize(size_t size) noexcept { StackSize = size; return *this; } inline TParams& SetStackPointer(void* ptr) noexcept { StackPointer = ptr; return *this; } }; TThread(const TParams& params); TThread(TThreadProc threadProc, void* param); template <typename Callable> TThread(Callable&& callable) : TThread(TPrivateCtor{}, MakeHolder<TCallableParams<Callable>>(std::forward<Callable>(callable))) { } TThread(TParams&& params) : TThread((const TParams&)params) { } TThread(TParams& params) : TThread((const TParams&)params) { } ~TThread(); void Start(); void* Join(); void Detach(); bool Running() const noexcept; TId Id() const noexcept; static TId ImpossibleThreadId() noexcept; static TId CurrentThreadId() noexcept; /* * Returns numeric thread id, as visible in e. g. htop. * Consider using this value for logging. */ static TId CurrentThreadNumericId() noexcept; // NOTE: Content of `name` will be copied. // // NOTE: On Linux thread name is limited to 15 symbols which is probably the smallest one among // all platforms. If you provide a name longer than 15 symbols it will be cut. So if you expect // `CurrentThreadName` to return the same name as `name` make sure it's not longer than 15 // symbols. static void SetCurrentThreadName(const char* name); // NOTE: Will return empty string where CanGetCurrentThreadName() returns false. static TString CurrentThreadName(); // NOTE: Depends on a platform version. // Will return true for Darwin, Linux or fresh Windows 10. static bool CanGetCurrentThreadName(); private: struct TCallableBase { virtual ~TCallableBase() = default; virtual void run() = 0; static void* ThreadWorker(void* arg) { static_cast<TCallableBase*>(arg)->run(); return nullptr; } }; template <typename Callable> struct TCallableParams: public TCallableBase { TCallableParams(Callable&& callable) : Callable_(std::forward<Callable>(callable)) { } Callable Callable_; void run() override { Callable_(); } }; TThread(TPrivateCtor, THolder<TCallableBase> callable); private: class TImpl; THolder<TImpl> Impl_; }; class ISimpleThread: public TThread { public: ISimpleThread(size_t stackSize = 0); virtual ~ISimpleThread() = default; virtual void* ThreadProc() = 0; }; struct TCurrentThreadLimits { TCurrentThreadLimits() noexcept; const void* StackBegin; size_t StackLength; };