/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2019 Danny Robson */ #pragma once #include "../win32/handle.hpp" #include "../win32/windows.hpp" #include "../win32/except.hpp" #include namespace cruft::thread { inline namespace win32 { namespace detail { template std::decay_t decay_copy (T&& v) { return std::forward(v); } template class dispatcher { public: dispatcher (FunctionT &&func, ArgsT &&...args) : m_func (std::forward (func)) , m_args (std::forward (args)...) { ; } void run (void) { return _run ( std::make_index_sequence {} ); } private: template void _run (std::index_sequence ) { std::invoke ( decay_copy (std::forward (m_func)), decay_copy (std::forward (std::get (m_args)))... ); } FunctionT m_func; std::tuple m_args; }; template DWORD WINAPI run (LPVOID arg) { auto *obj = reinterpret_cast (arg); try { obj->run (); return 0; } catch (...) { delete obj; throw; } } }; struct thread { using id = ::cruft::win32::handle::native_type; thread () noexcept; thread (thread &&) noexcept; template thread (FunctionT &&func, ArgsT&&...args) { using dispatch_t = detail::dispatcher; auto data = std::make_unique ( std::forward (func), std::forward (args)... ); m_handle.reset ( CreateThread ( nullptr, 0, detail::run, static_cast (data.get ()), 0, nullptr ) ); if (!m_handle) throw std::system_error ( cruft::win32::error::last_code (), std::generic_category () ); data.release (); } thread (thread const&) = delete; thread& operator= (thread&&) noexcept; void join (void); static unsigned int hardware_concurrency () noexcept; private: ::cruft::win32::handle m_handle; }; namespace this_thread { void yield (void) noexcept; thread::id get_id (void) noexcept; template void sleep_for ( std::chrono::duration const& sleep_duration ) { auto remain = std::chrono::duration_cast ( sleep_duration ).count (); while (remain > 0) { auto const step = cruft::min (remain, INFINITE - 1); Sleep (remain); remain -= step; } } template void sleep_until (std::chrono::time_point const& sleep_time) { if (ClockT::is_steady) return sleep_for (sleep_time - ClockT::now ()); for (auto now = ClockT::now (); now < sleep_time; now = ClockT::now ()) sleep_for (sleep_time - now); } template void sleep_until (std::chrono::time_point const& sleep_time); } }; }