From 0e8e82d88bb8f0ec31cd16df44f7b0eddc4aa1f6 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Fri, 7 Nov 2025 21:51:58 +0800 Subject: [PATCH 01/43] Refactor tuple element access in fast_io_dsal - Updated `get` function signatures in `tuple.h` to return `decltype(auto)` for improved type deduction. - Enhanced consistency by ensuring `[[nodiscard]]` attribute is applied uniformly across all overloads of `get`. - Added new overloads for `get` to support retrieval by type, improving usability and flexibility. - Minor formatting adjustments for better readability in the `forward_as_tuple` function. --- include/fast_io_dsal/impl/tuple.h | 49 +++++++++++++------ .../fast_io_hosted/process/process/option.h | 4 +- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/include/fast_io_dsal/impl/tuple.h b/include/fast_io_dsal/impl/tuple.h index 45369ddfa..3af0ef19c 100644 --- a/include/fast_io_dsal/impl/tuple.h +++ b/include/fast_io_dsal/impl/tuple.h @@ -94,24 +94,24 @@ tuple(Args &&...) -> tuple; template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE -[[nodiscard]] -constexpr auto&& get(::fast_io::containers::tuple &self) noexcept + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple &self) noexcept { return static_cast<::fast_io::containers::details::tuple_element_impl_> &>(self).val_; } template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE -[[nodiscard]] -constexpr auto&& get(::fast_io::containers::tuple const &self) noexcept + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple const &self) noexcept { return static_cast<::fast_io::containers::details::tuple_element_impl_> const &>(self).val_; } template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE -[[nodiscard]] -constexpr auto&& get(::fast_io::containers::tuple &&self) noexcept + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple &&self) noexcept { return ::std::move( static_cast<::fast_io::containers::details::tuple_element_impl_> &&>(self).val_); @@ -119,8 +119,8 @@ constexpr auto&& get(::fast_io::containers::tuple &&self) noexcept template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE -[[nodiscard]] -constexpr auto&& get(::fast_io::containers::tuple const &&self) noexcept + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple const &&self) noexcept { return ::std::move( static_cast<::fast_io::containers::details::tuple_element_impl_> const &&>(self).val_); @@ -147,8 +147,8 @@ constexpr auto get_tuple_element_by_type_() noexcept template requires((::std::same_as + ...) == 1) FAST_IO_GNU_ALWAYS_INLINE -[[nodiscard]] -constexpr auto&& get(::fast_io::containers::tuple const &self) noexcept + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple const &self) noexcept { return static_cast())::type const &>(self).val_; } @@ -156,8 +156,27 @@ constexpr auto&& get(::fast_io::containers::tuple const &self) noexcept template requires((::std::same_as + ...) == 1) FAST_IO_GNU_ALWAYS_INLINE -[[nodiscard]] -constexpr auto&& get(::fast_io::containers::tuple const &&self) noexcept + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple const &&self) noexcept +{ + return ::std::move( + static_cast())::type const &&>(self).val_); +} + +template + requires((::std::same_as + ...) == 1) +FAST_IO_GNU_ALWAYS_INLINE + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple &self) noexcept +{ + return static_cast())::type const &>(self).val_; +} + +template + requires((::std::same_as + ...) == 1) +FAST_IO_GNU_ALWAYS_INLINE + [[nodiscard]] + constexpr decltype(auto) get(::fast_io::containers::tuple &&self) noexcept { return ::std::move( static_cast())::type const &&>(self).val_); @@ -177,15 +196,15 @@ constexpr bool is_tuple_> = true; template concept is_tuple = ::fast_io::containers::details::is_tuple_<::std::remove_cvref_t>; -template +template [[nodiscard]] -constexpr auto forward_as_tuple(Args&&... args) +constexpr auto forward_as_tuple(Args &&...args) { #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-braces" #endif - return ::fast_io::containers::tuple{::std::forward(args)...}; + return ::fast_io::containers::tuple{::std::forward(args)...}; #if defined(__clang__) #pragma clang diagnostic pop #endif diff --git a/include/fast_io_hosted/process/process/option.h b/include/fast_io_hosted/process/process/option.h index f94a98957..7ca20584b 100644 --- a/include/fast_io_hosted/process/process/option.h +++ b/include/fast_io_hosted/process/process/option.h @@ -8,8 +8,10 @@ enum process_mode : ::std::uint_least64_t // *indicates that the process mode has not been evaluated yet new_session = static_cast<::std::uint_least64_t>(1) << 0, // [POSIX] setsid(), [WINDOWS, WINNT] CREATE_NEW_PROCESS_GROUP (Windows is currently not implemented) - alloc_new_console = static_cast<::std::uint_least64_t>(1) << 1 + alloc_new_console = static_cast<::std::uint_least64_t>(1) << 1, // [WINDOWS, WINNT] CREATE_NEW_CONSOLE (Automatically assign a console to new threads) + argv0_no_appname = static_cast<::std::uint_least64_t>(1) << 2, + // Do not automatically append appname to argv0 }; inline constexpr process_mode operator&(process_mode x, process_mode y) noexcept From 6315171b93fb389cbbd422e3dedde0f893cf47db Mon Sep 17 00:00:00 2001 From: MacroModel Date: Fri, 7 Nov 2025 21:53:58 +0800 Subject: [PATCH 02/43] Add tuple application utility and size retrieval in fast_io_dsal - Introduced `apply` function to facilitate the application of a callable to elements of a tuple. - Added `tuple_size` function to retrieve the size of a `fast_io::containers::tuple`. - Implemented helper functions in the `details` namespace for improved code organization and clarity. --- include/fast_io_dsal/impl/tuple.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/fast_io_dsal/impl/tuple.h b/include/fast_io_dsal/impl/tuple.h index 3af0ef19c..f995e9f08 100644 --- a/include/fast_io_dsal/impl/tuple.h +++ b/include/fast_io_dsal/impl/tuple.h @@ -182,6 +182,32 @@ FAST_IO_GNU_ALWAYS_INLINE static_cast())::type const &&>(self).val_); } +namespace details +{ +template +inline constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, ::std::index_sequence) +{ + return ::std::forward(f)(get(::std::forward(t))...); +} + +template +inline consteval ::std::size_t tuple_size(::fast_io::containers::tuple const &) noexcept +{ + return sizeof...(Args); +} + +} // namespace details + +template +inline constexpr decltype(auto) apply(F &&f, Tuple &&t) +{ + constexpr ::std::size_t N{details::tuple_size(t)}; + return details::apply_impl( + ::std::forward(f), + ::std::forward(t), + ::std::make_index_sequence{}); +} + namespace details { From 13e051dbc87e2beb6c71b0f9359157332ec41448 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Fri, 7 Nov 2025 23:54:08 +0800 Subject: [PATCH 03/43] Refactor error handling and improve function signatures across platform headers - Updated error handling in various platform headers to consistently use `throw_posix_error()` with appropriate error codes. - Enhanced function signatures in POSIX and platform-specific implementations for clarity and consistency. - Replaced direct calls to system functions with `noexcept_call` for safer error management. - Improved readability and maintainability of the code by standardizing error checks and function calls. --- include/fast_io_driver/install_path/argv0.h | 34 +-- include/fast_io_driver/install_path/bsd.h | 4 +- include/fast_io_driver/install_path/darwin.h | 9 +- include/fast_io_driver/install_path/linux.h | 3 +- include/fast_io_driver/install_path/null.h | 2 +- include/fast_io_driver/install_path/openbsd.h | 2 +- include/fast_io_dsal/impl/tuple.h | 1 + include/fast_io_dsal/tuple.h | 3 + .../file_loaders/allocation_file_loader.h | 2 +- .../fast_io_hosted/file_loaders/file_size.h | 14 +- include/fast_io_hosted/filesystem/dos_at.h | 42 ++-- include/fast_io_hosted/filesystem/posix_at.h | 212 ++++++++++-------- include/fast_io_hosted/platforms/posix.h | 77 +++++-- .../fast_io_hosted/platforms/posix/common.h | 4 +- .../platforms/posix/preadwrite.h | 8 +- .../fast_io_hosted/platforms/posix/scatter.h | 4 +- include/fast_io_hosted/platforms/posix/seek.h | 5 +- .../platforms/posix_file_lock.h | 8 +- .../fast_io_hosted/platforms/posix_mapping.h | 33 ++- .../fast_io_hosted/platforms/posix_netmode.h | 4 +- .../platforms/systemcall_details.h | 11 +- .../fast_io_hosted/process/process/option.h | 2 +- .../fast_io_hosted/process/process/posix.h | 162 ++++++++++++- include/fast_io_hosted/timeutil/time.h | 8 +- 24 files changed, 467 insertions(+), 187 deletions(-) diff --git a/include/fast_io_driver/install_path/argv0.h b/include/fast_io_driver/install_path/argv0.h index 5bd457b17..6102d1a10 100644 --- a/include/fast_io_driver/install_path/argv0.h +++ b/include/fast_io_driver/install_path/argv0.h @@ -20,7 +20,7 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar { if (!argv0) [[unlikely]] { - throw_posix_error(); + throw_posix_error(EINVAL); } ::fast_io::install_path ret; @@ -36,8 +36,8 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar char path_list_separator[8] = ":"; // could be ":; " if (argv0[0] == path_separator) { - [[maybe_unused]] auto const unused1{::fast_io::noexcept_call(realpath, argv0, newpath)}; - if (auto status{::fast_io::noexcept_call(access, newpath, F_OK)}; !status) + [[maybe_unused]] auto const unused1{::fast_io::noexcept_call(::realpath, argv0, newpath)}; + if (auto status{::fast_io::noexcept_call(::access, newpath, F_OK)}; !status) { newpath[PATH_MAX - 1] = 0; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); @@ -57,16 +57,16 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar } else { - throw_posix_error(status); + throw_posix_error(); } } else if (__builtin_strchr(argv0, static_cast(path_separator))) { - [[maybe_unused]] auto const unused1{::fast_io::noexcept_call(getcwd, newpath2, PATH_MAX)}; - ::fast_io::noexcept_call(strncat, newpath2, path_separator_as_string, PATH_MAX + 256); - ::fast_io::noexcept_call(strncat, newpath2, argv0, PATH_MAX + 256); - [[maybe_unused]] auto const unused2{::fast_io::noexcept_call(realpath, newpath2, newpath)}; - if (auto status{::fast_io::noexcept_call(access, newpath, F_OK)};!status) + [[maybe_unused]] auto const unused1{::fast_io::noexcept_call(::getcwd, newpath2, PATH_MAX)}; + ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, PATH_MAX + 256); + ::fast_io::noexcept_call(::strncat, newpath2, argv0, PATH_MAX + 256); + [[maybe_unused]] auto const unused2{::fast_io::noexcept_call(::realpath, newpath2, newpath)}; + if (auto status{::fast_io::noexcept_call(::access, newpath, F_OK)};!status) { newpath[PATH_MAX - 1] = 0; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); @@ -93,15 +93,15 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar { char *saveptr; char *pathitem; - char *save_path{::fast_io::noexcept_call(getenv, "PATH")}; - for (pathitem = ::fast_io::noexcept_call(strtok_r, save_path, path_list_separator, &saveptr); pathitem; - pathitem = ::fast_io::noexcept_call(strtok_r, nullptr, path_list_separator, &saveptr)) + char *save_path{::fast_io::noexcept_call(::getenv, "PATH")}; + for (pathitem = ::fast_io::noexcept_call(::strtok_r, save_path, path_list_separator, &saveptr); pathitem; + pathitem = ::fast_io::noexcept_call(::strtok_r, nullptr, path_list_separator, &saveptr)) { - ::fast_io::noexcept_call(strncpy, newpath2, pathitem, PATH_MAX + 256); - ::fast_io::noexcept_call(strncat, newpath2, path_separator_as_string, PATH_MAX + 256); - ::fast_io::noexcept_call(strncat, newpath2, argv0, PATH_MAX + 256); + ::fast_io::noexcept_call(::strncpy, newpath2, pathitem, PATH_MAX + 256); + ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, PATH_MAX + 256); + ::fast_io::noexcept_call(::strncat, newpath2, argv0, PATH_MAX + 256); [[maybe_unused]] auto const unused1{::realpath(newpath2, newpath)}; - if (!::fast_io::noexcept_call(access, newpath, F_OK)) + if (!::fast_io::noexcept_call(::access, newpath, F_OK)) { newpath[PATH_MAX - 1] = 0; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); @@ -120,7 +120,7 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar return ret; } } // end for - throw_posix_error(); + throw_posix_error(EINVAL); } // end else } diff --git a/include/fast_io_driver/install_path/bsd.h b/include/fast_io_driver/install_path/bsd.h index 982b90ce6..0af531bc0 100644 --- a/include/fast_io_driver/install_path/bsd.h +++ b/include/fast_io_driver/install_path/bsd.h @@ -38,14 +38,14 @@ inline ::fast_io::install_path get_module_install_path() if (auto status{::fast_io::noexcept_call(::sysctl, mib, 4, buffer1, __builtin_addressof(size), nullptr, 0)}; !status) [[unlikely]] { - throw_posix_error(status); + throw_posix_error(); } resolved = ::fast_io::noexcept_call(::realpath, buffer1, buffer2); if (!resolved) [[unlikely]] { - throw_posix_error(resolved); + throw_posix_error(); } ::fast_io::install_path ret; diff --git a/include/fast_io_driver/install_path/darwin.h b/include/fast_io_driver/install_path/darwin.h index 5dd97f43d..0bc007420 100644 --- a/include/fast_io_driver/install_path/darwin.h +++ b/include/fast_io_driver/install_path/darwin.h @@ -30,7 +30,14 @@ inline ::fast_io::install_path get_module_install_path() ::std::uint_least32_t size{PATH_MAX}; if (::fast_io::noexcept_call(::_NSGetExecutablePath, buffer, __builtin_addressof(size)) == -1) [[unlikely]] { - throw_posix_error(); + if (size > PATH_MAX) + { + throw_posix_error(ERANGE); + } + else + { + throw_posix_error(EINVAL); + } } char buffer2[PATH_MAX + 1]; char *resolved{::fast_io::noexcept_call(::realpath, buffer, buffer2)}; diff --git a/include/fast_io_driver/install_path/linux.h b/include/fast_io_driver/install_path/linux.h index 2fc1be12b..20c97841c 100644 --- a/include/fast_io_driver/install_path/linux.h +++ b/include/fast_io_driver/install_path/linux.h @@ -22,8 +22,9 @@ inline ::fast_io::install_path get_module_install_path() char buffer[PATH_MAX + 1]; ::fast_io::install_path ret; + using my_ssize_t = ::std::make_signed_t<::std::size_t>; #if defined(__linux__) && defined(__NR_readlink) - auto resolved{::fast_io::system_call<__NR_readlink, int>("/proc/self/exe", buffer, PATH_MAX)}; + auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>("/proc/self/exe", buffer, PATH_MAX)}; system_call_throw_error(resolved); buffer[resolved] = '\0'; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt(::fast_io::mnp::os_c_str_with_known_size(buffer, resolved))); diff --git a/include/fast_io_driver/install_path/null.h b/include/fast_io_driver/install_path/null.h index f2809bb2a..7d6d9bb3c 100644 --- a/include/fast_io_driver/install_path/null.h +++ b/include/fast_io_driver/install_path/null.h @@ -11,6 +11,6 @@ namespace fast_io::details [[noreturn]] inline void get_module_install_path() { - throw_posix_error(); + throw_posix_error(ENOTSUP); } } // namespace fast_io::details diff --git a/include/fast_io_driver/install_path/openbsd.h b/include/fast_io_driver/install_path/openbsd.h index 8a3ff8fcf..6f235456f 100644 --- a/include/fast_io_driver/install_path/openbsd.h +++ b/include/fast_io_driver/install_path/openbsd.h @@ -43,7 +43,7 @@ inline ::fast_io::install_path get_module_install_path() if (size > PATH_MAX) [[unlikely]] { - throw_posix_error(); + throw_posix_error(ERANGE); } if (::fast_io::noexcept_call(::sysctl, mib, 4, argv, __builtin_addressof(size), nullptr, 0) != 0) [[unlikely]] diff --git a/include/fast_io_dsal/impl/tuple.h b/include/fast_io_dsal/impl/tuple.h index f995e9f08..1a0a19dfb 100644 --- a/include/fast_io_dsal/impl/tuple.h +++ b/include/fast_io_dsal/impl/tuple.h @@ -92,6 +92,7 @@ struct tuple<> template tuple(Args &&...) -> tuple; +// ADL get template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] diff --git a/include/fast_io_dsal/tuple.h b/include/fast_io_dsal/tuple.h index 8061c8491..43e549a31 100644 --- a/include/fast_io_dsal/tuple.h +++ b/include/fast_io_dsal/tuple.h @@ -14,7 +14,10 @@ using ::fast_io::containers::tuple; using ::fast_io::containers::get; using ::fast_io::containers::is_tuple; using ::fast_io::containers::forward_as_tuple; +using ::fast_io::containers::apply; +using ::std::tuple_element; +using ::std::tuple_size; } #include "impl/misc/pop_macros.h" diff --git a/include/fast_io_hosted/file_loaders/allocation_file_loader.h b/include/fast_io_hosted/file_loaders/allocation_file_loader.h index 89cf854d9..ba941db46 100644 --- a/include/fast_io_hosted/file_loaders/allocation_file_loader.h +++ b/include/fast_io_hosted/file_loaders/allocation_file_loader.h @@ -141,7 +141,7 @@ inline allocation_file_loader_ret allocation_load_address_impl(int fd) inline void rewind_allocation_file_loader(int fd) { #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WINE__) && !defined(__BIONIC__) - auto seekret = ::fast_io::noexcept_call(_lseeki64, fd, 0, 0); + auto seekret = ::fast_io::noexcept_call(::_lseeki64, fd, 0, 0); #else #if defined(_LARGEFILE64_SOURCE) auto seekret = ::fast_io::noexcept_call(::lseek64, fd, 0, 0); diff --git a/include/fast_io_hosted/file_loaders/file_size.h b/include/fast_io_hosted/file_loaders/file_size.h index 74a16f93c..1bbc2ced3 100644 --- a/include/fast_io_hosted/file_loaders/file_size.h +++ b/include/fast_io_hosted/file_loaders/file_size.h @@ -133,19 +133,25 @@ inline ::std::size_t posix_loader_get_file_size(int fd) } return static_cast<::std::size_t>(statxbuf.stx_size); #else + #if defined(__linux__) && !defined(__MLIBC_O_CLOEXEC) struct stat64 st; #else struct stat st; #endif - if ( + + if (::fast_io::noexcept_call( #if defined(__linux__) && !defined(__MLIBC_O_CLOEXEC) - fstat64 + ::fstat64 #else - fstat + ::fstat #endif - (fd, __builtin_addressof(st)) < 0) + , + fd, __builtin_addressof(st)) == -1) [[unlikely]] + { throw_posix_error(); + } + using st_size_unsigned_type = ::std::make_unsigned_t; if constexpr (sizeof(st_size_unsigned_type) > sizeof(::std::size_t)) { diff --git a/include/fast_io_hosted/filesystem/dos_at.h b/include/fast_io_hosted/filesystem/dos_at.h index 0b37bbbce..158c8794c 100644 --- a/include/fast_io_hosted/filesystem/dos_at.h +++ b/include/fast_io_hosted/filesystem/dos_at.h @@ -113,16 +113,24 @@ inline constexpr dos_at_flags &operator^=(dos_at_flags &x, dos_at_flags y) noexc namespace details { +inline void djgpp_libc_throw_posix_error(int ret) +{ + if (ret == -1) [[unlikely]] + { + throw_posix_error(); + } +} + inline void dos_renameat_impl(int olddirfd, char const *oldpath, int newdirfd, char const *newpath) { - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_rename(::fast_io::details::my_dos_concat_tlc_path(olddirfd, oldpath).c_str(), - ::fast_io::details::my_dos_concat_tlc_path(newdirfd, newpath).c_str())); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_rename(::fast_io::details::my_dos_concat_tlc_path(olddirfd, oldpath).c_str(), + ::fast_io::details::my_dos_concat_tlc_path(newdirfd, newpath).c_str())); } inline void dos_linkat_impl(int olddirfd, char const *oldpath, int newdirfd, char const *newpath) { - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_link(::fast_io::details::my_dos_concat_tlc_path(olddirfd, oldpath).c_str(), - ::fast_io::details::my_dos_concat_tlc_path(newdirfd, newpath).c_str())); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_link(::fast_io::details::my_dos_concat_tlc_path(olddirfd, oldpath).c_str(), + ::fast_io::details::my_dos_concat_tlc_path(newdirfd, newpath).c_str())); } template @@ -141,7 +149,7 @@ inline auto dos22_api_dispatcher(int olddirfd, char const *oldpath, int newdirfd inline void dos_symlinkat_impl([[maybe_unused]] char const *oldpath, [[maybe_unused]] int newdirfd, [[maybe_unused]] char const *newpath) { #if defined(FAST_IO_USE_DJGPP_SYMLINK) - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_symlink(oldpath, ::fast_io::details::my_dos_concat_tlc_path(newdirfd, newpath).c_str())); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_symlink(oldpath, ::fast_io::details::my_dos_concat_tlc_path(newdirfd, newpath).c_str())); #else throw_posix_error(ENOSYS); #endif @@ -158,37 +166,37 @@ inline auto dos12_api_dispatcher(char const *oldpath, int newdirfd, char const * inline void dos_faccessat_impl(int dirfd, char const *pathname, int flags) { - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_access(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), flags)); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_access(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), flags)); } inline void dos_fchownat_impl(int dirfd, char const *pathname, uintmax_t owner, uintmax_t group) { // chown does nothing under MS-DOS, so just check is_valid filename - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_chown(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), - static_cast(owner), static_cast(group))); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_chown(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), + static_cast(owner), static_cast(group))); } inline void dos_fchmodat_impl(int dirfd, char const *pathname, mode_t mode) { - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_chmod(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), mode)); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_chmod(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), mode)); } inline posix_file_status dos_fstatat_impl(int dirfd, char const *pathname) { struct stat buf; - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_stat(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), __builtin_addressof(buf))); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_stat(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), __builtin_addressof(buf))); return ::fast_io::details::struct_stat_to_posix_file_status(buf); } inline void dos_mkdirat_impl(int dirfd, char const *pathname, mode_t mode) { - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_mkdir(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), mode)); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_mkdir(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), mode)); } inline void dos_unlinkat_impl(int dirfd, char const *pathname) { - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_unlink(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str())); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_unlink(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str())); } inline constexpr ::std::time_t unix_timestamp_to_time_t(unix_timestamp stmp) noexcept @@ -227,7 +235,7 @@ inline void dos_utimensat_impl(int dirfd, char const *pathname, unix_timestamp_o ::fast_io::details::unix_timestamp_to_time_t(last_modification_time), }; - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_utime(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), __builtin_addressof(ts))); + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_utime(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), __builtin_addressof(ts))); } template @@ -266,12 +274,12 @@ inline auto dos1x_api_dispatcher(int dirfd, char const *path, Args... args) template <::std::integral char_type> inline ::fast_io::details::basic_ct_string dos_readlinkat_impl(int dirfd, char const *pathname) { - // DOS does not support readlink, so you must first verify its validity before throwing a einval exception (not symlink). - ::fast_io::system_call_throw_error(::fast_io::posix::my_dos_access(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), 0)); + // DOS does not support readlink, so you must first verify its validity before throwing a einval exception (not symlink). + djgpp_libc_throw_posix_error(::fast_io::posix::my_dos_access(::fast_io::details::my_dos_concat_tlc_path(dirfd, pathname).c_str(), 0)); - throw_posix_error(EINVAL); + throw_posix_error(EINVAL); - return {}; + return {}; } template <::std::integral char_type, posix_api_ct dsp, typename... Args> diff --git a/include/fast_io_hosted/filesystem/posix_at.h b/include/fast_io_hosted/filesystem/posix_at.h index e19b5eebe..6467b97ad 100644 --- a/include/fast_io_hosted/filesystem/posix_at.h +++ b/include/fast_io_hosted/filesystem/posix_at.h @@ -128,24 +128,26 @@ namespace details inline void posix_renameat_impl(int olddirfd, char const *oldpath, int newdirfd, char const *newpath) { - system_call_throw_error( #if defined(__linux__) && defined(__NR_renameat) - system_call<__NR_renameat, int> + system_call_throw_error(system_call<__NR_renameat, int>(olddirfd, oldpath, newdirfd, newpath)); #else - ::fast_io::posix::libc_renameat + if (::fast_io::posix::libc_renameat(olddirfd, oldpath, newdirfd, newpath) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (olddirfd, oldpath, newdirfd, newpath)); } inline void posix_linkat_impl(int olddirfd, char const *oldpath, int newdirfd, char const *newpath, int flags) { - system_call_throw_error( -#if defined(__linux__) - system_call<__NR_linkat, int> +#if defined(__linux__) && defined(__NR_linkat) + system_call_throw_error(system_call<__NR_linkat, int>(olddirfd, oldpath, newdirfd, newpath, flags)); #else - ::fast_io::posix::libc_linkat + if (::fast_io::posix::libc_linkat(olddirfd, oldpath, newdirfd, newpath, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (olddirfd, oldpath, newdirfd, newpath, flags)); } template @@ -164,13 +166,14 @@ inline auto posix22_api_dispatcher(int olddirfd, char const *oldpath, int newdir inline void posix_symlinkat_impl(char const *oldpath, int newdirfd, char const *newpath) { - system_call_throw_error( -#if defined(__linux__) - system_call<__NR_symlinkat, int> +#if defined(__linux__) && defined(__NR_symlinkat) + system_call_throw_error(system_call<__NR_symlinkat, int>(oldpath, newdirfd, newpath)); #else - ::fast_io::posix::libc_symlinkat + if (::fast_io::posix::libc_symlinkat(oldpath, newdirfd, newpath) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (oldpath, newdirfd, newpath)); } template @@ -184,15 +187,16 @@ inline auto posix12_api_dispatcher(char const *oldpath, int newdirfd, char const inline void posix_faccessat_impl(int dirfd, char const *pathname, int mode, int flags) { - system_call_throw_error( #if defined(__linux__) && defined(__NR_faccessat2) - system_call<__NR_faccessat2, int>(dirfd, pathname, mode, flags) + system_call_throw_error(system_call<__NR_faccessat2, int>(dirfd, pathname, mode, flags)); #elif defined(__linux__) && defined(__NR_faccessat) - system_call<__NR_faccessat, int>(dirfd, pathname, mode) + system_call_throw_error(system_call<__NR_faccessat, int>(dirfd, pathname, mode)); #else - ::fast_io::posix::libc_faccessat(dirfd, pathname, mode, flags) + if (::fast_io::posix::libc_faccessat(dirfd, pathname, mode, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - ); } #if defined(__wasi__) && !defined(__wasilibc_unmodified_upstream) @@ -219,13 +223,14 @@ inline void posix_fchownat_impl(int dirfd, char const *pathname, uintmax_t owner throw_posix_error(EOVERFLOW); } } - system_call_throw_error( -#if defined(__linux__) - system_call<__NR_fchownat, int> +#if defined(__linux__) && defined(__NR_fchownat) + system_call_throw_error(system_call<__NR_fchownat, int>(dirfd, pathname, static_cast(owner), static_cast(group), flags)); #else - ::fast_io::posix::libc_fchownat + if (::fast_io::posix::libc_fchownat(dirfd, pathname, static_cast(owner), static_cast(group), flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (dirfd, pathname, static_cast(owner), static_cast(group), flags)); } #endif @@ -237,13 +242,17 @@ inline void posix_fchmodat_impl(int, char const *, mode_t, int) #else inline void posix_fchmodat_impl(int dirfd, char const *pathname, mode_t mode, int flags) { - system_call_throw_error( -#if defined(__linux__) - system_call<__NR_fchmodat, int> + +#if defined(__linux__) && defined(__NR_fchmodat2) + system_call_throw_error(system_call<__NR_fchmodat2, int>(dirfd, pathname, mode, flags)); +#elif defined(__linux__) && defined(__NR_fchmodat) + system_call_throw_error(system_call<__NR_fchmodat, int>(dirfd, pathname, mode)); #else - ::fast_io::posix::libc_fchmodat + if (::fast_io::posix::libc_fchmodat(dirfd, pathname, mode, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (dirfd, pathname, mode, flags)); } #endif @@ -269,7 +278,7 @@ inline posix_file_status posix_fstatat_impl(int dirfd, char const *pathname, int int>(dirfd, pathname, __builtin_addressof(buf), flags)); #else - if ((::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), flags)) < 0) + if (::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), flags) == -1) [[unlikely]] { throw_posix_error(); } @@ -277,20 +286,24 @@ inline posix_file_status posix_fstatat_impl(int dirfd, char const *pathname, int #else struct stat buf; - system_call_throw_error(::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), flags)); + if (::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif return ::fast_io::details::struct_stat_to_posix_file_status(buf); } inline void posix_mkdirat_impl(int dirfd, char const *pathname, mode_t mode) { - system_call_throw_error( -#if defined(__linux__) - system_call<__NR_mkdirat, int> +#if defined(__linux__) && defined(__NR_mkdirat) + system_call_throw_error(system_call<__NR_mkdirat, int>(dirfd, pathname, mode)); #else - ::fast_io::posix::libc_mkdirat + if (::fast_io::posix::libc_mkdirat(dirfd, pathname, mode) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (dirfd, pathname, mode)); } #if 0 #if (defined(__wasi__) && !defined(__wasilibc_unmodified_upstream)) || defined(__DARWIN_C_LEVEL) @@ -308,30 +321,28 @@ inline void posix_mknodat_impl(int dirfd, char const* pathname, mode_t mode,::st if(static_cast<::std::uintmax_t>(dev)>mx) throw_posix_error(EOVERFLOW); } - system_call_throw_error( -#if defined(__linux__) - system_call< -#if __NR_mknodat - __NR_mknodat -#endif - ,int> +#if defined(__linux__) && defined(__NR_mknodat) + system_call_throw_error(system_call<__NR_mknodat, int>(dirfd, pathname, mode, static_cast(dev))); #else - ::fast_io::posix::libc_mknodat + if (::fast_io::posix::libc_mknodat(dirfd, pathname, mode, static_cast(dev)) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (dirfd,pathname,mode,static_cast(dev))); } #endif #endif inline void posix_unlinkat_impl(int dirfd, char const *path, int flags) { - system_call_throw_error( -#if defined(__linux__) - system_call<__NR_unlinkat, int> +#if defined(__linux__) && defined(__NR_unlinkat) + system_call_throw_error(system_call<__NR_unlinkat, int>(dirfd, path, flags)); #else - ::fast_io::posix::libc_unlinkat + if (::fast_io::posix::libc_unlinkat(dirfd, path, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (dirfd, path, flags)); } namespace details @@ -387,7 +398,7 @@ inline #if defined(UTIME_NOW) && defined(UTIME_OMIT) constexpr #endif - kernel_timespec64 + kernel_timespec64 unix_timestamp_to_struct_timespec64([[maybe_unused]] unix_timestamp_option opt) noexcept { #if defined(UTIME_NOW) && defined(UTIME_OMIT) @@ -418,7 +429,7 @@ inline void posix_utimensat_impl(int dirfd, char const *path, unix_timestamp_opt } #if defined(__linux__) && defined(__NR_utimensat_time64) - details::kernel_timespec64 ts[2]{ + details::kernel_timespec64 ts[2]{ details::unix_timestamp_to_struct_timespec64(last_access_time), details::unix_timestamp_to_struct_timespec64(last_modification_time), }; @@ -431,26 +442,23 @@ inline void posix_utimensat_impl(int dirfd, char const *path, unix_timestamp_opt struct timespec *tsptr{ts}; #endif - system_call_throw_error( -#if defined(__linux__) -#if defined(__NR_utimensat_time64) - system_call<__NR_utimensat_time64, int> -#elif defined(__NR_utimensat) - system_call<__NR_utimensat, int> -#else - ::fast_io::posix::libc_utimensat -#endif +#if defined(__linux__) && defined(__NR_utimensat_time64) + system_call_throw_error(system_call<__NR_utimensat_time64, int>(dirfd, path, tsptr, flags)); +#elif defined(__linux__) && defined(__NR_utimensat) + system_call_throw_error(system_call<__NR_utimensat, int>(dirfd, path, tsptr, flags)); #else - ::fast_io::posix::libc_utimensat + if (::fast_io::posix::libc_utimensat(dirfd, path, tsptr, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - (dirfd, path, tsptr, flags)); } -template<::std::integral char_type> +template <::std::integral char_type> inline ::fast_io::details::basic_ct_string posix_readlinkat_impl([[maybe_unused]] int dirfd, [[maybe_unused]] char const *pathname) { #if defined(AT_SYMLINK_NOFOLLOW) - using posix_ssize_t = ::std::make_signed_t<::std::size_t>; + using posix_ssize_t = ::std::make_signed_t<::std::size_t>; // The standard POSIX API does not provide a direct interface to call readlink using an fd, so toctou cannot be avoided. @@ -474,7 +482,7 @@ inline ::fast_io::details::basic_ct_string posix_readlinkat_impl([[ma int>(dirfd, pathname, __builtin_addressof(buf), AT_SYMLINK_NOFOLLOW)); #else - if ((::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), AT_SYMLINK_NOFOLLOW)) < 0) + if (::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), AT_SYMLINK_NOFOLLOW) == -1) [[unlikely]] { throw_posix_error(); } @@ -482,10 +490,13 @@ inline ::fast_io::details::basic_ct_string posix_readlinkat_impl([[ma #else struct ::stat buf; - system_call_throw_error(::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf),AT_SYMLINK_NOFOLLOW)); + if (::fast_io::posix::libc_fstatat(dirfd, pathname, __builtin_addressof(buf), AT_SYMLINK_NOFOLLOW) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif - auto const symlink_size{static_cast<::std::size_t>(buf.st_size)}; + auto const symlink_size{static_cast<::std::size_t>(buf.st_size)}; if constexpr (::std::same_as) { @@ -493,36 +504,50 @@ inline ::fast_io::details::basic_ct_string posix_readlinkat_impl([[ma posix_ssize_t readlink_bytes{ #if defined(__linux__) && defined(__NR_readlinkat) - system_call<__NR_readlinkat, posix_ssize_t>(dirfd, pathname, result.data(), symlink_size) + system_call<__NR_readlinkat, posix_ssize_t>(dirfd, pathname, result.data(), symlink_size) #else - static_cast(::fast_io::posix::libc_readlinkat(dirfd, pathname, result.data(), symlink_size)) + static_cast(::fast_io::posix::libc_readlinkat(dirfd, pathname, result.data(), symlink_size)) #endif - }; - + }; + +#if defined(__linux__) && defined(__NR_readlinkat) system_call_throw_error(readlink_bytes); - - if(static_cast<::std::size_t>(readlink_bytes) != symlink_size) +#else + if (readlink_bytes == -1) [[unlikely]] + { + throw_posix_error(); + } +#endif + + if (static_cast<::std::size_t>(readlink_bytes) != symlink_size) { throw_posix_error(EIO); } return result; } - else + else { local_operator_new_array_ptr dynamic_buffer{symlink_size}; posix_ssize_t readlink_bytes{ #if defined(__linux__) && defined(__NR_readlinkat) - system_call<__NR_readlinkat, posix_ssize_t>(dirfd, pathname, dynamic_buffer.get(), symlink_size) + system_call<__NR_readlinkat, posix_ssize_t>(dirfd, pathname, dynamic_buffer.get(), symlink_size) #else - static_cast(::fast_io::posix::libc_readlinkat(dirfd, pathname, dynamic_buffer.get(), symlink_size)) + static_cast(::fast_io::posix::libc_readlinkat(dirfd, pathname, dynamic_buffer.get(), symlink_size)) #endif - }; - + }; + +#if defined(__linux__) && defined(__NR_readlinkat) system_call_throw_error(readlink_bytes); - - if(static_cast<::std::size_t>(readlink_bytes) != symlink_size) [[unlikely]] +#else + if (readlink_bytes == -1) [[unlikely]] + { + throw_posix_error(); + } +#endif + + if (static_cast<::std::size_t>(readlink_bytes) != symlink_size) [[unlikely]] { throw_posix_error(EIO); } @@ -575,10 +600,10 @@ inline auto posix1x_api_dispatcher(int dirfd, char const *path, Args... args) template <::std::integral char_type, posix_api_ct dsp, typename... Args> inline auto posixct_api_dispatcher(int dirfd, char const *path, Args... args) { - if constexpr (dsp == posix_api_ct::readlinkat) - { - return posix_readlinkat_impl(dirfd, path, args...); - } + if constexpr (dsp == posix_api_ct::readlinkat) + { + return posix_readlinkat_impl(dirfd, path, args...); + } } template inline auto posix_deal_withct(int dirfd, path_type const &path, Args... args) { - return fast_io::posix_api_common(path, [&](char const *path_c_str) { return posixct_api_dispatcher(dirfd, path_c_str, args...); }); + return fast_io::posix_api_common(path, [&](char const *path_c_str) { return posixct_api_dispatcher(dirfd, path_c_str, args...); }); } } // namespace details @@ -803,13 +828,13 @@ inline void native_utimensat(posix_at_entry ent, path_type const &path, unix_tim template <::std::integral char_type, ::fast_io::constructible_to_os_c_str path_type> inline ::fast_io::details::basic_ct_string posix_readlinkat(posix_at_entry ent, path_type const &path) { - return details::posix_deal_withct(ent.fd, path); + return details::posix_deal_withct(ent.fd, path); } template <::std::integral char_type, ::fast_io::constructible_to_os_c_str path_type> inline ::fast_io::details::basic_ct_string native_readlinkat(posix_at_entry ent, path_type const &path) { - return details::posix_deal_withct(ent.fd, path); + return details::posix_deal_withct(ent.fd, path); } #if 0 @@ -876,13 +901,10 @@ inline constexpr ::std::size_t read_linkbuffer_size() noexcept inline ::std::size_t posix_readlinkat_common_impl(int dirfd,char const* pathname,char* buffer) { constexpr ::std::size_t buffer_size{read_linkbuffer_size()}; - ::std::ptrdiff_t bytes{ -#if defined(__linux__) - system_call< -#if __NR_readlinkat - __NR_readlinkat -#endif - ,int> + using my_ssize_t = ::std::make_signed_t<::std::size_t>; + my_ssize_t bytes{ +#if defined(__linux__) && defined(__NR_readlinkat) + system_call<__NR_readlinkat, my_ssize_t> #else ::fast_io::posix::libc_readlinkat #endif diff --git a/include/fast_io_hosted/platforms/posix.h b/include/fast_io_hosted/platforms/posix.h index c53cb1845..d5172e89b 100644 --- a/include/fast_io_hosted/platforms/posix.h +++ b/include/fast_io_hosted/platforms/posix.h @@ -545,9 +545,9 @@ inline constexpr posix_at_entry posix_at_fdcwd() noexcept { return posix_at_entry( #if defined(AT_FDCWD) - AT_FDCWD + AT_FDCWD #else - -2 + -2 #endif ); } @@ -556,9 +556,9 @@ inline constexpr posix_at_entry at_fdcwd() noexcept { return posix_at_entry( #if defined(AT_FDCWD) - AT_FDCWD + AT_FDCWD #else - -2 + -2 #endif ); } @@ -783,17 +783,17 @@ inline posix_file_status fstat_impl(int fd) if (::fast_io::noexcept_call( #if (defined(_WIN32) && !defined(__WINE__) && !defined(__BIONIC__)) && !defined(__CYGWIN__) #if (!defined(__MINGW32__) || __has_include(<_mingw_stat64.h>)) - _fstat64 + ::_fstat64 #else - _fstati64 + ::_fstati64 #endif #elif defined(__linux__) && defined(__USE_LARGEFILE64) - fstat64 + ::fstat64 #else - fstat + ::fstat #endif , - fd, __builtin_addressof(st)) < 0) + fd, __builtin_addressof(st)) == -1) [[unlikely]] throw_posix_error(); return struct_stat_to_posix_file_status(st); } @@ -950,7 +950,14 @@ inline constexpr dos_path_tlc_string my_dos_concat_tlc_path(int dirfd, char cons auto [failed, path]{my_dos_concat_tlc_path_common(dirfd, pathname)}; if (failed) [[unlikely]] { - ::fast_io::system_call_throw_error(-1); + if constexpr (always_terminate) + { + fast_terminate(); + } + else + { + throw_posix_error(EINVAL); + } } return path; } @@ -959,7 +966,17 @@ template inline int my_posix_openat(int dirfd, char const *pathname, int flags, mode_t mode) { int fd{::fast_io::details::my_posix_open_noexcept(my_dos_concat_tlc_path(dirfd, pathname).c_str(), flags, mode)}; - system_call_throw_error(fd); + if (fd == -1) [[unlikely]] + { + if constexpr (always_terminate) + { + fast_terminate(); + } + else + { + throw_posix_error(); + } + } return fd; } @@ -995,7 +1012,23 @@ inline int my_posix_openat(int dirfd, char const *pathname, int flags, mode_t mo my_posix_openat_noexcept #endif (dirfd, pathname, flags, mode)}; + +#if defined(__linux__) && defined(__NR_openat) system_call_throw_error(fd); +#else + if (fd == -1) [[unlikely]] + { + if constexpr (always_terminate) + { + fast_terminate(); + } + else + { + throw_posix_error(); + } + } +#endif + return fd; } #endif @@ -1061,7 +1094,17 @@ inline int my_posix_open(char const *pathname, int flags, { #if defined(__MSDOS__) || (defined(__NEWLIB__) && !defined(AT_FDCWD)) || defined(_PICOLIBC__) int fd{::fast_io::details::my_posix_open_noexcept(pathname, flags, mode)}; - ::fast_io::system_call_throw_error(fd); + if(fd == -1) [[unlikely]] + { + if constexpr (always_terminate) + { + fast_terminate(); + } + else + { + throw_posix_error(); + } + } return fd; #else return ::fast_io::details::my_posix_openat(AT_FDCWD, pathname, flags, mode); @@ -1152,7 +1195,7 @@ inline int my_open_posix_fd_temp_file() } wf.release(); return fd; -#elif defined(O_TMPFILE) && defined(__linux__) +#elif defined(O_TMPFILE) && defined(__linux__) && defined(__NR_openat) int fd{system_call<__NR_openat, int>(AT_FDCWD, u8"/tmp", O_EXCL | O_RDWR | O_TMPFILE | O_APPEND | O_NOATIME, S_IRUSR | S_IWUSR)}; system_call_throw_error(fd); @@ -1441,7 +1484,7 @@ inline void posix_truncate_impl(int fd, ::fast_io::uintfpos_t size) } } - if (noexcept_call(ftruncate, fd, static_cast(size)) < 0) + if (noexcept_call(::ftruncate, fd, static_cast(size)) < 0) { throw_posix_error(); } @@ -1497,7 +1540,7 @@ inline void posix_truncate_impl(int fd, ::fast_io::uintfpos_t size) } } - if (noexcept_call(ftruncate, fd, static_cast(size)) < 0) + if (noexcept_call(::ftruncate, fd, static_cast(size)) < 0) { throw_posix_error(); } @@ -1513,7 +1556,7 @@ inline void posix_truncate_impl(int fd, ::fast_io::uintfpos_t size) } } - if (noexcept_call(ftruncate, fd, static_cast(size)) < 0) + if (noexcept_call(::ftruncate, fd, static_cast(size)) < 0) { throw_posix_error(); } @@ -1527,7 +1570,7 @@ inline void posix_truncate_impl(int fd, ::fast_io::uintfpos_t size) } } - if (noexcept_call(ftruncate, fd, static_cast(size)) < 0) + if (noexcept_call(::ftruncate, fd, static_cast(size)) < 0) { throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/posix/common.h b/include/fast_io_hosted/platforms/posix/common.h index 26af1e1e8..9fbfcc7b5 100644 --- a/include/fast_io_hosted/platforms/posix/common.h +++ b/include/fast_io_hosted/platforms/posix/common.h @@ -20,7 +20,7 @@ inline ::std::byte *posix_read_bytes_impl(int fd, ::std::byte *first, ::std::byt #else auto ret{::fast_io::noexcept_call(::read, fd, first, static_cast<::std::size_t>(last - first))}; #endif - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } @@ -42,7 +42,7 @@ inline ::std::byte const *posix_write_bytes_impl(int fd, ::std::byte const *firs #else auto ret{::fast_io::noexcept_call(::write, fd, first, static_cast<::std::size_t>(last - first))}; #endif - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/posix/preadwrite.h b/include/fast_io_hosted/platforms/posix/preadwrite.h index b930343b9..aef81438a 100644 --- a/include/fast_io_hosted/platforms/posix/preadwrite.h +++ b/include/fast_io_hosted/platforms/posix/preadwrite.h @@ -10,7 +10,7 @@ namespace details inline ::std::byte *posix_pread_bytes_impl(int fd, ::std::byte *first, ::std::byte *last, ::fast_io::intfpos_t off) { auto ret{::fast_io::noexcept_call(::pread, fd, first, static_cast<::std::size_t>(last - first), off)}; - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } @@ -21,7 +21,7 @@ inline ::std::byte const *posix_pwrite_bytes_impl(int fd, ::std::byte const *fir ::fast_io::intfpos_t off) { auto ret{::fast_io::noexcept_call(::pwrite, fd, first, static_cast<::std::size_t>(last - first), off)}; - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } @@ -56,7 +56,7 @@ inline ::fast_io::io_scatter_status_t posix_scatter_pread_bytes_impl(int fd, ::f = struct iovec const *; auto ret{::fast_io::noexcept_call(::preadv, fd, reinterpret_cast(pscatter), n, off)}; - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } @@ -91,7 +91,7 @@ inline ::fast_io::io_scatter_status_t posix_scatter_pwrite_bytes_impl(int fd, :: = struct iovec const *; auto ret{::fast_io::noexcept_call(::pwritev, fd, reinterpret_cast(pscatter), n, off)}; - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/posix/scatter.h b/include/fast_io_hosted/platforms/posix/scatter.h index e3596cd29..003ed17df 100644 --- a/include/fast_io_hosted/platforms/posix/scatter.h +++ b/include/fast_io_hosted/platforms/posix/scatter.h @@ -33,7 +33,7 @@ inline ::fast_io::io_scatter_status_t posix_scatter_read_bytes_impl(int fd, ::fa = struct iovec const *; auto ret{::fast_io::noexcept_call(::readv, fd, reinterpret_cast(pscatter), n)}; - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } @@ -68,7 +68,7 @@ inline ::fast_io::io_scatter_status_t posix_scatter_write_bytes_impl(int fd, ::f = struct iovec const *; auto ret{::fast_io::noexcept_call(::writev, fd, reinterpret_cast(pscatter), n)}; - if (ret < 0) + if (ret == -1) { ::fast_io::throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/posix/seek.h b/include/fast_io_hosted/platforms/posix/seek.h index 86f53801b..1d22fe2ff 100644 --- a/include/fast_io_hosted/platforms/posix/seek.h +++ b/include/fast_io_hosted/platforms/posix/seek.h @@ -65,7 +65,10 @@ inline ::fast_io::intfpos_t posix_seek_impl(int fd, ::fast_io::intfpos_t offset, ::lseek #endif (fd, static_cast(offset), static_cast(s))); - system_call_throw_error(ret); + if(ret == -1) [[unlikely]] + { + throw_posix_error(); + } return static_cast<::fast_io::intfpos_t>(static_cast<::std::uint_least64_t>(ret)); #endif } diff --git a/include/fast_io_hosted/platforms/posix_file_lock.h b/include/fast_io_hosted/platforms/posix_file_lock.h index 9812aaadc..c44a9ac16 100644 --- a/include/fast_io_hosted/platforms/posix_file_lock.h +++ b/include/fast_io_hosted/platforms/posix_file_lock.h @@ -4,9 +4,9 @@ namespace fast_io namespace details { -inline int fcntl_file_lock(int fd, int cmd, struct flock const *lockp) +inline int fcntl_file_lock(int fd, int cmd, struct flock const *lockp) noexcept { - return ::fcntl(fd, cmd, lockp); + return ::fast_io::details::posix::fcntl(fd, cmd, lockp); } inline void posix_file_lock_lock_common_impl(int fd, struct flock const &lockp) @@ -14,8 +14,8 @@ inline void posix_file_lock_lock_common_impl(int fd, struct flock const &lockp) #if defined(__linux__) && defined(__NR_fcntl) system_call_throw_error(system_call<__NR_fcntl, int>(fd, F_SETLKW, __builtin_addressof(lockp))); #else - int ret{noexcept_call(fcntl_file_lock, fd, F_SETLKW, __builtin_addressof(lockp))}; - if (ret < 0) + int ret{fcntl_file_lock(fd, F_SETLKW, __builtin_addressof(lockp))}; + if (ret == -1) [[unlikely]] { throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/posix_mapping.h b/include/fast_io_hosted/platforms/posix_mapping.h index 031b7c26f..6a3f9d1f6 100644 --- a/include/fast_io_hosted/platforms/posix_mapping.h +++ b/include/fast_io_hosted/platforms/posix_mapping.h @@ -29,7 +29,7 @@ inline ::std::byte *sys_mmap(void *addr, ::std::size_t len, int prot, int flags, throw_posix_error(EINVAL); } } - auto ret{reinterpret_cast<::std::byte *>(mmap64(addr, len, prot, flags, fd, offset))}; + auto ret{reinterpret_cast<::std::byte *>(::fast_io::noexcept_call(::mmap64, addr, len, prot, flags, fd, offset))}; if (ret == MAP_FAILED) { throw_posix_error(); @@ -59,13 +59,19 @@ inline int sys_mprotect(void *start, ::std::size_t len, int prot) #if defined(__linux__) && defined(__NR_mprotect) system_call<__NR_mprotect, int>(start, len, prot) #else - ::mprotect(start, len, prot) + ::fast_io::noexcept_call(::mprotect, start, len, prot) #endif }; - if (result) [[unlikely]] + +#if defined(__linux__) && defined(__NR_mprotect) + system_call_throw_error(result); +#else + if (result == -1) [[unlikely]] { throw_posix_error(); } +#endif + return result; } @@ -75,13 +81,21 @@ inline int sys_munmap_nothrow(void *addr, ::std::size_t len) #if defined(__linux__) && defined(__NR_munmap) system_call<__NR_munmap, int>(addr, len); #else - ::munmap(addr, len); + ::fast_io::noexcept_call(::munmap, addr, len); #endif } inline void sys_munmap(void *addr, ::std::size_t len) { - system_call_throw_error(sys_munmap_nothrow(addr, len)); + auto const ret{sys_munmap_nothrow(addr, len)}; +#if defined(__linux__) && defined(__NR_munmap) + system_call_throw_error(ret); +#else + if (ret == -1) [[unlikely]] + { + throw_posix_error(); + } +#endif } } // namespace details @@ -174,7 +188,7 @@ class posix_memory_map_file { } inline posix_memory_map_file(posix_at_entry bf, file_map_attribute attr, ::std::size_t bytes, - ::std::uintmax_t start_address = 0) + ::std::uintmax_t start_address = 0) : address_begin{details::sys_mmap(nullptr, bytes, static_cast(to_posix_file_map_attribute(attr)), MAP_SHARED, bf.fd, start_address)}, address_end{address_begin + bytes} @@ -297,7 +311,14 @@ class posix_memory_map_file { auto ret{details::sys_munmap_nothrow(this->address_begin, static_cast<::std::size_t>(address_end - address_begin))}; this->address_end = this->address_begin = reinterpret_cast<::std::byte *>(MAP_FAILED); +#if defined(__linux__) && defined(__NR_munmap) system_call_throw_error(ret); +#else + if (ret == -1) [[unlikely]] + { + throw_posix_error(); + } +#endif } } inline constexpr ~posix_memory_map_file() diff --git a/include/fast_io_hosted/platforms/posix_netmode.h b/include/fast_io_hosted/platforms/posix_netmode.h index 3c5691e4b..9a9dff3c8 100644 --- a/include/fast_io_hosted/platforms/posix_netmode.h +++ b/include/fast_io_hosted/platforms/posix_netmode.h @@ -662,7 +662,7 @@ inline ::std::size_t posix_socket_write_impl(int fd, void const *data, ::std::si return static_cast<::std::size_t>(written); #else ::std::ptrdiff_t written{::fast_io::noexcept_call(::send, fd, data, to_write, 0)}; - if (written < 0) + if (written == -1) { throw_posix_error(); } @@ -678,7 +678,7 @@ inline ::std::size_t posix_socket_read_impl(int fd, void *data, ::std::size_t to return static_cast<::std::size_t>(written); #else ::std::ptrdiff_t written{::fast_io::noexcept_call(::recv, fd, data, to_write, 0)}; - if (written < 0) + if (written == -1) { throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/systemcall_details.h b/include/fast_io_hosted/platforms/systemcall_details.h index 58c9ff3b2..9675aafef 100644 --- a/include/fast_io_hosted/platforms/systemcall_details.h +++ b/include/fast_io_hosted/platforms/systemcall_details.h @@ -29,9 +29,9 @@ inline int sys_dup(int old_fd) #else auto fd{noexcept_call( #if defined(_WIN32) && !defined(__BIONIC__) - _dup + ::_dup #else - dup + ::dup #endif , old_fd)}; @@ -121,7 +121,14 @@ inline void sys_close_throw_error(int &fd) { auto ret{sys_close(fd)}; fd = -1; // POSIX standard says we should never call close(2) again even close syscall fails +#if defined(__linux__) && defined(__NR_close) system_call_throw_error(ret); +#else + if (ret == -1) [[unlikely]] + { + throw_posix_error(); + } +#endif } #if (!defined(__NEWLIB__) || defined(__CYGWIN__)) && !defined(_WIN32) && __has_include() && !defined(_PICOLIBC__) diff --git a/include/fast_io_hosted/process/process/option.h b/include/fast_io_hosted/process/process/option.h index 7ca20584b..aa2dd6e22 100644 --- a/include/fast_io_hosted/process/process/option.h +++ b/include/fast_io_hosted/process/process/option.h @@ -10,7 +10,7 @@ enum process_mode : ::std::uint_least64_t // [POSIX] setsid(), [WINDOWS, WINNT] CREATE_NEW_PROCESS_GROUP (Windows is currently not implemented) alloc_new_console = static_cast<::std::uint_least64_t>(1) << 1, // [WINDOWS, WINNT] CREATE_NEW_CONSOLE (Automatically assign a console to new threads) - argv0_no_appname = static_cast<::std::uint_least64_t>(1) << 2, + argv0_no_path_append = static_cast<::std::uint_least64_t>(1) << 2, // Do not automatically append appname to argv0 }; diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 7a5be8f0d..ad75a94b2 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -108,6 +108,161 @@ inline constexpr Iter print_reserve_define(io_reserve_type_t + * - macOS: fcntl(fd, F_GETPATH, ...) + * - FreeBSD: /dev/fd/ (requires fdescfs mounted) + * - Solaris: /proc/self/path/ + * + * Returns: + * 0 on success, with `buf` containing a NUL-terminated absolute path + * -1 on error, with errno set appropriately + * + * Limitations: + * - If file has been unlinked or is anonymous (memfd, pipe, etc.), no valid path can be returned. + * - The returned path may differ from original open() argument due to symlinks or namespaces. + */ + +inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) +{ + if (buf == nullptr || bufsz == 0u) [[unlikely]] + { + throw_posix_error(EINVAL); + } + +#if defined(__APPLE__) || defined(__DARWIN_C_LEVEL) + /* macOS / Darwin */ + +#if defined(PATH_MAX) + if (bufsz < static_cast<::std::size_t>(PATH_MAX)) [[unlikely]] + { + throw_posix_error(ENOBUFS); + } +#elif defined(MAXPATHLEN) + if (bufsz < static_cast<::std::size_t>(MAXPATHLEN)) [[unlikely]] + { + throw_posix_error(ENOBUFS); + } +#else + if (bufsz < 1024u) [[unlikely]] + { + throw_posix_error(ENOBUFS); + } +#endif + + if (::fast_io::details::posix::fcntl(fd, F_GETPATH, buf) == -1) [[unlikely]] + { + throw_posix_error(); + } + +#elif defined(__linux__) + /* Linux: /proc/self/fd/ */ + + if (bufsz == 0u) [[unlikely]] + { + throw_posix_error(ENOBUFS); + } + + decltype(auto) path_str{"/proc/self/fd/"}; + constexpr auto path_str_sz{::fast_io::cstr_len(path_str)}; + constexpr auto fd_sz{::fast_io::pr_rsv_size}; + constexpr auto all_sz{path_str_sz + fd_sz}; + + char linkpath[all_sz]; + ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; + ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd); + + using my_ssize_t = ::std::make_signed_t<::std::size_t>; + +#if defined(__linux__) && defined(__NR_readlink) + auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>(linkpath, buf, bufsz - 1u)}; + system_call_throw_error(resolved); +#else + auto resolved{::fast_io::noexcept_call(::readlink, linkpath, buf, bufsz - 1u)}; + if (resolved == -1) [[unlikely]] + { + throw_posix_error(); + } +#endif + + if (static_cast<::std::size_t>(resolved) >= bufsz - 1u) [[unlikely]] + { + throw_posix_error(ENAMETOOLONG); + } + + buf[resolved] = '\0'; + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + /* BSD: /dev/fd/ (requires fdescfs mounted) */ + + if (bufsz == 0u) [[unlikely]] + { + throw_posix_error(ENOBUFS); + } + + decltype(auto) path_str{"/dev/fd/"}; + constexpr auto path_str_sz{::fast_io::cstr_len(path_str)}; + constexpr auto fd_sz{::fast_io::pr_rsv_size}; + constexpr auto all_sz{path_str_sz + fd_sz}; + + char linkpath[all_sz]; + ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; + ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd); + + auto resolved{::fast_io::noexcept_call(::readlink, linkpath, buf, bufsz - 1u)}; + if (resolved == -1) [[unlikely]] + { + throw_posix_error(); + } + + if (static_cast<::std::size_t>(resolved) >= bufsz - 1u) [[unlikely]] + { + throw_posix_error(ENAMETOOLONG); + } + + buf[resolved] = '\0'; + +#elif defined(__sun) + /* Solaris / illumos */ + + if (bufsz == 0u) [[unlikely]] + { + throw_posix_error(ENOBUFS); + } + + decltype(auto) path_str{"/proc/self/path/"}; + constexpr auto path_str_sz{::fast_io::cstr_len(path_str)}; + constexpr auto fd_sz{::fast_io::pr_rsv_size}; + constexpr auto all_sz{path_str_sz + fd_sz}; + + char linkpath[all_sz]; + ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; + ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd); + + auto resolved{::fast_io::noexcept_call(::readlink, linkpath, buf, bufsz - 1u)}; + if (resolved == -1) [[unlikely]] + { + throw_posix_error(); + } + + if (static_cast<::std::size_t>(resolved) >= bufsz - 1u) [[unlikely]] + { + throw_posix_error(ENAMETOOLONG); + } + + buf[resolved] = '\0'; + +#else + throw_posix_error(ENOTSUP); +#endif +} + + inline pid_t posix_fork() { @@ -481,7 +636,7 @@ struct fd_remapper // only used in vfork_execveat_common_impl() inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, int volatile &t_errno, process_mode mode) noexcept { - // vfork can only be called through libc wrapper + // vfork can only be called through libc wrapper pid = ::fast_io::posix::libc_vfork(); if (pid == -1) [[unlikely]] { @@ -627,7 +782,10 @@ inline void kill(posix_process_observer ppob, posix_wait_status exit_code) #if defined(__linux__) && defined(__NR_kill) system_call_throw_error(system_call<__NR_kill, int>(ppob.pid, exit_code.wait_loc)); #else - system_call_throw_error(::fast_io::posix::libc_kill(ppob.pid, exit_code.wait_loc)); + if(::fast_io::posix::libc_kill(ppob.pid, exit_code.wait_loc) == -1) [[unlikely]] + { + throw_posix_error(); + } #endif } diff --git a/include/fast_io_hosted/timeutil/time.h b/include/fast_io_hosted/timeutil/time.h index b13b47026..5910bd58a 100644 --- a/include/fast_io_hosted/timeutil/time.h +++ b/include/fast_io_hosted/timeutil/time.h @@ -739,11 +739,11 @@ inline struct tm unix_timestamp_to_tm_impl(::std::int_least64_t seconds) #if defined(__AVR__) if constexpr (local_tm) { - noexcept_call(localtime_r, __builtin_addressof(val), __builtin_addressof(t)); + noexcept_call(::localtime_r, __builtin_addressof(val), __builtin_addressof(t)); } else { - noexcept_call(gmtime_r, __builtin_addressof(val), __builtin_addressof(t)); + noexcept_call(::gmtime_r, __builtin_addressof(val), __builtin_addressof(t)); } #elif defined(__MSDOS__) if constexpr (local_tm) @@ -763,14 +763,14 @@ inline struct tm unix_timestamp_to_tm_impl(::std::int_least64_t seconds) #else if constexpr (local_tm) { - if (localtime_r(__builtin_addressof(val), __builtin_addressof(t)) == 0) + if (::fast_io::noexcept_call(::localtime_r, __builtin_addressof(val), __builtin_addressof(t)) == 0) { throw_posix_error(); } } else { - if (gmtime_r(__builtin_addressof(val), __builtin_addressof(t)) == 0) + if (::fast_io::noexcept_call(::gmtime_r, __builtin_addressof(val), __builtin_addressof(t)) == 0) { throw_posix_error(); } From e9f5daf119e73fc450eaeb5dee9c3e172fcb1289 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 00:13:03 +0800 Subject: [PATCH 04/43] Refactor thread start routine declaration and improve error handling in POSIX headers - Updated `thread_start_routine` in both NT and Win32 headers to include `FAST_IO_WINSTDCALL` for better calling convention compatibility. - Enhanced error handling in `get_module_install_path_from_argv0` by checking for a null environment path and throwing an appropriate error. - Improved readability by initializing pointers to empty and using consistent formatting in the `argv0.h` file. - Adjusted conditional compilation checks in `posix.h` for clearer handling of open mode flags. --- include/fast_io_driver/install_path/argv0.h | 17 ++++++++++++----- include/fast_io_hosted/platforms/posix.h | 2 +- include/fast_io_hosted/threads/thread/nt.h | 2 +- include/fast_io_hosted/threads/thread/win32.h | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/fast_io_driver/install_path/argv0.h b/include/fast_io_driver/install_path/argv0.h index 6102d1a10..3849fc0de 100644 --- a/include/fast_io_driver/install_path/argv0.h +++ b/include/fast_io_driver/install_path/argv0.h @@ -66,7 +66,7 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, PATH_MAX + 256); ::fast_io::noexcept_call(::strncat, newpath2, argv0, PATH_MAX + 256); [[maybe_unused]] auto const unused2{::fast_io::noexcept_call(::realpath, newpath2, newpath)}; - if (auto status{::fast_io::noexcept_call(::access, newpath, F_OK)};!status) + if (auto status{::fast_io::noexcept_call(::access, newpath, F_OK)}; !status) { newpath[PATH_MAX - 1] = 0; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); @@ -91,10 +91,17 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar } else { - char *saveptr; - char *pathitem; - char *save_path{::fast_io::noexcept_call(::getenv, "PATH")}; - for (pathitem = ::fast_io::noexcept_call(::strtok_r, save_path, path_list_separator, &saveptr); pathitem; + char *saveptr{}; + char *pathitem{}; + char const *env_path{::fast_io::noexcept_call(::getenv, "PATH")}; + if (!env_path) [[unlikely]] + { + throw_posix_error(EINVAL); + } + char pathbuf[PATH_MAX + 256 + 1]{}; + ::fast_io::noexcept_call(::strncpy, pathbuf, env_path, PATH_MAX + 256); + + for (pathitem = ::fast_io::noexcept_call(::strtok_r, pathbuf, path_list_separator, &saveptr); pathitem; pathitem = ::fast_io::noexcept_call(::strtok_r, nullptr, path_list_separator, &saveptr)) { ::fast_io::noexcept_call(::strncpy, newpath2, pathitem, PATH_MAX + 256); diff --git a/include/fast_io_hosted/platforms/posix.h b/include/fast_io_hosted/platforms/posix.h index d5172e89b..dceeee6be 100644 --- a/include/fast_io_hosted/platforms/posix.h +++ b/include/fast_io_hosted/platforms/posix.h @@ -194,7 +194,7 @@ inline constexpr int calculate_posix_open_mode(open_mode value) noexcept if ((value & open_mode::inherit) == open_mode::none) #ifdef O_CLOEXEC mode |= O_CLOEXEC; -#elif _O_NOINHERIT +#elif defined(_O_NOINHERIT) mode |= _O_NOINHERIT; #endif #ifdef O_BINARY diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index ffe9a10a9..45a0cb4b0 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -38,7 +38,7 @@ class nt_thread_start_routine_tuple_allocate_guard }; template -constexpr ::std::uint_least32_t thread_start_routine(void *args) noexcept(noexcept( +constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept( ::std::invoke(::fast_io::get(*reinterpret_cast(args))...))) { [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _(args); diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 4498d8971..6c8d85543 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -38,7 +38,7 @@ class win32_thread_start_routine_tuple_allocate_guard }; template -constexpr ::std::uint_least32_t thread_start_routine(void *args) noexcept(noexcept( +constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept( ::std::invoke(::fast_io::get(*reinterpret_cast(args))...))) { [[maybe_unused]] ::fast_io::win32::details::win32_thread_start_routine_tuple_allocate_guard _(args); From c986bc1d9f632411bdb5c18ad860be6dbaff1f3d Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 00:33:23 +0800 Subject: [PATCH 05/43] Refactor `get` function signatures in tuple.h for improved type deduction - Updated `get` function signatures to return `auto&&` instead of `decltype(auto)` for better type handling. - Enhanced consistency across all overloads of `get` by applying uniform return types. - Minor adjustments made to improve readability and maintainability of the code. --- include/fast_io_dsal/impl/tuple.h | 16 ++++++++-------- include/fast_io_hosted/platforms/posix.h | 4 ++-- include/fast_io_hosted/platforms/win32.h | 4 ++++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/fast_io_dsal/impl/tuple.h b/include/fast_io_dsal/impl/tuple.h index 1a0a19dfb..33a1c9cdc 100644 --- a/include/fast_io_dsal/impl/tuple.h +++ b/include/fast_io_dsal/impl/tuple.h @@ -96,7 +96,7 @@ tuple(Args &&...) -> tuple; template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple &self) noexcept + constexpr auto&& get(::fast_io::containers::tuple &self) noexcept { return static_cast<::fast_io::containers::details::tuple_element_impl_> &>(self).val_; } @@ -104,7 +104,7 @@ FAST_IO_GNU_ALWAYS_INLINE template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple const &self) noexcept + constexpr auto&& get(::fast_io::containers::tuple const &self) noexcept { return static_cast<::fast_io::containers::details::tuple_element_impl_> const &>(self).val_; } @@ -112,7 +112,7 @@ FAST_IO_GNU_ALWAYS_INLINE template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple &&self) noexcept + constexpr auto&& get(::fast_io::containers::tuple &&self) noexcept { return ::std::move( static_cast<::fast_io::containers::details::tuple_element_impl_> &&>(self).val_); @@ -121,7 +121,7 @@ FAST_IO_GNU_ALWAYS_INLINE template <::std::size_t I, typename... Args> FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple const &&self) noexcept + constexpr auto&& get(::fast_io::containers::tuple const &&self) noexcept { return ::std::move( static_cast<::fast_io::containers::details::tuple_element_impl_> const &&>(self).val_); @@ -149,7 +149,7 @@ template requires((::std::same_as + ...) == 1) FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple const &self) noexcept + constexpr auto&& get(::fast_io::containers::tuple const &self) noexcept { return static_cast())::type const &>(self).val_; } @@ -158,7 +158,7 @@ template requires((::std::same_as + ...) == 1) FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple const &&self) noexcept + constexpr auto&& get(::fast_io::containers::tuple const &&self) noexcept { return ::std::move( static_cast())::type const &&>(self).val_); @@ -168,7 +168,7 @@ template requires((::std::same_as + ...) == 1) FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple &self) noexcept + constexpr auto&& get(::fast_io::containers::tuple &self) noexcept { return static_cast())::type const &>(self).val_; } @@ -177,7 +177,7 @@ template requires((::std::same_as + ...) == 1) FAST_IO_GNU_ALWAYS_INLINE [[nodiscard]] - constexpr decltype(auto) get(::fast_io::containers::tuple &&self) noexcept + constexpr auto&& get(::fast_io::containers::tuple &&self) noexcept { return ::std::move( static_cast())::type const &&>(self).val_); diff --git a/include/fast_io_hosted/platforms/posix.h b/include/fast_io_hosted/platforms/posix.h index dceeee6be..12d6e5537 100644 --- a/include/fast_io_hosted/platforms/posix.h +++ b/include/fast_io_hosted/platforms/posix.h @@ -1448,7 +1448,7 @@ inline void posix_truncate_impl(int fd, ::fast_io::uintfpos_t size) auto err(noexcept_call(_chsize_s, fd, static_cast<::std::int_least64_t>(size))); if (err) { - throw_posix_error(err); + throw_posix_error(); } #else if (size > ::std::numeric_limits::max()) @@ -1458,7 +1458,7 @@ inline void posix_truncate_impl(int fd, ::fast_io::uintfpos_t size) auto err(noexcept_call(_chsize, fd, static_cast(size))); if (err) { - throw_posix_error(err); + throw_posix_error(); } #endif diff --git a/include/fast_io_hosted/platforms/win32.h b/include/fast_io_hosted/platforms/win32.h index 3167656ff..7ac88c0de 100644 --- a/include/fast_io_hosted/platforms/win32.h +++ b/include/fast_io_hosted/platforms/win32.h @@ -115,6 +115,10 @@ inline void *create_win32_temp_file_impl() { throw_win32_error(); } + if (temp_path_size > 122 /*ERROR_INSUFFICIENT_BUFFER*/) [[unlikely]] + { + throw_win32_error(ERROR_INVALID_PARAMETER); + } auto arrp{arr + temp_path_size}; constexpr bool winver_support_rtl_gen_random{ #if !defined(_WIN32_WINDOWS) && (!defined(_WIN32_WINNT) || _WIN32_WINNT >= 0x0501) From 8102ddcec9467ef0a0abe450e2e1fb82fa5ff1e2 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 00:35:44 +0800 Subject: [PATCH 06/43] f --- include/fast_io_hosted/platforms/win32.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_io_hosted/platforms/win32.h b/include/fast_io_hosted/platforms/win32.h index 7ac88c0de..28760ecc3 100644 --- a/include/fast_io_hosted/platforms/win32.h +++ b/include/fast_io_hosted/platforms/win32.h @@ -115,9 +115,9 @@ inline void *create_win32_temp_file_impl() { throw_win32_error(); } - if (temp_path_size > 122 /*ERROR_INSUFFICIENT_BUFFER*/) [[unlikely]] + if (temp_path_size > maximum_temp_path_size) [[unlikely]] { - throw_win32_error(ERROR_INVALID_PARAMETER); + throw_win32_error(122/*ERROR_INSUFFICIENT_BUFFER*/); } auto arrp{arr + temp_path_size}; constexpr bool winver_support_rtl_gen_random{ From d88268e0ef87d08e92373d7edf1486a138f1be48 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 00:51:57 +0800 Subject: [PATCH 07/43] Enhance error handling and improve path resolution in module installation functions - Added error checks for null pointers and buffer overflows in `get_module_install_path_from_argv0` to ensure robust path resolution. - Updated `get_module_install_path` to handle `sysctl` errors more accurately. - Replaced direct system calls with `noexcept_call` for safer error management across various platform headers. - Improved readability and maintainability by standardizing error handling and function calls. --- include/fast_io_driver/install_path/argv0.h | 73 ++++++++++++++++----- include/fast_io_driver/install_path/bsd.h | 2 +- include/fast_io_driver/install_path/linux.h | 10 ++- include/fast_io_hosted/filesystem/dos.h | 10 +-- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/include/fast_io_driver/install_path/argv0.h b/include/fast_io_driver/install_path/argv0.h index 3849fc0de..6401b1096 100644 --- a/include/fast_io_driver/install_path/argv0.h +++ b/include/fast_io_driver/install_path/argv0.h @@ -3,6 +3,7 @@ #include #include #include +#include #ifndef PATH_MAX #define PATH_MAX 4096 @@ -36,10 +37,13 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar char path_list_separator[8] = ":"; // could be ":; " if (argv0[0] == path_separator) { - [[maybe_unused]] auto const unused1{::fast_io::noexcept_call(::realpath, argv0, newpath)}; - if (auto status{::fast_io::noexcept_call(::access, newpath, F_OK)}; !status) + char *rp{::fast_io::noexcept_call(::realpath, argv0, newpath)}; + if (!rp) [[unlikely]] + { + throw_posix_error(); + } + if (::fast_io::noexcept_call(::access, newpath, F_OK) == 0) { - newpath[PATH_MAX - 1] = 0; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); auto const begin{strlike_begin(::fast_io::io_strlike_type, ret.module_name)}; auto curr{strlike_curr(::fast_io::io_strlike_type, ret.module_name)}; @@ -62,13 +66,34 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar } else if (__builtin_strchr(argv0, static_cast(path_separator))) { - [[maybe_unused]] auto const unused1{::fast_io::noexcept_call(::getcwd, newpath2, PATH_MAX)}; - ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, PATH_MAX + 256); - ::fast_io::noexcept_call(::strncat, newpath2, argv0, PATH_MAX + 256); - [[maybe_unused]] auto const unused2{::fast_io::noexcept_call(::realpath, newpath2, newpath)}; - if (auto status{::fast_io::noexcept_call(::access, newpath, F_OK)}; !status) + if (!::fast_io::noexcept_call(::getcwd, newpath2, PATH_MAX)) [[unlikely]] + { + throw_posix_error(); + } + { + auto const used1{::std::strlen(newpath2)}; + if (used1 + 1 >= sizeof(newpath2)) [[unlikely]] + { + throw_posix_error(ERANGE); + } + ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, sizeof(newpath2) - used1 - 1); + } + { + auto const used2{::std::strlen(newpath2)}; + auto const add2{::std::strlen(argv0)}; + if (used2 + add2 >= sizeof(newpath2)) [[unlikely]] + { + throw_posix_error(ERANGE); + } + ::fast_io::noexcept_call(::strncat, newpath2, argv0, sizeof(newpath2) - used2 - 1); + } + char *rp2{::fast_io::noexcept_call(::realpath, newpath2, newpath)}; + if (!rp2) [[unlikely]] + { + throw_posix_error(); + } + if (::fast_io::noexcept_call(::access, newpath, F_OK) == 0) { - newpath[PATH_MAX - 1] = 0; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); auto const begin{strlike_begin(::fast_io::io_strlike_type, ret.module_name)}; auto curr{strlike_curr(::fast_io::io_strlike_type, ret.module_name)}; @@ -84,10 +109,7 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar ret.module_name.erase(begin, curr); return ret; } - else - { - throw_posix_error(status); - } + throw_posix_error(); } else { @@ -100,17 +122,32 @@ inline ::fast_io::install_path get_module_install_path_from_argv0(char const *ar } char pathbuf[PATH_MAX + 256 + 1]{}; ::fast_io::noexcept_call(::strncpy, pathbuf, env_path, PATH_MAX + 256); + pathbuf[PATH_MAX + 256] = 0; for (pathitem = ::fast_io::noexcept_call(::strtok_r, pathbuf, path_list_separator, &saveptr); pathitem; pathitem = ::fast_io::noexcept_call(::strtok_r, nullptr, path_list_separator, &saveptr)) { ::fast_io::noexcept_call(::strncpy, newpath2, pathitem, PATH_MAX + 256); - ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, PATH_MAX + 256); - ::fast_io::noexcept_call(::strncat, newpath2, argv0, PATH_MAX + 256); - [[maybe_unused]] auto const unused1{::realpath(newpath2, newpath)}; - if (!::fast_io::noexcept_call(::access, newpath, F_OK)) { - newpath[PATH_MAX - 1] = 0; + auto const used1{::std::strlen(newpath2)}; + if (used1 + 1 >= sizeof(newpath2)) [[unlikely]] + { + continue; + } + ::fast_io::noexcept_call(::strncat, newpath2, path_separator_as_string, sizeof(newpath2) - used1 - 1); + } + { + auto const used2{::std::strlen(newpath2)}; + auto const add2{::std::strlen(argv0)}; + if (used2 + add2 >= sizeof(newpath2)) [[unlikely]] + { + continue; + } + ::fast_io::noexcept_call(::strncat, newpath2, argv0, sizeof(newpath2) - used2 - 1); + } + char *rp{::fast_io::noexcept_call(::realpath, newpath2, newpath)}; + if (rp && ::fast_io::noexcept_call(::access, newpath, F_OK) == 0) + { ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt_os_c_str(newpath)); auto const begin{strlike_begin(::fast_io::io_strlike_type, ret.module_name)}; auto curr{strlike_curr(::fast_io::io_strlike_type, ret.module_name)}; diff --git a/include/fast_io_driver/install_path/bsd.h b/include/fast_io_driver/install_path/bsd.h index 0af531bc0..a0615fef5 100644 --- a/include/fast_io_driver/install_path/bsd.h +++ b/include/fast_io_driver/install_path/bsd.h @@ -36,7 +36,7 @@ inline ::fast_io::install_path get_module_install_path() #endif ::std::size_t size{PATH_MAX}; - if (auto status{::fast_io::noexcept_call(::sysctl, mib, 4, buffer1, __builtin_addressof(size), nullptr, 0)}; !status) [[unlikely]] + if (auto status{::fast_io::noexcept_call(::sysctl, mib, 4, buffer1, __builtin_addressof(size), nullptr, 0)}; status == -1) [[unlikely]] { throw_posix_error(); } diff --git a/include/fast_io_driver/install_path/linux.h b/include/fast_io_driver/install_path/linux.h index 20c97841c..f42f71692 100644 --- a/include/fast_io_driver/install_path/linux.h +++ b/include/fast_io_driver/install_path/linux.h @@ -19,13 +19,19 @@ namespace fast_io::details #endif inline ::fast_io::install_path get_module_install_path() { - char buffer[PATH_MAX + 1]; + constexpr ::std::size_t path_max{::std::max<::std::size_t>(PATH_MAX, 4096u)}; + + char buffer[path_max + 1]; ::fast_io::install_path ret; using my_ssize_t = ::std::make_signed_t<::std::size_t>; #if defined(__linux__) && defined(__NR_readlink) - auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>("/proc/self/exe", buffer, PATH_MAX)}; + auto resolved{::fast_io::system_call<__NR_readlink, my_ssize_t>("/proc/self/exe", buffer, path_max)}; system_call_throw_error(resolved); + if (static_cast<::std::size_t>(resolved) >= path_max) + { + throw_posix_error(ERANGE); + } buffer[resolved] = '\0'; ret.module_name = ::fast_io::u8concat_fast_io(::fast_io::mnp::code_cvt(::fast_io::mnp::os_c_str_with_known_size(buffer, resolved))); #else diff --git a/include/fast_io_hosted/filesystem/dos.h b/include/fast_io_hosted/filesystem/dos.h index e1f3dfcc6..8159c9570 100644 --- a/include/fast_io_hosted/filesystem/dos.h +++ b/include/fast_io_hosted/filesystem/dos.h @@ -340,7 +340,7 @@ inline dos_directory_iterator &operator++(dos_directory_iterator &pdit) To fix: avoid setting errno */ errno = 0; - auto entry{readdir(pdit.dirp.dirp)}; + auto entry{::fast_io::noexcept_call(::readdir, pdit.dirp.dirp)}; auto en{errno}; if (entry == nullptr && en) { @@ -365,7 +365,7 @@ inline dos_directory_iterator &operator++(dos_directory_iterator &pdit) inline dos_directory_iterator begin(posix_directory_generator const &pdg) { auto dirp{pdg.dir_fl.dirp.dirp}; - ::rewinddir(dirp); + ::fast_io::noexcept_call(::rewinddir, dirp); dos_directory_iterator pdit{dirp}; ++pdit; return pdit; @@ -445,7 +445,7 @@ inline basic_dos_recursive_directory_iterator &operator++(basic_dos_r errno = 0; if (prdit.stack.empty()) { - auto entry{readdir(prdit.dirp.dirp)}; + auto entry{::fast_io::noexcept_call(::readdir, prdit.dirp.dirp)}; if (entry == nullptr) { auto en{errno}; @@ -460,7 +460,7 @@ inline basic_dos_recursive_directory_iterator &operator++(basic_dos_r } else { - auto entry = readdir(prdit.stack.back().dirp.dirp); + auto entry = ::fast_io::noexcept_call(::readdir, prdit.stack.back().dirp.dirp); if (entry == nullptr) { auto en{errno}; @@ -524,7 +524,7 @@ inline void pop(basic_dos_recursive_directory_iterator &prdit) noexce template inline basic_dos_recursive_directory_iterator begin(basic_posix_recursive_directory_generator const &pdg) { - ::rewinddir(pdg.dir_fl.dirp.dirp); + ::fast_io::noexcept_call(::rewinddir, pdg.dir_fl.dirp.dirp); basic_dos_recursive_directory_iterator pdit{pdg.dir_fl.dirp}; ++pdit; return pdit; From c5c1b520fb43e6d202648d1f18972fbe33b6ffde Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 01:16:16 +0800 Subject: [PATCH 08/43] Enhance Android logger functionality with noexcept specifier - Updated function signatures in `android.h` to include `noexcept` for improved safety and performance. - Refactored operator overloads and logging implementations to ensure exception safety during logging operations. - Improved code clarity and maintainability by standardizing function signatures across the Android logging interface. --- include/fast_io_hosted/dbg/android.h | 18 +++++++-------- include/fast_io_hosted/filesystem/dos_at.h | 2 +- include/fast_io_hosted/filesystem/posix_at.h | 24 ++++++++++++++++++-- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/include/fast_io_hosted/dbg/android.h b/include/fast_io_hosted/dbg/android.h index befd53cf4..e1f830b6c 100644 --- a/include/fast_io_hosted/dbg/android.h +++ b/include/fast_io_hosted/dbg/android.h @@ -167,18 +167,18 @@ inline void my_android_log_write_message_impl(android_logmessage_meta_v30 const struct my_android_log_write_common { android_logmessage_meta_base b{}; - inline void operator()(char const *text) + inline void operator()(char const *text) noexcept { my_android_log_write_impl(b.priority, b.tag, text); } }; -inline void android_logger_write_impl(android_logmessage_meta_base b, void const *base, ::std::size_t n) +inline void android_logger_write_impl(android_logmessage_meta_base b, void const *base, ::std::size_t n) noexcept { cstr_concat_write_impl(base, n, my_android_log_write_common{b}); } -inline void android_logger_writev_impl(android_logmessage_meta_base b, io_scatter_t const *first, ::std::size_t n) +inline void android_logger_writev_impl(android_logmessage_meta_base b, io_scatter_t const *first, ::std::size_t n) noexcept { cstr_concat_writev_impl(first, n, my_android_log_write_common{b}); } @@ -186,33 +186,33 @@ inline void android_logger_writev_impl(android_logmessage_meta_base b, io_scatte struct my_android_log_write_v30_common { android_logmessage_meta_v30 const *pmeta{}; - inline void operator()(char const *text) + inline void operator()(char const *text) noexcept { my_android_log_write_message_impl(pmeta, text); } }; -inline void android_logger_write_impl(android_logmessage_meta_v30 const &meta, void const *base, ::std::size_t n) +inline void android_logger_write_impl(android_logmessage_meta_v30 const &meta, void const *base, ::std::size_t n) noexcept { cstr_concat_write_impl(base, n, my_android_log_write_v30_common{__builtin_addressof(meta)}); } inline void android_logger_writev_impl(android_logmessage_meta_v30 const &meta, io_scatter_t const *first, - ::std::size_t n) + ::std::size_t n) noexcept { cstr_concat_writev_impl(first, n, my_android_log_write_v30_common{__builtin_addressof(meta)}); } } // namespace details template -inline void write(basic_android_family_logger const &b, Iter first, Iter last) +inline void write(basic_android_family_logger const &b, Iter first, Iter last) noexcept { ::fast_io::details::android_logger_write_impl(b.meta, ::std::to_address(first), static_cast<::std::size_t>(last - first) * sizeof(*first)); } template -inline void scatter_write(basic_android_family_logger const &b, io_scatters_t scatters) +inline void scatter_write(basic_android_family_logger const &b, io_scatters_t scatters) noexcept { ::fast_io::details::android_logger_writev_impl(b.meta, scatters.base, scatters.len); } @@ -223,7 +223,7 @@ namespace details { template <::std::integral char_type> -inline constexpr auto android_dbg_impl(::std::int_least32_t priorit, char const *tg, ::std::source_location const &loc) +inline constexpr auto android_dbg_impl(::std::int_least32_t priorit, char const *tg, ::std::source_location const &loc) noexcept { return basic_android_logger{.meta = {.priority = priorit, .tag = tg, diff --git a/include/fast_io_hosted/filesystem/dos_at.h b/include/fast_io_hosted/filesystem/dos_at.h index 158c8794c..1b180dd36 100644 --- a/include/fast_io_hosted/filesystem/dos_at.h +++ b/include/fast_io_hosted/filesystem/dos_at.h @@ -201,7 +201,7 @@ inline void dos_unlinkat_impl(int dirfd, char const *pathname) inline constexpr ::std::time_t unix_timestamp_to_time_t(unix_timestamp stmp) noexcept { - return static_cast(static_cast<::std::time_t>(stmp.seconds)); + return static_cast<::std::time_t>(stmp.seconds); } inline diff --git a/include/fast_io_hosted/filesystem/posix_at.h b/include/fast_io_hosted/filesystem/posix_at.h index 6467b97ad..5804f21d1 100644 --- a/include/fast_io_hosted/filesystem/posix_at.h +++ b/include/fast_io_hosted/filesystem/posix_at.h @@ -190,7 +190,17 @@ inline void posix_faccessat_impl(int dirfd, char const *pathname, int mode, int #if defined(__linux__) && defined(__NR_faccessat2) system_call_throw_error(system_call<__NR_faccessat2, int>(dirfd, pathname, mode, flags)); #elif defined(__linux__) && defined(__NR_faccessat) - system_call_throw_error(system_call<__NR_faccessat, int>(dirfd, pathname, mode)); + if (flags != 0) + { + if (::fast_io::posix::libc_faccessat(dirfd, pathname, mode, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } + } + else + { + system_call_throw_error(system_call<__NR_faccessat, int>(dirfd, pathname, mode)); + } #else if (::fast_io::posix::libc_faccessat(dirfd, pathname, mode, flags) == -1) [[unlikely]] { @@ -246,7 +256,17 @@ inline void posix_fchmodat_impl(int dirfd, char const *pathname, mode_t mode, in #if defined(__linux__) && defined(__NR_fchmodat2) system_call_throw_error(system_call<__NR_fchmodat2, int>(dirfd, pathname, mode, flags)); #elif defined(__linux__) && defined(__NR_fchmodat) - system_call_throw_error(system_call<__NR_fchmodat, int>(dirfd, pathname, mode)); + if (flags != 0) + { + if (::fast_io::posix::libc_fchmodat(dirfd, pathname, mode, flags) == -1) [[unlikely]] + { + throw_posix_error(); + } + } + else + { + system_call_throw_error(system_call<__NR_fchmodat, int>(dirfd, pathname, mode)); + } #else if (::fast_io::posix::libc_fchmodat(dirfd, pathname, mode, flags) == -1) [[unlikely]] { From d10b547775743aa01f938a333d1c75f78b9653a5 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 01:56:46 +0800 Subject: [PATCH 09/43] Enhance error handling and improve function signatures across platform headers - Added null pointer check in `is_invalid_dos_filename_with_size` to prevent crashes. - Refactored `zero_copy_transmit64_define` to streamline character transmission logic and improve performance. - Updated `try_lock` method in `posix_file_lock` to return a boolean indicating lock success. - Adjusted function signatures in various headers for consistency and clarity, including changes to `NtSetSystemTime` and `RtlAcquirePebLock`. - Improved error handling in `posix_seek_impl` to throw appropriate errors for overflow conditions. --- .../fast_io_hosted/platforms/dos_filename.h | 5 +++ .../fast_io_hosted/platforms/linux_zerocopy.h | 38 +++++++++---------- include/fast_io_hosted/platforms/nt/nt_api.h | 14 +++---- .../fast_io_hosted/platforms/path_dir_file.h | 2 +- include/fast_io_hosted/platforms/posix/seek.h | 32 ++++++++++------ include/fast_io_hosted/platforms/posix_dns.h | 1 + .../platforms/posix_file_lock.h | 4 +- include/fast_io_hosted/platforms/win32/apis.h | 8 ++-- .../platforms/win32_network/service.h | 8 +++- .../platforms/win32_network/socket_file.h | 15 +++++++- 10 files changed, 79 insertions(+), 48 deletions(-) diff --git a/include/fast_io_hosted/platforms/dos_filename.h b/include/fast_io_hosted/platforms/dos_filename.h index b890e339a..9da0b5689 100644 --- a/include/fast_io_hosted/platforms/dos_filename.h +++ b/include/fast_io_hosted/platforms/dos_filename.h @@ -4,6 +4,11 @@ namespace fast_io::details template <::std::integral char_type> inline constexpr bool is_invalid_dos_filename_with_size(char_type const *filename, ::std::size_t filename_size) noexcept { + if (filename == nullptr) [[unlikely]] + { + return true; + } + auto const os_str_filename_len{filename_size}; if (os_str_filename_len == 0) [[unlikely]] diff --git a/include/fast_io_hosted/platforms/linux_zerocopy.h b/include/fast_io_hosted/platforms/linux_zerocopy.h index 4907300bd..138369e23 100644 --- a/include/fast_io_hosted/platforms/linux_zerocopy.h +++ b/include/fast_io_hosted/platforms/linux_zerocopy.h @@ -120,32 +120,30 @@ inline ::std::uint_least64_t zero_copy_transmit64_define(io_alias_t, basic_linux ::std::uint_least64_t characters) { constexpr ::std::size_t input_char_type_size{sizeof(ch_type2)}; - if constexpr (input_char_type_size != 1) + if constexpr (input_char_type_size == 1) { - constexpr ::std::uint_least64_t mx{::std::numeric_limits<::std::uint_least64_t>::max() / input_char_type_size}; - ::std::uint_least64_t chars{}; - for (::std::size_t i{}; i != input_char_type_size; ++i) + return ::fast_io::details::zero_copy_transmit_define64_impl(outs.fd, ins.fd, characters); + } + else + { + constexpr ::std::uint_least64_t max_chars_per_round{ + ::std::numeric_limits<::std::uint_least64_t>::max() / input_char_type_size}; + ::std::uint_least64_t total_chars{}; + while (characters) { - bool const overflow_copy{characters > mx}; - ::std::uint_least64_t copy_this_round{characters}; - if (overflow_copy) [[unlikely]] - { - copy_this_round = mx; - } - chars += ::fast_io::details::zero_copy_transmit_define64_impl(io_alias, outs.fd, ins.fd, characters, - copy_this_round) / - sizeof(input_char_type_size); - if (!overflow_copy) [[likely]] + ::std::uint_least64_t this_round_chars{characters > max_chars_per_round ? max_chars_per_round : characters}; + ::std::uint_least64_t this_round_bytes{this_round_chars * static_cast<::std::uint_least64_t>(input_char_type_size)}; + ::std::uint_least64_t transferred_bytes{ + ::fast_io::details::zero_copy_transmit_define64_impl(outs.fd, ins.fd, this_round_bytes)}; + ::std::uint_least64_t transferred_chars{transferred_bytes / static_cast<::std::uint_least64_t>(input_char_type_size)}; + total_chars += transferred_chars; + if (transferred_chars < this_round_chars) { break; } - characters -= mx; + characters -= this_round_chars; } - return chars; - } - else - { - return ::fast_io::details::zero_copy_transmit_define64_impl(outs.fd, ins.fd, characters); + return total_chars; } } diff --git a/include/fast_io_hosted/platforms/nt/nt_api.h b/include/fast_io_hosted/platforms/nt/nt_api.h index 52d7b7b34..52e6c8c9a 100644 --- a/include/fast_io_hosted/platforms/nt/nt_api.h +++ b/include/fast_io_hosted/platforms/nt/nt_api.h @@ -32,8 +32,8 @@ FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtDuplicateObject(voi FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwDuplicateObject(void *, void *, void *, void **, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(ZwDuplicateObject, 28); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtWaitForSingleObject(void *, int, ::std::uint_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtWaitForSingleObject, 12); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwWaitForSingleObject(void *, int, ::std::uint_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwWaitForSingleObject, 12); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtSetSystemTime(::std::uint_least64_t *, ::std::uint_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtSetSystemTime, 8); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwSetSystemTime(::std::uint_least64_t *, ::std::uint_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwSetSystemTime, 8); +FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtSetSystemTime(::std::int_least64_t *, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtSetSystemTime, 8); +FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwSetSystemTime(::std::int_least64_t *, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwSetSystemTime, 8); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtCreateProcess(void **, ::std::uint_least32_t, ::fast_io::win32::nt::object_attributes *, void *, ::std::uint_least32_t, void *, void *, void *) noexcept FAST_IO_WINSTDCALL_RENAME(NtCreateProcess, 32); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwCreateProcess(void **, ::std::uint_least32_t, ::fast_io::win32::nt::object_attributes *, void *, ::std::uint_least32_t, void *, void *, void *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwCreateProcess, 32); FAST_IO_DLLIMPORT char unsigned FAST_IO_WINSTDCALL rtl_dos_path_name_to_nt_path_name_u(char16_t const *, ::fast_io::win32::nt::unicode_string *, char16_t const **, ::fast_io::win32::nt::rtl_relative_name_u *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlDosPathNameToNtPathName_U, 16); @@ -71,18 +71,18 @@ FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtReadVirtualMemory(v FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwReadVirtualMemory(void *, void *, void *, ::std::size_t, ::std::size_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwReadVirtualMemory, 20); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtWriteVirtualMemory(void *, void *, void *, ::std::size_t, ::std::size_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtWriteVirtualMemory, 20); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwWriteVirtualMemory(void *, void *, void *, ::std::size_t, ::std::size_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwWriteVirtualMemory, 20); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlAcquirePebLock() noexcept FAST_IO_WINSTDCALL_RENAME(RtlAcquirePebLock, 0); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlReleasePebLock() noexcept FAST_IO_WINSTDCALL_RENAME(RtlReleasePebLock, 0); +FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlAcquirePebLock() noexcept FAST_IO_WINSTDCALL_RENAME(RtlAcquirePebLock, 0); +FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlReleasePebLock() noexcept FAST_IO_WINSTDCALL_RENAME(RtlReleasePebLock, 0); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtAllocateVirtualMemory(void *, void **, ::std::size_t, ::std::size_t *, ::std::uint_least32_t, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(NtAllocateVirtualMemory, 24); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwAllocateVirtualMemory(void *, void **, ::std::size_t, ::std::size_t *, ::std::uint_least32_t, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(ZwAllocateVirtualMemory, 24); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtFreeVirtualMemory(void *, void **, ::std::size_t *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(NtFreeVirtualMemory, 16); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwFreeVirtualMemory(void *, void **, ::std::size_t *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(ZwFreeVirtualMemory, 16); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlInitUnicodeString(::fast_io::win32::nt::unicode_string *, char16_t *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlInitUnicodeString, 8); +FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlInitUnicodeString(::fast_io::win32::nt::unicode_string *, char16_t *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlInitUnicodeString, 8); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL CsrClientCallServer(void *, void *, ::std::uint_least32_t, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(CsrClientCallServer, 16); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtQuerySystemInformation(::fast_io::win32::nt::system_information_class, void *, ::std::uint_least32_t, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtQuerySystemInformation, 16); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwQuerySystemInformation(::fast_io::win32::nt::system_information_class, void *, ::std::uint_least32_t, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwQuerySystemInformation, 16); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlAcquireSRWLockExclusive(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlAcquireSRWLockExclusive, 4); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlTryAcquireSRWLockExclusive(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlTryAcquireSRWLockExclusive, 4); +FAST_IO_DLLIMPORT ::std::uint_least8_t FAST_IO_WINSTDCALL RtlTryAcquireSRWLockExclusive(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlTryAcquireSRWLockExclusive, 4); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlReleaseSRWLockExclusive(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlReleaseSRWLockExclusive, 4); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtQueryVolumeInformationFile(void *__restrict, ::fast_io::win32::nt::io_status_block *__restrict, void *__restrict, ::std::uint_least32_t, ::fast_io::win32::nt::fs_information_class) noexcept FAST_IO_WINSTDCALL_RENAME(NtQueryVolumeInformationFile, 20); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwQueryVolumeInformationFile(void *__restrict, ::fast_io::win32::nt::io_status_block *__restrict, void *__restrict, ::std::uint_least32_t, ::fast_io::win32::nt::fs_information_class) noexcept FAST_IO_WINSTDCALL_RENAME(ZwQueryVolumeInformationFile, 20); @@ -92,7 +92,7 @@ FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtCreateNamedPipeFile FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwCreateNamedPipeFile(void **__restrict, ::std::uint_least32_t, ::fast_io::win32::nt::object_attributes *__restrict, ::fast_io::win32::nt::io_status_block *__restrict, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwCreateNamedPipeFile, 56); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtQueryPerformanceCounter(::std::int_least64_t *, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtQueryPerformanceCounter, 8); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwQueryPerformanceCounter(::std::int_least64_t *, ::std::int_least64_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwQueryPerformanceCounter, 8); -FAST_IO_DLLIMPORT ::std::int_least64_t FAST_IO_WINSTDCALL RtlGetSystemTimePrecise() noexcept FAST_IO_WINSTDCALL_RENAME(RtlGetSystemTimePrecise, 0); +FAST_IO_DLLIMPORT ::std::uint_least64_t FAST_IO_WINSTDCALL RtlGetSystemTimePrecise() noexcept FAST_IO_WINSTDCALL_RENAME(RtlGetSystemTimePrecise, 0); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtQueryInformationThread(void *__restrict, ::fast_io::win32::nt::thread_information_class, void *, ::std::uint_least32_t, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtQueryInformationThread, 20); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwQueryInformationThread(void *__restrict, ::fast_io::win32::nt::thread_information_class, void *, ::std::uint_least32_t, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwQueryInformationThread, 20); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlAdjustPrivilege(::std::uint_least32_t, ::std::uint_least8_t, ::std::uint_least8_t, ::std::uint_least8_t *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlAdjustPrivilege, 16); // TODO can the first param be `::fast_io::win32::nt::privileges`? diff --git a/include/fast_io_hosted/platforms/path_dir_file.h b/include/fast_io_hosted/platforms/path_dir_file.h index a9219b2a5..7e299ef56 100644 --- a/include/fast_io_hosted/platforms/path_dir_file.h +++ b/include/fast_io_hosted/platforms/path_dir_file.h @@ -19,7 +19,7 @@ class basic_path_dir_file char8_t const *directory_path_buffer{}; ::std::size_t directory_path_length{}; - inline explicit constexpr basic_path_dir_file() noexcept + inline explicit constexpr basic_path_dir_file() noexcept {} basic_path_dir_file(basic_path_dir_file const &) = delete; inline basic_path_dir_file &operator=(basic_path_dir_file const &) = delete; diff --git a/include/fast_io_hosted/platforms/posix/seek.h b/include/fast_io_hosted/platforms/posix/seek.h index 1d22fe2ff..02afbde21 100644 --- a/include/fast_io_hosted/platforms/posix/seek.h +++ b/include/fast_io_hosted/platforms/posix/seek.h @@ -12,7 +12,7 @@ inline ::fast_io::intfpos_t posix_seek_impl(int fd, ::fast_io::intfpos_t offset, if (offset < static_cast<::fast_io::intfpos_t>(::std::numeric_limits::min()) || offset > static_cast<::fast_io::intfpos_t>(::std::numeric_limits::max())) { - throw_posix_error(EINVAL); + throw_posix_error(EOVERFLOW); } } auto ret{noexcept_call(::lseek, fd, static_cast(offset), static_cast(s))}; @@ -37,7 +37,7 @@ inline ::fast_io::intfpos_t posix_seek_impl(int fd, ::fast_io::intfpos_t offset, else #endif { - if constexpr (sizeof(off_t) <= sizeof(::std::int_least32_t)) + if constexpr (sizeof(off_t) < sizeof(::fast_io::intfpos_t)) { if (offset < static_cast<::fast_io::intfpos_t>(::std::numeric_limits::min()) || offset > static_cast<::fast_io::intfpos_t>(::std::numeric_limits::max())) @@ -49,8 +49,24 @@ inline ::fast_io::intfpos_t posix_seek_impl(int fd, ::fast_io::intfpos_t offset, system_call_throw_error(ret); return static_cast<::fast_io::intfpos_t>(static_cast<::std::uint_least64_t>(ret)); } +#elif (defined(_WIN32) && !defined(__WINE__) && !defined(__BIONIC__)) && !defined(__CYGWIN__) + if constexpr (sizeof(::std::int_least64_t) < sizeof(::fast_io::intfpos_t)) + { + if (offset < static_cast<::fast_io::intfpos_t>(::std::numeric_limits<::std::int_least64_t>::min()) || + offset > static_cast<::fast_io::intfpos_t>(::std::numeric_limits<::std::int_least64_t>::max())) + { + throw_posix_error(EOVERFLOW); + } + } + auto ret(::fast_io::noexcept_call(::_lseeki64, fd, static_cast<::std::int_least64_t>(offset), static_cast(s))); + if (ret == -1) [[unlikely]] + { + throw_posix_error(); + } + return static_cast<::fast_io::intfpos_t>(static_cast<::std::uint_least64_t>(ret)); + #else - if constexpr (sizeof(off_t) <= sizeof(::std::int_least32_t)) + if constexpr (sizeof(off_t) < sizeof(::fast_io::intfpos_t)) { if (offset < static_cast<::fast_io::intfpos_t>(::std::numeric_limits::min()) || offset > static_cast<::fast_io::intfpos_t>(::std::numeric_limits::max())) @@ -58,14 +74,8 @@ inline ::fast_io::intfpos_t posix_seek_impl(int fd, ::fast_io::intfpos_t offset, throw_posix_error(EOVERFLOW); } } - auto ret( -#if (defined(_WIN32) && !defined(__WINE__) && !defined(__BIONIC__)) && !defined(__CYGWIN__) - ::_lseeki64 -#else - ::lseek -#endif - (fd, static_cast(offset), static_cast(s))); - if(ret == -1) [[unlikely]] + auto ret(::fast_io::noexcept_call(::lseek, fd, static_cast(offset), static_cast(s))); + if (ret == -1) [[unlikely]] { throw_posix_error(); } diff --git a/include/fast_io_hosted/platforms/posix_dns.h b/include/fast_io_hosted/platforms/posix_dns.h index c62471106..c07acfe7b 100644 --- a/include/fast_io_hosted/platforms/posix_dns.h +++ b/include/fast_io_hosted/platforms/posix_dns.h @@ -138,6 +138,7 @@ inline posix_addrinfo *my_getaddrinfo_impl(char const *node, char const *service int ec{libc_getaddrinfo(node, service, hints, __builtin_addressof(res))}; if (ec) { + // EAL* error throw_posix_error(ec); } return res; diff --git a/include/fast_io_hosted/platforms/posix_file_lock.h b/include/fast_io_hosted/platforms/posix_file_lock.h index c44a9ac16..54a285092 100644 --- a/include/fast_io_hosted/platforms/posix_file_lock.h +++ b/include/fast_io_hosted/platforms/posix_file_lock.h @@ -137,9 +137,9 @@ struct posix_file_lock ::fast_io::details::posix_file_lock_unlock_impl(this->fd, t); } template <::std::integral int_type> - inline void try_lock(basic_flock_request const &__restrict t) + inline bool try_lock(basic_flock_request const &__restrict t) noexcept { - ::fast_io::details::posix_file_lock_lock_impl(this->fd, t); + return ::fast_io::details::posix_file_lock_try_lock_impl(this->fd, t); } }; diff --git a/include/fast_io_hosted/platforms/win32/apis.h b/include/fast_io_hosted/platforms/win32/apis.h index 7439d8dc3..186db554a 100644 --- a/include/fast_io_hosted/platforms/win32/apis.h +++ b/include/fast_io_hosted/platforms/win32/apis.h @@ -51,7 +51,7 @@ FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL SystemFunction036(void *, ::std::uint_l FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL CloseHandle(void *) noexcept FAST_IO_WINSTDCALL_RENAME(CloseHandle, 4); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL LockFileEx(void *, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::fast_io::win32::overlapped *) noexcept FAST_IO_WINSTDCALL_RENAME(LockFileEx, 24); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL UnlockFileEx(void *, ::std::uint_least32_t, ::std::uint_least32_t, ::std::uint_least32_t, ::fast_io::win32::overlapped *) noexcept FAST_IO_WINSTDCALL_RENAME(UnlockFileEx, 20); -FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL DeviceIoControl(void *, ::std::uint_least32_t, void *, ::std::uint_least32_t, void *, ::std::uint_least32_t, void *, ::fast_io::win32::overlapped *) noexcept FAST_IO_WINSTDCALL_RENAME(DeviceIoControl, 32); +FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL DeviceIoControl(void *, ::std::uint_least32_t, void *, ::std::uint_least32_t, void *, ::std::uint_least32_t, ::std::uint_least32_t *, ::fast_io::win32::overlapped *) noexcept FAST_IO_WINSTDCALL_RENAME(DeviceIoControl, 32); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetFileType(void *) noexcept FAST_IO_WINSTDCALL_RENAME(GetFileType, 4); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetACP() noexcept FAST_IO_WINSTDCALL_RENAME(GetACP, 0); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetEnvironmentVariableA(char const *, char *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetEnvironmentVariableA, 12); @@ -73,8 +73,8 @@ FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL EnterCriticalSection(void *) noexcept FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL TryEnterCriticalSection(void *) noexcept FAST_IO_WINSTDCALL_RENAME(TryEnterCriticalSection, 4); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL LeaveCriticalSection(void *) noexcept FAST_IO_WINSTDCALL_RENAME(LeaveCriticalSection, 4); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL DeleteCriticalSection(void *) noexcept FAST_IO_WINSTDCALL_RENAME(DeleteCriticalSection, 4); -FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSADuplicateSocketA(void *, ::std::uint_least32_t, ::fast_io::win32::wsaprotocol_infoa *) noexcept FAST_IO_WINSTDCALL_RENAME(WSADuplicateSocketA, 12); -FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSADuplicateSocketW(void *, ::std::uint_least32_t, ::fast_io::win32::wsaprotocol_infow *) noexcept FAST_IO_WINSTDCALL_RENAME(WSADuplicateSocketW, 12); +FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSADuplicateSocketA(::std::size_t, ::std::uint_least32_t, ::fast_io::win32::wsaprotocol_infoa *) noexcept FAST_IO_WINSTDCALL_RENAME(WSADuplicateSocketA, 12); +FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSADuplicateSocketW(::std::size_t, ::std::uint_least32_t, ::fast_io::win32::wsaprotocol_infow *) noexcept FAST_IO_WINSTDCALL_RENAME(WSADuplicateSocketW, 12); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSACleanup() noexcept FAST_IO_WINSTDCALL_RENAME(WSACleanup, 0); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSAStartup(::std::uint_least32_t, ::fast_io::win32::wsadata *) noexcept FAST_IO_WINSTDCALL_RENAME(WSAStartup, 8); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSAGetLastError() noexcept FAST_IO_WINSTDCALL_RENAME(WSAGetLastError, 0); @@ -98,7 +98,7 @@ FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL WSAConnect(::std::size_t, void const *, FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL shutdown(::std::size_t, int) noexcept FAST_IO_WINSTDCALL_RENAME(shutdown, 8); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL GetCurrentProcessId() noexcept FAST_IO_WINSTDCALL_RENAME(GetCurrentProcessId, 0); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL FlushFileBuffers(void *) noexcept FAST_IO_WINSTDCALL_RENAME(FlushFileBuffers, 4); -FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetQueuedCompletionStatus(void *, ::std::uint_least32_t *, ::std::size_t *, ::fast_io::win32::overlapped *, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetQueuedCompletionStatus, 20); +FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL GetQueuedCompletionStatus(void *, ::std::uint_least32_t *, ::std::size_t *, ::fast_io::win32::overlapped **, ::std::uint_least32_t) noexcept FAST_IO_WINSTDCALL_RENAME(GetQueuedCompletionStatus, 20); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL freeaddrinfo(::fast_io::win32::win32_addrinfo_9xa *) noexcept FAST_IO_WINSTDCALL_RENAME(freeaddrinfo, 4); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL FreeAddrInfoW(::fast_io::win32::win32_addrinfo_ntw *) noexcept FAST_IO_WINSTDCALL_RENAME(FreeAddrInfoW, 4); FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL getaddrinfo(char const *, char const *, ::fast_io::win32::win32_addrinfo_9xa const *, ::fast_io::win32::win32_addrinfo_9xa **) noexcept FAST_IO_WINSTDCALL_RENAME(getaddrinfo, 16); diff --git a/include/fast_io_hosted/platforms/win32_network/service.h b/include/fast_io_hosted/platforms/win32_network/service.h index fff771f0e..f46610248 100644 --- a/include/fast_io_hosted/platforms/win32_network/service.h +++ b/include/fast_io_hosted/platforms/win32_network/service.h @@ -9,9 +9,13 @@ struct win32_wsa_service native_handle_type wsa_data; inline explicit win32_wsa_service(::std::uint_least16_t version) { - if (::fast_io::win32::WSAStartup(version, __builtin_addressof(wsa_data))) + // The WSAStartup function directly returns the extended error code in its return value. Calling the WSAGetLastError function is unnecessary and should not be used. + + auto const res{::fast_io::win32::WSAStartup(version, __builtin_addressof(wsa_data))}; + + if (res) [[unlikely]] { - throw_win32_error(static_cast<::std::uint_least32_t>(::fast_io::win32::WSAGetLastError())); + throw_win32_error(static_cast<::std::uint_least32_t>(res)); } } inline win32_wsa_service() diff --git a/include/fast_io_hosted/platforms/win32_network/socket_file.h b/include/fast_io_hosted/platforms/win32_network/socket_file.h index 7132fc9e7..7e231e537 100644 --- a/include/fast_io_hosted/platforms/win32_network/socket_file.h +++ b/include/fast_io_hosted/platforms/win32_network/socket_file.h @@ -187,7 +187,20 @@ namespace win32::details inline ::std::size_t win32_duphsocket(::std::size_t s) { - return reinterpret_cast<::std::size_t>(win32_dup_impl(reinterpret_cast(s))); + // Duplicate a SOCKET using WSADuplicateSocket + WSASocket, per MSDN guidance. + ::fast_io::win32::wsaprotocol_infoa info{}; + ::std::uint_least32_t const pid{::fast_io::win32::GetCurrentProcessId()}; + if (::fast_io::win32::WSADuplicateSocketA(reinterpret_cast(s), pid, __builtin_addressof(info)) != 0) + { + throw_win32_error(static_cast<::std::uint_least32_t>(::fast_io::win32::WSAGetLastError())); + } + ::std::size_t dup{ + ::fast_io::win32::WSASocketA(info.iAddressFamily, info.iSocketType, info.iProtocol, __builtin_addressof(info), 0, 0)}; + if (dup == UINTPTR_MAX) + { + throw_win32_error(static_cast<::std::uint_least32_t>(::fast_io::win32::WSAGetLastError())); + } + return dup; } inline ::std::size_t win32_dup2hsocket(::std::size_t handle, ::std::size_t newhandle) { From f36b40905e5c7aa3856c8ff0f61f2ab52fe5d827 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 02:10:08 +0800 Subject: [PATCH 10/43] Enhance POSIX and Win32 platform headers with improved error handling and function signatures - Updated `sys_mmap` to use `long` for return type and improved error handling for memory mapping. - Refactored `open_socket_impl` to include checks for socket open modes and set appropriate flags for non-blocking and close-on-exec behavior. - Introduced `to_win32_page_protect` function for better handling of file map attributes in Win32. - Enhanced error handling in `create_file_mapping_impl` and random number generation functions to account for API behavior as per MSDN documentation. --- .../fast_io_hosted/platforms/posix_mapping.h | 20 ++++++------ .../fast_io_hosted/platforms/posix_netmode.h | 31 +++++++++++++++++-- include/fast_io_hosted/platforms/win32.h | 3 +- .../fast_io_hosted/platforms/win32_mapping.h | 16 ++++++++-- .../timeutil/environ_timezone.h | 12 ++++++- .../white_hole/rtl_gen_random.h | 6 ++-- 6 files changed, 70 insertions(+), 18 deletions(-) diff --git a/include/fast_io_hosted/platforms/posix_mapping.h b/include/fast_io_hosted/platforms/posix_mapping.h index 6a3f9d1f6..ae9d1aee5 100644 --- a/include/fast_io_hosted/platforms/posix_mapping.h +++ b/include/fast_io_hosted/platforms/posix_mapping.h @@ -11,16 +11,16 @@ namespace details inline ::std::byte *sys_mmap(void *addr, ::std::size_t len, int prot, int flags, int fd, ::std::uintmax_t offset) { #if defined(__linux__) && defined(__NR_mmap) && !defined(__NR_mmap2) - if constexpr (sizeof(::std::uintmax_t) > sizeof(off_t)) - { - if (offset > static_cast<::std::uintmax_t>(::std::numeric_limits::max())) - { - throw_posix_error(EINVAL); - } - } - ::std::ptrdiff_t ret{system_call<__NR_mmap, ::std::ptrdiff_t>(addr, len, prot, flags, fd, offset)}; - system_call_throw_error(ret); - return reinterpret_cast<::std::byte *>(ret); + if constexpr (sizeof(::std::uintmax_t) > sizeof(off_t)) + { + if (offset > static_cast<::std::uintmax_t>(::std::numeric_limits::max())) + { + throw_posix_error(EINVAL); + } + } + long ret{system_call<__NR_mmap, long>(addr, len, prot, flags, fd, offset)}; + system_call_throw_error(ret); + return reinterpret_cast<::std::byte *>(static_cast<::std::uintptr_t>(ret)); #elif defined(HAVE_MMAP64) if constexpr (sizeof(::std::uintmax_t) > sizeof(off64_t)) { diff --git a/include/fast_io_hosted/platforms/posix_netmode.h b/include/fast_io_hosted/platforms/posix_netmode.h index 9a9dff3c8..11b2b4794 100644 --- a/include/fast_io_hosted/platforms/posix_netmode.h +++ b/include/fast_io_hosted/platforms/posix_netmode.h @@ -650,8 +650,35 @@ inline int sys_socket(int domain, int type, int protocol) inline int open_socket_impl(sock_family d, sock_type t, open_mode m, sock_protocol p) { - return sys_socket(to_posix_sock_family(d), to_posix_sock_type(t) | to_posix_sock_open_mode(m), - to_posix_sock_protocol(p)); + int domain{to_posix_sock_family(d)}; + int type{to_posix_sock_type(t)}; + int mode{to_posix_sock_open_mode(m)}; + if (mode < 0) + { + mode = 0; + } + int fd{sys_socket(domain, type | mode, to_posix_sock_protocol(p))}; + +#if !defined(SOCK_NONBLOCK) + if ((m & open_mode::no_block) == open_mode::no_block) + { +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + int flags{details::sys_fcntl(fd, F_GETFL)}; + details::sys_fcntl(fd, F_SETFL, flags | O_NONBLOCK); +#endif + } +#endif + +#if !defined(SOCK_CLOEXEC) + if ((m & open_mode::inherit) != open_mode::inherit) + { +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) + int fdflags{details::sys_fcntl(fd, F_GETFD)}; + details::sys_fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC); +#endif + } +#endif + return fd; } inline ::std::size_t posix_socket_write_impl(int fd, void const *data, ::std::size_t to_write) diff --git a/include/fast_io_hosted/platforms/win32.h b/include/fast_io_hosted/platforms/win32.h index 28760ecc3..e047f6d26 100644 --- a/include/fast_io_hosted/platforms/win32.h +++ b/include/fast_io_hosted/platforms/win32.h @@ -137,7 +137,8 @@ inline void *create_win32_temp_file_impl() { if (!::fast_io::win32::SystemFunction036(uuid_buffer, uuid_buffer_sz)) { - throw_win32_error(); + //However, according to MSDN, this API does not set LastError. + throw_win32_error(31 /*ERROR_GEN_FAILURE*/); } } else diff --git a/include/fast_io_hosted/platforms/win32_mapping.h b/include/fast_io_hosted/platforms/win32_mapping.h index 22ef80e37..0617f3eb6 100644 --- a/include/fast_io_hosted/platforms/win32_mapping.h +++ b/include/fast_io_hosted/platforms/win32_mapping.h @@ -72,6 +72,18 @@ inline constexpr win32_file_map_attribute to_win32_file_map_attribute(file_map_a }; } +inline constexpr ::std::uint_least32_t to_win32_page_protect(file_map_attribute x) +{ + static_assert(file_map_attribute::execute_read == 0x00000020); + static_assert(file_map_attribute::execute_read_write == 0x00000040); + static_assert(file_map_attribute::execute_write_copy == 0x00000080); + static_assert(file_map_attribute::read_only == 0x00000002); + static_assert(file_map_attribute::read_write == 0x00000004); + static_assert(file_map_attribute::write_copy == 0x00000008); + + return static_cast<::std::uint_least32_t>(x); +} + namespace win32::details { @@ -80,7 +92,7 @@ inline void *create_file_mapping_impl(void *handle, file_map_attribute attr) { if constexpr (family == win32_family::wide_nt) { - void *addr{win32::CreateFileMappingW(handle, nullptr, static_cast<::std::uint_least32_t>(attr), 0, 0, nullptr)}; + void *addr{win32::CreateFileMappingW(handle, nullptr, to_win32_page_protect(attr), 0, 0, nullptr)}; if (addr == nullptr) { throw_win32_error(); @@ -89,7 +101,7 @@ inline void *create_file_mapping_impl(void *handle, file_map_attribute attr) } else { - void *addr{win32::CreateFileMappingA(handle, nullptr, static_cast<::std::uint_least32_t>(attr), 0, 0, nullptr)}; + void *addr{win32::CreateFileMappingA(handle, nullptr, to_win32_page_protect(attr), 0, 0, nullptr)}; if (addr == nullptr) { throw_win32_error(); diff --git a/include/fast_io_hosted/timeutil/environ_timezone.h b/include/fast_io_hosted/timeutil/environ_timezone.h index f848d82f4..68cc59301 100644 --- a/include/fast_io_hosted/timeutil/environ_timezone.h +++ b/include/fast_io_hosted/timeutil/environ_timezone.h @@ -17,13 +17,23 @@ struct environ_timezone_name namespace details { +namespace posix +{ +extern char const *libc_getenv(char const *) noexcept +#if (defined(__APPLE__) || defined(__DARWIN_C_LEVEL)) || (defined(__MSDOS__) || defined(__DJGPP__)) + __asm__("_getenv"); +#else + __asm__("getenv"); +#endif +} // namespace posix + inline environ_timezone_name environ_localtimezone_impl() noexcept { auto ptr{reinterpret_cast<::fast_io::environ_timezone_name::char8_const_may_alias_ptr>( #if FAST_IO_HAS_BUILTIN(__builtin_getenv) __builtin_getenv #else - ::std::getenv + posix::libc_getenv #endif (reinterpret_cast(u8"TZ")))}; if (ptr == nullptr) diff --git a/include/fast_io_hosted/white_hole/rtl_gen_random.h b/include/fast_io_hosted/white_hole/rtl_gen_random.h index 5112ac98c..6477a77cd 100644 --- a/include/fast_io_hosted/white_hole/rtl_gen_random.h +++ b/include/fast_io_hosted/white_hole/rtl_gen_random.h @@ -29,7 +29,8 @@ inline ::std::byte *rtl_gen_random_some_impl(::std::byte *first, ::std::byte *la ::std::size_t sz{static_cast<::std::size_t>(last - first)}; if (!::fast_io::win32::SystemFunction036(first, static_cast<::std::uint_least32_t>(sz))) { - throw_win32_error(); + //However, according to MSDN, this API does not set LastError. + throw_win32_error(31 /*ERROR_GEN_FAILURE*/); } return last; } @@ -46,7 +47,8 @@ inline ::std::byte *rtl_gen_random_some_impl(::std::byte *first, ::std::byte *la } if (!::fast_io::win32::SystemFunction036(first, static_cast<::std::uint_least32_t>(toreadthisround))) { - throw_win32_error(); + // However, according to MSDN, this API does not set LastError. + throw_win32_error(31 /*ERROR_GEN_FAILURE*/); } first += toreadthisround; } From ef502424a91047ff64e74aa741adcec7e136913b Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 02:10:45 +0800 Subject: [PATCH 11/43] f --- include/fast_io_hosted/platforms/win32_network/socket_file.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/platforms/win32_network/socket_file.h b/include/fast_io_hosted/platforms/win32_network/socket_file.h index 7e231e537..b4f202927 100644 --- a/include/fast_io_hosted/platforms/win32_network/socket_file.h +++ b/include/fast_io_hosted/platforms/win32_network/socket_file.h @@ -190,7 +190,7 @@ inline ::std::size_t win32_duphsocket(::std::size_t s) // Duplicate a SOCKET using WSADuplicateSocket + WSASocket, per MSDN guidance. ::fast_io::win32::wsaprotocol_infoa info{}; ::std::uint_least32_t const pid{::fast_io::win32::GetCurrentProcessId()}; - if (::fast_io::win32::WSADuplicateSocketA(reinterpret_cast(s), pid, __builtin_addressof(info)) != 0) + if (::fast_io::win32::WSADuplicateSocketA(s, pid, __builtin_addressof(info)) != 0) { throw_win32_error(static_cast<::std::uint_least32_t>(::fast_io::win32::WSAGetLastError())); } From 4a732611cd756e019da95ed182d86c880cc6f8d9 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 02:13:37 +0800 Subject: [PATCH 12/43] f2 --- include/fast_io_hosted/platforms/win32_mapping.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fast_io_hosted/platforms/win32_mapping.h b/include/fast_io_hosted/platforms/win32_mapping.h index 0617f3eb6..469add1a4 100644 --- a/include/fast_io_hosted/platforms/win32_mapping.h +++ b/include/fast_io_hosted/platforms/win32_mapping.h @@ -74,12 +74,12 @@ inline constexpr win32_file_map_attribute to_win32_file_map_attribute(file_map_a inline constexpr ::std::uint_least32_t to_win32_page_protect(file_map_attribute x) { - static_assert(file_map_attribute::execute_read == 0x00000020); - static_assert(file_map_attribute::execute_read_write == 0x00000040); - static_assert(file_map_attribute::execute_write_copy == 0x00000080); - static_assert(file_map_attribute::read_only == 0x00000002); - static_assert(file_map_attribute::read_write == 0x00000004); - static_assert(file_map_attribute::write_copy == 0x00000008); + static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::execute_read) == 0x00000020); + static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::execute_read_write) == 0x00000040); + static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::execute_write_copy) == 0x00000080); + static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::read_only) == 0x00000002); + static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::read_write) == 0x00000004); + static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::write_copy) == 0x00000008); return static_cast<::std::uint_least32_t>(x); } From 039820da89df1bde4af0053c604d867705658cc3 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 02:13:48 +0800 Subject: [PATCH 13/43] f3 --- include/fast_io_hosted/platforms/win32_mapping.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/platforms/win32_mapping.h b/include/fast_io_hosted/platforms/win32_mapping.h index 469add1a4..2d8fb1f54 100644 --- a/include/fast_io_hosted/platforms/win32_mapping.h +++ b/include/fast_io_hosted/platforms/win32_mapping.h @@ -72,7 +72,7 @@ inline constexpr win32_file_map_attribute to_win32_file_map_attribute(file_map_a }; } -inline constexpr ::std::uint_least32_t to_win32_page_protect(file_map_attribute x) +inline constexpr ::std::uint_least32_t to_win32_page_protect(file_map_attribute x) noexcept { static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::execute_read) == 0x00000020); static_assert(static_cast<::std::uint_least32_t>(file_map_attribute::execute_read_write) == 0x00000040); From 85eba537608a721b985053c4fbe0ebf8f03d636c Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 02:16:35 +0800 Subject: [PATCH 14/43] Refactor timestamp handling in nt_family_clock_settime for improved type safety - Changed the type of `tms` from `uint_least64_t` to `int_least64_t` to ensure proper handling of negative values. - Updated calculations for `tms` to maintain consistency and prevent potential overflow issues. --- include/fast_io_hosted/timeutil/time.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_io_hosted/timeutil/time.h b/include/fast_io_hosted/timeutil/time.h index 5910bd58a..35c0af21b 100644 --- a/include/fast_io_hosted/timeutil/time.h +++ b/include/fast_io_hosted/timeutil/time.h @@ -675,9 +675,9 @@ inline basic_timestamp nt_family_clock_settime(posix_clock_id pclk case posix_clock_id::tai: { constexpr ::std::uint_least64_t mul_factor{uint_least64_subseconds_per_second / 10000000u}; - ::std::uint_least64_t tms(static_cast<::std::uint_least64_t>(timestamp.seconds) * 10000000ULL + - timestamp.subseconds / mul_factor); - ::std::uint_least64_t old_tms{}; + ::std::int_least64_t tms(static_cast<::std::int_least64_t>(static_cast<::std::uint_least64_t>(timestamp.seconds) * 10000000ULL + + timestamp.subseconds / mul_factor)); + ::std::int_least64_t old_tms{}; auto ntstatus{win32::nt::nt_set_system_time<(family == nt_family::zw)>(__builtin_addressof(tms), __builtin_addressof(old_tms))}; if (ntstatus) { From 6eac4074f1f4d8b9f16aaf7127fa51739baa6578 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 11:38:55 +0800 Subject: [PATCH 15/43] Update Win32 linker headers to correct function signatures and improve consistency - Adjusted function signatures in `msvc_linker_32_i686.h`, `msvc_linker_32.h`, `msvc_linker_64.h`, and `msvc_linker_arm64ec.h` to ensure proper handling of parameters and return types. - Enhanced consistency across linker headers by standardizing the naming conventions for function aliases. - Improved clarity and maintainability of the code by ensuring uniformity in the handling of alternate names for Windows API functions. --- .../platforms/win32/msvc_linker_32.h | 35 ++++++++++++------- .../platforms/win32/msvc_linker_32_i686.h | 35 ++++++++++++------- .../platforms/win32/msvc_linker_64.h | 35 ++++++++++++------- .../platforms/win32/msvc_linker_arm64ec.h | 35 ++++++++++++------- 4 files changed, 92 insertions(+), 48 deletions(-) diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_32.h b/include/fast_io_hosted/platforms/win32/msvc_linker_32.h index a0e312070..be69dd236 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_32.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_32.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once // This file have been generated by example/0039.win32mangling, therefore, do NOT edit this file directely! // clang-format off // WIN32 @@ -48,7 +48,7 @@ #pragma comment(linker,"/alternatename:__imp_?CloseHandle@win32@fast_io@@YAHPAX@Z=__imp_CloseHandle") #pragma comment(linker,"/alternatename:__imp_?LockFileEx@win32@fast_io@@YAHPAXIIIIPAUoverlapped@12@@Z=__imp_LockFileEx") #pragma comment(linker,"/alternatename:__imp_?UnlockFileEx@win32@fast_io@@YAHPAXIIIPAUoverlapped@12@@Z=__imp_UnlockFileEx") -#pragma comment(linker,"/alternatename:__imp_?DeviceIoControl@win32@fast_io@@YAHPAXI0I0I0PAUoverlapped@12@@Z=__imp_DeviceIoControl") +#pragma comment(linker,"/alternatename:__imp_?DeviceIoControl@win32@fast_io@@YAHPAXI0I0IPAIPAUoverlapped@12@@Z=__imp_DeviceIoControl") #pragma comment(linker,"/alternatename:__imp_?GetFileType@win32@fast_io@@YAIPAX@Z=__imp_GetFileType") #pragma comment(linker,"/alternatename:__imp_?GetACP@win32@fast_io@@YAIXZ=__imp_GetACP") #pragma comment(linker,"/alternatename:__imp_?GetEnvironmentVariableA@win32@fast_io@@YAIPBDPADI@Z=__imp_GetEnvironmentVariableA") @@ -70,8 +70,8 @@ #pragma comment(linker,"/alternatename:__imp_?TryEnterCriticalSection@win32@fast_io@@YAHPAX@Z=__imp_TryEnterCriticalSection") #pragma comment(linker,"/alternatename:__imp_?LeaveCriticalSection@win32@fast_io@@YAXPAX@Z=__imp_LeaveCriticalSection") #pragma comment(linker,"/alternatename:__imp_?DeleteCriticalSection@win32@fast_io@@YAXPAX@Z=__imp_DeleteCriticalSection") -#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketA@win32@fast_io@@YAHPAXIPAUwsaprotocol_infoa@12@@Z=__imp_WSADuplicateSocketA") -#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketW@win32@fast_io@@YAHPAXIPAUwsaprotocol_infow@12@@Z=__imp_WSADuplicateSocketW") +#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketA@win32@fast_io@@YAHIIPAUwsaprotocol_infoa@12@@Z=__imp_WSADuplicateSocketA") +#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketW@win32@fast_io@@YAHIIPAUwsaprotocol_infow@12@@Z=__imp_WSADuplicateSocketW") #pragma comment(linker,"/alternatename:__imp_?WSACleanup@win32@fast_io@@YAHXZ=__imp_WSACleanup") #pragma comment(linker,"/alternatename:__imp_?WSAStartup@win32@fast_io@@YAHIPAUwsadata@12@@Z=__imp_WSAStartup") #pragma comment(linker,"/alternatename:__imp_?WSAGetLastError@win32@fast_io@@YAHXZ=__imp_WSAGetLastError") @@ -95,7 +95,7 @@ #pragma comment(linker,"/alternatename:__imp_?shutdown@win32@fast_io@@YAHIH@Z=__imp_shutdown") #pragma comment(linker,"/alternatename:__imp_?GetCurrentProcessId@win32@fast_io@@YAIXZ=__imp_GetCurrentProcessId") #pragma comment(linker,"/alternatename:__imp_?FlushFileBuffers@win32@fast_io@@YAHPAX@Z=__imp_FlushFileBuffers") -#pragma comment(linker,"/alternatename:__imp_?GetQueuedCompletionStatus@win32@fast_io@@YAHPAXPAI1PAUoverlapped@12@I@Z=__imp_GetQueuedCompletionStatus") +#pragma comment(linker,"/alternatename:__imp_?GetQueuedCompletionStatus@win32@fast_io@@YAHPAXPAI1PAPAUoverlapped@12@I@Z=__imp_GetQueuedCompletionStatus") #pragma comment(linker,"/alternatename:__imp_?freeaddrinfo@win32@fast_io@@YAXPAU?$win32_family_addrinfo@$0A@@12@@Z=__imp_freeaddrinfo") #pragma comment(linker,"/alternatename:__imp_?FreeAddrInfoW@win32@fast_io@@YAXPAU?$win32_family_addrinfo@$00@12@@Z=__imp_FreeAddrInfoW") #pragma comment(linker,"/alternatename:__imp_?getaddrinfo@win32@fast_io@@YAHPBD0PBU?$win32_family_addrinfo@$0A@@12@PAPAU312@@Z=__imp_getaddrinfo") @@ -167,6 +167,17 @@ #pragma comment(linker,"/alternatename:__imp_?SetConsoleTextAttribute@win32@fast_io@@YAHPAXH@Z=__imp_SetConsoleTextAttribute") #pragma comment(linker,"/alternatename:__imp_?GetCurrentThreadId@win32@fast_io@@YAIXZ=__imp_GetCurrentThreadId") #pragma comment(linker,"/alternatename:__imp_?Sleep@win32@fast_io@@YAXI@Z=__imp_Sleep") +#pragma comment(linker,"/alternatename:__imp_?GetEnvironmentStringsW@win32@fast_io@@YAPA_SXZ=__imp_GetEnvironmentStringsW") +#pragma comment(linker,"/alternatename:__imp_?GetEnvironmentStringsA@win32@fast_io@@YAPADXZ=__imp_GetEnvironmentStringsA") +#pragma comment(linker,"/alternatename:__imp_?FreeEnvironmentStringsW@win32@fast_io@@YAHPA_S@Z=__imp_FreeEnvironmentStringsW") +#pragma comment(linker,"/alternatename:__imp_?FreeEnvironmentStringsA@win32@fast_io@@YAHPAD@Z=__imp_FreeEnvironmentStringsA") +#pragma comment(linker,"/alternatename:__imp_?getsockopt@win32@fast_io@@YAHIHHPADPAH@Z=__imp_getsockopt") +#pragma comment(linker,"/alternatename:__imp_?GetFullPathNameW@win32@fast_io@@YAIPB_SIPA_SPAPA_S@Z=__imp_GetFullPathNameW") +#pragma comment(linker,"/alternatename:__imp_?GetFullPathNameA@win32@fast_io@@YAIPBDIPADPAPAD@Z=__imp_GetFullPathNameA") +#pragma comment(linker,"/alternatename:__imp_?GetVolumeInformationW@win32@fast_io@@YAHPB_SPA_SIPAI221I@Z=__imp_GetVolumeInformationW") +#pragma comment(linker,"/alternatename:__imp_?GetVolumeInformationA@win32@fast_io@@YAHPBDPADIPAI221I@Z=__imp_GetVolumeInformationA") +#pragma comment(linker,"/alternatename:__imp_?GetDiskFreeSpaceW@win32@fast_io@@YAHPB_SPAI111@Z=__imp_GetDiskFreeSpaceW") +#pragma comment(linker,"/alternatename:__imp_?GetDiskFreeSpaceA@win32@fast_io@@YAHPBDPAI111@Z=__imp_GetDiskFreeSpaceA") // NT #pragma comment(linker,"/alternatename:__imp_?rtl_nt_status_to_dos_error@nt@win32@fast_io@@YAII@Z=__imp_RtlNtStatusToDosError") #pragma comment(linker,"/alternatename:__imp_?NtClose@nt@win32@fast_io@@YAIPAX@Z=__imp_NtClose") @@ -195,8 +206,8 @@ #pragma comment(linker,"/alternatename:__imp_?ZwDuplicateObject@nt@win32@fast_io@@YAIPAX00PAPAXIII@Z=__imp_ZwDuplicateObject") #pragma comment(linker,"/alternatename:__imp_?NtWaitForSingleObject@nt@win32@fast_io@@YAIPAXHPA_K@Z=__imp_NtWaitForSingleObject") #pragma comment(linker,"/alternatename:__imp_?ZwWaitForSingleObject@nt@win32@fast_io@@YAIPAXHPA_K@Z=__imp_ZwWaitForSingleObject") -#pragma comment(linker,"/alternatename:__imp_?NtSetSystemTime@nt@win32@fast_io@@YAIPA_K0@Z=__imp_NtSetSystemTime") -#pragma comment(linker,"/alternatename:__imp_?ZwSetSystemTime@nt@win32@fast_io@@YAIPA_K0@Z=__imp_ZwSetSystemTime") +#pragma comment(linker,"/alternatename:__imp_?NtSetSystemTime@nt@win32@fast_io@@YAIPA_J0@Z=__imp_NtSetSystemTime") +#pragma comment(linker,"/alternatename:__imp_?ZwSetSystemTime@nt@win32@fast_io@@YAIPA_J0@Z=__imp_ZwSetSystemTime") #pragma comment(linker,"/alternatename:__imp_?NtCreateProcess@nt@win32@fast_io@@YAIPAPAXIPAUobject_attributes@123@PAXI222@Z=__imp_NtCreateProcess") #pragma comment(linker,"/alternatename:__imp_?ZwCreateProcess@nt@win32@fast_io@@YAIPAPAXIPAUobject_attributes@123@PAXI222@Z=__imp_ZwCreateProcess") #pragma comment(linker,"/alternatename:__imp_?rtl_dos_path_name_to_nt_path_name_u@nt@win32@fast_io@@YAEPB_SPAUunicode_string@123@PAPB_SPAUrtl_relative_name_u@123@@Z=__imp_RtlDosPathNameToNtPathName_U") @@ -234,18 +245,18 @@ #pragma comment(linker,"/alternatename:__imp_?ZwReadVirtualMemory@nt@win32@fast_io@@YAIPAX00IPAI@Z=__imp_ZwReadVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?NtWriteVirtualMemory@nt@win32@fast_io@@YAIPAX00IPAI@Z=__imp_NtWriteVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?ZwWriteVirtualMemory@nt@win32@fast_io@@YAIPAX00IPAI@Z=__imp_ZwWriteVirtualMemory") -#pragma comment(linker,"/alternatename:__imp_?RtlAcquirePebLock@nt@win32@fast_io@@YAIXZ=__imp_RtlAcquirePebLock") -#pragma comment(linker,"/alternatename:__imp_?RtlReleasePebLock@nt@win32@fast_io@@YAIXZ=__imp_RtlReleasePebLock") +#pragma comment(linker,"/alternatename:__imp_?RtlAcquirePebLock@nt@win32@fast_io@@YAXXZ=__imp_RtlAcquirePebLock") +#pragma comment(linker,"/alternatename:__imp_?RtlReleasePebLock@nt@win32@fast_io@@YAXXZ=__imp_RtlReleasePebLock") #pragma comment(linker,"/alternatename:__imp_?NtAllocateVirtualMemory@nt@win32@fast_io@@YAIPAXPAPAXIPAIII@Z=__imp_NtAllocateVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?ZwAllocateVirtualMemory@nt@win32@fast_io@@YAIPAXPAPAXIPAIII@Z=__imp_ZwAllocateVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?NtFreeVirtualMemory@nt@win32@fast_io@@YAIPAXPAPAXPAII@Z=__imp_NtFreeVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?ZwFreeVirtualMemory@nt@win32@fast_io@@YAIPAXPAPAXPAII@Z=__imp_ZwFreeVirtualMemory") -#pragma comment(linker,"/alternatename:__imp_?RtlInitUnicodeString@nt@win32@fast_io@@YAIPAUunicode_string@123@PA_S@Z=__imp_RtlInitUnicodeString") +#pragma comment(linker,"/alternatename:__imp_?RtlInitUnicodeString@nt@win32@fast_io@@YAXPAUunicode_string@123@PA_S@Z=__imp_RtlInitUnicodeString") #pragma comment(linker,"/alternatename:__imp_?CsrClientCallServer@nt@win32@fast_io@@YAIPAX0II@Z=__imp_CsrClientCallServer") #pragma comment(linker,"/alternatename:__imp_?NtQuerySystemInformation@nt@win32@fast_io@@YAIW4system_information_class@123@PAXIPAI@Z=__imp_NtQuerySystemInformation") #pragma comment(linker,"/alternatename:__imp_?ZwQuerySystemInformation@nt@win32@fast_io@@YAIW4system_information_class@123@PAXIPAI@Z=__imp_ZwQuerySystemInformation") #pragma comment(linker,"/alternatename:__imp_?RtlAcquireSRWLockExclusive@nt@win32@fast_io@@YAXPAX@Z=__imp_RtlAcquireSRWLockExclusive") -#pragma comment(linker,"/alternatename:__imp_?RtlTryAcquireSRWLockExclusive@nt@win32@fast_io@@YAIPAX@Z=__imp_RtlTryAcquireSRWLockExclusive") +#pragma comment(linker,"/alternatename:__imp_?RtlTryAcquireSRWLockExclusive@nt@win32@fast_io@@YAEPAX@Z=__imp_RtlTryAcquireSRWLockExclusive") #pragma comment(linker,"/alternatename:__imp_?RtlReleaseSRWLockExclusive@nt@win32@fast_io@@YAXPAX@Z=__imp_RtlReleaseSRWLockExclusive") #pragma comment(linker,"/alternatename:__imp_?NtQueryVolumeInformationFile@nt@win32@fast_io@@YAIPIAXPIAUio_status_block@123@0IW4fs_information_class@123@@Z=__imp_NtQueryVolumeInformationFile") #pragma comment(linker,"/alternatename:__imp_?ZwQueryVolumeInformationFile@nt@win32@fast_io@@YAIPIAXPIAUio_status_block@123@0IW4fs_information_class@123@@Z=__imp_ZwQueryVolumeInformationFile") @@ -255,7 +266,7 @@ #pragma comment(linker,"/alternatename:__imp_?ZwCreateNamedPipeFile@nt@win32@fast_io@@YAIPIAPAXIPIAUobject_attributes@123@PIAUio_status_block@123@IIIIIIIIIPA_J@Z=__imp_ZwCreateNamedPipeFile") #pragma comment(linker,"/alternatename:__imp_?NtQueryPerformanceCounter@nt@win32@fast_io@@YAIPA_J0@Z=__imp_NtQueryPerformanceCounter") #pragma comment(linker,"/alternatename:__imp_?ZwQueryPerformanceCounter@nt@win32@fast_io@@YAIPA_J0@Z=__imp_ZwQueryPerformanceCounter") -#pragma comment(linker,"/alternatename:__imp_?RtlGetSystemTimePrecise@nt@win32@fast_io@@YA_JXZ=__imp_RtlGetSystemTimePrecise") +#pragma comment(linker,"/alternatename:__imp_?RtlGetSystemTimePrecise@nt@win32@fast_io@@YA_KXZ=__imp_RtlGetSystemTimePrecise") #pragma comment(linker,"/alternatename:__imp_?NtQueryInformationThread@nt@win32@fast_io@@YAIPIAXW4thread_information_class@123@PAXIPAI@Z=__imp_NtQueryInformationThread") #pragma comment(linker,"/alternatename:__imp_?ZwQueryInformationThread@nt@win32@fast_io@@YAIPIAXW4thread_information_class@123@PAXIPAI@Z=__imp_ZwQueryInformationThread") #pragma comment(linker,"/alternatename:__imp_?RtlAdjustPrivilege@nt@win32@fast_io@@YAIIEEPAE@Z=__imp_RtlAdjustPrivilege") diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h b/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h index a8493d1ba..3e19d9a98 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once // This file have been generated by example/0039.win32mangling, therefore, do NOT edit this file directely! // clang-format off // WIN32 @@ -48,7 +48,7 @@ #pragma comment(linker,"/alternatename:__imp_?CloseHandle@win32@fast_io@@YGHPAX@Z=__imp__CloseHandle@4") #pragma comment(linker,"/alternatename:__imp_?LockFileEx@win32@fast_io@@YGHPAXIIIIPAUoverlapped@12@@Z=__imp__LockFileEx@24") #pragma comment(linker,"/alternatename:__imp_?UnlockFileEx@win32@fast_io@@YGHPAXIIIPAUoverlapped@12@@Z=__imp__UnlockFileEx@20") -#pragma comment(linker,"/alternatename:__imp_?DeviceIoControl@win32@fast_io@@YGHPAXI0I0I0PAUoverlapped@12@@Z=__imp__DeviceIoControl@32") +#pragma comment(linker,"/alternatename:__imp_?DeviceIoControl@win32@fast_io@@YGHPAXI0I0IPAIPAUoverlapped@12@@Z=__imp__DeviceIoControl@32") #pragma comment(linker,"/alternatename:__imp_?GetFileType@win32@fast_io@@YGIPAX@Z=__imp__GetFileType@4") #pragma comment(linker,"/alternatename:__imp_?GetACP@win32@fast_io@@YGIXZ=__imp__GetACP@0") #pragma comment(linker,"/alternatename:__imp_?GetEnvironmentVariableA@win32@fast_io@@YGIPBDPADI@Z=__imp__GetEnvironmentVariableA@12") @@ -70,8 +70,8 @@ #pragma comment(linker,"/alternatename:__imp_?TryEnterCriticalSection@win32@fast_io@@YGHPAX@Z=__imp__TryEnterCriticalSection@4") #pragma comment(linker,"/alternatename:__imp_?LeaveCriticalSection@win32@fast_io@@YGXPAX@Z=__imp__LeaveCriticalSection@4") #pragma comment(linker,"/alternatename:__imp_?DeleteCriticalSection@win32@fast_io@@YGXPAX@Z=__imp__DeleteCriticalSection@4") -#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketA@win32@fast_io@@YGHPAXIPAUwsaprotocol_infoa@12@@Z=__imp__WSADuplicateSocketA@12") -#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketW@win32@fast_io@@YGHPAXIPAUwsaprotocol_infow@12@@Z=__imp__WSADuplicateSocketW@12") +#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketA@win32@fast_io@@YGHIIPAUwsaprotocol_infoa@12@@Z=__imp__WSADuplicateSocketA@12") +#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketW@win32@fast_io@@YGHIIPAUwsaprotocol_infow@12@@Z=__imp__WSADuplicateSocketW@12") #pragma comment(linker,"/alternatename:__imp_?WSACleanup@win32@fast_io@@YGHXZ=__imp__WSACleanup@0") #pragma comment(linker,"/alternatename:__imp_?WSAStartup@win32@fast_io@@YGHIPAUwsadata@12@@Z=__imp__WSAStartup@8") #pragma comment(linker,"/alternatename:__imp_?WSAGetLastError@win32@fast_io@@YGHXZ=__imp__WSAGetLastError@0") @@ -95,7 +95,7 @@ #pragma comment(linker,"/alternatename:__imp_?shutdown@win32@fast_io@@YGHIH@Z=__imp__shutdown@8") #pragma comment(linker,"/alternatename:__imp_?GetCurrentProcessId@win32@fast_io@@YGIXZ=__imp__GetCurrentProcessId@0") #pragma comment(linker,"/alternatename:__imp_?FlushFileBuffers@win32@fast_io@@YGHPAX@Z=__imp__FlushFileBuffers@4") -#pragma comment(linker,"/alternatename:__imp_?GetQueuedCompletionStatus@win32@fast_io@@YGHPAXPAI1PAUoverlapped@12@I@Z=__imp__GetQueuedCompletionStatus@20") +#pragma comment(linker,"/alternatename:__imp_?GetQueuedCompletionStatus@win32@fast_io@@YGHPAXPAI1PAPAUoverlapped@12@I@Z=__imp__GetQueuedCompletionStatus@20") #pragma comment(linker,"/alternatename:__imp_?freeaddrinfo@win32@fast_io@@YGXPAU?$win32_family_addrinfo@$0A@@12@@Z=__imp__freeaddrinfo@4") #pragma comment(linker,"/alternatename:__imp_?FreeAddrInfoW@win32@fast_io@@YGXPAU?$win32_family_addrinfo@$00@12@@Z=__imp__FreeAddrInfoW@4") #pragma comment(linker,"/alternatename:__imp_?getaddrinfo@win32@fast_io@@YGHPBD0PBU?$win32_family_addrinfo@$0A@@12@PAPAU312@@Z=__imp__getaddrinfo@16") @@ -167,6 +167,17 @@ #pragma comment(linker,"/alternatename:__imp_?SetConsoleTextAttribute@win32@fast_io@@YGHPAXH@Z=__imp__SetConsoleTextAttribute@8") #pragma comment(linker,"/alternatename:__imp_?GetCurrentThreadId@win32@fast_io@@YGIXZ=__imp__GetCurrentThreadId@0") #pragma comment(linker,"/alternatename:__imp_?Sleep@win32@fast_io@@YGXI@Z=__imp__Sleep@4") +#pragma comment(linker,"/alternatename:__imp_?GetEnvironmentStringsW@win32@fast_io@@YGPA_SXZ=__imp__GetEnvironmentStringsW@0") +#pragma comment(linker,"/alternatename:__imp_?GetEnvironmentStringsA@win32@fast_io@@YGPADXZ=__imp__GetEnvironmentStringsA@0") +#pragma comment(linker,"/alternatename:__imp_?FreeEnvironmentStringsW@win32@fast_io@@YGHPA_S@Z=__imp__FreeEnvironmentStringsW@4") +#pragma comment(linker,"/alternatename:__imp_?FreeEnvironmentStringsA@win32@fast_io@@YGHPAD@Z=__imp__FreeEnvironmentStringsA@4") +#pragma comment(linker,"/alternatename:__imp_?getsockopt@win32@fast_io@@YGHIHHPADPAH@Z=__imp__getsockopt@20") +#pragma comment(linker,"/alternatename:__imp_?GetFullPathNameW@win32@fast_io@@YGIPB_SIPA_SPAPA_S@Z=__imp__GetFullPathNameW@16") +#pragma comment(linker,"/alternatename:__imp_?GetFullPathNameA@win32@fast_io@@YGIPBDIPADPAPAD@Z=__imp__GetFullPathNameA@16") +#pragma comment(linker,"/alternatename:__imp_?GetVolumeInformationW@win32@fast_io@@YGHPB_SPA_SIPAI221I@Z=__imp__GetVolumeInformationW@32") +#pragma comment(linker,"/alternatename:__imp_?GetVolumeInformationA@win32@fast_io@@YGHPBDPADIPAI221I@Z=__imp__GetVolumeInformationA@32") +#pragma comment(linker,"/alternatename:__imp_?GetDiskFreeSpaceW@win32@fast_io@@YGHPB_SPAI111@Z=__imp__GetDiskFreeSpaceW@20") +#pragma comment(linker,"/alternatename:__imp_?GetDiskFreeSpaceA@win32@fast_io@@YGHPBDPAI111@Z=__imp__GetDiskFreeSpaceA@20") // NT #pragma comment(linker,"/alternatename:__imp_?rtl_nt_status_to_dos_error@nt@win32@fast_io@@YGII@Z=__imp__RtlNtStatusToDosError@4") #pragma comment(linker,"/alternatename:__imp_?NtClose@nt@win32@fast_io@@YGIPAX@Z=__imp__NtClose@4") @@ -195,8 +206,8 @@ #pragma comment(linker,"/alternatename:__imp_?ZwDuplicateObject@nt@win32@fast_io@@YGIPAX00PAPAXIII@Z=__imp__ZwDuplicateObject@28") #pragma comment(linker,"/alternatename:__imp_?NtWaitForSingleObject@nt@win32@fast_io@@YGIPAXHPA_K@Z=__imp__NtWaitForSingleObject@12") #pragma comment(linker,"/alternatename:__imp_?ZwWaitForSingleObject@nt@win32@fast_io@@YGIPAXHPA_K@Z=__imp__ZwWaitForSingleObject@12") -#pragma comment(linker,"/alternatename:__imp_?NtSetSystemTime@nt@win32@fast_io@@YGIPA_K0@Z=__imp__NtSetSystemTime@8") -#pragma comment(linker,"/alternatename:__imp_?ZwSetSystemTime@nt@win32@fast_io@@YGIPA_K0@Z=__imp__ZwSetSystemTime@8") +#pragma comment(linker,"/alternatename:__imp_?NtSetSystemTime@nt@win32@fast_io@@YGIPA_J0@Z=__imp__NtSetSystemTime@8") +#pragma comment(linker,"/alternatename:__imp_?ZwSetSystemTime@nt@win32@fast_io@@YGIPA_J0@Z=__imp__ZwSetSystemTime@8") #pragma comment(linker,"/alternatename:__imp_?NtCreateProcess@nt@win32@fast_io@@YGIPAPAXIPAUobject_attributes@123@PAXI222@Z=__imp__NtCreateProcess@32") #pragma comment(linker,"/alternatename:__imp_?ZwCreateProcess@nt@win32@fast_io@@YGIPAPAXIPAUobject_attributes@123@PAXI222@Z=__imp__ZwCreateProcess@32") #pragma comment(linker,"/alternatename:__imp_?rtl_dos_path_name_to_nt_path_name_u@nt@win32@fast_io@@YGEPB_SPAUunicode_string@123@PAPB_SPAUrtl_relative_name_u@123@@Z=__imp__RtlDosPathNameToNtPathName_U@16") @@ -234,18 +245,18 @@ #pragma comment(linker,"/alternatename:__imp_?ZwReadVirtualMemory@nt@win32@fast_io@@YGIPAX00IPAI@Z=__imp__ZwReadVirtualMemory@20") #pragma comment(linker,"/alternatename:__imp_?NtWriteVirtualMemory@nt@win32@fast_io@@YGIPAX00IPAI@Z=__imp__NtWriteVirtualMemory@20") #pragma comment(linker,"/alternatename:__imp_?ZwWriteVirtualMemory@nt@win32@fast_io@@YGIPAX00IPAI@Z=__imp__ZwWriteVirtualMemory@20") -#pragma comment(linker,"/alternatename:__imp_?RtlAcquirePebLock@nt@win32@fast_io@@YGIXZ=__imp__RtlAcquirePebLock@0") -#pragma comment(linker,"/alternatename:__imp_?RtlReleasePebLock@nt@win32@fast_io@@YGIXZ=__imp__RtlReleasePebLock@0") +#pragma comment(linker,"/alternatename:__imp_?RtlAcquirePebLock@nt@win32@fast_io@@YGXXZ=__imp__RtlAcquirePebLock@0") +#pragma comment(linker,"/alternatename:__imp_?RtlReleasePebLock@nt@win32@fast_io@@YGXXZ=__imp__RtlReleasePebLock@0") #pragma comment(linker,"/alternatename:__imp_?NtAllocateVirtualMemory@nt@win32@fast_io@@YGIPAXPAPAXIPAIII@Z=__imp__NtAllocateVirtualMemory@24") #pragma comment(linker,"/alternatename:__imp_?ZwAllocateVirtualMemory@nt@win32@fast_io@@YGIPAXPAPAXIPAIII@Z=__imp__ZwAllocateVirtualMemory@24") #pragma comment(linker,"/alternatename:__imp_?NtFreeVirtualMemory@nt@win32@fast_io@@YGIPAXPAPAXPAII@Z=__imp__NtFreeVirtualMemory@16") #pragma comment(linker,"/alternatename:__imp_?ZwFreeVirtualMemory@nt@win32@fast_io@@YGIPAXPAPAXPAII@Z=__imp__ZwFreeVirtualMemory@16") -#pragma comment(linker,"/alternatename:__imp_?RtlInitUnicodeString@nt@win32@fast_io@@YGIPAUunicode_string@123@PA_S@Z=__imp__RtlInitUnicodeString@8") +#pragma comment(linker,"/alternatename:__imp_?RtlInitUnicodeString@nt@win32@fast_io@@YGXPAUunicode_string@123@PA_S@Z=__imp__RtlInitUnicodeString@8") #pragma comment(linker,"/alternatename:__imp_?CsrClientCallServer@nt@win32@fast_io@@YGIPAX0II@Z=__imp__CsrClientCallServer@16") #pragma comment(linker,"/alternatename:__imp_?NtQuerySystemInformation@nt@win32@fast_io@@YGIW4system_information_class@123@PAXIPAI@Z=__imp__NtQuerySystemInformation@16") #pragma comment(linker,"/alternatename:__imp_?ZwQuerySystemInformation@nt@win32@fast_io@@YGIW4system_information_class@123@PAXIPAI@Z=__imp__ZwQuerySystemInformation@16") #pragma comment(linker,"/alternatename:__imp_?RtlAcquireSRWLockExclusive@nt@win32@fast_io@@YGXPAX@Z=__imp__RtlAcquireSRWLockExclusive@4") -#pragma comment(linker,"/alternatename:__imp_?RtlTryAcquireSRWLockExclusive@nt@win32@fast_io@@YGIPAX@Z=__imp__RtlTryAcquireSRWLockExclusive@4") +#pragma comment(linker,"/alternatename:__imp_?RtlTryAcquireSRWLockExclusive@nt@win32@fast_io@@YGEPAX@Z=__imp__RtlTryAcquireSRWLockExclusive@4") #pragma comment(linker,"/alternatename:__imp_?RtlReleaseSRWLockExclusive@nt@win32@fast_io@@YGXPAX@Z=__imp__RtlReleaseSRWLockExclusive@4") #pragma comment(linker,"/alternatename:__imp_?NtQueryVolumeInformationFile@nt@win32@fast_io@@YGIPIAXPIAUio_status_block@123@0IW4fs_information_class@123@@Z=__imp__NtQueryVolumeInformationFile@20") #pragma comment(linker,"/alternatename:__imp_?ZwQueryVolumeInformationFile@nt@win32@fast_io@@YGIPIAXPIAUio_status_block@123@0IW4fs_information_class@123@@Z=__imp__ZwQueryVolumeInformationFile@20") @@ -255,7 +266,7 @@ #pragma comment(linker,"/alternatename:__imp_?ZwCreateNamedPipeFile@nt@win32@fast_io@@YGIPIAPAXIPIAUobject_attributes@123@PIAUio_status_block@123@IIIIIIIIIPA_J@Z=__imp__ZwCreateNamedPipeFile@56") #pragma comment(linker,"/alternatename:__imp_?NtQueryPerformanceCounter@nt@win32@fast_io@@YGIPA_J0@Z=__imp__NtQueryPerformanceCounter@8") #pragma comment(linker,"/alternatename:__imp_?ZwQueryPerformanceCounter@nt@win32@fast_io@@YGIPA_J0@Z=__imp__ZwQueryPerformanceCounter@8") -#pragma comment(linker,"/alternatename:__imp_?RtlGetSystemTimePrecise@nt@win32@fast_io@@YG_JXZ=__imp__RtlGetSystemTimePrecise@0") +#pragma comment(linker,"/alternatename:__imp_?RtlGetSystemTimePrecise@nt@win32@fast_io@@YG_KXZ=__imp__RtlGetSystemTimePrecise@0") #pragma comment(linker,"/alternatename:__imp_?NtQueryInformationThread@nt@win32@fast_io@@YGIPIAXW4thread_information_class@123@PAXIPAI@Z=__imp__NtQueryInformationThread@20") #pragma comment(linker,"/alternatename:__imp_?ZwQueryInformationThread@nt@win32@fast_io@@YGIPIAXW4thread_information_class@123@PAXIPAI@Z=__imp__ZwQueryInformationThread@20") #pragma comment(linker,"/alternatename:__imp_?RtlAdjustPrivilege@nt@win32@fast_io@@YGIIEEPAE@Z=__imp__RtlAdjustPrivilege@16") diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_64.h b/include/fast_io_hosted/platforms/win32/msvc_linker_64.h index 184427533..0999223b4 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_64.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_64.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once // This file have been generated by example/0039.win32mangling, therefore, do NOT edit this file directely! // clang-format off // WIN32 @@ -48,7 +48,7 @@ #pragma comment(linker,"/alternatename:__imp_?CloseHandle@win32@fast_io@@YAHPEAX@Z=__imp_CloseHandle") #pragma comment(linker,"/alternatename:__imp_?LockFileEx@win32@fast_io@@YAHPEAXIIIIPEAUoverlapped@12@@Z=__imp_LockFileEx") #pragma comment(linker,"/alternatename:__imp_?UnlockFileEx@win32@fast_io@@YAHPEAXIIIPEAUoverlapped@12@@Z=__imp_UnlockFileEx") -#pragma comment(linker,"/alternatename:__imp_?DeviceIoControl@win32@fast_io@@YAHPEAXI0I0I0PEAUoverlapped@12@@Z=__imp_DeviceIoControl") +#pragma comment(linker,"/alternatename:__imp_?DeviceIoControl@win32@fast_io@@YAHPEAXI0I0IPEAIPEAUoverlapped@12@@Z=__imp_DeviceIoControl") #pragma comment(linker,"/alternatename:__imp_?GetFileType@win32@fast_io@@YAIPEAX@Z=__imp_GetFileType") #pragma comment(linker,"/alternatename:__imp_?GetACP@win32@fast_io@@YAIXZ=__imp_GetACP") #pragma comment(linker,"/alternatename:__imp_?GetEnvironmentVariableA@win32@fast_io@@YAIPEBDPEADI@Z=__imp_GetEnvironmentVariableA") @@ -70,8 +70,8 @@ #pragma comment(linker,"/alternatename:__imp_?TryEnterCriticalSection@win32@fast_io@@YAHPEAX@Z=__imp_TryEnterCriticalSection") #pragma comment(linker,"/alternatename:__imp_?LeaveCriticalSection@win32@fast_io@@YAXPEAX@Z=__imp_LeaveCriticalSection") #pragma comment(linker,"/alternatename:__imp_?DeleteCriticalSection@win32@fast_io@@YAXPEAX@Z=__imp_DeleteCriticalSection") -#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketA@win32@fast_io@@YAHPEAXIPEAUwsaprotocol_infoa@12@@Z=__imp_WSADuplicateSocketA") -#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketW@win32@fast_io@@YAHPEAXIPEAUwsaprotocol_infow@12@@Z=__imp_WSADuplicateSocketW") +#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketA@win32@fast_io@@YAH_KIPEAUwsaprotocol_infoa@12@@Z=__imp_WSADuplicateSocketA") +#pragma comment(linker,"/alternatename:__imp_?WSADuplicateSocketW@win32@fast_io@@YAH_KIPEAUwsaprotocol_infow@12@@Z=__imp_WSADuplicateSocketW") #pragma comment(linker,"/alternatename:__imp_?WSACleanup@win32@fast_io@@YAHXZ=__imp_WSACleanup") #pragma comment(linker,"/alternatename:__imp_?WSAStartup@win32@fast_io@@YAHIPEAUwsadata@12@@Z=__imp_WSAStartup") #pragma comment(linker,"/alternatename:__imp_?WSAGetLastError@win32@fast_io@@YAHXZ=__imp_WSAGetLastError") @@ -95,7 +95,7 @@ #pragma comment(linker,"/alternatename:__imp_?shutdown@win32@fast_io@@YAH_KH@Z=__imp_shutdown") #pragma comment(linker,"/alternatename:__imp_?GetCurrentProcessId@win32@fast_io@@YAIXZ=__imp_GetCurrentProcessId") #pragma comment(linker,"/alternatename:__imp_?FlushFileBuffers@win32@fast_io@@YAHPEAX@Z=__imp_FlushFileBuffers") -#pragma comment(linker,"/alternatename:__imp_?GetQueuedCompletionStatus@win32@fast_io@@YAHPEAXPEAIPEA_KPEAUoverlapped@12@I@Z=__imp_GetQueuedCompletionStatus") +#pragma comment(linker,"/alternatename:__imp_?GetQueuedCompletionStatus@win32@fast_io@@YAHPEAXPEAIPEA_KPEAPEAUoverlapped@12@I@Z=__imp_GetQueuedCompletionStatus") #pragma comment(linker,"/alternatename:__imp_?freeaddrinfo@win32@fast_io@@YAXPEAU?$win32_family_addrinfo@$0A@@12@@Z=__imp_freeaddrinfo") #pragma comment(linker,"/alternatename:__imp_?FreeAddrInfoW@win32@fast_io@@YAXPEAU?$win32_family_addrinfo@$00@12@@Z=__imp_FreeAddrInfoW") #pragma comment(linker,"/alternatename:__imp_?getaddrinfo@win32@fast_io@@YAHPEBD0PEBU?$win32_family_addrinfo@$0A@@12@PEAPEAU312@@Z=__imp_getaddrinfo") @@ -167,6 +167,17 @@ #pragma comment(linker,"/alternatename:__imp_?SetConsoleTextAttribute@win32@fast_io@@YAHPEAXH@Z=__imp_SetConsoleTextAttribute") #pragma comment(linker,"/alternatename:__imp_?GetCurrentThreadId@win32@fast_io@@YAIXZ=__imp_GetCurrentThreadId") #pragma comment(linker,"/alternatename:__imp_?Sleep@win32@fast_io@@YAXI@Z=__imp_Sleep") +#pragma comment(linker,"/alternatename:__imp_?GetEnvironmentStringsW@win32@fast_io@@YAPEA_SXZ=__imp_GetEnvironmentStringsW") +#pragma comment(linker,"/alternatename:__imp_?GetEnvironmentStringsA@win32@fast_io@@YAPEADXZ=__imp_GetEnvironmentStringsA") +#pragma comment(linker,"/alternatename:__imp_?FreeEnvironmentStringsW@win32@fast_io@@YAHPEA_S@Z=__imp_FreeEnvironmentStringsW") +#pragma comment(linker,"/alternatename:__imp_?FreeEnvironmentStringsA@win32@fast_io@@YAHPEAD@Z=__imp_FreeEnvironmentStringsA") +#pragma comment(linker,"/alternatename:__imp_?getsockopt@win32@fast_io@@YAH_KHHPEADPEAH@Z=__imp_getsockopt") +#pragma comment(linker,"/alternatename:__imp_?GetFullPathNameW@win32@fast_io@@YAIPEB_SIPEA_SPEAPEA_S@Z=__imp_GetFullPathNameW") +#pragma comment(linker,"/alternatename:__imp_?GetFullPathNameA@win32@fast_io@@YAIPEBDIPEADPEAPEAD@Z=__imp_GetFullPathNameA") +#pragma comment(linker,"/alternatename:__imp_?GetVolumeInformationW@win32@fast_io@@YAHPEB_SPEA_SIPEAI221I@Z=__imp_GetVolumeInformationW") +#pragma comment(linker,"/alternatename:__imp_?GetVolumeInformationA@win32@fast_io@@YAHPEBDPEADIPEAI221I@Z=__imp_GetVolumeInformationA") +#pragma comment(linker,"/alternatename:__imp_?GetDiskFreeSpaceW@win32@fast_io@@YAHPEB_SPEAI111@Z=__imp_GetDiskFreeSpaceW") +#pragma comment(linker,"/alternatename:__imp_?GetDiskFreeSpaceA@win32@fast_io@@YAHPEBDPEAI111@Z=__imp_GetDiskFreeSpaceA") // NT #pragma comment(linker,"/alternatename:__imp_?rtl_nt_status_to_dos_error@nt@win32@fast_io@@YAII@Z=__imp_RtlNtStatusToDosError") #pragma comment(linker,"/alternatename:__imp_?NtClose@nt@win32@fast_io@@YAIPEAX@Z=__imp_NtClose") @@ -195,8 +206,8 @@ #pragma comment(linker,"/alternatename:__imp_?ZwDuplicateObject@nt@win32@fast_io@@YAIPEAX00PEAPEAXIII@Z=__imp_ZwDuplicateObject") #pragma comment(linker,"/alternatename:__imp_?NtWaitForSingleObject@nt@win32@fast_io@@YAIPEAXHPEA_K@Z=__imp_NtWaitForSingleObject") #pragma comment(linker,"/alternatename:__imp_?ZwWaitForSingleObject@nt@win32@fast_io@@YAIPEAXHPEA_K@Z=__imp_ZwWaitForSingleObject") -#pragma comment(linker,"/alternatename:__imp_?NtSetSystemTime@nt@win32@fast_io@@YAIPEA_K0@Z=__imp_NtSetSystemTime") -#pragma comment(linker,"/alternatename:__imp_?ZwSetSystemTime@nt@win32@fast_io@@YAIPEA_K0@Z=__imp_ZwSetSystemTime") +#pragma comment(linker,"/alternatename:__imp_?NtSetSystemTime@nt@win32@fast_io@@YAIPEA_J0@Z=__imp_NtSetSystemTime") +#pragma comment(linker,"/alternatename:__imp_?ZwSetSystemTime@nt@win32@fast_io@@YAIPEA_J0@Z=__imp_ZwSetSystemTime") #pragma comment(linker,"/alternatename:__imp_?NtCreateProcess@nt@win32@fast_io@@YAIPEAPEAXIPEAUobject_attributes@123@PEAXI222@Z=__imp_NtCreateProcess") #pragma comment(linker,"/alternatename:__imp_?ZwCreateProcess@nt@win32@fast_io@@YAIPEAPEAXIPEAUobject_attributes@123@PEAXI222@Z=__imp_ZwCreateProcess") #pragma comment(linker,"/alternatename:__imp_?rtl_dos_path_name_to_nt_path_name_u@nt@win32@fast_io@@YAEPEB_SPEAUunicode_string@123@PEAPEB_SPEAUrtl_relative_name_u@123@@Z=__imp_RtlDosPathNameToNtPathName_U") @@ -234,18 +245,18 @@ #pragma comment(linker,"/alternatename:__imp_?ZwReadVirtualMemory@nt@win32@fast_io@@YAIPEAX00_KPEA_K@Z=__imp_ZwReadVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?NtWriteVirtualMemory@nt@win32@fast_io@@YAIPEAX00_KPEA_K@Z=__imp_NtWriteVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?ZwWriteVirtualMemory@nt@win32@fast_io@@YAIPEAX00_KPEA_K@Z=__imp_ZwWriteVirtualMemory") -#pragma comment(linker,"/alternatename:__imp_?RtlAcquirePebLock@nt@win32@fast_io@@YAIXZ=__imp_RtlAcquirePebLock") -#pragma comment(linker,"/alternatename:__imp_?RtlReleasePebLock@nt@win32@fast_io@@YAIXZ=__imp_RtlReleasePebLock") +#pragma comment(linker,"/alternatename:__imp_?RtlAcquirePebLock@nt@win32@fast_io@@YAXXZ=__imp_RtlAcquirePebLock") +#pragma comment(linker,"/alternatename:__imp_?RtlReleasePebLock@nt@win32@fast_io@@YAXXZ=__imp_RtlReleasePebLock") #pragma comment(linker,"/alternatename:__imp_?NtAllocateVirtualMemory@nt@win32@fast_io@@YAIPEAXPEAPEAX_KPEA_KII@Z=__imp_NtAllocateVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?ZwAllocateVirtualMemory@nt@win32@fast_io@@YAIPEAXPEAPEAX_KPEA_KII@Z=__imp_ZwAllocateVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?NtFreeVirtualMemory@nt@win32@fast_io@@YAIPEAXPEAPEAXPEA_KI@Z=__imp_NtFreeVirtualMemory") #pragma comment(linker,"/alternatename:__imp_?ZwFreeVirtualMemory@nt@win32@fast_io@@YAIPEAXPEAPEAXPEA_KI@Z=__imp_ZwFreeVirtualMemory") -#pragma comment(linker,"/alternatename:__imp_?RtlInitUnicodeString@nt@win32@fast_io@@YAIPEAUunicode_string@123@PEA_S@Z=__imp_RtlInitUnicodeString") +#pragma comment(linker,"/alternatename:__imp_?RtlInitUnicodeString@nt@win32@fast_io@@YAXPEAUunicode_string@123@PEA_S@Z=__imp_RtlInitUnicodeString") #pragma comment(linker,"/alternatename:__imp_?CsrClientCallServer@nt@win32@fast_io@@YAIPEAX0II@Z=__imp_CsrClientCallServer") #pragma comment(linker,"/alternatename:__imp_?NtQuerySystemInformation@nt@win32@fast_io@@YAIW4system_information_class@123@PEAXIPEAI@Z=__imp_NtQuerySystemInformation") #pragma comment(linker,"/alternatename:__imp_?ZwQuerySystemInformation@nt@win32@fast_io@@YAIW4system_information_class@123@PEAXIPEAI@Z=__imp_ZwQuerySystemInformation") #pragma comment(linker,"/alternatename:__imp_?RtlAcquireSRWLockExclusive@nt@win32@fast_io@@YAXPEAX@Z=__imp_RtlAcquireSRWLockExclusive") -#pragma comment(linker,"/alternatename:__imp_?RtlTryAcquireSRWLockExclusive@nt@win32@fast_io@@YAIPEAX@Z=__imp_RtlTryAcquireSRWLockExclusive") +#pragma comment(linker,"/alternatename:__imp_?RtlTryAcquireSRWLockExclusive@nt@win32@fast_io@@YAEPEAX@Z=__imp_RtlTryAcquireSRWLockExclusive") #pragma comment(linker,"/alternatename:__imp_?RtlReleaseSRWLockExclusive@nt@win32@fast_io@@YAXPEAX@Z=__imp_RtlReleaseSRWLockExclusive") #pragma comment(linker,"/alternatename:__imp_?NtQueryVolumeInformationFile@nt@win32@fast_io@@YAIPEIAXPEIAUio_status_block@123@0IW4fs_information_class@123@@Z=__imp_NtQueryVolumeInformationFile") #pragma comment(linker,"/alternatename:__imp_?ZwQueryVolumeInformationFile@nt@win32@fast_io@@YAIPEIAXPEIAUio_status_block@123@0IW4fs_information_class@123@@Z=__imp_ZwQueryVolumeInformationFile") @@ -255,7 +266,7 @@ #pragma comment(linker,"/alternatename:__imp_?ZwCreateNamedPipeFile@nt@win32@fast_io@@YAIPEIAPEAXIPEIAUobject_attributes@123@PEIAUio_status_block@123@IIIIIIIIIPEA_J@Z=__imp_ZwCreateNamedPipeFile") #pragma comment(linker,"/alternatename:__imp_?NtQueryPerformanceCounter@nt@win32@fast_io@@YAIPEA_J0@Z=__imp_NtQueryPerformanceCounter") #pragma comment(linker,"/alternatename:__imp_?ZwQueryPerformanceCounter@nt@win32@fast_io@@YAIPEA_J0@Z=__imp_ZwQueryPerformanceCounter") -#pragma comment(linker,"/alternatename:__imp_?RtlGetSystemTimePrecise@nt@win32@fast_io@@YA_JXZ=__imp_RtlGetSystemTimePrecise") +#pragma comment(linker,"/alternatename:__imp_?RtlGetSystemTimePrecise@nt@win32@fast_io@@YA_KXZ=__imp_RtlGetSystemTimePrecise") #pragma comment(linker,"/alternatename:__imp_?NtQueryInformationThread@nt@win32@fast_io@@YAIPEIAXW4thread_information_class@123@PEAXIPEAI@Z=__imp_NtQueryInformationThread") #pragma comment(linker,"/alternatename:__imp_?ZwQueryInformationThread@nt@win32@fast_io@@YAIPEIAXW4thread_information_class@123@PEAXIPEAI@Z=__imp_ZwQueryInformationThread") #pragma comment(linker,"/alternatename:__imp_?RtlAdjustPrivilege@nt@win32@fast_io@@YAIIEEPEAE@Z=__imp_RtlAdjustPrivilege") diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h b/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h index 262482bb7..139157f5c 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once // This file have been generated by example/0039.win32mangling, therefore, do NOT edit this file directely! // clang-format off // WIN32 @@ -48,7 +48,7 @@ #pragma comment(linker,"/alternatename:?CloseHandle$exit_thunk@win32@fast_io@@$$hYAHPEAX@Z=#CloseHandle") #pragma comment(linker,"/alternatename:?LockFileEx$exit_thunk@win32@fast_io@@$$hYAHPEAXIIIIPEAUoverlapped@12@@Z=#LockFileEx") #pragma comment(linker,"/alternatename:?UnlockFileEx$exit_thunk@win32@fast_io@@$$hYAHPEAXIIIPEAUoverlapped@12@@Z=#UnlockFileEx") -#pragma comment(linker,"/alternatename:?DeviceIoControl$exit_thunk@win32@fast_io@@$$hYAHPEAXI0I0I0PEAUoverlapped@12@@Z=#DeviceIoControl") +#pragma comment(linker,"/alternatename:?DeviceIoControl$exit_thunk@win32@fast_io@@$$hYAHPEAXI0I0IPEAIPEAUoverlapped@12@@Z=#DeviceIoControl") #pragma comment(linker,"/alternatename:?GetFileType$exit_thunk@win32@fast_io@@$$hYAIPEAX@Z=#GetFileType") #pragma comment(linker,"/alternatename:?GetACP$exit_thunk@win32@fast_io@@$$hYAIXZ=#GetACP") #pragma comment(linker,"/alternatename:?GetEnvironmentVariableA$exit_thunk@win32@fast_io@@$$hYAIPEBDPEADI@Z=#GetEnvironmentVariableA") @@ -70,8 +70,8 @@ #pragma comment(linker,"/alternatename:?TryEnterCriticalSection$exit_thunk@win32@fast_io@@$$hYAHPEAX@Z=#TryEnterCriticalSection") #pragma comment(linker,"/alternatename:?LeaveCriticalSection$exit_thunk@win32@fast_io@@$$hYAXPEAX@Z=#LeaveCriticalSection") #pragma comment(linker,"/alternatename:?DeleteCriticalSection$exit_thunk@win32@fast_io@@$$hYAXPEAX@Z=#DeleteCriticalSection") -#pragma comment(linker,"/alternatename:?WSADuplicateSocketA$exit_thunk@win32@fast_io@@$$hYAHPEAXIPEAUwsaprotocol_infoa@12@@Z=#WSADuplicateSocketA") -#pragma comment(linker,"/alternatename:?WSADuplicateSocketW$exit_thunk@win32@fast_io@@$$hYAHPEAXIPEAUwsaprotocol_infow@12@@Z=#WSADuplicateSocketW") +#pragma comment(linker,"/alternatename:?WSADuplicateSocketA$exit_thunk@win32@fast_io@@$$hYAH_KIPEAUwsaprotocol_infoa@12@@Z=#WSADuplicateSocketA") +#pragma comment(linker,"/alternatename:?WSADuplicateSocketW$exit_thunk@win32@fast_io@@$$hYAH_KIPEAUwsaprotocol_infow@12@@Z=#WSADuplicateSocketW") #pragma comment(linker,"/alternatename:?WSACleanup$exit_thunk@win32@fast_io@@$$hYAHXZ=#WSACleanup") #pragma comment(linker,"/alternatename:?WSAStartup$exit_thunk@win32@fast_io@@$$hYAHIPEAUwsadata@12@@Z=#WSAStartup") #pragma comment(linker,"/alternatename:?WSAGetLastError$exit_thunk@win32@fast_io@@$$hYAHXZ=#WSAGetLastError") @@ -95,7 +95,7 @@ #pragma comment(linker,"/alternatename:?shutdown$exit_thunk@win32@fast_io@@$$hYAH_KH@Z=#shutdown") #pragma comment(linker,"/alternatename:?GetCurrentProcessId$exit_thunk@win32@fast_io@@$$hYAIXZ=#GetCurrentProcessId") #pragma comment(linker,"/alternatename:?FlushFileBuffers$exit_thunk@win32@fast_io@@$$hYAHPEAX@Z=#FlushFileBuffers") -#pragma comment(linker,"/alternatename:?GetQueuedCompletionStatus$exit_thunk@win32@fast_io@@$$hYAHPEAXPEAIPEA_KPEAUoverlapped@12@I@Z=#GetQueuedCompletionStatus") +#pragma comment(linker,"/alternatename:?GetQueuedCompletionStatus$exit_thunk@win32@fast_io@@$$hYAHPEAXPEAIPEA_KPEAPEAUoverlapped@12@I@Z=#GetQueuedCompletionStatus") #pragma comment(linker,"/alternatename:?freeaddrinfo$exit_thunk@win32@fast_io@@$$hYAXPEAU?$win32_family_addrinfo@$0A@@12@@Z=#freeaddrinfo") #pragma comment(linker,"/alternatename:?FreeAddrInfoW$exit_thunk@win32@fast_io@@$$hYAXPEAU?$win32_family_addrinfo@$00@12@@Z=#FreeAddrInfoW") #pragma comment(linker,"/alternatename:?getaddrinfo$exit_thunk@win32@fast_io@@$$hYAHPEBD0PEBU?$win32_family_addrinfo@$0A@@12@PEAPEAU312@@Z=#getaddrinfo") @@ -167,6 +167,17 @@ #pragma comment(linker,"/alternatename:?SetConsoleTextAttribute$exit_thunk@win32@fast_io@@$$hYAHPEAXH@Z=#SetConsoleTextAttribute") #pragma comment(linker,"/alternatename:?GetCurrentThreadId$exit_thunk@win32@fast_io@@$$hYAIXZ=#GetCurrentThreadId") #pragma comment(linker,"/alternatename:?Sleep$exit_thunk@win32@fast_io@@$$hYAXI@Z=#Sleep") +#pragma comment(linker,"/alternatename:?GetEnvironmentStringsW$exit_thunk@win32@fast_io@@$$hYAPEA_SXZ=#GetEnvironmentStringsW") +#pragma comment(linker,"/alternatename:?GetEnvironmentStringsA$exit_thunk@win32@fast_io@@$$hYAPEADXZ=#GetEnvironmentStringsA") +#pragma comment(linker,"/alternatename:?FreeEnvironmentStringsW$exit_thunk@win32@fast_io@@$$hYAHPEA_S@Z=#FreeEnvironmentStringsW") +#pragma comment(linker,"/alternatename:?FreeEnvironmentStringsA$exit_thunk@win32@fast_io@@$$hYAHPEAD@Z=#FreeEnvironmentStringsA") +#pragma comment(linker,"/alternatename:?getsockopt$exit_thunk@win32@fast_io@@$$hYAH_KHHPEADPEAH@Z=#getsockopt") +#pragma comment(linker,"/alternatename:?GetFullPathNameW$exit_thunk@win32@fast_io@@$$hYAIPEB_SIPEA_SPEAPEA_S@Z=#GetFullPathNameW") +#pragma comment(linker,"/alternatename:?GetFullPathNameA$exit_thunk@win32@fast_io@@$$hYAIPEBDIPEADPEAPEAD@Z=#GetFullPathNameA") +#pragma comment(linker,"/alternatename:?GetVolumeInformationW$exit_thunk@win32@fast_io@@$$hYAHPEB_SPEA_SIPEAI221I@Z=#GetVolumeInformationW") +#pragma comment(linker,"/alternatename:?GetVolumeInformationA$exit_thunk@win32@fast_io@@$$hYAHPEBDPEADIPEAI221I@Z=#GetVolumeInformationA") +#pragma comment(linker,"/alternatename:?GetDiskFreeSpaceW$exit_thunk@win32@fast_io@@$$hYAHPEB_SPEAI111@Z=#GetDiskFreeSpaceW") +#pragma comment(linker,"/alternatename:?GetDiskFreeSpaceA$exit_thunk@win32@fast_io@@$$hYAHPEBDPEAI111@Z=#GetDiskFreeSpaceA") // NT #pragma comment(linker,"/alternatename:?rtl_nt_status_to_dos_error$exit_thunk@nt@win32@fast_io@@$$hYAII@Z=#RtlNtStatusToDosError") #pragma comment(linker,"/alternatename:?NtClose$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX@Z=#NtClose") @@ -195,8 +206,8 @@ #pragma comment(linker,"/alternatename:?ZwDuplicateObject$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX00PEAPEAXIII@Z=#ZwDuplicateObject") #pragma comment(linker,"/alternatename:?NtWaitForSingleObject$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXHPEA_K@Z=#NtWaitForSingleObject") #pragma comment(linker,"/alternatename:?ZwWaitForSingleObject$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXHPEA_K@Z=#ZwWaitForSingleObject") -#pragma comment(linker,"/alternatename:?NtSetSystemTime$exit_thunk@nt@win32@fast_io@@$$hYAIPEA_K0@Z=#NtSetSystemTime") -#pragma comment(linker,"/alternatename:?ZwSetSystemTime$exit_thunk@nt@win32@fast_io@@$$hYAIPEA_K0@Z=#ZwSetSystemTime") +#pragma comment(linker,"/alternatename:?NtSetSystemTime$exit_thunk@nt@win32@fast_io@@$$hYAIPEA_J0@Z=#NtSetSystemTime") +#pragma comment(linker,"/alternatename:?ZwSetSystemTime$exit_thunk@nt@win32@fast_io@@$$hYAIPEA_J0@Z=#ZwSetSystemTime") #pragma comment(linker,"/alternatename:?NtCreateProcess$exit_thunk@nt@win32@fast_io@@$$hYAIPEAPEAXIPEAUobject_attributes@123@PEAXI222@Z=#NtCreateProcess") #pragma comment(linker,"/alternatename:?ZwCreateProcess$exit_thunk@nt@win32@fast_io@@$$hYAIPEAPEAXIPEAUobject_attributes@123@PEAXI222@Z=#ZwCreateProcess") #pragma comment(linker,"/alternatename:?rtl_dos_path_name_to_nt_path_name_u$exit_thunk@nt@win32@fast_io@@$$hYAEPEB_SPEAUunicode_string@123@PEAPEB_SPEAUrtl_relative_name_u@123@@Z=#RtlDosPathNameToNtPathName_U") @@ -234,18 +245,18 @@ #pragma comment(linker,"/alternatename:?ZwReadVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX00_KPEA_K@Z=#ZwReadVirtualMemory") #pragma comment(linker,"/alternatename:?NtWriteVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX00_KPEA_K@Z=#NtWriteVirtualMemory") #pragma comment(linker,"/alternatename:?ZwWriteVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX00_KPEA_K@Z=#ZwWriteVirtualMemory") -#pragma comment(linker,"/alternatename:?RtlAcquirePebLock$exit_thunk@nt@win32@fast_io@@$$hYAIXZ=#RtlAcquirePebLock") -#pragma comment(linker,"/alternatename:?RtlReleasePebLock$exit_thunk@nt@win32@fast_io@@$$hYAIXZ=#RtlReleasePebLock") +#pragma comment(linker,"/alternatename:?RtlAcquirePebLock$exit_thunk@nt@win32@fast_io@@$$hYAXXZ=#RtlAcquirePebLock") +#pragma comment(linker,"/alternatename:?RtlReleasePebLock$exit_thunk@nt@win32@fast_io@@$$hYAXXZ=#RtlReleasePebLock") #pragma comment(linker,"/alternatename:?NtAllocateVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXPEAPEAX_KPEA_KII@Z=#NtAllocateVirtualMemory") #pragma comment(linker,"/alternatename:?ZwAllocateVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXPEAPEAX_KPEA_KII@Z=#ZwAllocateVirtualMemory") #pragma comment(linker,"/alternatename:?NtFreeVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXPEAPEAXPEA_KI@Z=#NtFreeVirtualMemory") #pragma comment(linker,"/alternatename:?ZwFreeVirtualMemory$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXPEAPEAXPEA_KI@Z=#ZwFreeVirtualMemory") -#pragma comment(linker,"/alternatename:?RtlInitUnicodeString$exit_thunk@nt@win32@fast_io@@$$hYAIPEAUunicode_string@123@PEA_S@Z=#RtlInitUnicodeString") +#pragma comment(linker,"/alternatename:?RtlInitUnicodeString$exit_thunk@nt@win32@fast_io@@$$hYAXPEAUunicode_string@123@PEA_S@Z=#RtlInitUnicodeString") #pragma comment(linker,"/alternatename:?CsrClientCallServer$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX0II@Z=#CsrClientCallServer") #pragma comment(linker,"/alternatename:?NtQuerySystemInformation$exit_thunk@nt@win32@fast_io@@$$hYAIW4system_information_class@123@PEAXIPEAI@Z=#NtQuerySystemInformation") #pragma comment(linker,"/alternatename:?ZwQuerySystemInformation$exit_thunk@nt@win32@fast_io@@$$hYAIW4system_information_class@123@PEAXIPEAI@Z=#ZwQuerySystemInformation") #pragma comment(linker,"/alternatename:?RtlAcquireSRWLockExclusive$exit_thunk@nt@win32@fast_io@@$$hYAXPEAX@Z=#RtlAcquireSRWLockExclusive") -#pragma comment(linker,"/alternatename:?RtlTryAcquireSRWLockExclusive$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX@Z=#RtlTryAcquireSRWLockExclusive") +#pragma comment(linker,"/alternatename:?RtlTryAcquireSRWLockExclusive$exit_thunk@nt@win32@fast_io@@$$hYAEPEAX@Z=#RtlTryAcquireSRWLockExclusive") #pragma comment(linker,"/alternatename:?RtlReleaseSRWLockExclusive$exit_thunk@nt@win32@fast_io@@$$hYAXPEAX@Z=#RtlReleaseSRWLockExclusive") #pragma comment(linker,"/alternatename:?NtQueryVolumeInformationFile$exit_thunk@nt@win32@fast_io@@$$hYAIPEIAXPEIAUio_status_block@123@0IW4fs_information_class@123@@Z=#NtQueryVolumeInformationFile") #pragma comment(linker,"/alternatename:?ZwQueryVolumeInformationFile$exit_thunk@nt@win32@fast_io@@$$hYAIPEIAXPEIAUio_status_block@123@0IW4fs_information_class@123@@Z=#ZwQueryVolumeInformationFile") @@ -255,7 +266,7 @@ #pragma comment(linker,"/alternatename:?ZwCreateNamedPipeFile$exit_thunk@nt@win32@fast_io@@$$hYAIPEIAPEAXIPEIAUobject_attributes@123@PEIAUio_status_block@123@IIIIIIIIIPEA_J@Z=#ZwCreateNamedPipeFile") #pragma comment(linker,"/alternatename:?NtQueryPerformanceCounter$exit_thunk@nt@win32@fast_io@@$$hYAIPEA_J0@Z=#NtQueryPerformanceCounter") #pragma comment(linker,"/alternatename:?ZwQueryPerformanceCounter$exit_thunk@nt@win32@fast_io@@$$hYAIPEA_J0@Z=#ZwQueryPerformanceCounter") -#pragma comment(linker,"/alternatename:?RtlGetSystemTimePrecise$exit_thunk@nt@win32@fast_io@@$$hYA_JXZ=#RtlGetSystemTimePrecise") +#pragma comment(linker,"/alternatename:?RtlGetSystemTimePrecise$exit_thunk@nt@win32@fast_io@@$$hYA_KXZ=#RtlGetSystemTimePrecise") #pragma comment(linker,"/alternatename:?NtQueryInformationThread$exit_thunk@nt@win32@fast_io@@$$hYAIPEIAXW4thread_information_class@123@PEAXIPEAI@Z=#NtQueryInformationThread") #pragma comment(linker,"/alternatename:?ZwQueryInformationThread$exit_thunk@nt@win32@fast_io@@$$hYAIPEIAXW4thread_information_class@123@PEAXIPEAI@Z=#ZwQueryInformationThread") #pragma comment(linker,"/alternatename:?RtlAdjustPrivilege$exit_thunk@nt@win32@fast_io@@$$hYAIIEEPEAE@Z=#RtlAdjustPrivilege") From 3c0384396778a6a905874471c38eb861915e41ed Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 13:01:47 +0800 Subject: [PATCH 16/43] Refactor append methods in process argument and environment structures to return references - Updated `append` methods in `basic_win32_process_args`, `basic_win32_process_envs`, and `posix_process_args` to return a reference to the current object, enhancing method chaining capabilities. - Improved code clarity and consistency across process argument and environment handling. --- .../fast_io_hosted/process/process/arg_env.h | 12 ++- .../fast_io_hosted/process/process/posix.h | 92 +++++++++++++++++-- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/include/fast_io_hosted/process/process/arg_env.h b/include/fast_io_hosted/process/process/arg_env.h index 3039c9e00..de3fafe16 100644 --- a/include/fast_io_hosted/process/process/arg_env.h +++ b/include/fast_io_hosted/process/process/arg_env.h @@ -181,9 +181,11 @@ struct basic_win32_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } - inline constexpr void append(basic_win32_process_args const &others) noexcept + inline constexpr basic_win32_process_args& append(basic_win32_process_args const &others) noexcept { args.append(others.args); + + return *this; } }; @@ -240,9 +242,11 @@ struct basic_win32_process_envs FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } - inline constexpr void append(basic_win32_process_envs const &others) noexcept + inline constexpr basic_win32_process_envs& append(basic_win32_process_envs const &others) noexcept { envs.append(others.envs); + + return *this; } }; @@ -440,7 +444,7 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return reinterpret_cast(arg_envs.data()); } - inline constexpr void append(posix_process_args const &others) noexcept + inline constexpr posix_process_args& append(posix_process_args const &others) noexcept { if (others.arg_envs.size() > 1) [[likely]] { @@ -456,6 +460,8 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE arg_envs.emplace_back_unchecked(); // nullptr } + + return *this; } }; diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index ad75a94b2..440d6b5e1 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -262,6 +262,66 @@ inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) #endif } +inline ::fast_io::containers::basic_string get_tls_str_fd_path(int fd) +{ + constexpr auto fdcwd_val{ +#if defined(AT_FDCWD) + AT_FDCWD +#else + -2 +#endif + }; + + if (fd == fdcwd_val) + { + return {}; + } + +#if defined(PATH_MAX) + constexpr ::std::size_t path_max{PATH_MAX}; +#elif defined(MAXPATHLEN) + constexpr ::std::size_t path_max{MAXPATHLEN}; +#else + constexpr ::std::size_t path_max{1024u}; +#endif + + ::fast_io::containers::basic_string ret{}; + ret.resize(path_max + 1u); + portable_fd_path(fd, ret.data(), path_max); + ret.resize(::fast_io::cstr_nlen(ret.data(), path_max)); + return ret; +} + +inline ::fast_io::containers::basic_string get_tls_str_fd_path_filename(int fd, char const *filename) +{ + constexpr auto fdcwd_val{ +#if defined(AT_FDCWD) + AT_FDCWD +#else + -2 +#endif + }; + + if (fd == fdcwd_val) + { + return ::fast_io::containers::basic_string{filename, filename + ::fast_io::cstr_len(filename)}; + } + +#if defined(PATH_MAX) + constexpr ::std::size_t path_max{PATH_MAX}; +#elif defined(MAXPATHLEN) + constexpr ::std::size_t path_max{MAXPATHLEN}; +#else + constexpr ::std::size_t path_max{1024u}; +#endif + + ::fast_io::containers::basic_string ret{}; + ret.resize(path_max + 1u); + portable_fd_path(fd, ret.data(), path_max); + ret.resize(::fast_io::cstr_nlen(ret.data(), path_max)); + ret.append(::fast_io::containers::basic_string_view{filename, ::fast_io::cstr_len(filename)}); + return ret; +} inline pid_t posix_fork() { @@ -782,7 +842,7 @@ inline void kill(posix_process_observer ppob, posix_wait_status exit_code) #if defined(__linux__) && defined(__NR_kill) system_call_throw_error(system_call<__NR_kill, int>(ppob.pid, exit_code.wait_loc)); #else - if(::fast_io::posix::libc_kill(ppob.pid, exit_code.wait_loc) == -1) [[unlikely]] + if (::fast_io::posix::libc_kill(ppob.pid, exit_code.wait_loc) == -1) [[unlikely]] { throw_posix_error(); } @@ -815,10 +875,14 @@ class posix_process : public posix_process_observer posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ // #ifdef __DARWIN_C_LEVEL -#if 0 - ::fast_io::details::pipefork_execveat_impl(pate.fd, filename, args.get(), envp.get(), pio, mode) +#ifdef FAST_IO_POSIX_PROCESS_USE_FORK + ::fast_io::details::pipefork_execveat_impl(pate.fd, filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get(), + args.get(), envp.get(), pio, mode) #else - ::fast_io::details::vfork_execveat_impl(pate.fd, filename, args.get(), envp.get(), pio, mode) + ::fast_io::details::vfork_execveat_impl(pate.fd, filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get(), + envp.get(), pio, mode) #endif } { @@ -829,10 +893,14 @@ class posix_process : public posix_process_observer posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ // #ifdef __DARWIN_C_LEVEL -#if 0 - ::fast_io::details::pipefork_execve_impl(filename, args.get(), envp.get(), pio, mode) +#ifdef FAST_IO_POSIX_PROCESS_USE_FORK + ::fast_io::details::pipefork_execve_impl(filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{filename}.append(args).get(), + envp.get(), pio, mode) #else - ::fast_io::details::vfork_execve_impl(filename, args.get(), envp.get(), pio, mode) + ::fast_io::details::vfork_execve_impl(filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{filename}.append(args).get(), + envp.get(), pio, mode) #endif } { @@ -842,10 +910,14 @@ class posix_process : public posix_process_observer posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ // #ifdef __DARWIN_C_LEVEL -#if 0 - ::fast_io::details::pipefork_execveat_common_impl(ent.fd, ent.filename, args.get(), envp.get(), pio, mode) +#ifdef FAST_IO_POSIX_PROCESS_USE_FORK + ::fast_io::details::pipefork_execveat_common_impl(ent.fd, ent.filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get(), + envp.get(), pio, mode) #else - ::fast_io::details::vfork_execveat_common_impl(ent.fd, ent.filename, args.get(), envp.get(), pio, mode) + ::fast_io::details::vfork_execveat_common_impl(ent.fd, ent.filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get(), + envp.get(), pio, mode) #endif } { From 26a99a4b640124ac567dfd9576ba900b9e9dbec7 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 13:04:22 +0800 Subject: [PATCH 17/43] Fix path resizing logic in POSIX process header for accurate string length calculation - Updated the resizing logic in `posix.h` to correctly account for the null terminator when determining the length of the string. - Added a trailing slash to the returned path string to ensure proper formatting when appending filenames. --- include/fast_io_hosted/process/process/posix.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 440d6b5e1..5aa8f9880 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -288,7 +288,7 @@ inline ::fast_io::containers::basic_string ret{}; ret.resize(path_max + 1u); portable_fd_path(fd, ret.data(), path_max); - ret.resize(::fast_io::cstr_nlen(ret.data(), path_max)); + ret.resize(::fast_io::cstr_nlen(ret.data(), path_max + 1u)); return ret; } @@ -318,8 +318,11 @@ inline ::fast_io::containers::basic_string ret{}; ret.resize(path_max + 1u); portable_fd_path(fd, ret.data(), path_max); - ret.resize(::fast_io::cstr_nlen(ret.data(), path_max)); + ret.resize(::fast_io::cstr_nlen(ret.data(), path_max + 1u)); + + ret.push_back('/'); ret.append(::fast_io::containers::basic_string_view{filename, ::fast_io::cstr_len(filename)}); + return ret; } From 7aebe7d1d16a6738a50584c998ce5ebb4a196c11 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 13:25:15 +0800 Subject: [PATCH 18/43] Add posix_vfork option and refactor process execution methods for POSIX - Introduced a new `posix_vfork` option in `option.h` to support process creation using vfork, which has specific limitations on parameter modifications. - Refactored process execution methods in `posix.h` to utilize a common `fork_execveat_impl` function, streamlining the handling of process creation based on the selected mode. - Enhanced clarity and maintainability of the code by consolidating vfork and pipefork logic into unified implementations. --- .../fast_io_hosted/process/process/option.h | 4 +- .../fast_io_hosted/process/process/posix.h | 82 +++++++++++-------- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/include/fast_io_hosted/process/process/option.h b/include/fast_io_hosted/process/process/option.h index aa2dd6e22..c92fdf832 100644 --- a/include/fast_io_hosted/process/process/option.h +++ b/include/fast_io_hosted/process/process/option.h @@ -11,7 +11,9 @@ enum process_mode : ::std::uint_least64_t alloc_new_console = static_cast<::std::uint_least64_t>(1) << 1, // [WINDOWS, WINNT] CREATE_NEW_CONSOLE (Automatically assign a console to new threads) argv0_no_path_append = static_cast<::std::uint_least64_t>(1) << 2, - // Do not automatically append appname to argv0 + // [POSIX, WINDOWS, WINNT] Do not automatically append appname to argv0 + posix_vfork = static_cast<::std::uint_least64_t>(1) << 3, + // [POSIX] Using vfork to create processes, but this prevents many parameters from taking effect (vfork does not allow modification of global memory before exec). }; inline constexpr process_mode operator&(process_mode x, process_mode y) noexcept diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 5aa8f9880..71a6b11ab 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -322,7 +322,7 @@ inline ::fast_io::containers::basic_string{filename, ::fast_io::cstr_len(filename)}); - + return ret; } @@ -791,6 +791,44 @@ inline pid_t vfork_execve_impl(path_type const &csv, char const *const *args, ch #endif } +inline pid_t fork_execveat_common_impl(int dirfd, char const *cstr, char const *const *args, char const *const *envp, posix_process_io const &pio, process_mode mode) +{ + if ((mode & process_mode::posix_vfork) == process_mode::posix_vfork) + { + return vfork_execveat_common_impl(dirfd, cstr, args, envp, pio, mode); + } + else + { + return pipefork_execveat_common_impl(dirfd, cstr, args, envp, pio, mode); + } +} + +template +inline pid_t fork_execveat_impl(int dirfd, path_type const &csv, char const *const *args, char const *const *envp, posix_process_io const &pio, process_mode mode) +{ + if ((mode & process_mode::posix_vfork) == process_mode::posix_vfork) + { + return vfork_execveat_impl(dirfd, csv, args, envp, pio, mode); + } + else + { + return pipefork_execveat_impl(dirfd, csv, args, envp, pio, mode); + } +} + +template +inline pid_t fork_execve_impl(path_type const &csv, char const *const *args, char const *const *envp, posix_process_io const &pio, process_mode mode) +{ + if ((mode & process_mode::posix_vfork) == process_mode::posix_vfork) + { + return vfork_execve_impl(csv, args, envp, pio, mode); + } + else + { + return pipefork_execve_impl(csv, args, envp, pio, mode); + } +} + } // namespace details class posix_process_observer @@ -877,16 +915,10 @@ class posix_process : public posix_process_observer inline posix_process(posix_at_entry pate, path_type const &filename, posix_process_args const &args = {}, posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ -// #ifdef __DARWIN_C_LEVEL -#ifdef FAST_IO_POSIX_PROCESS_USE_FORK - ::fast_io::details::pipefork_execveat_impl(pate.fd, filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get(), - args.get(), envp.get(), pio, mode) -#else - ::fast_io::details::vfork_execveat_impl(pate.fd, filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get(), - envp.get(), pio, mode) -#endif + ::fast_io::details::fork_execveat_impl(pate.fd, filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get(), + envp.get(), pio, mode) + } { } @@ -895,16 +927,10 @@ class posix_process : public posix_process_observer inline posix_process(path_type const &filename, posix_process_args const &args = {}, posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ -// #ifdef __DARWIN_C_LEVEL -#ifdef FAST_IO_POSIX_PROCESS_USE_FORK - ::fast_io::details::pipefork_execve_impl(filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{filename}.append(args).get(), - envp.get(), pio, mode) -#else - ::fast_io::details::vfork_execve_impl(filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{filename}.append(args).get(), - envp.get(), pio, mode) -#endif + ::fast_io::details::fork_execve_impl(filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{filename}.append(args).get(), + envp.get(), pio, mode) + } { } @@ -912,17 +938,9 @@ class posix_process : public posix_process_observer inline posix_process(::fast_io::posix_fs_dirent ent, posix_process_args const &args = {}, posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ -// #ifdef __DARWIN_C_LEVEL -#ifdef FAST_IO_POSIX_PROCESS_USE_FORK - ::fast_io::details::pipefork_execveat_common_impl(ent.fd, ent.filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get(), - envp.get(), pio, mode) -#else - ::fast_io::details::vfork_execveat_common_impl(ent.fd, ent.filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get(), - envp.get(), pio, mode) -#endif - } + ::fast_io::details::fork_execveat_common_impl(ent.fd, ent.filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get(), + envp.get(), pio, mode)} { } From e70856c6ce3d9e2d79256ac1b3e81f2bdb74390d Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 13:27:14 +0800 Subject: [PATCH 19/43] Refactor process execution logic in posix.h to improve clarity and maintainability - Added conditional compilation for session management in the vfork_and_execveat function, enhancing the handling of process creation modes. - Improved code organization by encapsulating session management logic within preprocessor directives, allowing for easier modifications in the future. --- include/fast_io_hosted/process/process/posix.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 71a6b11ab..14976272a 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -712,12 +712,15 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con // parent process ends here // subprocess begin // No modifications to the memory of the parent process are allowed until exec + +#if 0 if ((mode & process_mode::new_session) == process_mode::new_session) { // No modification of parent process memory /// @error: Whether the syscall or libc implementation does not modify the parent process posix_setsid_noexcept(); } +#endif #if defined(__linux__) && defined(__NR_execveat) auto ret{system_call<__NR_execveat, int>(dirfd, cstr, args, envp, AT_SYMLINK_NOFOLLOW)}; From be06549a62dcf24261d174fd8fe3a6084ace7f39 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 13:35:16 +0800 Subject: [PATCH 20/43] Update vfork_and_execveat function to include unused parameter for process mode - Modified the vfork_and_execveat function signature to add [[maybe_unused]] for the process_mode parameter, improving code clarity and indicating that the parameter may not be utilized in all contexts. --- include/fast_io_hosted/process/process/posix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 14976272a..ddf77cee7 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -697,7 +697,7 @@ struct fd_remapper }; // only used in vfork_execveat_common_impl() -inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, int volatile &t_errno, process_mode mode) noexcept +inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, int volatile &t_errno, [[maybe_unused]] process_mode mode) noexcept { // vfork can only be called through libc wrapper pid = ::fast_io::posix::libc_vfork(); From 58aa2c76c32272103df465c3e328ca7fc53d17c3 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sat, 8 Nov 2025 18:36:38 +0800 Subject: [PATCH 21/43] Enhance process_mode enumeration and update posix_execveat function - Changed the process_mode enumeration to a scoped enum class for better type safety and clarity. - Added a new 'follow' option to the process_mode enum to allow symbolic links to be followed during process execution. - Updated the posix_execveat function to accept the process_mode parameter, modifying behavior based on the follow option. - Refactored flags handling in posix_execveat and vfork_and_execveat functions to improve clarity and maintainability. --- .../fast_io_hosted/process/process/option.h | 5 ++- .../fast_io_hosted/process/process/posix.h | 40 +++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/include/fast_io_hosted/process/process/option.h b/include/fast_io_hosted/process/process/option.h index c92fdf832..a4ee07fb1 100644 --- a/include/fast_io_hosted/process/process/option.h +++ b/include/fast_io_hosted/process/process/option.h @@ -2,7 +2,7 @@ namespace fast_io { -enum process_mode : ::std::uint_least64_t +enum class process_mode : ::std::uint_least64_t { none = 0, // *indicates that the process mode has not been evaluated yet @@ -14,6 +14,9 @@ enum process_mode : ::std::uint_least64_t // [POSIX, WINDOWS, WINNT] Do not automatically append appname to argv0 posix_vfork = static_cast<::std::uint_least64_t>(1) << 3, // [POSIX] Using vfork to create processes, but this prevents many parameters from taking effect (vfork does not allow modification of global memory before exec). + follow = static_cast<::std::uint_least64_t>(1) << 4, + // [POSIX, WINDOWS, WINNT] Allow symbolic links to follow + }; inline constexpr process_mode operator&(process_mode x, process_mode y) noexcept diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index ddf77cee7..4a56ba0a4 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -394,12 +394,24 @@ inline void posix_waitpid_noexcept(pid_t pid) noexcept #endif } -inline int posix_execveat(int dirfd, char const *cstr, char const *const *args, char const *const *envp) noexcept +inline int posix_execveat(int dirfd, char const *cstr, char const *const *args, char const *const *envp, process_mode mode) noexcept { + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + #if defined(__linux__) && defined(__NR_execveat) - return -(system_call<__NR_execveat, int>(dirfd, cstr, args, envp, AT_SYMLINK_NOFOLLOW)); + int flags{}; + if (!follow) + { + flags |= AT_SYMLINK_NOFOLLOW; + } + return -(system_call<__NR_execveat, int>(dirfd, cstr, args, envp, flags)); #else - int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, O_RDONLY | O_NOFOLLOW, 0644)}; + int flags{O_RDONLY}; + if (!follow) + { + flags |= O_NOFOLLOW; + } + int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, flags, 0644)}; if (fd != -1) [[likely]] { ::fast_io::posix::libc_fexecve(fd, const_cast(args), const_cast(envp)); @@ -537,7 +549,7 @@ inline pid_t pipefork_execveat_common_impl(int dirfd, char const *cstr, char con if (t_errno == 0) { - t_errno = posix_execveat(dirfd, cstr, args, envp); + t_errno = posix_execveat(dirfd, cstr, args, envp, mode); } // execve only return on error, so t_errno always contains an error code // send error code back to parent process @@ -697,7 +709,7 @@ struct fd_remapper }; // only used in vfork_execveat_common_impl() -inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, int volatile &t_errno, [[maybe_unused]] process_mode mode) noexcept +inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, int volatile &t_errno, process_mode mode) noexcept { // vfork can only be called through libc wrapper pid = ::fast_io::posix::libc_vfork(); @@ -722,8 +734,16 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con } #endif + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + #if defined(__linux__) && defined(__NR_execveat) - auto ret{system_call<__NR_execveat, int>(dirfd, cstr, args, envp, AT_SYMLINK_NOFOLLOW)}; + int flags{}; + if (!follow) + { + flags |= AT_SYMLINK_NOFOLLOW; + } + + auto ret{system_call<__NR_execveat, int>(dirfd, cstr, args, envp, flags)}; if (::fast_io::linux_system_call_fails(ret)) { t_errno = -ret; @@ -738,7 +758,13 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con ::fast_io::system_call_no_return<__NR_exit>(127); #endif #else - int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, O_RDONLY | O_NOFOLLOW, 0644)}; + int flags{O_RDONLY}; + if (!follow) + { + flags |= O_NOFOLLOW; + } + + int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, flags, 0644)}; if (fd != -1) [[likely]] { ::fast_io::posix::libc_fexecve(fd, const_cast(args), const_cast(envp)); From 5c27a0c72799e40a7f8ec68e59f6c568b7e96991 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 01:49:33 +0800 Subject: [PATCH 22/43] Refactor process creation logic in nt.h and update process_mode options - Introduced a new flag in process_mode to control the appending of paths to argv0, enhancing process creation flexibility. - Updated the nt_6x_process_create_impl and nt_create_process_overloads functions to utilize the new argv0_no_path_append flag for improved argument handling. - Refactored open_mode handling in process creation functions to accommodate the follow option, ensuring consistent behavior across different modes. - Enhanced clarity and maintainability of the code by organizing process parameter initialization and handling logic. --- .../fast_io_hosted/process/process/option.h | 2 +- .../fast_io_hosted/process/process/posix.h | 65 ++++++++++++------- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/include/fast_io_hosted/process/process/option.h b/include/fast_io_hosted/process/process/option.h index a4ee07fb1..99f760a22 100644 --- a/include/fast_io_hosted/process/process/option.h +++ b/include/fast_io_hosted/process/process/option.h @@ -8,6 +8,7 @@ enum class process_mode : ::std::uint_least64_t // *indicates that the process mode has not been evaluated yet new_session = static_cast<::std::uint_least64_t>(1) << 0, // [POSIX] setsid(), [WINDOWS, WINNT] CREATE_NEW_PROCESS_GROUP (Windows is currently not implemented) + // POSIX: This parameter is only valid under fork; vfork does not support it. alloc_new_console = static_cast<::std::uint_least64_t>(1) << 1, // [WINDOWS, WINNT] CREATE_NEW_CONSOLE (Automatically assign a console to new threads) argv0_no_path_append = static_cast<::std::uint_least64_t>(1) << 2, @@ -16,7 +17,6 @@ enum class process_mode : ::std::uint_least64_t // [POSIX] Using vfork to create processes, but this prevents many parameters from taking effect (vfork does not allow modification of global memory before exec). follow = static_cast<::std::uint_least64_t>(1) << 4, // [POSIX, WINDOWS, WINNT] Allow symbolic links to follow - }; inline constexpr process_mode operator&(process_mode x, process_mode y) noexcept diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 4a56ba0a4..9239d54bd 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -10,6 +10,7 @@ namespace posix { #if defined(__DARWIN_C_LEVEL) || defined(__MSDOS__) extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("_fexecve"); +extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("_execveat"); extern int libc_kill(pid_t pid, int sig) noexcept __asm__("_kill"); extern pid_t libc_fork() noexcept __asm__("_fork"); extern pid_t libc_vfork() noexcept __asm__("_vfork"); @@ -19,6 +20,7 @@ extern pid_t libc_waitpid(pid_t pid, int *status, int options) noexcept __asm__( [[noreturn]] extern void libc_exit2(int status) noexcept __asm__("__exit"); #else extern int libc_fexecve(int fd, char *const *argv, char *const *envp) noexcept __asm__("fexecve"); +extern int libc_execveat(int dirfd, char const *pathname, char *const *argv, char *const *envp, int flags) noexcept __asm__("execveat"); extern int libc_kill(pid_t pid, int sig) noexcept __asm__("kill"); extern pid_t libc_fork() noexcept __asm__("fork"); extern pid_t libc_vfork() noexcept __asm__("vfork"); @@ -171,11 +173,11 @@ inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) decltype(auto) path_str{"/proc/self/fd/"}; constexpr auto path_str_sz{::fast_io::cstr_len(path_str)}; constexpr auto fd_sz{::fast_io::pr_rsv_size}; - constexpr auto all_sz{path_str_sz + fd_sz}; + constexpr auto all_sz{path_str_sz + fd_sz + 1u}; char linkpath[all_sz]; ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; - ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd); + ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd, ::fast_io::mnp::chvw(::fast_io::char_literal_v)); using my_ssize_t = ::std::make_signed_t<::std::size_t>; @@ -208,11 +210,11 @@ inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) decltype(auto) path_str{"/dev/fd/"}; constexpr auto path_str_sz{::fast_io::cstr_len(path_str)}; constexpr auto fd_sz{::fast_io::pr_rsv_size}; - constexpr auto all_sz{path_str_sz + fd_sz}; + constexpr auto all_sz{path_str_sz + fd_sz + 1u}; char linkpath[all_sz]; ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; - ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd); + ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd, ::fast_io::mnp::chvw(::fast_io::char_literal_v)); auto resolved{::fast_io::noexcept_call(::readlink, linkpath, buf, bufsz - 1u)}; if (resolved == -1) [[unlikely]] @@ -238,11 +240,11 @@ inline void portable_fd_path(int fd, char *buf, ::std::size_t bufsz) decltype(auto) path_str{"/proc/self/path/"}; constexpr auto path_str_sz{::fast_io::cstr_len(path_str)}; constexpr auto fd_sz{::fast_io::pr_rsv_size}; - constexpr auto all_sz{path_str_sz + fd_sz}; + constexpr auto all_sz{path_str_sz + fd_sz + 1u}; char linkpath[all_sz]; ::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz}; - ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd); + ::fast_io::operations::print_freestanding(linkpath_ov, path_str, fd, ::fast_io::mnp::chvw(::fast_io::char_literal_v)); auto resolved{::fast_io::noexcept_call(::readlink, linkpath, buf, bufsz - 1u)}; if (resolved == -1) [[unlikely]] @@ -409,7 +411,7 @@ inline int posix_execveat(int dirfd, char const *cstr, char const *const *args, int flags{O_RDONLY}; if (!follow) { - flags |= O_NOFOLLOW; + flags |= AT_SYMLINK_NOFOLLOW; } int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, flags, 0644)}; if (fd != -1) [[likely]] @@ -709,7 +711,7 @@ struct fd_remapper }; // only used in vfork_execveat_common_impl() -inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, int volatile &t_errno, process_mode mode) noexcept +inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char const *const *args, char const *const *envp, sig_atomic_t volatile &t_errno, process_mode mode) noexcept { // vfork can only be called through libc wrapper pid = ::fast_io::posix::libc_vfork(); @@ -736,7 +738,9 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con bool const follow{(mode & process_mode::follow) == process_mode::follow}; -#if defined(__linux__) && defined(__NR_execveat) +#if defined(__linux__) + +#if defined(__NR_execveat) int flags{}; if (!follow) { @@ -752,41 +756,56 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con { t_errno = 0; } -#if defined(__NR_exit_group) - ::fast_io::system_call_no_return<__NR_exit_group>(127); #else - ::fast_io::system_call_no_return<__NR_exit>(127); -#endif -#else - int flags{O_RDONLY}; + int flags{}; if (!follow) { - flags |= O_NOFOLLOW; + flags |= AT_SYMLINK_NOFOLLOW; } - int fd{::fast_io::details::my_posix_openat_noexcept(dirfd, cstr, flags, 0644)}; - if (fd != -1) [[likely]] + auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, args, envp, flags)}; + if (ret == -1) { - ::fast_io::posix::libc_fexecve(fd, const_cast(args), const_cast(envp)); + t_errno = errno; } - t_errno = errno; -#if defined(__linux__) + else + { + t_errno = 0; + } +#endif + #if defined(__NR_exit_group) ::fast_io::system_call_no_return<__NR_exit_group>(127); #else ::fast_io::system_call_no_return<__NR_exit>(127); #endif #else + int flags{}; + if (!follow) + { + flags |= AT_SYMLINK_NOFOLLOW; + } + + auto ret{::fast_io::posix::libc_execveat(dirfd, cstr, args, envp, flags)}; + if (ret == -1) + { + t_errno = errno; + } + else + { + t_errno = 0; + } + ::fast_io::posix::libc_exit2(127); #endif -#endif + __builtin_unreachable(); } inline pid_t vfork_execveat_common_impl(int dirfd, char const *cstr, char const *const *args, char const *const *envp, posix_process_io const &pio, process_mode mode) { pid_t pid{}; - int volatile t_errno{}; // receive error from vfork subproc + sig_atomic_t volatile t_errno{}; // receive error from vfork subproc { fd_remapper fm; fm.map(0, pio.in); From 21fd346da82545e20e5b89f79dae47840820a604 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 03:39:17 +0800 Subject: [PATCH 23/43] nt_process_args --- include/fast_io_core_impl/buffer_view.h | 5 + include/fast_io_dsal/impl/string.h | 8 + .../fast_io_hosted/process/process/arg_env.h | 187 +++++++++++------ .../fast_io_hosted/process/process/native.h | 5 +- include/fast_io_hosted/process/process/nt.h | 196 ++++++++++++++++-- .../fast_io_hosted/process/process/posix.h | 12 +- .../fast_io_hosted/process/process/win32.h | 30 +-- 7 files changed, 347 insertions(+), 96 deletions(-) diff --git a/include/fast_io_core_impl/buffer_view.h b/include/fast_io_core_impl/buffer_view.h index 596485754..b23563457 100644 --- a/include/fast_io_core_impl/buffer_view.h +++ b/include/fast_io_core_impl/buffer_view.h @@ -181,6 +181,11 @@ struct basic_obuffer_view { return static_cast<::std::size_t>(end_ptr - begin_ptr); } + + inline constexpr bool empty() const noexcept + { + return begin_ptr == curr_ptr; + } }; template <::std::integral char_type> diff --git a/include/fast_io_dsal/impl/string.h b/include/fast_io_dsal/impl/string.h index 5f4eedf72..a4e728aaf 100644 --- a/include/fast_io_dsal/impl/string.h +++ b/include/fast_io_dsal/impl/string.h @@ -631,6 +631,14 @@ class basic_string FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { this->append_impl(other.data(), other.size()); } + inline constexpr void append(char_type const *begin, char_type const *end) noexcept + { + this->append_impl(begin, static_cast<::std::size_t>(end - begin)); + } + inline constexpr void append(char_type const *otherptr, size_type othern) noexcept + { + this->append_impl(otherptr, othern); + } inline constexpr void clear() noexcept { diff --git a/include/fast_io_hosted/process/process/arg_env.h b/include/fast_io_hosted/process/process/arg_env.h index de3fafe16..44cdc878b 100644 --- a/include/fast_io_hosted/process/process/arg_env.h +++ b/include/fast_io_hosted/process/process/arg_env.h @@ -11,6 +11,59 @@ inline constexpr default_args_t default_args{}; namespace details { +template <::std::integral replace_char_type, typename Iter> +inline constexpr void append_win32_quoted_arg_common( + bool is_first, + ::fast_io::containers::basic_string &str, + Iter first, Iter last) +{ + // Reserve rough upper bound: quotes + worst-case doubling + str.reserve(str.size() + 3 + static_cast<::std::size_t>(last - first) * 2u); + str.push_back_unchecked(::fast_io::char_literal_v); + + ::std::size_t backslash_count{}; + for (; first != last; ++first) + { + auto const c{*first}; + if (c == ::fast_io::char_literal_v) + { + if (is_first) [[unlikely]] + { + // Windows argv[0] does not allow double quotes even if escaped + throw_win32_error(13); + } + // Output 2*n+1 backslashes before a quote + for (::std::size_t i{}; i != ((backslash_count << 1u) + 1u); ++i) + { + str.push_back_unchecked(::fast_io::char_literal_v); + } + str.push_back_unchecked(::fast_io::char_literal_v); + backslash_count = 0; + } + else if (c == ::fast_io::char_literal_v) + { + ++backslash_count; + } + else + { + // Flush pending backslashes (not before a quote): output as-is + for (::std::size_t i{}; i != backslash_count; ++i) + { + str.push_back_unchecked(::fast_io::char_literal_v); + } + backslash_count = 0; + str.push_back_unchecked(c); + } + } + // Before closing quote, double any trailing backslashes + for (::std::size_t i{}; i != (backslash_count << 1u); ++i) + { + str.push_back_unchecked(::fast_io::char_literal_v); + } + str.push_back_unchecked(::fast_io::char_literal_v); + str.push_back_unchecked(::fast_io::char_literal_v); +} + template <::std::integral replace_char_type, typename T> inline constexpr void construct_win32_process_args_decay_singal(bool is_first, ::fast_io::containers::basic_string &str, T t) { @@ -21,30 +74,7 @@ inline constexpr void construct_win32_process_args_decay_singal(bool is_first, : replace_char_type buf[32767]; ::fast_io::basic_obuffer_view obf{buf, buf + 32767}; ::fast_io::operations::decay::print_freestanding_decay(::fast_io::operations::output_stream_ref(obf), t); - str.reserve(str.size() + 3 + obf.size() * 2); - str.push_back_unchecked(::fast_io::char_literal_v); - for (auto const c : obf) - { - if (c == ::fast_io::char_literal_v) - { - if (is_first) [[unlikely]] - { - // The first argument of windows does not support double quotes - throw_win32_error(13); - } - else - { - str.push_back_unchecked(::fast_io::char_literal_v); - str.push_back_unchecked(::fast_io::char_literal_v); - } - } - else - { - str.push_back_unchecked(c); - } - } - str.push_back_unchecked(::fast_io::char_literal_v); - str.push_back_unchecked(::fast_io::char_literal_v); + append_win32_quoted_arg_common(is_first, str, obf.cbegin(), obf.cend()); } else if constexpr (requires { ::fast_io::mnp::code_cvt(t); }) { @@ -52,30 +82,7 @@ inline constexpr void construct_win32_process_args_decay_singal(bool is_first, : ::fast_io::basic_obuffer_view obf{buf, buf + 32767}; // need decay ::fast_io::operations::print_freestanding(obf, ::fast_io::mnp::code_cvt(t)); - str.reserve(str.size() + 3 + obf.size() * 2); - str.push_back_unchecked(::fast_io::char_literal_v); - for (auto const c : obf) - { - if (c == ::fast_io::char_literal_v) - { - if (is_first) [[unlikely]] - { - // The first argument of windows does not support double quotes - throw_win32_error(13); - } - else - { - str.push_back_unchecked(::fast_io::char_literal_v); - str.push_back_unchecked(::fast_io::char_literal_v); - } - } - else - { - str.push_back_unchecked(c); - } - } - str.push_back_unchecked(::fast_io::char_literal_v); - str.push_back_unchecked(::fast_io::char_literal_v); + append_win32_quoted_arg_common(is_first, str, obf.cbegin(), obf.cend()); } else { @@ -133,7 +140,7 @@ inline constexpr void construct_win32_process_envs_decay( } // namespace details -template <::fast_io::win32_family family> +template <::fast_io::win32_family family, bool is_first> struct basic_win32_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { inline static constexpr bool is_nt{family == ::fast_io::win32_family::wide_nt}; @@ -164,9 +171,9 @@ struct basic_win32_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE requires(!::std::same_as<::std::remove_cvref_t, default_args_t>) inline constexpr basic_win32_process_args(T &&t, Args &&...as) { - details::construct_win32_process_args_decay(args, - ::fast_io::io_print_forward(::fast_io::io_print_alias(t)), - ::fast_io::io_print_forward(::fast_io::io_print_alias(as))...); + details::construct_win32_process_args_decay(args, + ::fast_io::io_print_forward(::fast_io::io_print_alias(t)), + ::fast_io::io_print_forward(::fast_io::io_print_alias(as))...); } inline constexpr char_type_may_alias_const_ptr get() const noexcept @@ -181,7 +188,7 @@ struct basic_win32_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } - inline constexpr basic_win32_process_args& append(basic_win32_process_args const &others) noexcept + inline constexpr basic_win32_process_args &append(basic_win32_process_args const &others) noexcept { args.append(others.args); @@ -242,7 +249,7 @@ struct basic_win32_process_envs FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } - inline constexpr basic_win32_process_envs& append(basic_win32_process_envs const &others) noexcept + inline constexpr basic_win32_process_envs &append(basic_win32_process_envs const &others) noexcept { envs.append(others.envs); @@ -250,16 +257,22 @@ struct basic_win32_process_envs FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } }; -using win32_process_args_ntw = ::fast_io::basic_win32_process_args<::fast_io::win32_family::wide_nt>; +// Provide a Windows command line with argv0 version conversion, where argv0 is specially handled. + +using win32_process_args_ntw = ::fast_io::basic_win32_process_args<::fast_io::win32_family::wide_nt, false>; +using win32_process_args_ntw_with_argv0 = ::fast_io::basic_win32_process_args<::fast_io::win32_family::wide_nt, true>; using win32_process_envs_ntw = ::fast_io::basic_win32_process_envs<::fast_io::win32_family::wide_nt>; -using win32_process_args_9xa = ::fast_io::basic_win32_process_args<::fast_io::win32_family::ansi_9x>; +using win32_process_args_9xa = ::fast_io::basic_win32_process_args<::fast_io::win32_family::ansi_9x, false>; +using win32_process_args_9xa_with_argv0 = ::fast_io::basic_win32_process_args<::fast_io::win32_family::ansi_9x, true>; using win32_process_envs_9xa = ::fast_io::basic_win32_process_envs<::fast_io::win32_family::ansi_9x>; -using win32_process_args = ::fast_io::basic_win32_process_args<::fast_io::win32_family::native>; +using win32_process_args = ::fast_io::basic_win32_process_args<::fast_io::win32_family::native, false>; +using win32_process_args_with_argv0 = ::fast_io::basic_win32_process_args<::fast_io::win32_family::native, true>; using win32_process_envs = ::fast_io::basic_win32_process_envs<::fast_io::win32_family::native>; -using nt_process_args = ::fast_io::basic_win32_process_args<::fast_io::win32_family::wide_nt>; +using nt_process_args = ::fast_io::basic_win32_process_args<::fast_io::win32_family::wide_nt, false>; +using nt_process_args_with_argv0 = ::fast_io::basic_win32_process_args<::fast_io::win32_family::wide_nt, true>; using nt_process_envs = ::fast_io::basic_win32_process_envs<::fast_io::win32_family::wide_nt>; #else @@ -273,12 +286,18 @@ struct cstr_guard FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { using Alloc = ::fast_io::native_typed_global_allocator; - char_type *cstr; + char_type *cstr{}; inline constexpr cstr_guard() noexcept = default; inline constexpr cstr_guard(cstr_guard const &others) noexcept { + if (others.cstr == nullptr) + { + cstr = nullptr; + return *this; + } + ::std::size_t str_size{::fast_io::cstr_len(others.cstr)}; cstr = Alloc::allocate(str_size + 1); auto const lase_ptr{::fast_io::freestanding::non_overlapped_copy_n(others.cstr, str_size, cstr)}; @@ -294,10 +313,18 @@ struct cstr_guard FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE Alloc::deallocate(cstr); + if (others.cstr == nullptr) + { + cstr = nullptr; + return *this; + } + ::std::size_t str_size{::fast_io::cstr_len(others.cstr)}; cstr = Alloc::allocate(str_size + 1); auto const lase_ptr{::fast_io::freestanding::non_overlapped_copy_n(others.cstr, str_size, cstr)}; *lase_ptr = ::fast_io::char_literal_v; + + return *this; } inline constexpr cstr_guard(cstr_guard &&others) noexcept @@ -317,6 +344,8 @@ struct cstr_guard FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE cstr = others.cstr; others.cstr = nullptr; + + return *this; } inline constexpr ~cstr_guard() @@ -433,7 +462,7 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE arg_envs.emplace_back(); // nullptr } - inline char const *const *get() const noexcept + inline char const *const *get_argv() const noexcept { using char_const_p_const_p_may_alias_ptr #if __has_cpp_attribute(__gnu__::__may_alias__) @@ -444,7 +473,39 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return reinterpret_cast(arg_envs.data()); } - inline constexpr posix_process_args& append(posix_process_args const &others) noexcept + inline char const *const *get_envs() const noexcept + { + using char_const_p_const_p_may_alias_ptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = char const *const *; + + if (arg_envs.size() < 2u) + { +#if defined(__APPLE__) && defined(__MACH__) + extern char ***_NSGetEnviron() noexcept __asm__("__NSGetEnviron"); + + return reinterpret_cast(*_NSGetEnviron()); +#else +#if defined(__MSDOS__) || defined(__DJGPP__) + // djgpp only provides `char** _environ`. For consistency, a symbolic link is used here. + extern char **environ __asm__("__environ"); +#elif !(defined(_WIN32) || defined(__CYGWIN__)) + // Reference to the global `environ` variable + extern "C" char **environ; +#endif + + return reinterpret_cast(environ); +#endif + } + else + { + return reinterpret_cast(arg_envs.data()); + } + } + + inline constexpr posix_process_args &append(posix_process_args const &others) noexcept { if (others.arg_envs.size() > 1) [[likely]] { @@ -473,8 +534,8 @@ namespace freestanding { #if (defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__) -template <::fast_io::win32_family family> -struct is_trivially_copyable_or_relocatable> +template <::fast_io::win32_family family, bool is_first> +struct is_trivially_copyable_or_relocatable> { inline static constexpr bool value = true; }; diff --git a/include/fast_io_hosted/process/process/native.h b/include/fast_io_hosted/process/process/native.h index 911603d5e..ed6c02c9e 100644 --- a/include/fast_io_hosted/process/process/native.h +++ b/include/fast_io_hosted/process/process/native.h @@ -15,16 +15,18 @@ namespace fast_io { -#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WINE__) +#if (defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__) #if !defined(_WIN32_WINDOWS) && (!defined(_WIN32_WINNT) || _WIN32_WINNT >= 0x600) using native_wait_status = ::fast_io::nt_wait_status; using native_process_args = ::fast_io::nt_process_args; +using native_process_args_with_argv0 = ::fast_io::nt_process_args_with_argv0; using native_process_envs = ::fast_io::nt_process_envs; using native_process_observer = ::fast_io::nt_process_observer; using native_process = ::fast_io::nt_process; #else using native_wait_status = ::fast_io::win32_wait_status; using native_process_args = ::fast_io::win32_process_args; +using native_process_args_with_argv0 = ::fast_io::win32_process_args_with_argv0; using native_process_envs = ::fast_io::win32_process_envs; using native_process_observer = ::fast_io::win32_process_observer; using native_process = ::fast_io::win32_process; @@ -32,6 +34,7 @@ using native_process = ::fast_io::win32_process; #else using native_wait_status = ::fast_io::posix_wait_status; using native_process_args = ::fast_io::posix_process_args; +using native_process_args_with_argv0 = ::fast_io::posix_process_args; using native_process_envs = ::fast_io::posix_process_envs; using native_process_observer = ::fast_io::posix_process_observer; using native_process = ::fast_io::posix_process; diff --git a/include/fast_io_hosted/process/process/nt.h b/include/fast_io_hosted/process/process/nt.h index a4748f032..805bde37d 100644 --- a/include/fast_io_hosted/process/process/nt.h +++ b/include/fast_io_hosted/process/process/nt.h @@ -53,10 +53,14 @@ template inline void close_nt_user_process_information_and_wait(nt_user_process_information hnt_user_process_info) noexcept(!throw_eh) { + // only need to wait hprocess nt_wait_and_close_user_process_or_thread(hnt_user_process_info.hprocess); // close hthread (main thread) - ::fast_io::win32::nt::nt_close(hnt_user_process_info.hthread); + if (hnt_user_process_info.hthread != nullptr) [[likely]] + { + ::fast_io::win32::nt::nt_close(hnt_user_process_info.hthread); + } } struct nt_process_rtl_guard @@ -73,8 +77,11 @@ struct nt_process_rtl_guard } inline void clear() noexcept { - ::fast_io::win32::nt::RtlDestroyProcessParameters(rtl_up); - rtl_up = nullptr; + if (rtl_up != nullptr) [[likely]] + { + ::fast_io::win32::nt::RtlDestroyProcessParameters(rtl_up); + rtl_up = nullptr; + } } }; @@ -325,13 +332,14 @@ inline nt_user_process_information nt_6x_process_create_impl(void *__restrict fh win32_process_io const &__restrict processio, process_mode mode, bool kernel) { constexpr bool zw{family == nt_family::zw}; + auto const argv0_no_path_append{(mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append}; // Create the NtImagePath ::std::uint_least32_t NtImagePath_len{}; ::fast_io::win32::nt::nt_query_object(fhandle, object_information_class::ObjectNameInformation, nullptr, 0, __builtin_addressof(NtImagePath_len)); - auto NtImagePath = static_cast(nt_process_thread_local_heap_allocate_guard::alloc::allocate(NtImagePath_len)); + auto NtImagePath{static_cast(nt_process_thread_local_heap_allocate_guard::alloc::allocate(NtImagePath_len))}; nt_process_thread_local_heap_allocate_guard NtImagePath_guard{NtImagePath}; // guard check_nt_status(::fast_io::win32::nt::nt_query_object(fhandle, object_information_class::ObjectNameInformation, @@ -351,6 +359,18 @@ inline nt_user_process_information nt_6x_process_create_impl(void *__restrict fh if (kernel) // nt_path { + ::fast_io::containers::basic_string tmp_append{}; + if (args && !argv0_no_path_append) + { + // Whether argv0 is set to nullptr or points to u"" will automatically populate argv0. + tmp_append.append(NtImagePath->Buffer, static_cast<::std::size_t>(NtImagePath->Length / sizeof(char16_t))); + tmp_append.append(ps_para.Buffer, static_cast<::std::size_t>(ps_para.Length / sizeof(char16_t))); + + ps_para.Buffer = tmp_append.data(); + ps_para.Length = static_cast<::std::uint_least16_t>(tmp_append.size() * sizeof(char16_t)); + ps_para.MaximumLength = ::fast_io::win32::nt::details::nt_filename_bytes_check(ps_para.Length + sizeof(char16_t)); + } + check_nt_status(::fast_io::win32::nt::RtlCreateProcessParametersEx( __builtin_addressof(rtl_temp), NtImagePath, nullptr, nullptr, args ? __builtin_addressof(ps_para) : nullptr, static_cast(const_cast(envs)), nullptr, nullptr, nullptr, nullptr, 0x01)); @@ -470,6 +490,18 @@ inline nt_user_process_information nt_6x_process_create_impl(void *__restrict fh str_uni = *NtImagePath; } + ::fast_io::containers::basic_string tmp_append{}; + if (args && !argv0_no_path_append) + { + // Whether argv0 is set to nullptr or points to u"" will automatically populate argv0. + tmp_append.append(str_uni.Buffer, static_cast<::std::size_t>(str_uni.Length / sizeof(char16_t))); + tmp_append.append(ps_para.Buffer, static_cast<::std::size_t>(ps_para.Length / sizeof(char16_t))); + + ps_para.Buffer = tmp_append.data(); + ps_para.Length = static_cast<::std::uint_least16_t>(tmp_append.size() * sizeof(char16_t)); + ps_para.MaximumLength = ::fast_io::win32::nt::details::nt_filename_bytes_check(ps_para.Length + sizeof(char16_t)); + } + check_nt_status(::fast_io::win32::nt::RtlCreateProcessParametersEx( __builtin_addressof(rtl_temp), __builtin_addressof(str_uni), nullptr, nullptr, args ? __builtin_addressof(ps_para) : nullptr, static_cast(const_cast(envs)), nullptr, nullptr, nullptr, nullptr, 0x01)); @@ -632,14 +664,21 @@ inline nt_user_process_information nt_create_process_overloads(nt_at_entry entry nt_process_args const &args, nt_process_envs const &envs, win32_process_io const &processio, process_mode mode, bool kernel) { + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + basic_nt_family_file nf; if (kernel) { - nf = basic_nt_family_file(io_kernel, entry, filename, open_mode::in | open_mode::excl); + nf = basic_nt_family_file(io_kernel, entry, filename, curr_open_mode); } else { - nf = basic_nt_family_file(entry, filename, open_mode::in | open_mode::excl); + nf = basic_nt_family_file(entry, filename, curr_open_mode); } return nt_process_create_impl(nf.handle, args.get(), envs.get(), processio, mode, kernel); } @@ -649,14 +688,21 @@ inline nt_user_process_information nt_create_process_overloads(path_type const & nt_process_envs const &envs, win32_process_io const &processio, process_mode mode, bool kernel) { + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + basic_nt_family_file nf; if (kernel) { - nf = basic_nt_family_file(io_kernel, filename, open_mode::in | open_mode::excl); + nf = basic_nt_family_file(io_kernel, filename, curr_open_mode); } else { - nf = basic_nt_family_file(filename, open_mode::in | open_mode::excl); + nf = basic_nt_family_file(filename, curr_open_mode); } return nt_process_create_impl(nf.handle, args.get(), envs.get(), processio, mode, kernel); } @@ -666,18 +712,96 @@ inline nt_user_process_information nt_create_process_overloads(::fast_io::nt_fs_ nt_process_envs const &envs, win32_process_io const &processio, process_mode mode, bool kernel) { + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + + basic_nt_family_file nf; + if (kernel) + { + nf = basic_nt_family_file(io_kernel, ent, curr_open_mode); + } + else + { + nf = basic_nt_family_file(ent, curr_open_mode); + } + return nt_process_create_impl(nf.handle, args.get(), envs.get(), processio, mode, kernel); +} + +template +inline nt_user_process_information nt_create_process_overloads(nt_at_entry entry, path_type const &filename, + nt_process_args_with_argv0 const &args, nt_process_envs const &envs, + win32_process_io const &processio, process_mode mode, bool kernel) +{ + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + + basic_nt_family_file nf; + if (kernel) + { + nf = basic_nt_family_file(io_kernel, entry, filename, curr_open_mode); + } + else + { + nf = basic_nt_family_file(entry, filename, curr_open_mode); + } + return nt_process_create_impl(nf.handle, args.get(), envs.get(), processio, mode, kernel); +} + +template +inline nt_user_process_information nt_create_process_overloads(path_type const &filename, nt_process_args_with_argv0 const &args, + nt_process_envs const &envs, + win32_process_io const &processio, process_mode mode, bool kernel) +{ + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + basic_nt_family_file nf; if (kernel) { - nf = basic_nt_family_file(io_kernel, ent, open_mode::in | open_mode::excl); + nf = basic_nt_family_file(io_kernel, filename, curr_open_mode); } else { - nf = basic_nt_family_file(ent, open_mode::in | open_mode::excl); + nf = basic_nt_family_file(filename, curr_open_mode); } return nt_process_create_impl(nf.handle, args.get(), envs.get(), processio, mode, kernel); } +template +inline nt_user_process_information nt_create_process_overloads(::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args, + nt_process_envs const &envs, + win32_process_io const &processio, process_mode mode, bool kernel) +{ + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + + basic_nt_family_file nf; + if (kernel) + { + nf = basic_nt_family_file(io_kernel, ent, curr_open_mode); + } + else + { + nf = basic_nt_family_file(ent, curr_open_mode); + } + return nt_process_create_impl(nf.handle, args.get(), envs.get(), processio, mode, kernel); +} } // namespace win32::nt::details template @@ -767,7 +891,7 @@ inline nt_wait_status wait(nt_family_process_observer ppob) noexcept(!th { if constexpr (throw_eh) { - throw_nt_error(status); + throw_nt_error(status2); } else { @@ -802,7 +926,7 @@ inline nt_process_id get_process_id(nt_family_process_observer ppob) noe ::fast_io::win32::nt::process_basic_information pbi; auto status{::fast_io::win32::nt::nt_query_information_process( - ppob.native_handle(), + ppob.native_handle().hprocess, ::fast_io::win32::nt::process_information_class::ProcessBasicInformation, __builtin_addressof(pbi), sizeof(pbi), @@ -875,6 +999,54 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, true)} { } + + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit nt_family_process(nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args = {}, + nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) + : nt_family_process_observer{ + win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, false)} + { + } + + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit nt_family_process(path_type const &filename, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = {}) + : nt_family_process_observer{ + win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, false)} + { + } + + inline explicit nt_family_process(::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = {}) + : nt_family_process_observer{ + win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, false)} + { + } + + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit nt_family_process(io_kernel_t, nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args = {}, + nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) + : nt_family_process_observer{ + win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, true)} + { + } + + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit nt_family_process(io_kernel_t, path_type const &filename, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = {}) + : nt_family_process_observer{ + win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, true)} + { + } + + inline explicit nt_family_process(io_kernel_t, ::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = {}) + : nt_family_process_observer{ + win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, true)} + { + } + + inline nt_family_process(nt_family_process const &b) = delete; inline nt_family_process &operator=(nt_family_process const &b) = delete; inline constexpr nt_family_process(nt_family_process &&__restrict b) noexcept diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 9239d54bd..85a266dc8 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -964,8 +964,8 @@ class posix_process : public posix_process_observer posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ ::fast_io::details::fork_execveat_impl(pate.fd, filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get(), - envp.get(), pio, mode) + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get_argv(), + envp.get_envs(), pio, mode) } { @@ -976,8 +976,8 @@ class posix_process : public posix_process_observer posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ ::fast_io::details::fork_execve_impl(filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{filename}.append(args).get(), - envp.get(), pio, mode) + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{filename}.append(args).get_argv(), + envp.get_envs(), pio, mode) } { @@ -987,8 +987,8 @@ class posix_process : public posix_process_observer posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) : posix_process_observer{ ::fast_io::details::fork_execveat_common_impl(ent.fd, ent.filename, - (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get(), - envp.get(), pio, mode)} + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get_argv(), + envp.get_envs(), pio, mode)} { } diff --git a/include/fast_io_hosted/process/process/win32.h b/include/fast_io_hosted/process/process/win32.h index 719bb96cd..6d18446ed 100644 --- a/include/fast_io_hosted/process/process/win32.h +++ b/include/fast_io_hosted/process/process/win32.h @@ -584,9 +584,9 @@ struct win32_9xa_win9x_create_process_at_fs_dirent } }; -template +template inline win32_user_process_information win32_winnt_create_process_overloads(nt_at_entry entry, path_type const &filename, - basic_win32_process_args const &args, basic_win32_process_envs const &envs, + basic_win32_process_args const &args, basic_win32_process_envs const &envs, win32_process_io const &processio, process_mode mode) { basic_win32_family_file nf(entry, filename, open_mode::in | open_mode::excl); @@ -608,8 +608,8 @@ inline win32_user_process_information win32_9xa_win9x_create_process_overloads(w mode}); } -template -inline win32_user_process_information win32_winnt_create_process_overloads(path_type const &filename, basic_win32_process_args const &args, +template +inline win32_user_process_information win32_winnt_create_process_overloads(path_type const &filename, basic_win32_process_args const &args, basic_win32_process_envs const &envs, win32_process_io const &processio, process_mode mode) { @@ -631,8 +631,8 @@ inline win32_user_process_information win32_9xa_win9x_create_process_overloads(p mode}); } -template -inline win32_user_process_information win32_winnt_create_process_overloads(::fast_io::nt_fs_dirent const &ent, basic_win32_process_args const &args, +template +inline win32_user_process_information win32_winnt_create_process_overloads(::fast_io::nt_fs_dirent const &ent, basic_win32_process_args const &args, basic_win32_process_envs const &envs, win32_process_io const &processio, process_mode mode) { @@ -775,24 +775,24 @@ class win32_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public wi { } - template <::fast_io::constructible_to_os_c_str path_type> - inline explicit win32_family_process(nt_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, + template <::fast_io::constructible_to_os_c_str path_type, bool is_first> + inline explicit win32_family_process(nt_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_winnt_create_process_overloads(nate, filename, args, envs, processio, mode)} { } - template <::fast_io::constructible_to_os_c_str path_type> - inline explicit win32_family_process(win32_9xa_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, + template <::fast_io::constructible_to_os_c_str path_type, bool is_first> + inline explicit win32_family_process(win32_9xa_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_9xa_win9x_create_process_overloads(nate, filename, args, envs, processio, mode)} { } - template <::fast_io::constructible_to_os_c_str path_type> - inline explicit win32_family_process(path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + template <::fast_io::constructible_to_os_c_str path_type, bool is_first> + inline explicit win32_family_process(path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ #if defined(_WIN32_WINDOWS) @@ -804,14 +804,16 @@ class win32_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public wi { } - inline explicit win32_family_process(::fast_io::nt_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + template + inline explicit win32_family_process(::fast_io::nt_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_winnt_create_process_overloads(ent, args, envs, processio, mode)} { } - inline explicit win32_family_process(::fast_io::win32_9xa_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + template + inline explicit win32_family_process(::fast_io::win32_9xa_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_9xa_win9x_create_process_overloads(ent, args, envs, processio, mode)} From c74a3122cef29921f94ffa6d3ac61918086e2ff3 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 03:44:09 +0800 Subject: [PATCH 24/43] Enhance argument handling in nt_6x_process_create_impl by adding quotation marks around paths - Updated the process creation logic to include double quotation marks around the image path and process parameters when appending to argv0. - Improved clarity in the handling of DOS and NT paths by ensuring proper formatting during argument construction. --- include/fast_io_hosted/process/process/nt.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/fast_io_hosted/process/process/nt.h b/include/fast_io_hosted/process/process/nt.h index 805bde37d..a87958063 100644 --- a/include/fast_io_hosted/process/process/nt.h +++ b/include/fast_io_hosted/process/process/nt.h @@ -363,7 +363,11 @@ inline nt_user_process_information nt_6x_process_create_impl(void *__restrict fh if (args && !argv0_no_path_append) { // Whether argv0 is set to nullptr or points to u"" will automatically populate argv0. + // Neither DOS paths nor NT paths contain double quotation marks internally. + tmp_append.push_back('\"'); tmp_append.append(NtImagePath->Buffer, static_cast<::std::size_t>(NtImagePath->Length / sizeof(char16_t))); + tmp_append.push_back('\"'); + tmp_append.push_back(' '); tmp_append.append(ps_para.Buffer, static_cast<::std::size_t>(ps_para.Length / sizeof(char16_t))); ps_para.Buffer = tmp_append.data(); @@ -494,7 +498,11 @@ inline nt_user_process_information nt_6x_process_create_impl(void *__restrict fh if (args && !argv0_no_path_append) { // Whether argv0 is set to nullptr or points to u"" will automatically populate argv0. + // Neither DOS paths nor NT paths contain double quotation marks internally. + tmp_append.push_back('\"'); tmp_append.append(str_uni.Buffer, static_cast<::std::size_t>(str_uni.Length / sizeof(char16_t))); + tmp_append.push_back('\"'); + tmp_append.push_back(' '); tmp_append.append(ps_para.Buffer, static_cast<::std::size_t>(ps_para.Length / sizeof(char16_t))); ps_para.Buffer = tmp_append.data(); From d0349bc7d19d69a669d664e4efb7b0eabccb3922 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 03:46:49 +0800 Subject: [PATCH 25/43] Refactor environment handling in posix_process_args for improved clarity - Updated the `cstr_guard` return logic to enhance readability by removing unnecessary return statements. - Introduced a new namespace `posix` to encapsulate platform-specific environment variable handling, including `_NSGetEnviron` for Darwin and `environ` for other platforms. - Streamlined the `get_envs` function to utilize the new `posix` namespace, improving code organization and maintainability. --- .../fast_io_hosted/process/process/arg_env.h | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/include/fast_io_hosted/process/process/arg_env.h b/include/fast_io_hosted/process/process/arg_env.h index 44cdc878b..23886ae05 100644 --- a/include/fast_io_hosted/process/process/arg_env.h +++ b/include/fast_io_hosted/process/process/arg_env.h @@ -295,7 +295,7 @@ struct cstr_guard FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if (others.cstr == nullptr) { cstr = nullptr; - return *this; + return; } ::std::size_t str_size{::fast_io::cstr_len(others.cstr)}; @@ -473,6 +473,20 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return reinterpret_cast(arg_envs.data()); } + namespace posix + { +#if defined(__APPLE__) || defined(__DARWIN_C_LEVEL) + // Darwin does not provide an `environ` function; here we use `_NSGetEnviron` to obtain it. + extern char*** _NSGetEnviron() noexcept __asm__("__NSGetEnviron"); +#elif defined(__MSDOS__) || defined(__DJGPP__) + // djgpp only provides `char** _environ`. For consistency, a symbolic link is used here. + extern char** environ __asm__("__environ"); +#elif !(defined(_WIN32) || defined(__CYGWIN__)) + // Reference to the global `environ` variable + extern "C" char** environ; +#endif + } // namespace details + inline char const *const *get_envs() const noexcept { using char_const_p_const_p_may_alias_ptr @@ -484,19 +498,9 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if (arg_envs.size() < 2u) { #if defined(__APPLE__) && defined(__MACH__) - extern char ***_NSGetEnviron() noexcept __asm__("__NSGetEnviron"); - - return reinterpret_cast(*_NSGetEnviron()); + return reinterpret_cast(*posix::_NSGetEnviron()); #else -#if defined(__MSDOS__) || defined(__DJGPP__) - // djgpp only provides `char** _environ`. For consistency, a symbolic link is used here. - extern char **environ __asm__("__environ"); -#elif !(defined(_WIN32) || defined(__CYGWIN__)) - // Reference to the global `environ` variable - extern "C" char **environ; -#endif - - return reinterpret_cast(environ); + return reinterpret_cast(posix::environ); #endif } else From 579529b11c8c2ef29ab0a415a91b4a6cd9cdc513 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 03:48:32 +0800 Subject: [PATCH 26/43] Fix argument initialization in args_envs.cc by updating process argument structure - Changed the initialization of process arguments from a string to a native__process_args structure for improved clarity and consistency in argument handling. - This update enhances the readability of the code and aligns with recent refactoring efforts in process management. --- examples/0035.process/args_envs.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/0035.process/args_envs.cc b/examples/0035.process/args_envs.cc index 34f76011a..cd9ae1def 100644 --- a/examples/0035.process/args_envs.cc +++ b/examples/0035.process/args_envs.cc @@ -19,14 +19,14 @@ int main(int argc, char **argv) ::fast_io::native_process p{ ::fast_io::mnp::os_c_str(argv[1]), - {"char", - L"wchar Double\"quotation\"marks", - u8"u8", - u"u16", - U"u32", - 114514, - 115145.1919810, - ::fast_io::concat_fast_io("This ", 1, "s ", ::fast_io::mnp::code_cvt_os_c_str(u8"just "), "a parameter")}, + native_process_args{"char", + L"wchar Double\"quotation\"marks", + u8"u8", + u"u16", + U"u32", + 114514, + 115145.1919810, + ::fast_io::concat_fast_io("This ", 1, "s ", ::fast_io::mnp::code_cvt_os_c_str(u8"just "), "a parameter")}, {"env1", L"env2", 3, From 9f3788a6e551cbd4e317f25614fa1cf45d87c9f7 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 03:49:34 +0800 Subject: [PATCH 27/43] Refactor posix namespace in arg_env.h to improve environment variable handling - Moved platform-specific environment variable declarations into the posix namespace for better organization and clarity. - Updated references in the get_envs function to utilize the new namespace, enhancing code maintainability and readability. - Removed redundant declarations to streamline the code structure. --- .../fast_io_hosted/process/process/arg_env.h | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/fast_io_hosted/process/process/arg_env.h b/include/fast_io_hosted/process/process/arg_env.h index 23886ae05..ebbcfb11b 100644 --- a/include/fast_io_hosted/process/process/arg_env.h +++ b/include/fast_io_hosted/process/process/arg_env.h @@ -413,6 +413,20 @@ inline constexpr void construct_posix_process_argenvs_decay( construct_posix_process_argenvs_decay(str, args...); } } + +namespace posix +{ +#if defined(__APPLE__) || defined(__DARWIN_C_LEVEL) + // Darwin does not provide an `environ` function; here we use `_NSGetEnviron` to obtain it. + extern char*** _NSGetEnviron() noexcept __asm__("__NSGetEnviron"); +#elif defined(__MSDOS__) || defined(__DJGPP__) + // djgpp only provides `char** _environ`. For consistency, a symbolic link is used here. + extern char** environ __asm__("__environ"); +#elif !(defined(_WIN32) || defined(__CYGWIN__)) + // Reference to the global `environ` variable + extern "C" char** environ; +#endif +} // namespace details } // namespace details struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE @@ -473,20 +487,6 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return reinterpret_cast(arg_envs.data()); } - namespace posix - { -#if defined(__APPLE__) || defined(__DARWIN_C_LEVEL) - // Darwin does not provide an `environ` function; here we use `_NSGetEnviron` to obtain it. - extern char*** _NSGetEnviron() noexcept __asm__("__NSGetEnviron"); -#elif defined(__MSDOS__) || defined(__DJGPP__) - // djgpp only provides `char** _environ`. For consistency, a symbolic link is used here. - extern char** environ __asm__("__environ"); -#elif !(defined(_WIN32) || defined(__CYGWIN__)) - // Reference to the global `environ` variable - extern "C" char** environ; -#endif - } // namespace details - inline char const *const *get_envs() const noexcept { using char_const_p_const_p_may_alias_ptr @@ -498,9 +498,9 @@ struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if (arg_envs.size() < 2u) { #if defined(__APPLE__) && defined(__MACH__) - return reinterpret_cast(*posix::_NSGetEnviron()); + return reinterpret_cast(*::fast_io::details::posix::_NSGetEnviron()); #else - return reinterpret_cast(posix::environ); + return reinterpret_cast(::fast_io::details::posix::environ); #endif } else From f9b88b68a866297bb9bf8c5fe6d4f6b1cc8f538b Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 03:54:31 +0800 Subject: [PATCH 28/43] f --- examples/0035.process/args_envs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/0035.process/args_envs.cc b/examples/0035.process/args_envs.cc index cd9ae1def..ada824cb5 100644 --- a/examples/0035.process/args_envs.cc +++ b/examples/0035.process/args_envs.cc @@ -19,7 +19,7 @@ int main(int argc, char **argv) ::fast_io::native_process p{ ::fast_io::mnp::os_c_str(argv[1]), - native_process_args{"char", + ::fast_io::native_process_args{"char", L"wchar Double\"quotation\"marks", u8"u8", u"u16", From 4de5251f15f2ca1854d5d562fadd5349b9f39e80 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 12:46:22 +0800 Subject: [PATCH 29/43] f --- examples/0035.process/args_envs.cc | 14 +++++++------- examples/0035.process/pipe.cc | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/0035.process/args_envs.cc b/examples/0035.process/args_envs.cc index ada824cb5..e4c5c60d5 100644 --- a/examples/0035.process/args_envs.cc +++ b/examples/0035.process/args_envs.cc @@ -20,13 +20,13 @@ int main(int argc, char **argv) ::fast_io::native_process p{ ::fast_io::mnp::os_c_str(argv[1]), ::fast_io::native_process_args{"char", - L"wchar Double\"quotation\"marks", - u8"u8", - u"u16", - U"u32", - 114514, - 115145.1919810, - ::fast_io::concat_fast_io("This ", 1, "s ", ::fast_io::mnp::code_cvt_os_c_str(u8"just "), "a parameter")}, + L"wchar Double\"quotation\"marks", + u8"u8", + u"u16", + U"u32", + 114514, + 115145.1919810, + ::fast_io::concat_fast_io("This ", 1, "s ", ::fast_io::mnp::code_cvt_os_c_str(u8"just "), "a parameter")}, {"env1", L"env2", 3, diff --git a/examples/0035.process/pipe.cc b/examples/0035.process/pipe.cc index f3af423ef..6b57203db 100644 --- a/examples/0035.process/pipe.cc +++ b/examples/0035.process/pipe.cc @@ -20,7 +20,7 @@ int main(int argc, char **argv) ::fast_io::iobuf_pipe pipe_err; ::fast_io::native_process p{ ::fast_io::mnp::os_c_str(argv[1]), - {}, + ::fast_io::native_process_args{}, {}, {::fast_io::posix_dev_null(), pipe_out.handle, pipe_err.handle}, ::fast_io::process_mode::none}; From 06a3f1d40ffabbea27a1afb953ddf8fe1d01f57e Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 17:13:45 +0800 Subject: [PATCH 30/43] Update process argument handling in process.cc and nt.h - Changed the initialization of process arguments in process.cc to use native_process_args for improved clarity. - Updated constructor signatures in nt.h to remove default arguments for process_args_with_argv0, enhancing consistency and readability across process creation functions. --- examples/0035.process/process.cc | 2 +- include/fast_io_hosted/process/process/nt.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/0035.process/process.cc b/examples/0035.process/process.cc index 523130129..42a5378c4 100644 --- a/examples/0035.process/process.cc +++ b/examples/0035.process/process.cc @@ -11,7 +11,7 @@ int main(int argc, char **argv) ::fast_io::io::perr("Usage: ", ::fast_io::mnp::os_c_str(*argv), " \n"); return 1; } - ::fast_io::native_process p{::fast_io::mnp::os_c_str(argv[1]), {}, {}, {.in = fast_io::in(), .out = fast_io::out(), .err = fast_io::err()}, ::fast_io::process_mode::none}; + ::fast_io::native_process p{::fast_io::mnp::os_c_str(argv[1]), ::fast_io::native_process_args{}, {}, {.in = fast_io::in(), .out = fast_io::out(), .err = fast_io::err()}, ::fast_io::process_mode::none}; auto ec{wait(p)}; ::fast_io::io::perrln(::fast_io::mnp::os_c_str(*argv), " -> Exit code: ", static_cast(ec.wait_loc)); } diff --git a/include/fast_io_hosted/process/process/nt.h b/include/fast_io_hosted/process/process/nt.h index a87958063..46a5437a8 100644 --- a/include/fast_io_hosted/process/process/nt.h +++ b/include/fast_io_hosted/process/process/nt.h @@ -1009,7 +1009,7 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args = {}, + inline explicit nt_family_process(nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, false)} @@ -1017,14 +1017,14 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(path_type const &filename, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + inline explicit nt_family_process(path_type const &filename, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, false)} { } - inline explicit nt_family_process(::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + inline explicit nt_family_process(::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, false)} @@ -1032,7 +1032,7 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(io_kernel_t, nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args = {}, + inline explicit nt_family_process(io_kernel_t, nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, true)} @@ -1040,14 +1040,14 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(io_kernel_t, path_type const &filename, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + inline explicit nt_family_process(io_kernel_t, path_type const &filename, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, true)} { } - inline explicit nt_family_process(io_kernel_t, ::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, + inline explicit nt_family_process(io_kernel_t, ::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, true)} From 6c17ce4d86451ee6878c75aeb9032ba967166717 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 17:23:31 +0800 Subject: [PATCH 31/43] Add args_with_argv0_t structure and update process constructors - Introduced a new `args_with_argv0_t` structure to encapsulate argument handling with `argv0`. - Updated constructors in `nt.h` and `posix.h` to accept `args_with_argv0_t`, enhancing consistency in process creation across platforms. - Improved clarity in argument handling by ensuring all relevant constructors utilize the new structure, streamlining the process initialization logic. --- .../fast_io_hosted/process/process/arg_env.h | 6 ++++ include/fast_io_hosted/process/process/nt.h | 12 +++---- .../fast_io_hosted/process/process/posix.h | 33 +++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/include/fast_io_hosted/process/process/arg_env.h b/include/fast_io_hosted/process/process/arg_env.h index ebbcfb11b..858c233c4 100644 --- a/include/fast_io_hosted/process/process/arg_env.h +++ b/include/fast_io_hosted/process/process/arg_env.h @@ -7,6 +7,12 @@ struct default_args_t }; inline constexpr default_args_t default_args{}; +struct args_with_argv0_t +{ + inline explicit constexpr args_with_argv0_t() noexcept = default; +}; +inline constexpr args_with_argv0_t args_with_argv0{}; + #if (defined(_WIN32) && !defined(__WINE__)) || defined(__CYGWIN__) namespace details diff --git a/include/fast_io_hosted/process/process/nt.h b/include/fast_io_hosted/process/process/nt.h index 46a5437a8..1724e8409 100644 --- a/include/fast_io_hosted/process/process/nt.h +++ b/include/fast_io_hosted/process/process/nt.h @@ -1009,7 +1009,7 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args, + inline explicit nt_family_process(nt_at_entry nate, path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, false)} @@ -1017,14 +1017,14 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(path_type const &filename, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, + inline explicit nt_family_process(path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, false)} { } - inline explicit nt_family_process(::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, + inline explicit nt_family_process(::fast_io::nt_fs_dirent ent, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, false)} @@ -1032,7 +1032,7 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(io_kernel_t, nt_at_entry nate, path_type const &filename, nt_process_args_with_argv0 const &args, + inline explicit nt_family_process(io_kernel_t, nt_at_entry nate, path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, true)} @@ -1040,14 +1040,14 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa } template <::fast_io::constructible_to_os_c_str path_type> - inline explicit nt_family_process(io_kernel_t, path_type const &filename, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, + inline explicit nt_family_process(io_kernel_t, path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, true)} { } - inline explicit nt_family_process(io_kernel_t, ::fast_io::nt_fs_dirent ent, nt_process_args_with_argv0 const &args, nt_process_envs const &envs = {}, + inline explicit nt_family_process(io_kernel_t, ::fast_io::nt_fs_dirent ent, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, true)} diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 85a266dc8..9f1d57773 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -992,6 +992,39 @@ class posix_process : public posix_process_observer { } + template <::fast_io::constructible_to_os_c_str path_type> + inline posix_process(posix_at_entry pate, path_type const &filename, ::fast_io::args_with_argv0_t, posix_process_args const &args = {}, + posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) + : posix_process_observer{ + ::fast_io::details::fork_execveat_impl(pate.fd, filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get_argv(), + envp.get_envs(), pio, mode) + + } + { + } + + template <::fast_io::constructible_to_os_c_str path_type> + inline posix_process(path_type const &filename, ::fast_io::args_with_argv0_t, posix_process_args const &args = {}, posix_process_envs const &envp = {}, + posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) + : posix_process_observer{ + ::fast_io::details::fork_execve_impl(filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{filename}.append(args).get_argv(), + envp.get_envs(), pio, mode) + + } + { + } + + inline posix_process(::fast_io::posix_fs_dirent ent, ::fast_io::args_with_argv0_t, posix_process_args const &args = {}, posix_process_envs const &envp = {}, + posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) + : posix_process_observer{ + ::fast_io::details::fork_execveat_common_impl(ent.fd, ent.filename, + (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get_argv(), + envp.get_envs(), pio, mode)} + { + } + inline posix_process(posix_process const &) = delete; inline posix_process &operator=(posix_process const &) = delete; inline constexpr posix_process(posix_process &&__restrict other) noexcept From bf2fe18d2213c703de555fb6bcc2a497265ba1c5 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 23:13:36 +0800 Subject: [PATCH 32/43] Refactor process constructors in nt.h, posix.h, and win32.h to standardize argument handling - Updated constructors across nt.h, posix.h, and win32.h to use a consistent default for `process_mode`, specifically `argv0_no_path_append`. - Enhanced clarity in argument handling by ensuring all relevant constructors utilize the new default, streamlining process initialization logic. - Improved maintainability and readability of the code by aligning constructor signatures across different platforms. --- include/fast_io_hosted/process/process/nt.h | 12 +- .../fast_io_hosted/process/process/posix.h | 6 +- .../fast_io_hosted/process/process/win32.h | 147 ++++++++++++++++-- 3 files changed, 139 insertions(+), 26 deletions(-) diff --git a/include/fast_io_hosted/process/process/nt.h b/include/fast_io_hosted/process/process/nt.h index 1724e8409..bb61e761a 100644 --- a/include/fast_io_hosted/process/process/nt.h +++ b/include/fast_io_hosted/process/process/nt.h @@ -1010,7 +1010,7 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa template <::fast_io::constructible_to_os_c_str path_type> inline explicit nt_family_process(nt_at_entry nate, path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, - nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) + nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, false)} { @@ -1018,14 +1018,14 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa template <::fast_io::constructible_to_os_c_str path_type> inline explicit nt_family_process(path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, - win32_process_io const &processio = {}, process_mode mode = {}) + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, false)} { } inline explicit nt_family_process(::fast_io::nt_fs_dirent ent, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, - win32_process_io const &processio = {}, process_mode mode = {}) + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, false)} { @@ -1033,7 +1033,7 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa template <::fast_io::constructible_to_os_c_str path_type> inline explicit nt_family_process(io_kernel_t, nt_at_entry nate, path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, - nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) + nt_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(nate, filename, args, envs, processio, mode, true)} { @@ -1041,14 +1041,14 @@ class nt_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public nt_fa template <::fast_io::constructible_to_os_c_str path_type> inline explicit nt_family_process(io_kernel_t, path_type const &filename, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, - win32_process_io const &processio = {}, process_mode mode = {}) + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(filename, args, envs, processio, mode, true)} { } inline explicit nt_family_process(io_kernel_t, ::fast_io::nt_fs_dirent ent, ::fast_io::args_with_argv0_t, nt_process_args_with_argv0 const &args = {}, nt_process_envs const &envs = {}, - win32_process_io const &processio = {}, process_mode mode = {}) + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) : nt_family_process_observer{ win32::nt::details::nt_create_process_overloads(ent, args, envs, processio, mode, true)} { diff --git a/include/fast_io_hosted/process/process/posix.h b/include/fast_io_hosted/process/process/posix.h index 9f1d57773..161b9bf20 100644 --- a/include/fast_io_hosted/process/process/posix.h +++ b/include/fast_io_hosted/process/process/posix.h @@ -994,7 +994,7 @@ class posix_process : public posix_process_observer template <::fast_io::constructible_to_os_c_str path_type> inline posix_process(posix_at_entry pate, path_type const &filename, ::fast_io::args_with_argv0_t, posix_process_args const &args = {}, - posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) + posix_process_envs const &envp = {}, posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = process_mode::argv0_no_path_append) : posix_process_observer{ ::fast_io::details::fork_execveat_impl(pate.fd, filename, (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{details::get_tls_str_fd_path_filename(pate.fd, filename)}.append(args).get_argv(), @@ -1006,7 +1006,7 @@ class posix_process : public posix_process_observer template <::fast_io::constructible_to_os_c_str path_type> inline posix_process(path_type const &filename, ::fast_io::args_with_argv0_t, posix_process_args const &args = {}, posix_process_envs const &envp = {}, - posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) + posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = process_mode::argv0_no_path_append) : posix_process_observer{ ::fast_io::details::fork_execve_impl(filename, (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{filename}.append(args).get_argv(), @@ -1017,7 +1017,7 @@ class posix_process : public posix_process_observer } inline posix_process(::fast_io::posix_fs_dirent ent, ::fast_io::args_with_argv0_t, posix_process_args const &args = {}, posix_process_envs const &envp = {}, - posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = {}) + posix_process_io const &pio = {}, [[maybe_unused]] process_mode mode = process_mode::argv0_no_path_append) : posix_process_observer{ ::fast_io::details::fork_execveat_common_impl(ent.fd, ent.filename, (mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append ? args.get_argv() : posix_process_args{details::get_tls_str_fd_path_filename(ent.fd, ent.filename)}.append(args).get_argv(), diff --git a/include/fast_io_hosted/process/process/win32.h b/include/fast_io_hosted/process/process/win32.h index 6d18446ed..14ac1b821 100644 --- a/include/fast_io_hosted/process/process/win32.h +++ b/include/fast_io_hosted/process/process/win32.h @@ -249,8 +249,23 @@ inline win32_user_process_information win32_winnt_process_create_from_handle_imp dwCreationFlags |= 0x00000010; // CREATE_NEW_CONSOLE } + win32_process_char_type const *actrual_args{args}; + auto const argv0_no_path_append{(mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append}; + + ::fast_io::containers::basic_string, ::fast_io::native_thread_local_allocator> tmp_actrual_args{}; + if (args && !argv0_no_path_append) + { + tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); + tmp_actrual_args.append(address_begin, ::fast_io::cstr_len(address_begin)); + tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); + tmp_actrual_args.push_back(::fast_io::char_literal_v < u8' ', win32_process_char_type); + tmp_actrual_args.append(args, ::fast_io::cstr_len(args)); + + actrual_args = tmp_actrual_args.data(); + } + ::fast_io::win32::process_information pi{}; - if (!::fast_io::win32::CreateProcessW(address_begin, const_cast(args), nullptr, nullptr, 1, + if (!::fast_io::win32::CreateProcessW(address_begin, const_cast(actrual_args), nullptr, nullptr, 1, dwCreationFlags, (void *)envs, nullptr, __builtin_addressof(si), __builtin_addressof(pi))) { throw_win32_error(); @@ -423,8 +438,23 @@ inline win32_user_process_information win32_winnt_process_create_from_handle_imp dwCreationFlags |= 0x00000010; // CREATE_NEW_CONSOLE } + win32_process_char_type const *actrual_args{args}; + auto const argv0_no_path_append{(mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append}; + + ::fast_io::containers::basic_string, ::fast_io::native_thread_local_allocator> tmp_actrual_args{}; + if (args && !argv0_no_path_append) + { + tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); + tmp_actrual_args.append(address_begin, ::fast_io::cstr_len(address_begin)); + tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); + tmp_actrual_args.push_back(::fast_io::char_literal_v < u8' ', win32_process_char_type); + tmp_actrual_args.append(args, ::fast_io::cstr_len(args)); + + actrual_args = tmp_actrual_args.data(); + } + ::fast_io::win32::process_information pi{}; - if (!::fast_io::win32::CreateProcessA(reinterpret_cast(address_begin), const_cast(args), nullptr, nullptr, 1, + if (!::fast_io::win32::CreateProcessA(reinterpret_cast(address_begin), const_cast(actrual_args), nullptr, nullptr, 1, dwCreationFlags, (void *)envs, nullptr, __builtin_addressof(si), __builtin_addressof(pi))) { throw_win32_error(); @@ -533,8 +563,23 @@ inline win32_user_process_information win32_9xa_win9x_process_create_from_filepa dwCreationFlags |= 0x00000010; // CREATE_NEW_CONSOLE } + char const *actrual_args{args}; + auto const argv0_no_path_append{(mode & process_mode::argv0_no_path_append) == process_mode::argv0_no_path_append}; + + ::fast_io::containers::basic_string tmp_actrual_args{}; + if (args && !argv0_no_path_append) + { + tmp_actrual_args.push_back('\"'); + tmp_actrual_args.append(filepath, ::fast_io::cstr_len(filepath)); + tmp_actrual_args.push_back('\"'); + tmp_actrual_args.push_back(' '); + tmp_actrual_args.append(args, ::fast_io::cstr_len(args)); + + actrual_args = tmp_actrual_args.data(); + } + ::fast_io::win32::process_information pi{}; - if (!::fast_io::win32::CreateProcessA(filepath, const_cast(args), nullptr, nullptr, 1, + if (!::fast_io::win32::CreateProcessA(filepath, const_cast(actrual_args), nullptr, nullptr, 1, dwCreationFlags, (void *)envs, nullptr, __builtin_addressof(si), __builtin_addressof(pi))) { throw_win32_error(); @@ -589,7 +634,14 @@ inline win32_user_process_information win32_winnt_create_process_overloads(nt_at basic_win32_process_args const &args, basic_win32_process_envs const &envs, win32_process_io const &processio, process_mode mode) { - basic_win32_family_file nf(entry, filename, open_mode::in | open_mode::excl); + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + + basic_win32_family_file nf{entry, filename, curr_open_mode}; return win32_winnt_process_create_from_handle_impl(nf.handle, args.get(), envs.get(), processio, mode); } @@ -599,6 +651,8 @@ inline win32_user_process_information win32_9xa_win9x_create_process_overloads(w win32_process_args_9xa const &args, win32_process_envs_9xa const &envs, win32_process_io const &processio, process_mode mode) { + // win9x no symlink + return win32_api_common_9xa(filename, win32_9xa_win9x_create_process_at_fs_dirent{ __builtin_addressof(entry.handle), @@ -613,7 +667,14 @@ inline win32_user_process_information win32_winnt_create_process_overloads(path_ basic_win32_process_envs const &envs, win32_process_io const &processio, process_mode mode) { - basic_win32_family_file nf(filename, open_mode::in | open_mode::excl); + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + + basic_win32_family_file nf{filename, curr_open_mode}; return win32_winnt_process_create_from_handle_impl(nf.handle, args.get(), envs.get(), processio, mode); } @@ -622,6 +683,8 @@ inline win32_user_process_information win32_9xa_win9x_create_process_overloads(p win32_process_envs_9xa const &envs, win32_process_io const &processio, process_mode mode) { + // win9x no symlink + return win32_api_common_9xa(filename, win32_9xa_win9x_create_process_at_fs_dirent{ nullptr, @@ -636,13 +699,22 @@ inline win32_user_process_information win32_winnt_create_process_overloads(::fas basic_win32_process_envs const &envs, win32_process_io const &processio, process_mode mode) { - basic_win32_family_file nf(ent, open_mode::in | open_mode::excl); + bool const follow{(mode & process_mode::follow) == process_mode::follow}; + open_mode curr_open_mode{open_mode::in | open_mode::excl}; + if (follow) + { + curr_open_mode |= open_mode::follow; + } + + basic_win32_family_file nf{ent, curr_open_mode}; return win32_winnt_process_create_from_handle_impl(nf.handle, args.get(), envs.get(), processio, mode); } inline win32_user_process_information win32_9xa_win9x_create_process_overloads(::fast_io::win32_9xa_fs_dirent const &ent, win32_process_args_9xa const &args, win32_process_envs_9xa const &envs, win32_process_io const &processio, process_mode mode) { + // win9x no symlink + return win32_api_common_9xa(ent.filename, win32_9xa_win9x_create_process_at_fs_dirent{ __builtin_addressof(ent.handle), @@ -754,7 +826,7 @@ struct win32_process_id template inline win32_process_id get_process_id(win32_family_process_observer ppob) noexcept { - auto pid{::fast_io::win32::GetProcessId(ppob.native_handle)}; + auto pid{::fast_io::win32::GetProcessId(ppob.native_handle().hprocess)}; if (pid == 0) [[unlikely]] { throw_win32_error(); @@ -775,24 +847,24 @@ class win32_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public wi { } - template <::fast_io::constructible_to_os_c_str path_type, bool is_first> - inline explicit win32_family_process(nt_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit win32_family_process(nt_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_winnt_create_process_overloads(nate, filename, args, envs, processio, mode)} { } - template <::fast_io::constructible_to_os_c_str path_type, bool is_first> - inline explicit win32_family_process(win32_9xa_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit win32_family_process(win32_9xa_at_entry nate, path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_9xa_win9x_create_process_overloads(nate, filename, args, envs, processio, mode)} { } - template <::fast_io::constructible_to_os_c_str path_type, bool is_first> - inline explicit win32_family_process(path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit win32_family_process(path_type const &filename, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ #if defined(_WIN32_WINDOWS) @@ -804,22 +876,63 @@ class win32_family_process FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE : public wi { } - template - inline explicit win32_family_process(::fast_io::nt_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + inline explicit win32_family_process(::fast_io::nt_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_winnt_create_process_overloads(ent, args, envs, processio, mode)} { } - template - inline explicit win32_family_process(::fast_io::win32_9xa_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + inline explicit win32_family_process(::fast_io::win32_9xa_fs_dirent ent, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = {}) : win32_family_process_observer{ win32::details::win32_9xa_win9x_create_process_overloads(ent, args, envs, processio, mode)} { } + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit win32_family_process(nt_at_entry nate, path_type const &filename, ::fast_io::args_with_argv0_t, basic_win32_process_args const &args = {}, + basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) + : win32_family_process_observer{ + win32::details::win32_winnt_create_process_overloads(nate, filename, args, envs, processio, mode)} + { + } + + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit win32_family_process(win32_9xa_at_entry nate, path_type const &filename, ::fast_io::args_with_argv0_t, basic_win32_process_args const &args = {}, + basic_win32_process_envs const &envs = {}, win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) + : win32_family_process_observer{ + win32::details::win32_9xa_win9x_create_process_overloads(nate, filename, args, envs, processio, mode)} + { + } + + template <::fast_io::constructible_to_os_c_str path_type> + inline explicit win32_family_process(path_type const &filename, ::fast_io::args_with_argv0_t, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) + : win32_family_process_observer{ +#if defined(_WIN32_WINDOWS) + win32::details::win32_9xa_win9x_create_process_overloads(filename, args, envs, processio, mode) +#else + win32::details::win32_winnt_create_process_overloads(filename, args, envs, processio, mode) +#endif + } + { + } + + inline explicit win32_family_process(::fast_io::nt_fs_dirent ent, ::fast_io::args_with_argv0_t, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) + : win32_family_process_observer{ + win32::details::win32_winnt_create_process_overloads(ent, args, envs, processio, mode)} + { + } + + inline explicit win32_family_process(::fast_io::win32_9xa_fs_dirent ent, ::fast_io::args_with_argv0_t, basic_win32_process_args const &args = {}, basic_win32_process_envs const &envs = {}, + win32_process_io const &processio = {}, process_mode mode = process_mode::argv0_no_path_append) + : win32_family_process_observer{ + win32::details::win32_9xa_win9x_create_process_overloads(ent, args, envs, processio, mode)} + { + } + inline win32_family_process(win32_family_process const &b) = delete; inline win32_family_process &operator=(win32_family_process const &b) = delete; inline constexpr win32_family_process(win32_family_process &&__restrict b) noexcept From eff1c0d6b0f885b4f8b4568267fe30c6d70b229b Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 23:14:18 +0800 Subject: [PATCH 33/43] Refactor argument handling in win32.h for consistency and clarity - Standardized the usage of `char_literal_v` in the argument construction process by removing unnecessary spaces in template syntax. - Enhanced readability and maintainability of the code by ensuring consistent formatting across argument handling in the `win32_winnt_process_create_from_handle_imp` function. --- include/fast_io_hosted/process/process/win32.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fast_io_hosted/process/process/win32.h b/include/fast_io_hosted/process/process/win32.h index 14ac1b821..9ee8d3663 100644 --- a/include/fast_io_hosted/process/process/win32.h +++ b/include/fast_io_hosted/process/process/win32.h @@ -255,10 +255,10 @@ inline win32_user_process_information win32_winnt_process_create_from_handle_imp ::fast_io::containers::basic_string, ::fast_io::native_thread_local_allocator> tmp_actrual_args{}; if (args && !argv0_no_path_append) { - tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); + tmp_actrual_args.push_back(::fast_io::char_literal_v>); tmp_actrual_args.append(address_begin, ::fast_io::cstr_len(address_begin)); - tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); - tmp_actrual_args.push_back(::fast_io::char_literal_v < u8' ', win32_process_char_type); + tmp_actrual_args.push_back(::fast_io::char_literal_v>); + tmp_actrual_args.push_back(::fast_io::char_literal_v>); tmp_actrual_args.append(args, ::fast_io::cstr_len(args)); actrual_args = tmp_actrual_args.data(); @@ -444,10 +444,10 @@ inline win32_user_process_information win32_winnt_process_create_from_handle_imp ::fast_io::containers::basic_string, ::fast_io::native_thread_local_allocator> tmp_actrual_args{}; if (args && !argv0_no_path_append) { - tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); + tmp_actrual_args.push_back(::fast_io::char_literal_v>); tmp_actrual_args.append(address_begin, ::fast_io::cstr_len(address_begin)); - tmp_actrual_args.push_back(::fast_io::char_literal_v < u8'\"', win32_process_char_type); - tmp_actrual_args.push_back(::fast_io::char_literal_v < u8' ', win32_process_char_type); + tmp_actrual_args.push_back(::fast_io::char_literal_v>); + tmp_actrual_args.push_back(::fast_io::char_literal_v>); tmp_actrual_args.append(args, ::fast_io::cstr_len(args)); actrual_args = tmp_actrual_args.data(); From dd37570cff8626306209e2bd22d8d37fb3bc4231 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Sun, 9 Nov 2025 23:39:44 +0800 Subject: [PATCH 34/43] Refactor error handling and object duplication in win32.h - Updated the `throw_win32_error` function call to remove the status argument for improved clarity in error handling. - Modified the `win32_duplicate_object_std` function to use a boolean for the `inherit` parameter, enhancing readability and consistency in handle duplication logic. --- include/fast_io_hosted/process/process/win32.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_io_hosted/process/process/win32.h b/include/fast_io_hosted/process/process/win32.h index 9ee8d3663..7f541d061 100644 --- a/include/fast_io_hosted/process/process/win32.h +++ b/include/fast_io_hosted/process/process/win32.h @@ -46,7 +46,7 @@ inline void win32_wait_and_close_user_process_or_thread(void *handle) noexcept(! { if (status) [[unlikely]] { - throw_win32_error(status); + throw_win32_error(); } } } @@ -68,8 +68,8 @@ inline void win32_duplicate_object_std(void *parent_process, void *&standard_io_ return; } if (!::fast_io::win32::DuplicateHandle( - parent_process, standard_io_handle, process_handle, __builtin_addressof(standard_io_handle), 0, 0, - 0x00000002 | 0x00000004)) [[unlikely]] + parent_process, standard_io_handle, process_handle, __builtin_addressof(standard_io_handle), 0, true, + 0x00000002 /*DUPLICATE_SAME_ACCESS*/)) [[unlikely]] { throw_win32_error(); } From 3fa5be6cd6cd971c04b8f0ff626f61e1270770a2 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 00:01:40 +0800 Subject: [PATCH 35/43] f --- include/fast_io_hosted/process/process/win32.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/fast_io_hosted/process/process/win32.h b/include/fast_io_hosted/process/process/win32.h index 7f541d061..51e1a59be 100644 --- a/include/fast_io_hosted/process/process/win32.h +++ b/include/fast_io_hosted/process/process/win32.h @@ -40,13 +40,18 @@ inline void win32_wait_and_close_user_process_or_thread(void *handle) noexcept(! { return; } + auto status{win32_wait_user_process_or_thread(handle)}; + auto const last_error{::fast_io::win32::GetLastError()}; + ::fast_io::win32::CloseHandle(handle); + if constexpr (throw_eh) { - if (status) [[unlikely]] + if (status == 0xFFFFFFFF) [[unlikely]] { - throw_win32_error(); + // Preventing errors caused by replacing closehandle + throw_win32_error(last_error); } } } @@ -786,11 +791,11 @@ inline win32_wait_status wait(win32_family_process_observer ppob) noexce // wait for process auto const status{win32::details::win32_wait_user_process_or_thread(ppob.hnt_user_process_info.hprocess)}; - if (status) [[unlikely]] + if (status == 0xFFFFFFFF) [[unlikely]] { if constexpr (throw_eh) { - throw_win32_error(status); + throw_win32_error(); } else { From 9ee1807e53894915a703d9206fafa5f6df24a2c9 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 10:17:51 +0800 Subject: [PATCH 36/43] k --- include/fast_io_hosted/platforms/posix_mapping.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_hosted/platforms/posix_mapping.h b/include/fast_io_hosted/platforms/posix_mapping.h index ae9d1aee5..2431568d8 100644 --- a/include/fast_io_hosted/platforms/posix_mapping.h +++ b/include/fast_io_hosted/platforms/posix_mapping.h @@ -18,7 +18,7 @@ inline ::std::byte *sys_mmap(void *addr, ::std::size_t len, int prot, int flags, throw_posix_error(EINVAL); } } - long ret{system_call<__NR_mmap, long>(addr, len, prot, flags, fd, offset)}; + ::std::ptrdiff_t ret{system_call<__NR_mmap, ::std::ptrdiff_t>(addr, len, prot, flags, fd, offset)}; system_call_throw_error(ret); return reinterpret_cast<::std::byte *>(static_cast<::std::uintptr_t>(ret)); #elif defined(HAVE_MMAP64) From c2b58ba31a4b732efcbee9f3ce7a002eef551289 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 15:01:26 +0800 Subject: [PATCH 37/43] Refactor thread implementation in nt.h and impl.h for clarity and consistency - Simplified the namespace structure for `fast_io::win32::nt`, improving organization. - Updated thread-related functions and constructors to use `inline constexpr` for better performance and clarity. - Enhanced error handling in sleep functions to ensure proper validation of input parameters. - Streamlined the usage of `nt_thread` and `this_thread` to improve readability and maintainability across the codebase. --- include/fast_io_hosted/threads/thread/impl.h | 34 +--- include/fast_io_hosted/threads/thread/nt.h | 183 +++++++++++++++---- 2 files changed, 148 insertions(+), 69 deletions(-) diff --git a/include/fast_io_hosted/threads/thread/impl.h b/include/fast_io_hosted/threads/thread/impl.h index b7d97f585..de087597a 100644 --- a/include/fast_io_hosted/threads/thread/impl.h +++ b/include/fast_io_hosted/threads/thread/impl.h @@ -1,41 +1,9 @@ #pragma once #if (defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__) -#ifdef _WIN32_WINDOWS #include "win32.h" - -namespace fast_io -{ -using thread = ::fast_io::win32::win32_thread; - -namespace this_thread -{ - -using ::fast_io::win32::this_thread::get_id; -using ::fast_io::win32::this_thread::sleep_for; -using ::fast_io::win32::this_thread::sleep_until; - -} // namespace this_thread - -} // namespace fast_io -#else +#ifndef _WIN32_WINDOWS #include "nt.h" - -namespace fast_io -{ -template -using thread = ::fast_io::win32::nt::nt_thread; - -namespace this_thread -{ - -using ::fast_io::win32::nt::this_thread::get_id; -using ::fast_io::win32::nt::this_thread::sleep_for; -using ::fast_io::win32::nt::this_thread::sleep_until; - -} // namespace this_thread - -} // namespace fast_io #endif #elif defined (__linux__) diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index 45a0cb4b0..ff112ffac 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -9,45 +9,50 @@ #include "../../../fast_io_dsal/tuple.h" #include "../../../fast_io_core_impl/allocation/common.h" -namespace fast_io::win32::nt +namespace fast_io +{ +namespace win32::nt { namespace details { +template class nt_thread_start_routine_tuple_allocate_guard { public: void *ptr_{nullptr}; - constexpr nt_thread_start_routine_tuple_allocate_guard() = default; + inline constexpr nt_thread_start_routine_tuple_allocate_guard() = default; - constexpr nt_thread_start_routine_tuple_allocate_guard(void *ptr) : ptr_{ptr} + inline constexpr nt_thread_start_routine_tuple_allocate_guard(void *ptr) + : ptr_{ptr} {} - constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; - constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default; + inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; + inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default; - constexpr ~nt_thread_start_routine_tuple_allocate_guard() + inline constexpr ~nt_thread_start_routine_tuple_allocate_guard() { if (ptr_ != nullptr) { + ::std::ranges::destroy_at(reinterpret_cast(this->ptr_)); ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(this->ptr_); } } }; template -constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept( +inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept( ::std::invoke(::fast_io::get(*reinterpret_cast(args))...))) { - [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _(args); + [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _(args); ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); return 0; } template -constexpr auto get_thread_start_routine(::std::index_sequence) noexcept +inline constexpr auto get_thread_start_routine(::std::index_sequence) noexcept { return ::fast_io::win32::nt::details::thread_start_routine; } @@ -66,13 +71,13 @@ class nt_thread native_handle_type handle_{nullptr}; public: - constexpr nt_thread() noexcept = default; + inline constexpr nt_thread() noexcept = default; template requires(::std::invocable) - constexpr nt_thread(Func &&func, Args &&...args) + inline constexpr nt_thread(Func &&func, Args &&...args) { - using start_routine_tuple_type = ::fast_io::tuple; + using start_routine_tuple_type = ::fast_io::tuple<::std::decay_t, ::std::decay_t...>; #if __has_cpp_attribute(indeterminate) ::fast_io::win32::nt::client_id cid [[indeterminate]]; #else @@ -107,11 +112,11 @@ class nt_thread this->id_ = cid.UniqueThread; } - constexpr nt_thread(nt_thread const &) noexcept = delete; + inline constexpr nt_thread(nt_thread const &) noexcept = delete; - constexpr nt_thread(nt_thread &&other) noexcept = default; + inline constexpr nt_thread(nt_thread &&other) noexcept = default; - constexpr ~nt_thread() noexcept + inline constexpr ~nt_thread() noexcept { if (handle_ != nullptr) { @@ -127,9 +132,9 @@ class nt_thread } } - constexpr nt_thread &operator=(nt_thread const &) noexcept = delete; + inline constexpr nt_thread &operator=(nt_thread const &) noexcept = delete; - constexpr nt_thread &operator=(nt_thread &&other) noexcept + inline constexpr nt_thread &operator=(nt_thread &&other) noexcept { if (this == __builtin_addressof(other)) [[unlikely]] { @@ -138,18 +143,18 @@ class nt_thread this->swap(other); return *this; } - constexpr bool joinable() const noexcept + inline constexpr bool joinable() const noexcept { return this->id_ != nullptr; } - constexpr void join() + inline constexpr void join() { if (!this->joinable()) [[unlikely]] { ::fast_io::fast_terminate(); } - auto status{::fast_io::win32::nt::nt_wait_for_single_object(this->handle_, /* INFINITE = */ int(0xffffffff), nullptr)}; + auto status{::fast_io::win32::nt::nt_wait_for_single_object(this->handle_, false, nullptr)}; if (status) [[unlikely]] { ::fast_io::throw_nt_error(status); @@ -157,7 +162,7 @@ class nt_thread this->id_ = nullptr; } - constexpr void detach() + inline constexpr void detach() { if (!this->joinable()) [[unlikely]] { @@ -172,20 +177,20 @@ class nt_thread this->id_ = nullptr; } - constexpr void swap(nt_thread &other) noexcept + inline constexpr void swap(nt_thread &other) noexcept { ::std::ranges::swap(handle_, other.handle_); ::std::ranges::swap(id_, other.id_); } [[nodiscard]] - constexpr auto get_id() const noexcept + inline constexpr auto get_id() const noexcept { return this->id_; } [[nodiscard]] - constexpr auto native_handle() const noexcept + inline constexpr auto native_handle() const noexcept { return this->handle_; } @@ -194,13 +199,22 @@ class nt_thread * @brief Get the win32 id of the thread. * @note same as win32 GetCurrentThreadId */ - constexpr ::std::uint_least32_t get_win32_id() const noexcept + inline constexpr ::std::uint_least32_t get_win32_id() const noexcept { - auto peb = ::fast_io::win32::nt::nt_current_teb(); - return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(peb->ClientId.UniqueThread)); + ::fast_io::win32::nt::thread_basic_information tbi; // no init + + auto status{::fast_io::win32::nt::nt_query_information_thread( + this->handle_, ::fast_io::win32::nt::thread_information_class::ThreadBasicInformation, __builtin_addressof(tbi), sizeof(tbi), nullptr)}; + + if (status) [[unlikely]] + { + ::fast_io::throw_nt_error(status); + } + + return reinterpret_cast<::std::uint_least32_t>(tbi.ClientId.UniqueThread); } - static constexpr ::std::uint_least32_t hardware_concurrency() + inline static constexpr ::std::uint_least32_t hardware_concurrency() { ::fast_io::win32::nt::system_basic_information sb{}; auto status{::fast_io::win32::nt::nt_query_system_information(::fast_io::win32::nt::system_information_class::SystemBasicInformation, @@ -217,7 +231,7 @@ namespace this_thread { template -constexpr auto get_id() -> ::fast_io::win32::nt::nt_thread::id +inline constexpr ::fast_io::win32::nt::nt_thread::id get_id() { ::fast_io::win32::nt::thread_basic_information tbi; ::std::uint_least32_t status{::fast_io::win32::nt::nt_query_information_thread( @@ -233,10 +247,48 @@ constexpr auto get_id() -> ::fast_io::win32::nt::nt_thread::id return tbi.ClientId.UniqueThread; } +inline ::std::uint_least32_t get_win32_id() noexcept +{ + auto teb{::fast_io::win32::nt::nt_current_teb()}; + return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(teb->ClientId.UniqueThread)); +} + template -constexpr void sleep_for(::std::chrono::duration const &sleep_duration) +inline constexpr void sleep_for(::std::chrono::duration const &sleep_duration) { - auto val = -static_cast<::std::int_least64_t>(::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count() * 10); + auto const count{ + ::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 constexpr void sleep_for(::fast_io::basic_timestamp const &sleep_duration) +{ + if (sleep_duration.seconds < 0) [[unlikely]] + { + ::fast_io::throw_nt_error(0xC000000D); + } + + auto const win_100ns_seconds{static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 10'000'000u + sleep_duration.subseconds / 100u)}; + + if (win_100ns_seconds > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) [[unlikely]] + { + ::fast_io::throw_nt_error(0xC000000D); + } + + auto val = -static_cast<::std::int_least64_t>(win_100ns_seconds); ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution(false, __builtin_addressof(val))}; if (status) [[unlikely]] { @@ -245,12 +297,30 @@ constexpr void sleep_for(::std::chrono::duration const &sleep_durat } template -constexpr void sleep_until(::std::chrono::time_point const &expect_time) +inline constexpr 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 nt_ts = (unix_ts + 11644473600) * 10000000; + 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]] { @@ -258,6 +328,47 @@ constexpr void sleep_until(::std::chrono::time_point const &exp } } +template +inline constexpr void sleep_until(::fast_io::basic_timestamp const &expect_time) +{ + if (expect_time.seconds < 0) [[unlikely]] + { + ::fast_io::throw_nt_error(0xC000000D); + } + + auto const win32_ts{static_cast<::fast_io::win32_timestamp>(expect_time)}; + + auto const win_100ns_seconds = static_cast<::std::uint_least64_t>(win32_ts.seconds) * 10'000'000u + win32_ts.subseconds / 100u; + + if (win_100ns_seconds > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) [[unlikely]] + { + ::fast_io::throw_nt_error(0xC000000D); + } + + auto val = static_cast<::std::int_least64_t>(win_100ns_seconds); + ::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); + } +} + } // namespace this_thread -} // namespace fast_io::win32::nt +} // namespace win32::nt + +using nt_thread = win32::nt::nt_thread; +using zw_thread = win32::nt::nt_thread; + +#if defined(_WIN32) && !defined(_WIN32_WINDOWS) +using native_thread = nt_thread; + +namespace this_thread +{ +using ::fast_io::win32::nt::this_thread::get_id; +using ::fast_io::win32::nt::this_thread::sleep_for; +using ::fast_io::win32::nt::this_thread::sleep_until; +} // namespace this_thread +#endif + +} // namespace fast_io From 81f7d3cd99e3a4cea50b8293a43bf0c421621340 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 16:16:03 +0800 Subject: [PATCH 38/43] fix thread --- examples/0040.thread/thread.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/0040.thread/thread.cc b/examples/0040.thread/thread.cc index f6887588e..3e6d4479b 100644 --- a/examples/0040.thread/thread.cc +++ b/examples/0040.thread/thread.cc @@ -4,7 +4,7 @@ int main() { #ifdef _WIN32 // temporaryly disable this example on rest platforms - auto t = ::fast_io::thread{[](int param) + auto t = ::fast_io::native_thread{[](int param) #if __cpp_static_call_operator >= 2020207L static #endif From a72ea6c92b73335c859161539c78df6277b16656 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 17:10:40 +0800 Subject: [PATCH 39/43] Enhance thread handling and error management in nt and win32 headers - Updated `RtlCreateUserThread` signature to accept a function pointer for improved flexibility. - Refined error handling in thread creation and management functions to ensure proper resource cleanup on failure. - Standardized the use of `inline constexpr` for thread-related functions to enhance performance and clarity. - Improved sleep functions to validate input parameters and handle edge cases more effectively. - Streamlined namespace usage and organization for better code maintainability. --- include/fast_io_hosted/platforms/nt/nt_api.h | 2 +- include/fast_io_hosted/threads/thread/nt.h | 88 +++++-- include/fast_io_hosted/threads/thread/win32.h | 233 +++++++++++++++--- 3 files changed, 267 insertions(+), 56 deletions(-) diff --git a/include/fast_io_hosted/platforms/nt/nt_api.h b/include/fast_io_hosted/platforms/nt/nt_api.h index 52e6c8c9a..e8a829a6c 100644 --- a/include/fast_io_hosted/platforms/nt/nt_api.h +++ b/include/fast_io_hosted/platforms/nt/nt_api.h @@ -45,7 +45,7 @@ FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlEnterCriticalSection(void *) noexce FAST_IO_DLLIMPORT int FAST_IO_WINSTDCALL RtlTryEnterCriticalSection(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlTryEnterCriticalSection, 4); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlLeaveCriticalSection(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlLeaveCriticalSection, 4); FAST_IO_DLLIMPORT void FAST_IO_WINSTDCALL RtlDeleteCriticalSection(void *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlDeleteCriticalSection, 4); -FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlCreateUserThread(void *, void *, int, ::std::uint_least32_t, ::std::size_t, ::std::size_t, void *, void *, void **, ::fast_io::win32::nt::client_id *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlCreateUserThread, 40); +FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL RtlCreateUserThread(void *, void *, int, ::std::uint_least32_t, ::std::size_t, ::std::size_t, ::std::uint_least32_t (FAST_IO_WINSTDCALL*)(void*), void *, void **, ::fast_io::win32::nt::client_id *) noexcept FAST_IO_WINSTDCALL_RENAME(RtlCreateUserThread, 40); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtResumeThread(void *, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(NtResumeThread, 8); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL ZwResumeThread(void *, ::std::uint_least32_t *) noexcept FAST_IO_WINSTDCALL_RENAME(ZwResumeThread, 8); FAST_IO_DLLIMPORT ::std::uint_least32_t FAST_IO_WINSTDCALL NtLockFile(void *, void *, ::fast_io::win32::nt::pio_apc_routine, void *, ::fast_io::win32::nt::io_status_block *, ::std::int_least64_t *, ::std::int_least64_t *, ::std::uint_least32_t, char unsigned, char unsigned) noexcept FAST_IO_WINSTDCALL_RENAME(NtLockFile, 40); diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index ff112ffac..00ed26d0a 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -43,11 +43,23 @@ class nt_thread_start_routine_tuple_allocate_guard }; template -inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept( - ::std::invoke(::fast_io::get(*reinterpret_cast(args))...))) +inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept { [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _(args); - ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); + +#ifdef FAST_IO_CPP_EXCEPTIONS + try +#endif + { + ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); + } +#ifdef FAST_IO_CPP_EXCEPTIONS + catch (...) + { + ::fast_io::fast_terminate(); + } +#endif + return 0; } @@ -101,14 +113,20 @@ class nt_thread 0, // StackZeroBits 0, // StackReserved 0, // StackCommit - reinterpret_cast(start_routine), + start_routine, start_routine_tuple, // args of func __builtin_addressof(this->handle_), __builtin_addressof(cid))}; + if (status) [[unlikely]] { + // Creation failed; manual release is required. + ::std::ranges::destroy_at(reinterpret_cast(start_routine_tuple)); + ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(start_routine_tuple); + ::fast_io::throw_nt_error(status); } + this->id_ = cid.UniqueThread; } @@ -159,6 +177,12 @@ class nt_thread { ::fast_io::throw_nt_error(status); } + status = ::fast_io::win32::nt::nt_close(this->handle_); + if (status) [[unlikely]] + { + ::fast_io::throw_nt_error(status); + } + this->handle_ = nullptr; this->id_ = nullptr; } @@ -211,7 +235,7 @@ class nt_thread ::fast_io::throw_nt_error(status); } - return reinterpret_cast<::std::uint_least32_t>(tbi.ClientId.UniqueThread); + return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(tbi.ClientId.UniqueThread)); } inline static constexpr ::std::uint_least32_t hardware_concurrency() @@ -231,7 +255,13 @@ namespace this_thread { template -inline constexpr ::fast_io::win32::nt::nt_thread::id get_id() +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 + ::fast_io::win32::nt::nt_thread::id get_id() { ::fast_io::win32::nt::thread_basic_information tbi; ::std::uint_least32_t status{::fast_io::win32::nt::nt_query_information_thread( @@ -247,18 +277,30 @@ inline constexpr ::fast_io::win32::nt::nt_thread::id get_id() return tbi.ClientId.UniqueThread; } -inline ::std::uint_least32_t get_win32_id() noexcept +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 + ::std::uint_least32_t get_win32_id() noexcept { auto teb{::fast_io::win32::nt::nt_current_teb()}; return static_cast<::std::uint_least32_t>(reinterpret_cast<::std::size_t>(teb->ClientId.UniqueThread)); } template -inline constexpr void sleep_for(::std::chrono::duration const &sleep_duration) +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{ + 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}; + ::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())) { @@ -274,7 +316,13 @@ inline constexpr void sleep_for(::std::chrono::duration const &slee } template -inline constexpr void sleep_for(::fast_io::basic_timestamp const &sleep_duration) +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) { if (sleep_duration.seconds < 0) [[unlikely]] { @@ -297,7 +345,13 @@ inline constexpr void sleep_for(::fast_io::basic_timestamp const & } template -inline constexpr void sleep_until(::std::chrono::time_point const &expect_time) +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()) @@ -329,7 +383,13 @@ inline constexpr void sleep_until(::std::chrono::time_point con } template -inline constexpr void sleep_until(::fast_io::basic_timestamp const &expect_time) +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) { if (expect_time.seconds < 0) [[unlikely]] { @@ -360,7 +420,7 @@ inline constexpr void sleep_until(::fast_io::basic_timestamp const using nt_thread = win32::nt::nt_thread; using zw_thread = win32::nt::nt_thread; -#if defined(_WIN32) && !defined(_WIN32_WINDOWS) +#if ((defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__)) && !defined(_WIN32_WINDOWS) using native_thread = nt_thread; namespace this_thread diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 6c8d85543..97cad7e41 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -9,45 +9,61 @@ #include "../../../fast_io_dsal/tuple.h" #include "../../../fast_io_core_impl/allocation/common.h" -namespace fast_io::win32 +namespace fast_io +{ +namespace win32 { namespace details { +template class win32_thread_start_routine_tuple_allocate_guard { public: void *ptr_{nullptr}; - constexpr win32_thread_start_routine_tuple_allocate_guard() = default; + inline constexpr win32_thread_start_routine_tuple_allocate_guard() = default; - constexpr win32_thread_start_routine_tuple_allocate_guard(void *ptr) : ptr_{ptr} + inline constexpr win32_thread_start_routine_tuple_allocate_guard(void *ptr) : ptr_{ptr} {} - constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; - constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard &&other) noexcept = default; + inline constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; + inline constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard &&other) noexcept = default; - constexpr ~win32_thread_start_routine_tuple_allocate_guard() + inline constexpr ~win32_thread_start_routine_tuple_allocate_guard() { if (ptr_ != nullptr) { + ::std::ranges::destroy_at(reinterpret_cast(this->ptr_)); ::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::deallocate(this->ptr_); } } }; template -constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept(noexcept( - ::std::invoke(::fast_io::get(*reinterpret_cast(args))...))) +inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept { - [[maybe_unused]] ::fast_io::win32::details::win32_thread_start_routine_tuple_allocate_guard _(args); - ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); + [[maybe_unused]] ::fast_io::win32::details::win32_thread_start_routine_tuple_allocate_guard _(args); + +#ifdef FAST_IO_CPP_EXCEPTIONS + try +#endif + { + ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); + } +#ifdef FAST_IO_CPP_EXCEPTIONS + catch (...) + { + ::fast_io::fast_terminate(); + } +#endif + return 0; } template -constexpr auto get_thread_start_routine(::std::index_sequence) noexcept +inline constexpr auto get_thread_start_routine(::std::index_sequence) noexcept { return ::fast_io::win32::details::thread_start_routine; } @@ -65,13 +81,13 @@ class win32_thread native_handle_type handle_{nullptr}; public: - win32_thread() noexcept = default; + inline constexpr win32_thread() noexcept = default; template requires(::std::invocable) - constexpr win32_thread(Func &&func, Args &&...args) + inline constexpr win32_thread(Func &&func, Args &&...args) { - using start_routine_tuple_type = ::fast_io::tuple; + using start_routine_tuple_type = ::fast_io::tuple<::std::decay_t, ::std::decay_t...>; void *start_routine_tuple{::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::allocate(sizeof(start_routine_tuple_type))}; #if defined(__clang__) #pragma clang diagnostic push @@ -92,15 +108,19 @@ class win32_thread __builtin_addressof(this->id_)); if (this->handle_ == nullptr) [[unlikely]] { + // Creation failed; manual release is required + ::std::ranges::destroy_at(reinterpret_cast(start_routine_tuple)); + ::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::deallocate(start_routine_tuple); + ::fast_io::throw_win32_error(); } } - constexpr win32_thread(win32_thread const &) noexcept = delete; + inline constexpr win32_thread(win32_thread const &) noexcept = delete; - constexpr win32_thread(win32_thread &&other) noexcept = default; + inline constexpr win32_thread(win32_thread &&other) noexcept = default; - constexpr ~win32_thread() noexcept + inline constexpr ~win32_thread() noexcept { if (handle_ != nullptr) { @@ -115,9 +135,9 @@ class win32_thread } } - constexpr win32_thread &operator=(win32_thread const &) noexcept = delete; + inline constexpr win32_thread &operator=(win32_thread const &) noexcept = delete; - constexpr win32_thread &operator=(win32_thread &&other) noexcept + inline constexpr win32_thread &operator=(win32_thread &&other) noexcept { if (this == __builtin_addressof(other)) [[unlikely]] { @@ -126,15 +146,16 @@ class win32_thread this->swap(other); return *this; } - constexpr bool joinable() const noexcept + inline constexpr bool joinable() const noexcept { return this->id_ != 0; } + inline #if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr + // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L + // for reduce some warning purpose + constexpr #endif void join() { @@ -142,14 +163,28 @@ class win32_thread { ::fast_io::fast_terminate(); } - ::fast_io::win32::WaitForSingleObject(this->handle_, /* INFINITE = */ 0xffffffff); + + auto const value{::fast_io::win32::WaitForSingleObject(this->handle_, /* INFINITE = */ 0xFFFFFFFFu)}; + + if (value == 0xFFFFFFFFu) [[unlikely]] + { + ::fast_io::throw_win32_error(); + } + + if (!::fast_io::win32::CloseHandle(this->handle_)) [[unlikely]] + { + ::fast_io::throw_win32_error(); + } + + this->handle_ = nullptr; this->id_ = 0; } + inline #if __cpp_constexpr >= 202207L - // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L - // for reduce some warning purpose - constexpr + // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L + // for reduce some warning purpose + constexpr #endif void detach() { @@ -165,26 +200,26 @@ class win32_thread this->id_ = 0; } - constexpr void swap(win32_thread &other) noexcept + inline constexpr void swap(win32_thread &other) noexcept { ::std::ranges::swap(handle_, other.handle_); ::std::ranges::swap(id_, other.id_); } [[nodiscard]] - constexpr auto get_id() const noexcept + inline constexpr auto get_id() const noexcept { return this->id_; } [[nodiscard]] - constexpr auto native_handle() const noexcept + inline constexpr auto native_handle() const noexcept { return this->handle_; } [[nodiscard]] - static + inline static #if __cpp_constexpr >= 202207L // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L // for reduce some warning purpose @@ -202,10 +237,11 @@ namespace this_thread { [[nodiscard]] +inline #if __cpp_constexpr >= 202207L -// https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L -// for reduce some warning purpose -constexpr + // https://en.cppreference.com/w/cpp/compiler_support/23.html#cpp_constexpr_202207L + // for reduce some warning purpose + constexpr #endif auto get_id() noexcept -> ::fast_io::win32::win32_thread::id { @@ -213,23 +249,138 @@ constexpr } template -constexpr void sleep_for(::std::chrono::duration const &sleep_duration) noexcept +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 { - ::fast_io::win32::Sleep(static_cast<::std::uint_least32_t>(::std::chrono::duration_cast<::std::chrono::milliseconds>(sleep_duration).count())); + 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 -constexpr void sleep_until(::std::chrono::time_point const &expect_time) noexcept +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 now = Clock::now(); + auto const now{Clock::now()}; if (now < expect_time) { - ::fast_io::win32::Sleep(static_cast<::std::uint_least32_t>( - ::std::chrono::duration_cast<::std::chrono::milliseconds>(expect_time - now).count())); + 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 + // 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; + } + + auto const win_100ns{ + static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 10'000'000ULL + + sleep_duration.subseconds / 100u)}; + + auto const ms64{win_100ns / 10'000ULL}; + auto const ms{ms64 > 0xFFFFFFFFu ? static_cast<::std::uint_least32_t>(0xFFFFFFFFu) + : static_cast<::std::uint_least32_t>(ms64)}; + if (ms == 0) + { + return; } + + ::fast_io::win32::Sleep(ms); +} + +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 +{ + ::fast_io::win32::filetime ft{}; + ::fast_io::win32::GetSystemTimeAsFileTime(__builtin_addressof(ft)); + auto const now_100ns{(static_cast<::std::uint_least64_t>(ft.dwHighDateTime) << 32) | + static_cast<::std::uint_least64_t>(ft.dwLowDateTime)}; + + + auto const win32_ts{static_cast<::fast_io::win32_timestamp>(expect_time)}; + + if (win32_ts.seconds < 0) + { + return; + } + auto const expect_100ns{ + static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(win32_ts.seconds) * 10'000'000ULL + + win32_ts.subseconds / 100u)}; + + if (expect_100ns <= now_100ns) + { + return; + } + + auto const delta_100ns{expect_100ns - now_100ns}; + auto const ms64{delta_100ns / 10'000ULL}; + auto const ms{ms64 > 0xFFFFFFFFu ? static_cast<::std::uint_least32_t>(0xFFFFFFFFu) + : static_cast<::std::uint_least32_t>(ms64)}; + if (ms == 0) + { + return; + } + + // Since Win9x lacks CreateWaitableTimerW, all implementations on WinNT use NT threads. Therefore, sleep is used here as a simulation. + ::fast_io::win32::Sleep(ms); } } // namespace this_thread -} // namespace fast_io::win32 +} // namespace win32 + +using win32_thread = win32::win32_thread; + +#if ((defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__)) && defined(_WIN32_WINDOWS) +using native_thread = win32_thread; + +namespace this_thread +{ +using ::fast_io::win32::this_thread::get_id; +using ::fast_io::win32::this_thread::sleep_for; +using ::fast_io::win32::this_thread::sleep_until; +} // namespace this_thread +#endif +} // namespace fast_io From 10b0ee1a55ee76946ec43fc4b43a7d338982c326 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 17:39:57 +0800 Subject: [PATCH 40/43] Update RtlCreateUserThread signatures across linker headers for consistency - Modified the `RtlCreateUserThread` linker comments in multiple platform-specific headers to ensure uniformity in function signature representation. - Replaced `std::ranges::destroy_at` with `std::destroy_at` in thread management code for improved clarity and performance. --- include/fast_io_hosted/platforms/win32/msvc_linker_32.h | 2 +- include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h | 2 +- include/fast_io_hosted/platforms/win32/msvc_linker_64.h | 2 +- include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h | 2 +- include/fast_io_hosted/threads/thread/nt.h | 4 ++-- include/fast_io_hosted/threads/thread/win32.h | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_32.h b/include/fast_io_hosted/platforms/win32/msvc_linker_32.h index be69dd236..76338f2fa 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_32.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_32.h @@ -219,7 +219,7 @@ #pragma comment(linker,"/alternatename:__imp_?RtlTryEnterCriticalSection@nt@win32@fast_io@@YAHPAX@Z=__imp_RtlTryEnterCriticalSection") #pragma comment(linker,"/alternatename:__imp_?RtlLeaveCriticalSection@nt@win32@fast_io@@YAXPAX@Z=__imp_RtlLeaveCriticalSection") #pragma comment(linker,"/alternatename:__imp_?RtlDeleteCriticalSection@nt@win32@fast_io@@YAXPAX@Z=__imp_RtlDeleteCriticalSection") -#pragma comment(linker,"/alternatename:__imp_?RtlCreateUserThread@nt@win32@fast_io@@YAIPAX0HIII00PAPAXPAUclient_id@123@@Z=__imp_RtlCreateUserThread") +#pragma comment(linker,"/alternatename:__imp_?RtlCreateUserThread@nt@win32@fast_io@@YAIPAX0HIIIP6AI0@Z0PAPAXPAUclient_id@123@@Z=__imp_RtlCreateUserThread") #pragma comment(linker,"/alternatename:__imp_?NtResumeThread@nt@win32@fast_io@@YAIPAXPAI@Z=__imp_NtResumeThread") #pragma comment(linker,"/alternatename:__imp_?ZwResumeThread@nt@win32@fast_io@@YAIPAXPAI@Z=__imp_ZwResumeThread") #pragma comment(linker,"/alternatename:__imp_?NtLockFile@nt@win32@fast_io@@YAIPAX0P6AX0PAUio_status_block@123@I@_E01PA_J3IEE@Z=__imp_NtLockFile") diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h b/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h index 3e19d9a98..f3dfc7e43 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_32_i686.h @@ -219,7 +219,7 @@ #pragma comment(linker,"/alternatename:__imp_?RtlTryEnterCriticalSection@nt@win32@fast_io@@YGHPAX@Z=__imp__RtlTryEnterCriticalSection@4") #pragma comment(linker,"/alternatename:__imp_?RtlLeaveCriticalSection@nt@win32@fast_io@@YGXPAX@Z=__imp__RtlLeaveCriticalSection@4") #pragma comment(linker,"/alternatename:__imp_?RtlDeleteCriticalSection@nt@win32@fast_io@@YGXPAX@Z=__imp__RtlDeleteCriticalSection@4") -#pragma comment(linker,"/alternatename:__imp_?RtlCreateUserThread@nt@win32@fast_io@@YGIPAX0HIII00PAPAXPAUclient_id@123@@Z=__imp__RtlCreateUserThread@40") +#pragma comment(linker,"/alternatename:__imp_?RtlCreateUserThread@nt@win32@fast_io@@YGIPAX0HIIIP6GI0@Z0PAPAXPAUclient_id@123@@Z=__imp__RtlCreateUserThread@40") #pragma comment(linker,"/alternatename:__imp_?NtResumeThread@nt@win32@fast_io@@YGIPAXPAI@Z=__imp__NtResumeThread@8") #pragma comment(linker,"/alternatename:__imp_?ZwResumeThread@nt@win32@fast_io@@YGIPAXPAI@Z=__imp__ZwResumeThread@8") #pragma comment(linker,"/alternatename:__imp_?NtLockFile@nt@win32@fast_io@@YGIPAX0P6AX0PAUio_status_block@123@I@_E01PA_J3IEE@Z=__imp__NtLockFile@40") diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_64.h b/include/fast_io_hosted/platforms/win32/msvc_linker_64.h index 0999223b4..e97858055 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_64.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_64.h @@ -219,7 +219,7 @@ #pragma comment(linker,"/alternatename:__imp_?RtlTryEnterCriticalSection@nt@win32@fast_io@@YAHPEAX@Z=__imp_RtlTryEnterCriticalSection") #pragma comment(linker,"/alternatename:__imp_?RtlLeaveCriticalSection@nt@win32@fast_io@@YAXPEAX@Z=__imp_RtlLeaveCriticalSection") #pragma comment(linker,"/alternatename:__imp_?RtlDeleteCriticalSection@nt@win32@fast_io@@YAXPEAX@Z=__imp_RtlDeleteCriticalSection") -#pragma comment(linker,"/alternatename:__imp_?RtlCreateUserThread@nt@win32@fast_io@@YAIPEAX0HI_K100PEAPEAXPEAUclient_id@123@@Z=__imp_RtlCreateUserThread") +#pragma comment(linker,"/alternatename:__imp_?RtlCreateUserThread@nt@win32@fast_io@@YAIPEAX0HI_K1P6AI0@Z0PEAPEAXPEAUclient_id@123@@Z=__imp_RtlCreateUserThread") #pragma comment(linker,"/alternatename:__imp_?NtResumeThread@nt@win32@fast_io@@YAIPEAXPEAI@Z=__imp_NtResumeThread") #pragma comment(linker,"/alternatename:__imp_?ZwResumeThread@nt@win32@fast_io@@YAIPEAXPEAI@Z=__imp_ZwResumeThread") #pragma comment(linker,"/alternatename:__imp_?NtLockFile@nt@win32@fast_io@@YAIPEAX0P6AX0PEAUio_status_block@123@I@_E01PEA_J3IEE@Z=__imp_NtLockFile") diff --git a/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h b/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h index 139157f5c..01f0e4d2e 100644 --- a/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h +++ b/include/fast_io_hosted/platforms/win32/msvc_linker_arm64ec.h @@ -219,7 +219,7 @@ #pragma comment(linker,"/alternatename:?RtlTryEnterCriticalSection$exit_thunk@nt@win32@fast_io@@$$hYAHPEAX@Z=#RtlTryEnterCriticalSection") #pragma comment(linker,"/alternatename:?RtlLeaveCriticalSection$exit_thunk@nt@win32@fast_io@@$$hYAXPEAX@Z=#RtlLeaveCriticalSection") #pragma comment(linker,"/alternatename:?RtlDeleteCriticalSection$exit_thunk@nt@win32@fast_io@@$$hYAXPEAX@Z=#RtlDeleteCriticalSection") -#pragma comment(linker,"/alternatename:?RtlCreateUserThread$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX0HI_K100PEAPEAXPEAUclient_id@123@@Z=#RtlCreateUserThread") +#pragma comment(linker,"/alternatename:?RtlCreateUserThread$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX0HI_K1P6AI0@Z0PEAPEAXPEAUclient_id@123@@Z=#RtlCreateUserThread") #pragma comment(linker,"/alternatename:?NtResumeThread$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXPEAI@Z=#NtResumeThread") #pragma comment(linker,"/alternatename:?ZwResumeThread$exit_thunk@nt@win32@fast_io@@$$hYAIPEAXPEAI@Z=#ZwResumeThread") #pragma comment(linker,"/alternatename:?NtLockFile$exit_thunk@nt@win32@fast_io@@$$hYAIPEAX0P6AX0PEAUio_status_block@123@I@_E01PEA_J3IEE@Z=#NtLockFile") diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index 00ed26d0a..65b859238 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -36,7 +36,7 @@ class nt_thread_start_routine_tuple_allocate_guard { if (ptr_ != nullptr) { - ::std::ranges::destroy_at(reinterpret_cast(this->ptr_)); + ::std::destroy_at(reinterpret_cast(this->ptr_)); ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(this->ptr_); } } @@ -121,7 +121,7 @@ class nt_thread if (status) [[unlikely]] { // Creation failed; manual release is required. - ::std::ranges::destroy_at(reinterpret_cast(start_routine_tuple)); + ::std::destroy_at(reinterpret_cast(start_routine_tuple)); ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(start_routine_tuple); ::fast_io::throw_nt_error(status); diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 97cad7e41..476507fc3 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -35,7 +35,7 @@ class win32_thread_start_routine_tuple_allocate_guard { if (ptr_ != nullptr) { - ::std::ranges::destroy_at(reinterpret_cast(this->ptr_)); + ::std::destroy_at(reinterpret_cast(this->ptr_)); ::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::deallocate(this->ptr_); } } @@ -109,7 +109,7 @@ class win32_thread if (this->handle_ == nullptr) [[unlikely]] { // Creation failed; manual release is required - ::std::ranges::destroy_at(reinterpret_cast(start_routine_tuple)); + ::std::destroy_at(reinterpret_cast(start_routine_tuple)); ::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::deallocate(start_routine_tuple); ::fast_io::throw_win32_error(); From 726cfe2747d3e4fdc2ae3ba859003e1fec903ff6 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 17:43:22 +0800 Subject: [PATCH 41/43] Add documentation comment to thread_start_routine in win32.h - Included a comment in the `thread_start_routine` function to clarify that the API function is called directly and that any CRT-specific processing occurs in `DllMain DLL_THREAD_ATTACH`. - This enhancement improves code readability and understanding of the threading implementation. --- include/fast_io_hosted/threads/thread/nt.h | 5 +++++ include/fast_io_hosted/threads/thread/win32.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index 65b859238..41bc79ed3 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -45,6 +45,11 @@ class nt_thread_start_routine_tuple_allocate_guard template inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept { + /* + * Just call the API function. Any CRT specific processing is done in + * DllMain DLL_THREAD_ATTACH + */ + [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _(args); #ifdef FAST_IO_CPP_EXCEPTIONS diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 476507fc3..0439d39c5 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -44,6 +44,11 @@ class win32_thread_start_routine_tuple_allocate_guard template inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(void *args) noexcept { + /* + * Just call the API function. Any CRT specific processing is done in + * DllMain DLL_THREAD_ATTACH + */ + [[maybe_unused]] ::fast_io::win32::details::win32_thread_start_routine_tuple_allocate_guard _(args); #ifdef FAST_IO_CPP_EXCEPTIONS From e2f16ca05ce2860dd7c1c3ff036ac08fec3d9c03 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 18:56:09 +0800 Subject: [PATCH 42/43] t1 --- include/fast_io_hosted.h | 1 + include/fast_io_hosted/threads/thread/impl.h | 4 +- include/fast_io_hosted/threads/thread/linux.h | 1 - .../threads/thread/linux_clone3.h | 206 ++++++++++++++++++ include/fast_io_hosted/threads/thread/nt.h | 4 +- include/fast_io_hosted/threads/thread/win32.h | 4 +- 6 files changed, 211 insertions(+), 9 deletions(-) delete mode 100644 include/fast_io_hosted/threads/thread/linux.h create mode 100644 include/fast_io_hosted/threads/thread/linux_clone3.h diff --git a/include/fast_io_hosted.h b/include/fast_io_hosted.h index e8376df61..446be4480 100644 --- a/include/fast_io_hosted.h +++ b/include/fast_io_hosted.h @@ -60,6 +60,7 @@ freestanding ones. #endif #if !defined(__AVR__) +#include "fast_io_dsal/impl/tuple.h" #include "fast_io_dsal/impl/string_view.h" #include "fast_io_dsal/impl/cstring_view.h" #include "fast_io_dsal/impl/string.h" diff --git a/include/fast_io_hosted/threads/thread/impl.h b/include/fast_io_hosted/threads/thread/impl.h index de087597a..d1f35521f 100644 --- a/include/fast_io_hosted/threads/thread/impl.h +++ b/include/fast_io_hosted/threads/thread/impl.h @@ -5,6 +5,6 @@ #ifndef _WIN32_WINDOWS #include "nt.h" #endif -#elif defined (__linux__) - +#elif defined(__linux__) +#include "linux_clone3.h" #endif diff --git a/include/fast_io_hosted/threads/thread/linux.h b/include/fast_io_hosted/threads/thread/linux.h deleted file mode 100644 index 73b4b8665..000000000 --- a/include/fast_io_hosted/threads/thread/linux.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/include/fast_io_hosted/threads/thread/linux_clone3.h b/include/fast_io_hosted/threads/thread/linux_clone3.h new file mode 100644 index 000000000..fc77fe9a8 --- /dev/null +++ b/include/fast_io_hosted/threads/thread/linux_clone3.h @@ -0,0 +1,206 @@ +#pragma once + +#if !defined(__linux__) +#error "This file is for linux only" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stack_pointer.h" + +namespace fast_io +{ + +class linux_clone3_thread +{ + using id = ::pid_t; + +private: + template + struct alignas(16) child_ctx + { + F func; + ::fast_io::containers::tuple args; + }; + + struct alignas(16) clone3_thread_stack + { + static constexpr ::std::size_t stack_size_{1024 * 1024}; + + ::std::byte tail_[stack_size_]; + alignas(4)::std::atomic futex_word_{1}; + }; + + using thread_stack_type_allocator = + ::fast_io::typed_generic_allocator_adapter<::fast_io::generic_allocator_adapter<::fast_io::c_malloc_allocator>, clone3_thread_stack>; + + id id_{}; + clone3_thread_stack *stack_{}; + +private: + template + [[gnu::noreturn]] + inline static constexpr void child_entry(child_ctx *ctx) noexcept + { +#ifdef FAST_IO_CPP_EXCEPTIONS + try +#endif + { + apply(ctx->func, ctx->args); + } +#ifdef FAST_IO_CPP_EXCEPTIONS + catch (...) + { + ::fast_io::fast_terminate(); + } +#endif + // Kernel-dependent CLONE_CHILD_CLEARTID is cleared to 0 upon exit and wakes the futex + + // libc will auto destroy stack_ + + ::fast_io::fast_exit(0); + } + +public: + inline constexpr linux_clone3_thread() noexcept = default; + + template + requires std::invocable + inline constexpr linux_clone3_thread(Func &&func, Args &&...args) + { + // Assume the returned address is 16 aligned + this->stack_ = thread_stack_type_allocator::allocate(1u); + ::new (this->stack_) clone3_thread_stack{}; + + using decF = ::std::decay_t; + using decArgsTuple = ::fast_io::containers::tuple<::std::decay_t...>; + using ctx_t = child_ctx...>; + + // Pre-construct the context at the top of the child thread stack; the child thread derives the address by backtracking via RSP. + auto tail_base{reinterpret_cast<::std::uintptr_t>(__builtin_addressof(this->stack_->tail_))}; + auto top_of_stack{tail_base + clone3_thread_stack::stack_size_}; + constexpr ::std::size_t ctx_size{sizeof(ctx_t)}; + constexpr ::std::size_t ctx_align{alignof(ctx_t)}; + auto ctx_addr{(top_of_stack - ctx_size) & ~static_cast<::std::uintptr_t>(ctx_align - 1u)}; + auto ctx_ptr{reinterpret_cast(ctx_addr)}; + ::new (ctx_ptr) ctx_t{::std::forward(func), decArgsTuple{::std::forward(args)...}}; + + // TODO support TLS (currently avoid using any glibc wrappers requiring TLS) + clone_args clone3_arg{ + .flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID, + .pidfd = 0, + .child_tid = reinterpret_cast<::std::size_t>(__builtin_addressof(this->stack_->futex_word_)), + .parent_tid = 0, + .exit_signal = 0, + .stack = reinterpret_cast<::std::size_t>(__builtin_addressof(this->stack_->tail_)), + .stack_size = clone3_thread_stack::stack_size_, + .tls = 0, + .set_tid = 0, + .set_tid_size = 0, + .cgroup = 0, + }; + + // futex_word_ is initially set to 1 (running). The kernel clears it to 0 and wakes it up upon exit. + + auto clone3_result = ::fast_io::inline_syscall<__NR_clone3, ::pid_t>(__builtin_addressof(clone3_arg), sizeof(clone_args)); + if (clone3_result < 0) + { + ::std::destroy_at(this->stack_); + thread_stack_type_allocator::deallocate_n(this->stack_, 1u); + + ::fast_io::throw_posix_error(); + } + else if (clone3_result == 0) + { + // Child thread: Derive the ctx address solely from RSP to avoid accessing the parent stack and this. + constexpr ::std::size_t ctx_size_c{sizeof(ctx_t)}; + constexpr ::std::size_t ctx_align_c{alignof(ctx_t)}; + auto sp{reinterpret_cast<::std::uintptr_t>(::fast_io::details::get_stack_pointer())}; + auto ctx_addr_child{(sp - ctx_size_c) & ~static_cast<::std::uintptr_t>(ctx_align_c - 1u)}; + auto ctx_child{reinterpret_cast(ctx_addr_child)}; + // Reserve sufficient stack space to prevent subsequent calls from overwriting the context, and align to 16 bytes. + auto reserve{(sp - ctx_addr_child) + static_cast<::std::uintptr_t>(128u)}; + reserve = (reserve + 15u) & ~static_cast<::std::uintptr_t>(15u); + + linux_clone3_thread::child_entry...>(ctx_child); + + __builtin_unreachable(); + } + else + { + this->id_ = clone3_result; + } + } + + inline constexpr linux_clone3_thread(linux_clone3_thread &&other) noexcept = default; + + inline constexpr linux_clone3_thread(linux_clone3_thread const &) noexcept = delete; + + inline constexpr ~linux_clone3_thread() + { + if (this->joinable()) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + + thread_stack_type_allocator::deallocate_n(this->stack_, 1u); + } + + inline constexpr linux_clone3_thread &operator=(linux_clone3_thread const &) noexcept = delete; + + inline constexpr linux_clone3_thread &operator=(linux_clone3_thread &&other) & noexcept + { + this->swap(other); + return *this; + } + + inline constexpr void swap(linux_clone3_thread &other) noexcept + { + ::std::ranges::swap(this->id_, other.id_); + ::std::ranges::swap(this->stack_, other.stack_); + } + + inline constexpr bool joinable() const noexcept + { + return this->stack_->futex_word_.load() != 0; + } + + inline constexpr void join() + { + if (!this->joinable()) [[unlikely]] + { + ::fast_io::throw_posix_error(); + } + // Wait for futex_word_ to change from 1 to 0 (cleared by the kernel upon child thread exit and awakened) + for (;;) + { + int v = this->stack_->futex_word_.load(::std::memory_order_acquire); + if (v == 0) + { + break; + } + (void)::fast_io::system_call<__NR_futex, long>( + reinterpret_cast(__builtin_addressof(this->stack_->futex_word_)), + FUTEX_WAIT, + v, + nullptr, + nullptr, + 0); + } + } + + inline constexpr void detach() noexcept + { + this->id_ = 0; + } +}; + +} // namespace fast_io \ No newline at end of file diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index 41bc79ed3..d742c98cb 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -6,8 +6,6 @@ #include #include #include -#include "../../../fast_io_dsal/tuple.h" -#include "../../../fast_io_core_impl/allocation/common.h" namespace fast_io { @@ -94,7 +92,7 @@ class nt_thread requires(::std::invocable) inline constexpr nt_thread(Func &&func, Args &&...args) { - using start_routine_tuple_type = ::fast_io::tuple<::std::decay_t, ::std::decay_t...>; + using start_routine_tuple_type = ::fast_io::containers::tuple<::std::decay_t, ::std::decay_t...>; #if __has_cpp_attribute(indeterminate) ::fast_io::win32::nt::client_id cid [[indeterminate]]; #else diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 0439d39c5..09a8e2b21 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -6,8 +6,6 @@ #include #include #include -#include "../../../fast_io_dsal/tuple.h" -#include "../../../fast_io_core_impl/allocation/common.h" namespace fast_io { @@ -92,7 +90,7 @@ class win32_thread requires(::std::invocable) inline constexpr win32_thread(Func &&func, Args &&...args) { - using start_routine_tuple_type = ::fast_io::tuple<::std::decay_t, ::std::decay_t...>; + using start_routine_tuple_type = ::fast_io::containers::tuple<::std::decay_t, ::std::decay_t...>; void *start_routine_tuple{::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::allocate(sizeof(start_routine_tuple_type))}; #if defined(__clang__) #pragma clang diagnostic push From 8bc184e5e65a4630214a5a8b6ba6aac90957f492 Mon Sep 17 00:00:00 2001 From: MacroModel Date: Mon, 10 Nov 2025 22:53:10 +0800 Subject: [PATCH 43/43] Refactor threading implementation for POSIX and Windows - Updated the threading example to enable functionality across all platforms by removing conditional compilation for non-Windows systems. - Enhanced error handling in mutex locking by throwing specific POSIX errors. - Introduced a new `pthread.h` file to encapsulate POSIX thread management, improving organization and maintainability. - Refined memory management in thread-related classes to utilize a consistent allocator pattern. - Removed the obsolete `posix.h` file to streamline the threading interface. --- examples/0040.thread/thread.cc | 8 +- .../threads/mutex/posix_pthread_mutex.h | 5 +- include/fast_io_hosted/threads/thread/impl.h | 5 +- .../threads/thread/linux_clone3.h | 2 + include/fast_io_hosted/threads/thread/nt.h | 27 +- include/fast_io_hosted/threads/thread/posix.h | 1 - .../fast_io_hosted/threads/thread/pthread.h | 384 ++++++++++++++++++ include/fast_io_hosted/threads/thread/win32.h | 31 +- 8 files changed, 439 insertions(+), 24 deletions(-) delete mode 100644 include/fast_io_hosted/threads/thread/posix.h create mode 100644 include/fast_io_hosted/threads/thread/pthread.h diff --git a/examples/0040.thread/thread.cc b/examples/0040.thread/thread.cc index 3e6d4479b..466669027 100644 --- a/examples/0040.thread/thread.cc +++ b/examples/0040.thread/thread.cc @@ -3,7 +3,6 @@ int main() { -#ifdef _WIN32 // temporaryly disable this example on rest platforms auto t = ::fast_io::native_thread{[](int param) #if __cpp_static_call_operator >= 2020207L static @@ -16,6 +15,8 @@ int main() #else ::fast_io::println("the child thread id is: ", ::fast_io::mnp::pointervw(::fast_io::this_thread::get_id())); #endif +#else + ::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}); @@ -29,8 +30,9 @@ int main() #else ::fast_io::println("the parent thread id is: ", ::fast_io::mnp::pointervw(::fast_io::this_thread::get_id())); #endif +#else + ::fast_io::println("the parent thread id is: ", ::fast_io::this_thread::get_id()); #endif - return 0; -#endif + } diff --git a/include/fast_io_hosted/threads/mutex/posix_pthread_mutex.h b/include/fast_io_hosted/threads/mutex/posix_pthread_mutex.h index a760bd1f2..0f1628c69 100644 --- a/include/fast_io_hosted/threads/mutex/posix_pthread_mutex.h +++ b/include/fast_io_hosted/threads/mutex/posix_pthread_mutex.h @@ -16,9 +16,10 @@ struct posix_pthread_mutex inline posix_pthread_mutex &operator=(posix_pthread_mutex const &) = delete; inline void lock() { - if (noexcept_call(pthread_mutex_lock, __builtin_addressof(mutex))) [[unlikely]] + auto const res{::fast_io::noexcept_call(::pthread_mutex_lock, __builtin_addressof(mutex))}; + if (res != 0) [[unlikely]] { - throw_posix_error(); + ::fast_io::throw_posix_error(res); } } inline bool try_lock() noexcept diff --git a/include/fast_io_hosted/threads/thread/impl.h b/include/fast_io_hosted/threads/thread/impl.h index d1f35521f..1f6677ba7 100644 --- a/include/fast_io_hosted/threads/thread/impl.h +++ b/include/fast_io_hosted/threads/thread/impl.h @@ -5,6 +5,7 @@ #ifndef _WIN32_WINDOWS #include "nt.h" #endif -#elif defined(__linux__) -#include "linux_clone3.h" +#elif !defined(__SINGLE_THREAD__) && !defined(__NEWLIB__) && \ + !defined(__MSDOS__) && !defined(__wasi__) && __has_include() +#include "pthread.h" #endif diff --git a/include/fast_io_hosted/threads/thread/linux_clone3.h b/include/fast_io_hosted/threads/thread/linux_clone3.h index fc77fe9a8..073aa6f59 100644 --- a/include/fast_io_hosted/threads/thread/linux_clone3.h +++ b/include/fast_io_hosted/threads/thread/linux_clone3.h @@ -4,6 +4,8 @@ #error "This file is for linux only" #endif +#error "We do not recommend using clone3, as it omits the allocation of numerous TLS signals and other components." + #include #include #include diff --git a/include/fast_io_hosted/threads/thread/nt.h b/include/fast_io_hosted/threads/thread/nt.h index d742c98cb..0dbb77c04 100644 --- a/include/fast_io_hosted/threads/thread/nt.h +++ b/include/fast_io_hosted/threads/thread/nt.h @@ -28,14 +28,17 @@ class nt_thread_start_routine_tuple_allocate_guard {} inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; - inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default; + inline constexpr nt_thread_start_routine_tuple_allocate_guard(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = delete; + inline constexpr nt_thread_start_routine_tuple_allocate_guard &operator=(nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; + inline constexpr nt_thread_start_routine_tuple_allocate_guard &operator=(nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = delete; inline constexpr ~nt_thread_start_routine_tuple_allocate_guard() { if (ptr_ != nullptr) { ::std::destroy_at(reinterpret_cast(this->ptr_)); - ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(this->ptr_); + using alloc = ::fast_io::native_typed_global_allocator; + alloc::deallocate_n(reinterpret_cast(this->ptr_), 1u); } } }; @@ -54,7 +57,7 @@ inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(v try #endif { - ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); + ::std::invoke(::fast_io::containers::get(*reinterpret_cast(args))...); } #ifdef FAST_IO_CPP_EXCEPTIONS catch (...) @@ -93,12 +96,13 @@ class nt_thread inline constexpr nt_thread(Func &&func, Args &&...args) { using start_routine_tuple_type = ::fast_io::containers::tuple<::std::decay_t, ::std::decay_t...>; + using alloc = ::fast_io::native_typed_global_allocator; #if __has_cpp_attribute(indeterminate) ::fast_io::win32::nt::client_id cid [[indeterminate]]; #else ::fast_io::win32::nt::client_id cid; #endif - void *start_routine_tuple{::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::allocate(sizeof(start_routine_tuple_type))}; + auto start_routine_tuple{alloc::allocate(1u)}; #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-braces" @@ -125,7 +129,7 @@ class nt_thread { // Creation failed; manual release is required. ::std::destroy_at(reinterpret_cast(start_routine_tuple)); - ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate(start_routine_tuple); + alloc::deallocate_n(start_routine_tuple, 1u); ::fast_io::throw_nt_error(status); } @@ -135,7 +139,11 @@ class nt_thread inline constexpr nt_thread(nt_thread const &) noexcept = delete; - inline constexpr nt_thread(nt_thread &&other) noexcept = default; + inline constexpr nt_thread(nt_thread &&other) noexcept : id_{other.id_}, handle_{other.handle_} + { + other.id_ = 0; + other.handle_ = nullptr; + } inline constexpr ~nt_thread() noexcept { @@ -332,7 +340,9 @@ inline ::fast_io::throw_nt_error(0xC000000D); } - auto const win_100ns_seconds{static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 10'000'000u + sleep_duration.subseconds / 100u)}; + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000000u}; + + auto const win_100ns_seconds{static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 10'000'000u + sleep_duration.subseconds / mul_factor / 100u)}; if (win_100ns_seconds > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) [[unlikely]] { @@ -401,7 +411,8 @@ inline auto const win32_ts{static_cast<::fast_io::win32_timestamp>(expect_time)}; - auto const win_100ns_seconds = static_cast<::std::uint_least64_t>(win32_ts.seconds) * 10'000'000u + win32_ts.subseconds / 100u; + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000000u}; + auto const win_100ns_seconds = static_cast<::std::uint_least64_t>(win32_ts.seconds) * 10'000'000u + win32_ts.subseconds / mul_factor / 100u; if (win_100ns_seconds > static_cast<::std::uint_least64_t>(::std::numeric_limits<::std::int_least64_t>::max())) [[unlikely]] { diff --git a/include/fast_io_hosted/threads/thread/posix.h b/include/fast_io_hosted/threads/thread/posix.h deleted file mode 100644 index 73b4b8665..000000000 --- a/include/fast_io_hosted/threads/thread/posix.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/include/fast_io_hosted/threads/thread/pthread.h b/include/fast_io_hosted/threads/thread/pthread.h new file mode 100644 index 000000000..20104ce8f --- /dev/null +++ b/include/fast_io_hosted/threads/thread/pthread.h @@ -0,0 +1,384 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fast_io +{ + +namespace posix +{ + +namespace details +{ + +template +class pthread_thread_start_routine_tuple_allocate_guard +{ +public: + void *ptr_{nullptr}; + + inline constexpr pthread_thread_start_routine_tuple_allocate_guard() = default; + + inline constexpr pthread_thread_start_routine_tuple_allocate_guard(void *ptr) : ptr_{ptr} + {} + + inline constexpr pthread_thread_start_routine_tuple_allocate_guard(pthread_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; + inline constexpr pthread_thread_start_routine_tuple_allocate_guard(pthread_thread_start_routine_tuple_allocate_guard &&other) noexcept = delete; + inline constexpr pthread_thread_start_routine_tuple_allocate_guard& operator=(pthread_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; + inline constexpr pthread_thread_start_routine_tuple_allocate_guard& operator=(pthread_thread_start_routine_tuple_allocate_guard &&other) noexcept = delete; + + inline constexpr ~pthread_thread_start_routine_tuple_allocate_guard() + { + if (ptr_ != nullptr) + { + ::std::destroy_at(reinterpret_cast(this->ptr_)); + + using alloc = ::fast_io::native_typed_global_allocator; + alloc::deallocate_n(reinterpret_cast(this->ptr_), 1u); + } + } +}; + +template +inline constexpr void *thread_start_routine(void *args) noexcept +{ + /* + * Just call the API function then destroy/deallocate tuple. + */ + + [[maybe_unused]] ::fast_io::posix::details::pthread_thread_start_routine_tuple_allocate_guard _(args); + +#ifdef FAST_IO_CPP_EXCEPTIONS + try +#endif + { + ::std::invoke(::fast_io::containers::get(*reinterpret_cast(args))...); + } +#ifdef FAST_IO_CPP_EXCEPTIONS + catch (...) + { + ::fast_io::fast_terminate(); + } +#endif + + return nullptr; +} + +template +inline constexpr auto get_thread_start_routine(::std::index_sequence) noexcept +{ + return ::fast_io::posix::details::thread_start_routine; +} + +} // namespace details + +class pthread_thread +{ +public: + using id = ::pthread_t; + using native_handle_type = ::pthread_t; + +private: + id id_{}; + bool joinable_{false}; + +private: + + +public: + inline constexpr pthread_thread() noexcept = default; + + template + requires(::std::invocable) + inline constexpr pthread_thread(Func &&func, Args &&...args) + { + using start_routine_tuple_type = ::fast_io::containers::tuple<::std::decay_t, ::std::decay_t...>; + using alloc = ::fast_io::native_typed_global_allocator; + + auto start_routine_tuple{alloc::allocate(1u)}; +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-braces" +#endif + ::new (start_routine_tuple) start_routine_tuple_type{::std::forward(func), ::std::forward(args)...}; +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + auto start_routine = ::fast_io::posix::details::get_thread_start_routine( + ::std::make_index_sequence{}); + int ec{::fast_io::noexcept_call(::pthread_create, __builtin_addressof(this->id_), nullptr, start_routine, start_routine_tuple)}; + if (ec != 0) [[unlikely]] + { + // Creation failed; manual release is required. + ::std::destroy_at(reinterpret_cast(start_routine_tuple)); + alloc::deallocate_n(start_routine_tuple, 1u); + + ::fast_io::throw_posix_error(ec); + } + this->joinable_ = true; + } + + inline constexpr pthread_thread(pthread_thread const &) noexcept = delete; + + inline constexpr pthread_thread(pthread_thread &&other) noexcept : id_{other.id_}, joinable_{other.joinable_} + { + other.id_ = 0; + other.joinable_ = false; + } + + inline constexpr ~pthread_thread() noexcept + { + if (this->joinable()) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + } + + inline constexpr pthread_thread &operator=(pthread_thread const &) noexcept = delete; + + inline constexpr pthread_thread &operator=(pthread_thread &&other) noexcept + { + if (this == __builtin_addressof(other)) [[unlikely]] + { + return *this; + } + this->swap(other); + return *this; + } + + inline constexpr bool joinable() const noexcept + { + return this->joinable_; + } + + inline constexpr void join() + { + if (!this->joinable()) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + int ec{::fast_io::noexcept_call(::pthread_join, this->id_, nullptr)}; + if (ec != 0) [[unlikely]] + { + ::fast_io::throw_posix_error(ec); + } + this->joinable_ = false; + } + + inline constexpr void detach() + { + if (!this->joinable()) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + int ec{::fast_io::noexcept_call(::pthread_detach, this->id_)}; + if (ec != 0) [[unlikely]] + { + ::fast_io::throw_posix_error(ec); + } + this->joinable_ = false; + } + + inline constexpr void swap(pthread_thread &other) noexcept + { + ::std::ranges::swap(this->id_, other.id_); + ::std::ranges::swap(this->joinable_, other.joinable_); + } + + [[nodiscard]] + inline constexpr auto get_id() const noexcept + { + return this->id_; + } + + [[nodiscard]] + inline constexpr auto native_handle() const noexcept + { + return this->id_; + } + + [[nodiscard]] + inline static constexpr ::std::uint_least32_t hardware_concurrency() noexcept + { +#ifdef _SC_NPROCESSORS_ONLN + long v = ::fast_io::noexcept_call(::sysconf, _SC_NPROCESSORS_ONLN); + if (v <= 0) + { + return 1u; + } + return static_cast<::std::uint_least32_t>(v); +#else + return 0u; +#endif + } +}; + +namespace this_thread +{ + +[[nodiscard]] +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 +::fast_io::posix::pthread_thread::id get_id() noexcept +{ + 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 + // 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; + } + + ::timespec req{}; + req.tv_sec = static_cast<::time_t>(sleep_duration.seconds); + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000000u}; + req.tv_nsec = static_cast(sleep_duration.subseconds / mul_factor); + + if (req.tv_sec == 0 && req.tv_nsec <= 0) + { + return; + } + + ::fast_io::noexcept_call(::nanosleep, __builtin_addressof(req), nullptr); +} + +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; + } + + ::timespec ts{}; + + auto const unix_ts{static_cast<::fast_io::unix_timestamp>(expect_time)}; + ts.tv_sec = static_cast<::time_t>(unix_ts.seconds); + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000000u}; + ts.tv_nsec = static_cast(unix_ts.subseconds / mul_factor); + +#if defined(CLOCK_REALTIME) && defined(TIMER_ABSTIME) + ::fast_io::noexcept_call(::clock_nanosleep, CLOCK_REALTIME, TIMER_ABSTIME, __builtin_addressof(ts), nullptr); +#else + ::timespec now{}; + ::fast_io::noexcept_call(::clock_gettime, CLOCK_REALTIME, __builtin_addressof(now)); + + if ((ts.tv_sec < now.tv_sec) || (ts.tv_sec == now.tv_sec && ts.tv_nsec <= now.tv_nsec)) + { + return; + } + ::timespec delta{}; + delta.tv_sec = ts.tv_sec - now.tv_sec; + delta.tv_nsec = ts.tv_nsec - now.tv_nsec; + if (delta.tv_nsec < 0) + { + delta.tv_nsec += 1'000'000'000L; + delta.tv_sec -= 1; + } + + ::fast_io::noexcept_call(::nanosleep, __builtin_addressof(delta), nullptr); +#endif +} + +} // namespace this_thread + +} // namespace posix + +using pthread_thread = posix::pthread_thread; + +#if !((defined(_WIN32) && !defined(__WINE__)) && !defined(__CYGWIN__)) && \ + !defined(__SINGLE_THREAD__) && !defined(__MSDOS__) && !defined(__wasi__) && __has_include() +using native_thread = pthread_thread; +namespace this_thread +{ +using ::fast_io::posix::this_thread::get_id; +using ::fast_io::posix::this_thread::sleep_for; +using ::fast_io::posix::this_thread::sleep_until; +} // namespace this_thread +#endif + +} // namespace fast_io \ No newline at end of file diff --git a/include/fast_io_hosted/threads/thread/win32.h b/include/fast_io_hosted/threads/thread/win32.h index 09a8e2b21..add5e8606 100644 --- a/include/fast_io_hosted/threads/thread/win32.h +++ b/include/fast_io_hosted/threads/thread/win32.h @@ -27,14 +27,18 @@ class win32_thread_start_routine_tuple_allocate_guard {} inline constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; - inline constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard &&other) noexcept = default; + inline constexpr win32_thread_start_routine_tuple_allocate_guard(win32_thread_start_routine_tuple_allocate_guard &&other) noexcept = delete; + inline constexpr win32_thread_start_routine_tuple_allocate_guard &operator=(win32_thread_start_routine_tuple_allocate_guard const &) noexcept = delete; + inline constexpr win32_thread_start_routine_tuple_allocate_guard &operator=(win32_thread_start_routine_tuple_allocate_guard &&other) noexcept = delete; inline constexpr ~win32_thread_start_routine_tuple_allocate_guard() { if (ptr_ != nullptr) { ::std::destroy_at(reinterpret_cast(this->ptr_)); - ::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::deallocate(this->ptr_); + + using alloc = ::fast_io::native_typed_global_allocator; + alloc::deallocate_n(reinterpret_cast(this->ptr_), 1u); } } }; @@ -53,7 +57,7 @@ inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine(v try #endif { - ::std::invoke(::fast_io::get(*reinterpret_cast(args))...); + ::std::invoke(::fast_io::containers::get(*reinterpret_cast(args))...); } #ifdef FAST_IO_CPP_EXCEPTIONS catch (...) @@ -91,7 +95,9 @@ class win32_thread inline constexpr win32_thread(Func &&func, Args &&...args) { using start_routine_tuple_type = ::fast_io::containers::tuple<::std::decay_t, ::std::decay_t...>; - void *start_routine_tuple{::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::allocate(sizeof(start_routine_tuple_type))}; + using alloc = ::fast_io::native_typed_global_allocator; + + auto start_routine_tuple{alloc::allocate(1u)}; #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-braces" @@ -113,7 +119,7 @@ class win32_thread { // Creation failed; manual release is required ::std::destroy_at(reinterpret_cast(start_routine_tuple)); - ::fast_io::generic_allocator_adapter<::fast_io::win32_heapalloc_allocator>::deallocate(start_routine_tuple); + alloc::deallocate_n(start_routine_tuple, 1u); ::fast_io::throw_win32_error(); } @@ -121,7 +127,11 @@ class win32_thread inline constexpr win32_thread(win32_thread const &) noexcept = delete; - inline constexpr win32_thread(win32_thread &&other) noexcept = default; + inline constexpr win32_thread(win32_thread &&other) noexcept : id_{other.id_}, handle_{other.handle_} + { + other.id_ = 0; + other.handle_ = nullptr; + } inline constexpr ~win32_thread() noexcept { @@ -312,9 +322,11 @@ inline return; } + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000000u}; + auto const win_100ns{ static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(sleep_duration.seconds) * 10'000'000ULL + - sleep_duration.subseconds / 100u)}; + sleep_duration.subseconds / mul_factor / 100u)}; auto const ms64{win_100ns / 10'000ULL}; auto const ms{ms64 > 0xFFFFFFFFu ? static_cast<::std::uint_least32_t>(0xFFFFFFFFu) @@ -348,9 +360,12 @@ inline { return; } + + constexpr ::std::uint_least64_t mul_factor{::fast_io::uint_least64_subseconds_per_second / 1000000000u}; + auto const expect_100ns{ static_cast<::std::uint_least64_t>(static_cast<::std::uint_least64_t>(win32_ts.seconds) * 10'000'000ULL + - win32_ts.subseconds / 100u)}; + win32_ts.subseconds / mul_factor / 100u)}; if (expect_100ns <= now_100ns) {