diff --git a/examples/0040.thread/thread.cc b/examples/0040.thread/thread.cc index 466669027..ed5a185be 100644 --- a/examples/0040.thread/thread.cc +++ b/examples/0040.thread/thread.cc @@ -1,4 +1,3 @@ -#include #include int main() @@ -19,7 +18,7 @@ int main() ::fast_io::println("the child thread id is: ", ::fast_io::this_thread::get_id()); #endif // ::fflush(stdout); - ::fast_io::this_thread::sleep_for(::std::chrono::seconds{1}); + ::fast_io::this_thread::sleep_for(::fast_io::unix_timestamp{.seconds = 1}); }, 5}; diff --git a/include/fast_io_hosted/platforms/systemcall_details.h b/include/fast_io_hosted/platforms/systemcall_details.h index a1c3e6bd1..9e512c36a 100644 --- a/include/fast_io_hosted/platforms/systemcall_details.h +++ b/include/fast_io_hosted/platforms/systemcall_details.h @@ -152,7 +152,8 @@ inline void sys_close_throw_error(int &fd) } #endif } -#if (!defined(__NEWLIB__) || defined(__CYGWIN__)) && !defined(_WIN32) && __has_include() && !defined(_PICOLIBC__) + +#if !defined(_WIN32) && __has_include() && !defined(_PICOLIBC__) namespace posix { diff --git a/include/fast_io_hosted/threads/thread/dos.h b/include/fast_io_hosted/threads/thread/dos.h index d136510dd..493951538 100644 --- a/include/fast_io_hosted/threads/thread/dos.h +++ b/include/fast_io_hosted/threads/thread/dos.h @@ -1,14 +1,6 @@ #pragma once -// std -#include -#include -#include -#include -#include -#include -// system -#include + namespace fast_io { @@ -27,46 +19,6 @@ inline constexpr dos_thread_id get_id() noexcept return 0u; } -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_for(::std::chrono::duration const &sleep_duration) noexcept -{ - auto const us64{::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count()}; - if (us64 <= 0) - { - return; - } - auto remaining{static_cast<::std::uint_least64_t>(us64)}; - constexpr ::std::uint_least64_t max_chunk{static_cast<::std::uint_least64_t>(static_cast(-1))}; - while (remaining != 0) - { - auto const chunk{remaining > max_chunk ? max_chunk : remaining}; - ::fast_io::details::posix::my_usleep(static_cast(chunk)); - remaining -= chunk; - } -} - -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_until(::std::chrono::time_point const &expect_time) noexcept -{ - auto const now{Clock::now()}; - if (now < expect_time) - { - ::fast_io::dos::this_thread::sleep_for(expect_time - now); - } -} - template <::std::int_least64_t off_to_epoch> inline #if __cpp_constexpr >= 202207L diff --git a/include/fast_io_hosted/threads/thread/impl.h b/include/fast_io_hosted/threads/thread/impl.h index d55c3c541..c21da3e2e 100644 --- a/include/fast_io_hosted/threads/thread/impl.h +++ b/include/fast_io_hosted/threads/thread/impl.h @@ -1,14 +1,29 @@ #pragma once +// std +#include +#include +#include +#include +#include + #if (defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__) #include "win32.h" #ifndef _WIN32_WINDOWS #include "nt.h" #endif #elif defined(__MSDOS__) || defined(__DJGPP__) +#include #include "dos.h" #elif defined(__wasi__) +#include #include "wasi.h" #elif !defined(__SINGLE_THREAD__) && !defined(__NEWLIB__) && !defined(__MSDOS__) && __has_include() +#include +#include +#include +#include #include "pthread.h" +#elif defined(__NEWLIB__) +#include "newlib.h" #endif diff --git a/include/fast_io_hosted/threads/thread/newlib.h b/include/fast_io_hosted/threads/thread/newlib.h new file mode 100644 index 000000000..f03d2e849 --- /dev/null +++ b/include/fast_io_hosted/threads/thread/newlib.h @@ -0,0 +1,105 @@ +#pragma once + +namespace fast_io +{ +namespace details::posix +{ +extern unsigned my_usleep(unsigned usec) noexcept __asm__("_usleep"); +extern int sched_yield() noexcept __asm__("_sched_yield"); +} // namespace details::posix + +namespace newlib::this_thread +{ + +using dos_thread_id = unsigned; + +inline constexpr dos_thread_id get_id() noexcept +{ + return 0u; +} + + +template <::std::int_least64_t off_to_epoch> +inline +#if __cpp_constexpr >= 202207L + // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L + // for reduce some warning purpose + constexpr +#endif + void sleep_for(::fast_io::basic_timestamp const &sleep_duration) noexcept +{ + if (sleep_duration.seconds < 0) + { + return; + } + + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000u}; + + auto const us64{ + static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 1000000u + + sleep_duration.subseconds / mul_factor)}; + if (us64 == 0) + { + return; + } + + auto remaining{us64}; + constexpr ::std::uint_least64_t max_chunk{static_cast<::std::uint_least64_t>(static_cast(-1))}; + while (remaining != 0) + { + auto const chunk{remaining > max_chunk ? max_chunk : remaining}; + ::fast_io::details::posix::my_usleep(static_cast(chunk)); + remaining -= chunk; + } +} + +template <::std::int_least64_t off_to_epoch> +inline +#if __cpp_constexpr >= 202207L + // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L + // for reduce some warning purpose + constexpr +#endif + void sleep_until(::fast_io::basic_timestamp const &expect_time) noexcept +{ + if (expect_time.seconds < 0) + { + return; + } + + auto const unix_expect{static_cast<::fast_io::unix_timestamp>(expect_time)}; + auto const now{::fast_io::posix_clock_gettime(::fast_io::posix_clock_id::realtime)}; + if (!(now < unix_expect)) + { + return; + } + + auto const delta{unix_expect - now}; + ::fast_io::newlib::this_thread::sleep_for(delta); +} + +inline +#if __cpp_constexpr >= 202207L + // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L + // for reduce some warning purpose + constexpr +#endif + void yield() noexcept +{ + ::fast_io::details::posix::sched_yield(); +} + +} // namespace newlib::this_thread + +#if defined(__NEWLIB__) + +namespace this_thread +{ +using ::fast_io::newlib::this_thread::get_id; +using ::fast_io::newlib::this_thread::sleep_for; +using ::fast_io::newlib::this_thread::sleep_until; +using ::fast_io::newlib::this_thread::yield; +} // namespace this_thread +#endif + +} // namespace fast_io diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index 155d4ff17..c0697afea 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -1,12 +1,5 @@ #pragma once -#include -#include -#include -#include -#include -#include - namespace fast_io { namespace win32::nt @@ -300,31 +293,6 @@ inline return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(teb->ClientId.UniqueThread)); } -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_for(::std::chrono::duration const &sleep_duration) -{ - auto const count{static_cast<::std::uint_least64_t>( - ::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count() * 10u + - ::std::chrono::duration_cast<::std::chrono::nanoseconds>(sleep_duration).count() / 100u % 10u)}; - - if (count > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) - { - ::fast_io::throw_nt_error(0xC000000D); - } - - auto val{-static_cast<::std::int_least64_t>(count)}; - ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution(false, __builtin_addressof(val))}; - if (status) [[unlikely]] - { - ::fast_io::throw_nt_error(status); - } -} template inline @@ -357,44 +325,6 @@ inline } } -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_until(::std::chrono::time_point const &expect_time) -{ - auto const unix_ts = ::std::chrono::duration_cast( - expect_time.time_since_epoch()) - .count(); - auto const unix_subsec_ts = ::std::chrono::duration_cast( - expect_time.time_since_epoch()) - .count() / - 100u % 10000000u; - - auto const unix_to_nt_secs{static_cast<::std::int_least64_t>(unix_ts) + 11644473600}; - if (unix_to_nt_secs < 0) [[unlikely]] - { - ::fast_io::throw_nt_error(0xC000000D); - } - - auto const count{static_cast<::std::uint_least64_t>(unix_to_nt_secs) * 10000000u + static_cast<::std::uint_least64_t>(unix_subsec_ts)}; - - if (count > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) - { - ::fast_io::throw_nt_error(0xC000000D); - } - - auto nt_ts{static_cast<::std::int_least64_t>(count)}; - ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution(false, __builtin_addressof(nt_ts))}; - if (status) [[unlikely]] - { - ::fast_io::throw_nt_error(status); - } -} - template inline #if __cpp_constexpr >= 202207L diff --git a/include/fast_io_hosted/threads/thread/pthread.h b/include/fast_io_hosted/threads/thread/pthread.h index 6f5627081..2c335e9eb 100644 --- a/include/fast_io_hosted/threads/thread/pthread.h +++ b/include/fast_io_hosted/threads/thread/pthread.h @@ -1,17 +1,6 @@ #pragma once -// std -#include -#include -#include -#include -#include -#include -// system -#include -#include -#include -#include + namespace fast_io { @@ -237,63 +226,6 @@ inline return ::fast_io::noexcept_call(::pthread_self); } -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_for(::std::chrono::duration const &sleep_duration) noexcept -{ - auto const ns64{::std::chrono::duration_cast<::std::chrono::nanoseconds>(sleep_duration).count()}; - if (ns64 <= 0) - { - return; - } - ::timespec req{}; - req.tv_sec = static_cast<::time_t>(ns64 / 1'000'000'000LL); - req.tv_nsec = static_cast(ns64 % 1'000'000'000LL); - (void)::fast_io::noexcept_call(::nanosleep, __builtin_addressof(req), nullptr); -} - -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_until(::std::chrono::time_point const &expect_time) noexcept -{ - auto const now{Clock::now()}; - if (now < expect_time) - { - auto const ns64{::std::chrono::duration_cast<::std::chrono::nanoseconds>(expect_time - now).count()}; - if (ns64 <= 0) - { - return; - } - ::timespec delta{}; - delta.tv_sec = static_cast<::time_t>(ns64 / 1'000'000'000LL); - delta.tv_nsec = static_cast(ns64 % 1'000'000'000LL); -#if defined(CLOCK_REALTIME) && defined(TIMER_ABSTIME) - ::timespec abs_ts{}; - (void)::fast_io::noexcept_call(::clock_gettime, CLOCK_REALTIME, __builtin_addressof(abs_ts)); - abs_ts.tv_sec += delta.tv_sec; - abs_ts.tv_nsec += delta.tv_nsec; - if (abs_ts.tv_nsec >= 1'000'000'000L) - { - abs_ts.tv_nsec -= 1'000'000'000L; - ++abs_ts.tv_sec; - } - ::fast_io::noexcept_call(::clock_nanosleep, CLOCK_REALTIME, TIMER_ABSTIME, __builtin_addressof(abs_ts), nullptr); -#else - ::fast_io::noexcept_call(::nanosleep, __builtin_addressof(delta), nullptr); -#endif - } -} - template <::std::int_least64_t off_to_epoch> inline #if __cpp_constexpr >= 202207L diff --git a/include/fast_io_hosted/threads/thread/wasi.h b/include/fast_io_hosted/threads/thread/wasi.h index 529d135c7..47038bbb7 100644 --- a/include/fast_io_hosted/threads/thread/wasi.h +++ b/include/fast_io_hosted/threads/thread/wasi.h @@ -2,15 +2,6 @@ #if defined(__wasi__) -#include -#include -#include -#include -#include -#include -#include - -#include namespace fast_io { @@ -23,23 +14,14 @@ namespace details using wasi_thread_id = ::std::uint_least64_t; -inline ::std::atomic next_thread_id{1u}; - -inline thread_local wasi_thread_id current_thread_id{}; inline #if __cpp_constexpr >= 202207L constexpr #endif -wasi_thread_id get_or_assign_thread_id() noexcept + wasi_thread_id get_or_assign_thread_id() noexcept { - auto id{current_thread_id}; - if (id == 0) - { - id = next_thread_id.fetch_add(1u, ::std::memory_order_relaxed); - current_thread_id = id; - } - return id; + return static_cast(-1); } inline void assign_thread_id_for_current(wasi_thread_id id) noexcept @@ -75,14 +57,14 @@ inline void sleep_for_ns(__wasi_timestamp_t ns) noexcept } } -#if defined(__wasi_thread__) +#if defined(__wasi_thread__) & 0 struct wasi_thread_control_block { wasi_thread_id id{}; void *data{}; - void (*run)(void *) noexcept{}; - void (*destroy)(void *) noexcept{}; + void (*run)(void *) noexcept {}; + void (*destroy)(void *) noexcept {}; ::std::atomic<::std::uint_least32_t> refcount{2u}; ::std::atomic done{false}; }; @@ -147,7 +129,7 @@ inline wasi_thread_control_block *make_control_block(Func &&func, Args &&...args auto cb{alloc_cb::allocate(1u)}; ::new (cb) wasi_thread_control_block{next_thread_id.fetch_add(1u, ::std::memory_order_relaxed), tup, - &run_impl, &destroy_impl, 2u, false}; + &run_impl, &destroy_impl, 2u, false}; return cb; } @@ -181,46 +163,17 @@ inline #if __cpp_constexpr >= 202207L constexpr #endif -id get_id() noexcept + id get_id() noexcept { return ::fast_io::wasi::details::get_or_assign_thread_id(); } -template -inline -#if __cpp_constexpr >= 202207L - constexpr -#endif -void sleep_for(::std::chrono::duration const &sleep_duration) noexcept -{ - auto const ns64{::std::chrono::duration_cast<::std::chrono::nanoseconds>(sleep_duration).count()}; - if (ns64 <= 0) - { - return; - } - ::fast_io::wasi::details::sleep_for_ns(static_cast<__wasi_timestamp_t>(ns64)); -} - -template -inline -#if __cpp_constexpr >= 202207L - constexpr -#endif -void sleep_until(::std::chrono::time_point const &expect_time) noexcept -{ - auto const now{Clock::now()}; - if (now < expect_time) - { - ::fast_io::wasi::this_thread::sleep_for(expect_time - now); - } -} - template <::std::int_least64_t off_to_epoch> inline #if __cpp_constexpr >= 202207L constexpr #endif -void sleep_for(::fast_io::basic_timestamp const &sleep_duration) noexcept + void sleep_for(::fast_io::basic_timestamp const &sleep_duration) noexcept { if (sleep_duration.seconds < 0) { @@ -246,7 +199,7 @@ inline #if __cpp_constexpr >= 202207L constexpr #endif -void sleep_until(::fast_io::basic_timestamp const &expect_time) noexcept + void sleep_until(::fast_io::basic_timestamp const &expect_time) noexcept { if (expect_time.seconds < 0) { @@ -268,7 +221,7 @@ inline #if __cpp_constexpr >= 202207L constexpr #endif -void yield() noexcept + void yield() noexcept { (void)__wasi_sched_yield(); } @@ -296,7 +249,7 @@ class wasi_thread inline wasi_thread(Func &&func, Args &&...args) { auto *cb{::fast_io::wasi::details::make_control_block(::std::forward(func), - ::std::forward(args)...)}; + ::std::forward(args)...)}; auto ec{__wasi_thread_spawn(cb)}; if (ec != 0) { diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 613a9147b..803bad900 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -1,12 +1,5 @@ #pragma once -#include -#include -#include -#include -#include -#include - namespace fast_io { namespace win32 @@ -261,52 +254,6 @@ inline return ::fast_io::win32::GetCurrentThreadId(); } -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_for(::std::chrono::duration const &sleep_duration) noexcept -{ - auto const ms64{::std::chrono::duration_cast<::std::chrono::milliseconds>(sleep_duration).count()}; - if (ms64 <= 0) - { - return; - } - - auto const u64{static_cast<::std::uint_least64_t>(ms64)}; - auto const ms{u64 > 0xFFFFFFFFu ? static_cast<::std::uint_least32_t>(0xFFFFFFFFu) - : static_cast<::std::uint_least32_t>(u64)}; - ::fast_io::win32::Sleep(ms); -} - -template -inline -#if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr -#endif - void sleep_until(::std::chrono::time_point const &expect_time) noexcept -{ - - auto const now{Clock::now()}; - if (now < expect_time) - { - auto const ms64{::std::chrono::duration_cast<::std::chrono::milliseconds>(expect_time - now).count()}; - if (ms64 <= 0) - { - return; - } - auto const u64{static_cast<::std::uint_least64_t>(ms64)}; - auto const ms{u64 > 0xFFFFFFFFu ? static_cast<::std::uint_least32_t>(0xFFFFFFFFu) - : static_cast<::std::uint_least32_t>(u64)}; - ::fast_io::win32::Sleep(ms); - } -} - template <::std::int_least64_t off_to_epoch> inline #if __cpp_constexpr >= 202207L diff --git a/include/fast_io_hosted/white_hole/white_hole.h b/include/fast_io_hosted/white_hole/white_hole.h index 70b07a093..b29434141 100644 --- a/include/fast_io_hosted/white_hole/white_hole.h +++ b/include/fast_io_hosted/white_hole/white_hole.h @@ -3,7 +3,7 @@ #include "rtl_gen_random.h" #include "win32_crypt_gen_random.h" #endif -#if defined(__wasi__) +#if defined(__wasi__) || defined(__EMSCRIPTEN__) #include "wasi_random_get.h" #endif @@ -25,7 +25,7 @@ concept minimum_buffer_input_stream_require_size_impl = } // namespace fast_io::details #if ((defined(__linux__) && defined(__NR_getrandom)) || \ - (!(defined(__linux__) && defined(__NR_getrandom)) && __has_include())) && !defined(__wasi__) && !defined(__DARWIN_C_LEVEL) && !defined(__CYGWIN__) + (!(defined(__linux__) && defined(__NR_getrandom)) && __has_include())) && !defined(__wasi__) && !defined(__EMSCRIPTEN__) && !defined(__DARWIN_C_LEVEL) && !defined(__CYGWIN__) #include "linux_getrandom.h" #endif #if ((defined(__linux__) && defined(__GLIBC__)) || (defined(__BSD_VISIBLE) && !defined(__DARWIN_C_LEVEL))) && 0 @@ -74,7 +74,7 @@ using basic_native_white_hole = #else basic_rtl_gen_random; #endif -#elif defined(__wasi__) +#elif defined(__wasi__) || defined(__EMSCRIPTEN__) basic_wasi_random_get; #elif (((defined(__linux__) && defined(__GLIBC__)) || (defined(__BSD_VISIBLE) && !defined(__DARWIN_C_LEVEL)))) && 0 basic_bsd_arc4random;