diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp | 685 |
1 files changed, 601 insertions, 84 deletions
diff --git a/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp b/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp index 07355e83eae..c56a512e462 100644 --- a/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp +++ b/3rdparty/asio/include/asio/detail/impl/descriptor_ops.ipp @@ -2,7 +2,7 @@ // detail/impl/descriptor_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -32,10 +32,16 @@ namespace descriptor_ops { int open(const char* path, int flags, asio::error_code& ec) { - errno = 0; - int result = error_wrapper(::open(path, flags), ec); - if (result >= 0) - ec = asio::error_code(); + int result = ::open(path, flags); + get_last_error(ec, result < 0); + return result; +} + +int open(const char* path, int flags, + unsigned mode, asio::error_code& ec) +{ + int result = ::open(path, flags, mode); + get_last_error(ec, result < 0); return result; } @@ -44,8 +50,8 @@ int close(int d, state_type& state, asio::error_code& ec) int result = 0; if (d != -1) { - errno = 0; - result = error_wrapper(::close(d), ec); + result = ::close(d); + get_last_error(ec, result < 0); if (result != 0 && (ec == asio::error::would_block @@ -57,23 +63,39 @@ int close(int d, state_type& state, asio::error_code& ec) // current OS where this behaviour is seen, Windows, says that the socket // remains open. Therefore we'll put the descriptor back into blocking // mode and have another attempt at closing it. -#if defined(__SYMBIAN32__) +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int flags = ::fcntl(d, F_GETFL, 0); if (flags >= 0) ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); -#else // defined(__SYMBIAN32__) +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = 0; +# if defined(ENOTTY) || defined(ENOTCAPABLE) + result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); + } +# else // defined(ENOTTY) || defined(ENOTCAPABLE) ::ioctl(d, FIONBIO, &arg); -#endif // defined(__SYMBIAN32__) +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) state &= ~non_blocking; - errno = 0; - result = error_wrapper(::close(d), ec); + result = ::close(d); + get_last_error(ec, result < 0); } } - if (result == 0) - ec = asio::error_code(); return result; } @@ -86,23 +108,43 @@ bool set_user_non_blocking(int d, state_type& state, return false; } - errno = 0; -#if defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - errno = 0; int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); } -#else // defined(__SYMBIAN32__) +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); -#endif // defined(__SYMBIAN32__) + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); +# if defined(ENOTTY) || defined(ENOTCAPABLE) + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); + } + } +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = asio::error_code(); if (value) state |= user_set_non_blocking; else @@ -136,23 +178,43 @@ bool set_internal_non_blocking(int d, state_type& state, return false; } - errno = 0; -#if defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); +#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - errno = 0; int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); } -#else // defined(__SYMBIAN32__) +#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); -#endif // defined(__SYMBIAN32__) + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); +# if defined(ENOTTY) || defined(ENOTCAPABLE) + if (false +# if defined(ENOTTY) + || ec.value() == ENOTTY +# endif // defined(ENOTTY) +# if defined(ENOTCAPABLE) + || ec.value() == ENOTCAPABLE +# endif // defined(ENOTCAPABLE) + ) + { + result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); + if (result >= 0) + { + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); + } + } +# endif // defined(ENOTTY) || defined(ENOTCAPABLE) +#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = asio::error_code(); if (value) state |= internal_non_blocking; else @@ -175,7 +237,53 @@ std::size_t sync_read(int d, state_type state, buf* bufs, // A request to read 0 bytes on a stream is a no-op. if (all_empty) { - ec = asio::error_code(); + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); return 0; } @@ -183,9 +291,8 @@ std::size_t sync_read(int d, state_type state, buf* bufs, for (;;) { // Try to complete the operation without blocking. - errno = 0; - signed_size_type bytes = error_wrapper(::readv( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes > 0) @@ -216,9 +323,8 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, for (;;) { // Read some data. - errno = 0; - signed_size_type bytes = error_wrapper(::readv( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); // Check for end of stream. if (bytes == 0) @@ -227,6 +333,13 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, return true; } + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -236,15 +349,46 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_read1(int d, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); + + // Check for end of stream. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. if (bytes > 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -261,7 +405,46 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, // A request to write 0 bytes on a stream is a no-op. if (all_empty) { - ec = asio::error_code(); + asio::error::clear(ec); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_write1(int d, state_type state, const void* data, + std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); return 0; } @@ -269,9 +452,8 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, for (;;) { // Try to complete the operation without blocking. - errno = 0; - signed_size_type bytes = error_wrapper(::writev( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes > 0) @@ -295,9 +477,15 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, for (;;) { // Write some data. - errno = 0; - signed_size_type bytes = error_wrapper(::writev( - d, bufs, static_cast<int>(count)), ec); + signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count)); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) @@ -308,19 +496,360 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_write1(int d, const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } +#if defined(ASIO_HAS_FILE) + +std::size_t sync_read_at(int d, state_type state, uint64_t offset, + buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::preadv(d, bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_read_at1(int d, state_type state, uint64_t offset, + void* data, std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::pread(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_read_at(int d, uint64_t offset, buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::preadv(d, bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_read_at1(int d, uint64_t offset, void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::pread(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check for EOF. + if (bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +std::size_t sync_write_at(int d, state_type state, uint64_t offset, + const buf* bufs, std::size_t count, bool all_empty, + asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + asio::error::clear(ec); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::pwritev(d, + bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +std::size_t sync_write_at1(int d, state_type state, uint64_t offset, + const void* data, std::size_t size, asio::error_code& ec) +{ + if (d == -1) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (size == 0) + { + asio::error::clear(ec); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::pwrite(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_write_at(int d, uint64_t offset, + const buf* bufs, std::size_t count, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::pwritev(d, + bufs, static_cast<int>(count), offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_write_at1(int d, uint64_t offset, + const void* data, std::size_t size, + asio::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::pwrite(d, data, size, offset); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +#endif // defined(ASIO_HAS_FILE) + int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, asio::error_code& ec) { @@ -330,13 +859,11 @@ int ioctl(int d, state_type& state, long cmd, return -1; } - errno = 0; - int result = error_wrapper(::ioctl(d, cmd, arg), ec); + int result = ::ioctl(d, cmd, arg); + get_last_error(ec, result < 0); if (result >= 0) { - ec = asio::error_code(); - // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the descriptor is // already in the correct state. This ensures that the underlying @@ -370,10 +897,8 @@ int fcntl(int d, int cmd, asio::error_code& ec) return -1; } - errno = 0; - int result = error_wrapper(::fcntl(d, cmd), ec); - if (result != -1) - ec = asio::error_code(); + int result = ::fcntl(d, cmd); + get_last_error(ec, result < 0); return result; } @@ -385,10 +910,8 @@ int fcntl(int d, int cmd, long arg, asio::error_code& ec) return -1; } - errno = 0; - int result = error_wrapper(::fcntl(d, cmd, arg), ec); - if (result != -1) - ec = asio::error_code(); + int result = ::fcntl(d, cmd, arg); + get_last_error(ec, result < 0); return result; } @@ -405,13 +928,11 @@ int poll_read(int d, state_type state, asio::error_code& ec) fds.events = POLLIN; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -428,13 +949,11 @@ int poll_write(int d, state_type state, asio::error_code& ec) fds.events = POLLOUT; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -451,13 +970,11 @@ int poll_error(int d, state_type state, asio::error_code& ec) fds.events = POLLPRI | POLLERR | POLLHUP; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } |