Skip to content
Merged

Next #1226

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 47 additions & 25 deletions include/fast_io_hosted/platforms/systemcall_details.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

namespace fast_io::details
{

#ifdef __MSDOS__
namespace posix
{
#if defined(__MSDOS__) || defined(__DJGPP__)
extern int dup(int) noexcept __asm__("_dup");
extern int dup2(int, int) noexcept __asm__("_dup2");
extern int _close(int) noexcept __asm__("_close");
extern int close(int) noexcept __asm__("_close");
#elif defined(__wasi__)
inline int dup(int) noexcept
{
Expand All @@ -19,22 +20,29 @@ inline int dup2(int old_fd, int new_fd) noexcept
return ::fast_io::noexcept_call(__wasi_fd_renumber, old_fd, new_fd);
}
#endif
} // namespace posix

inline int sys_dup(int old_fd)
{
#if defined(__linux__) && defined(__NR_dup)
int fd{system_call<__NR_dup, int>(old_fd)};
system_call_throw_error(fd);
int fd{::fast_io::system_call<__NR_dup, int>(old_fd)};
::fast_io::system_call_throw_error(fd);
return fd;
#else
auto fd{noexcept_call(

#if (defined(__MSDOS__) || defined(__DJGPP__)) || defined(__wasi__)
auto fd{::fast_io::details::posix::dup(old_fd)};
#else
auto fd{::fast_io::noexcept_call(
#if defined(_WIN32) && !defined(__BIONIC__)
::_dup
#else
::dup
#endif
,
old_fd)};
#endif

if (fd == -1)
{
throw_posix_error();
Expand All @@ -47,18 +55,24 @@ template <bool always_terminate = false>
inline int sys_dup2(int old_fd, int new_fd)
{
#if defined(__linux__) && defined(__NR_dup2)
int fd{system_call<__NR_dup2, int>(old_fd, new_fd)};
system_call_throw_error<always_terminate>(fd);
int fd{::fast_io::system_call<__NR_dup2, int>(old_fd, new_fd)};
::fast_io::system_call_throw_error<always_terminate>(fd);
return fd;
#else
auto fd{noexcept_call(

#if (defined(__MSDOS__) || defined(__DJGPP__)) || defined(__wasi__)
auto fd{::fast_io::details::posix::dup2(old_fd, new_fd)};
#else
auto fd{::fast_io::noexcept_call(
#if defined(_WIN32) && !defined(__BIONIC__)
_dup2
::_dup2
#else
dup2
::dup2
#endif
,
old_fd, new_fd)};
#endif

if (fd == -1)
{
if constexpr (always_terminate)
Expand All @@ -83,20 +97,26 @@ struct return_code
inline return_code sys_dup2_nothrow(int old_fd, int new_fd) noexcept
{
#if defined(__linux__) && defined(__NR_dup2)
int fd{system_call<__NR_dup2, int>(old_fd, new_fd)};
if (linux_system_call_fails(fd))
int fd{::fast_io::system_call<__NR_dup2, int>(old_fd, new_fd)};
if (::fast_io::linux_system_call_fails(fd))
{
return {-fd, true};
}
#else
auto fd{noexcept_call(

#if (defined(__MSDOS__) || defined(__DJGPP__)) || defined(__wasi__)
auto fd{::fast_io::details::posix::dup2(old_fd, new_fd)};
#else
auto fd{::fast_io::noexcept_call(
#if defined(_WIN32) && !defined(__BIONIC__)
_dup2
::_dup2
#else
dup2
#endif
,
old_fd, new_fd)};
#endif

if (fd == -1)
{
return {errno, true};
Expand All @@ -109,24 +129,26 @@ inline int sys_close(int fd) noexcept
{
return
#if defined(__linux__) && defined(__NR_close)
system_call<__NR_close, int>(fd);
#elif (defined(_WIN32) && !defined(__BIONIC__)) || defined(__MSDOS__)
noexcept_call(_close, fd);
::fast_io::system_call<__NR_close, int>(fd);
#elif (defined(_WIN32) && !defined(__BIONIC__))
::fast_io::noexcept_call(::_close, fd);
#elif defined(__MSDOS__) || defined(__DJGPP__)
::fast_io::details::posix::close(fd);
#else
noexcept_call(close, fd);
::fast_io::noexcept_call(::close, fd);
#endif
}

inline void sys_close_throw_error(int &fd)
{
auto ret{sys_close(fd)};
auto ret{::fast_io::details::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);
::fast_io::system_call_throw_error(ret);
#else
if (ret == -1) [[unlikely]]
{
throw_posix_error();
::fast_io::throw_posix_error();
}
#endif
}
Expand All @@ -148,14 +170,14 @@ template <typename... Args>
inline int sys_fcntl(int fd, int op, Args... args)
{
#if defined(__linux__) && defined(__NR_fcntl)
auto result{system_call<__NR_fcntl, int>(fd, op, args...)};
system_call_throw_error(result);
auto result{::fast_io::system_call<__NR_fcntl, int>(fd, op, args...)};
::fast_io::system_call_throw_error(result);
return result;
#else
auto result{posix::fcntl(fd, op, args...)};
if (result == -1)
{
throw_posix_error();
::fast_io::throw_posix_error();
}
return result;
#endif
Expand Down
2 changes: 1 addition & 1 deletion include/fast_io_hosted/platforms/win32/msvc_linker_32.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion include/fast_io_hosted/platforms/win32/msvc_linker_64.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
113 changes: 78 additions & 35 deletions include/fast_io_hosted/process/process/arg_env.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,51 +23,94 @@ inline constexpr void append_win32_quoted_arg_common(
::fast_io::containers::basic_string<replace_char_type, ::fast_io::native_global_allocator> &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<u8'\"', replace_char_type>);

::std::size_t backslash_count{};
for (; first != last; ++first)
if (is_first)
{
auto const c{*first};
if (c == ::fast_io::char_literal_v<u8'\"', replace_char_type>)
bool needs_quote{};
auto it{first};
for (; it != last; ++it)
{
if (is_first) [[unlikely]]
auto const c{*it};
if (c == ::fast_io::char_literal_v<u8'\"', replace_char_type>) [[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)
if (c <= ::fast_io::char_literal_v<u8' ', replace_char_type>)
{
str.push_back_unchecked(::fast_io::char_literal_v<u8'\\', replace_char_type>);
needs_quote = true;
}
str.push_back_unchecked(::fast_io::char_literal_v<u8'\"', replace_char_type>);
backslash_count = 0;
}
else if (c == ::fast_io::char_literal_v<u8'\\', replace_char_type>)

if (first == last)
{
++backslash_count;
str.push_back(::fast_io::char_literal_v<u8'\"', replace_char_type>);
str.push_back(::fast_io::char_literal_v<u8'\"', replace_char_type>);
str.push_back(::fast_io::char_literal_v<u8' ', replace_char_type>);
return;
}
else

if (!needs_quote)
{
// Flush pending backslashes (not before a quote): output as-is
for (::std::size_t i{}; i != backslash_count; ++i)
auto const sz{static_cast<::std::size_t>(last - first)};
for (it = first; it != last; ++it)
{
str.push_back_unchecked(::fast_io::char_literal_v<u8'\\', replace_char_type>);
str.push_back(*it);
}
backslash_count = 0;
str.push_back_unchecked(c);
str.push_back(::fast_io::char_literal_v<u8' ', replace_char_type>);
return;
}

auto const sz{static_cast<::std::size_t>(last - first)};
str.push_back(::fast_io::char_literal_v<u8'\"', replace_char_type>);
for (it = first; it != last; ++it)
{
str.push_back(*it);
}
str.push_back(::fast_io::char_literal_v<u8'\"', replace_char_type>);
str.push_back(::fast_io::char_literal_v<u8' ', replace_char_type>);
}
// Before closing quote, double any trailing backslashes
for (::std::size_t i{}; i != (backslash_count << 1u); ++i)
else
{
str.push_back_unchecked(::fast_io::char_literal_v<u8'\\', replace_char_type>);
// 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<u8'\"', replace_char_type>);

::std::size_t backslash_count{};
for (; first != last; ++first)
{
auto const c{*first};
if (c == ::fast_io::char_literal_v<u8'\"', replace_char_type>)
{
// 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<u8'\\', replace_char_type>);
}
str.push_back_unchecked(::fast_io::char_literal_v<u8'\"', replace_char_type>);
backslash_count = 0;
}
else if (c == ::fast_io::char_literal_v<u8'\\', replace_char_type>)
{
++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<u8'\\', replace_char_type>);
}
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<u8'\\', replace_char_type>);
}
str.push_back_unchecked(::fast_io::char_literal_v<u8'\"', replace_char_type>);
str.push_back_unchecked(::fast_io::char_literal_v<u8' ', replace_char_type>);
}
str.push_back_unchecked(::fast_io::char_literal_v<u8'\"', replace_char_type>);
str.push_back_unchecked(::fast_io::char_literal_v<u8' ', replace_char_type>);
}

template <::std::integral replace_char_type, typename T>
Expand Down Expand Up @@ -423,16 +466,16 @@ inline constexpr void construct_posix_process_argenvs_decay(
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");
// 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");
// 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;
// Reference to the global `environ` variable
extern "C" char **environ;
#endif
} // namespace details
} // namespace posix
} // namespace details

struct posix_process_args FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
Expand Down
6 changes: 3 additions & 3 deletions include/fast_io_hosted/process/process/posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ inline void portable_fd_path([[maybe_unused]] int fd, char *buf, ::std::size_t b
::fast_io::obuffer_view linkpath_ov{linkpath, linkpath + all_sz};
::fast_io::operations::print_freestanding<false>(linkpath_ov, path_str, fd, ::fast_io::mnp::chvw(::fast_io::char_literal_v<u8'\0', char>));

using my_ssize_t [[maybe_unused]] = ::std::make_signed_t<::std::size_t>;
using my_ssize_t [[maybe_unused]] = ::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)};
Expand Down Expand Up @@ -716,7 +716,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, sig_atomic_t 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, unsigned volatile &t_errno, process_mode mode) noexcept
{
// vfork can only be called through libc wrapper
pid = ::fast_io::posix::libc_vfork();
Expand Down Expand Up @@ -810,7 +810,7 @@ inline void vfork_and_execveat(pid_t &pid, int dirfd, char const *cstr, char con
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{};
sig_atomic_t volatile t_errno{}; // receive error from vfork subproc
unsigned volatile t_errno{}; // receive error from vfork subproc
{
fd_remapper fm;
fm.map(0, pio.in);
Expand Down
Loading