update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -2,7 +2,7 @@
// detail/impl/buffer_sequence_adapter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/descriptor_ops.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -33,10 +33,16 @@ namespace descriptor_ops {
int open(const char* path, int flags, boost::system::error_code& ec)
{
errno = 0;
int result = error_wrapper(::open(path, flags), ec);
if (result >= 0)
ec = boost::system::error_code();
int result = ::open(path, flags);
get_last_error(ec, result < 0);
return result;
}
int open(const char* path, int flags,
unsigned mode, boost::system::error_code& ec)
{
int result = ::open(path, flags, mode);
get_last_error(ec, result < 0);
return result;
}
@@ -45,8 +51,8 @@ int close(int d, state_type& state, boost::system::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 == boost::asio::error::would_block
@@ -58,23 +64,32 @@ int close(int d, state_type& state, boost::system::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)
result = ::ioctl(d, FIONBIO, &arg);
get_last_error(ec, result < 0);
if (ec.value() == ENOTTY)
{
int flags = ::fcntl(d, F_GETFL, 0);
if (flags >= 0)
::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
}
# else // defined(ENOTTY)
::ioctl(d, FIONBIO, &arg);
#endif // defined(__SYMBIAN32__)
# endif // defined(ENOTTY)
#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 = boost::system::error_code();
return result;
}
@@ -87,23 +102,36 @@ 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)
if (ec.value() == ENOTTY)
{
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)
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
if (result >= 0)
{
ec = boost::system::error_code();
if (value)
state |= user_set_non_blocking;
else
@@ -137,23 +165,36 @@ 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)
if (ec.value() == ENOTTY)
{
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)
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
if (result >= 0)
{
ec = boost::system::error_code();
if (value)
state |= internal_non_blocking;
else
@@ -176,7 +217,7 @@ 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 = boost::system::error_code();
boost::asio::error::clear(ec);
return 0;
}
@@ -184,9 +225,54 @@ 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 = ::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 = boost::asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::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, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::asio::error::clear(ec);
return 0;
}
// Read some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::read(d, data, size);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
@@ -217,9 +303,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)
@@ -228,6 +313,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 == boost::asio::error::interrupted)
continue;
@@ -237,15 +329,46 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
|| ec == boost::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,
boost::system::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 = boost::asio::error::eof;
return true;
}
// Check if operation succeeded.
if (bytes > 0)
{
ec = boost::system::error_code();
bytes_transferred = bytes;
return true;
}
else
bytes_transferred = 0;
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
@@ -262,7 +385,7 @@ 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 = boost::system::error_code();
boost::asio::error::clear(ec);
return 0;
}
@@ -270,9 +393,47 @@ 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 = ::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 != boost::asio::error::would_block
&& ec != boost::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, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::asio::error::clear(ec);
return 0;
}
// Write some data.
for (;;)
{
// Try to complete the operation without blocking.
signed_size_type bytes = ::write(d, data, size);
get_last_error(ec, bytes < 0);
// Check if operation succeeded.
if (bytes > 0)
@@ -296,9 +457,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 == boost::asio::error::interrupted)
@@ -309,19 +476,360 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count,
|| ec == boost::asio::error::try_again)
return false;
// Operation is complete.
if (bytes >= 0)
{
ec = boost::system::error_code();
bytes_transferred = bytes;
}
else
bytes_transferred = 0;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
bool non_blocking_write1(int d, const void* data, std::size_t size,
boost::system::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)
{
bytes_transferred = bytes;
return true;
}
// Retry operation if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
#if defined(BOOST_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, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (all_empty)
{
boost::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 = boost::asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::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, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to read 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::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 = boost::asio::error::eof;
return 0;
}
// Operation failed.
if ((state & user_set_non_blocking)
|| (ec != boost::asio::error::would_block
&& ec != boost::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,
boost::system::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 = boost::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 == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::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,
boost::system::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 = boost::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 == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::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,
boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (all_empty)
{
boost::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 != boost::asio::error::would_block
&& ec != boost::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, boost::system::error_code& ec)
{
if (d == -1)
{
ec = boost::asio::error::bad_descriptor;
return 0;
}
// A request to write 0 bytes on a stream is a no-op.
if (size == 0)
{
boost::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 != boost::asio::error::would_block
&& ec != boost::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,
boost::system::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 == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::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,
boost::system::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 == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return false;
// Operation failed.
bytes_transferred = 0;
return true;
}
}
#endif // defined(BOOST_ASIO_HAS_FILE)
int ioctl(int d, state_type& state, long cmd,
ioctl_arg_type* arg, boost::system::error_code& ec)
{
@@ -331,13 +839,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 = boost::system::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
@@ -371,10 +877,8 @@ int fcntl(int d, int cmd, boost::system::error_code& ec)
return -1;
}
errno = 0;
int result = error_wrapper(::fcntl(d, cmd), ec);
if (result != -1)
ec = boost::system::error_code();
int result = ::fcntl(d, cmd);
get_last_error(ec, result < 0);
return result;
}
@@ -386,10 +890,8 @@ int fcntl(int d, int cmd, long arg, boost::system::error_code& ec)
return -1;
}
errno = 0;
int result = error_wrapper(::fcntl(d, cmd, arg), ec);
if (result != -1)
ec = boost::system::error_code();
int result = ::fcntl(d, cmd, arg);
get_last_error(ec, result < 0);
return result;
}
@@ -406,13 +908,11 @@ int poll_read(int d, state_type state, boost::system::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)
? boost::asio::error::would_block : boost::system::error_code();
else if (result > 0)
ec = boost::system::error_code();
if (state & user_set_non_blocking)
ec = boost::asio::error::would_block;
return result;
}
@@ -429,13 +929,11 @@ int poll_write(int d, state_type state, boost::system::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)
? boost::asio::error::would_block : boost::system::error_code();
else if (result > 0)
ec = boost::system::error_code();
if (state & user_set_non_blocking)
ec = boost::asio::error::would_block;
return result;
}
@@ -452,13 +950,11 @@ int poll_error(int d, state_type state, boost::system::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)
? boost::asio::error::would_block : boost::system::error_code();
else if (result > 0)
ec = boost::system::error_code();
if (state & user_set_non_blocking)
ec = boost::asio::error::would_block;
return result;
}

View File

@@ -2,7 +2,7 @@
// detail/impl/dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -19,12 +19,20 @@
#if defined(BOOST_ASIO_HAS_DEV_POLL)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void dev_poll_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -69,6 +77,18 @@ std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void dev_poll_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/dev_poll_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -21,6 +21,7 @@
#include <boost/asio/detail/dev_poll_reactor.hpp>
#include <boost/asio/detail/assert.hpp>
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
@@ -148,15 +149,24 @@ void dev_poll_reactor::move_descriptor(socket_type,
{
}
void dev_poll_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const dev_poll_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
dev_poll_reactor::per_descriptor_data&, reactor_op* op,
bool is_continuation, bool allow_speculative)
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -169,7 +179,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
if (op->perform())
{
lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -202,6 +212,19 @@ void dev_poll_reactor::cancel_ops(socket_type descriptor,
cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
void dev_poll_reactor::cancel_ops_by_key(socket_type descriptor,
dev_poll_reactor::per_descriptor_data&,
int op_type, void* cancellation_key)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
bool need_interrupt = op_queue_[op_type].cancel_operations_by_key(
descriptor, ops, cancellation_key, boost::asio::error::operation_aborted);
scheduler_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
void dev_poll_reactor::deregister_descriptor(socket_type descriptor,
dev_poll_reactor::per_descriptor_data&, bool)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -17,12 +17,20 @@
#if defined(BOOST_ASIO_HAS_EPOLL)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void epoll_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -67,6 +75,18 @@ std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void epoll_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/epoll_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -22,6 +22,7 @@
#include <cstddef>
#include <sys/epoll.h>
#include <boost/asio/detail/epoll_reactor.hpp>
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
@@ -229,14 +230,23 @@ void epoll_reactor::move_descriptor(socket_type,
source_descriptor_data = 0;
}
void epoll_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const epoll_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void epoll_reactor::start_op(int op_type, socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
if (!descriptor_data)
{
op->ec_ = boost::asio::error::bad_descriptor;
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -244,7 +254,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -262,7 +272,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->registered_events_ != 0)
descriptor_data->try_speculative_[op_type] = false;
descriptor_lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -270,7 +280,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->registered_events_ == 0)
{
op->ec_ = boost::asio::error::operation_not_supported;
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -289,7 +299,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
{
op->ec_ = boost::system::error_code(errno,
boost::asio::error::get_system_category());
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -298,7 +308,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor,
else if (descriptor_data->registered_events_ == 0)
{
op->ec_ = boost::asio::error::operation_not_supported;
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
else
@@ -343,6 +353,35 @@ void epoll_reactor::cancel_ops(socket_type,
scheduler_.post_deferred_completions(ops);
}
void epoll_reactor::cancel_ops_by_key(socket_type,
epoll_reactor::per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
op_queue<reactor_op> other_ops;
while (reactor_op* op = descriptor_data->op_queue_[op_type].front())
{
descriptor_data->op_queue_[op_type].pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
descriptor_data->op_queue_[op_type].push(other_ops);
descriptor_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void epoll_reactor::deregister_descriptor(socket_type descriptor,
epoll_reactor::per_descriptor_data& descriptor_data, bool closing)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/eventfd_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -23,11 +23,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# include <asm/unistd.h>
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# include <sys/eventfd.h>
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
#include <boost/asio/detail/cstdint.hpp>
#include <boost/asio/detail/eventfd_select_interrupter.hpp>
#include <boost/asio/detail/throw_error.hpp>
@@ -46,14 +46,14 @@ eventfd_select_interrupter::eventfd_select_interrupter()
void eventfd_select_interrupter::open_descriptors()
{
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
if (read_descriptor_ != -1)
{
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
write_descriptor_ = read_descriptor_ =
::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
@@ -70,7 +70,7 @@ void eventfd_select_interrupter::open_descriptors()
::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
}
}
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__)
if (read_descriptor_ == -1)
{
@@ -135,8 +135,7 @@ bool eventfd_select_interrupter::reset()
int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
if (bytes_read < 0 && errno == EINTR)
continue;
bool was_interrupted = (bytes_read > 0);
return was_interrupted;
return true;
}
}
else
@@ -146,12 +145,19 @@ bool eventfd_select_interrupter::reset()
// Clear all data from the pipe.
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
if (bytes_read == sizeof(data))
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
if (bytes_read > 0)
return true;
if (bytes_read == 0)
return false;
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK)
return true;
if (errno == EAGAIN)
return true;
return false;
}
}
}

View File

@@ -2,7 +2,7 @@
// detail/impl/handler_tracking.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -74,11 +74,12 @@ struct handler_tracking::tracking_state
static_mutex mutex_;
uint64_t next_id_;
tss_ptr<completion>* current_completion_;
tss_ptr<location>* current_location_;
};
handler_tracking::tracking_state* handler_tracking::get_state()
{
static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0 };
static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0, 0 };
return &state;
}
@@ -91,6 +92,25 @@ void handler_tracking::init()
static_mutex::scoped_lock lock(state->mutex_);
if (state->current_completion_ == 0)
state->current_completion_ = new tss_ptr<completion>;
if (state->current_location_ == 0)
state->current_location_ = new tss_ptr<location>;
}
handler_tracking::location::location(
const char* file, int line, const char* func)
: file_(file),
line_(line),
func_(func),
next_(*get_state()->current_location_)
{
if (file_)
*get_state()->current_location_ = this;
}
handler_tracking::location::~location()
{
if (file_)
*get_state()->current_location_ = next_;
}
void handler_tracking::creation(execution_context&,
@@ -110,6 +130,24 @@ void handler_tracking::creation(execution_context&,
if (completion* current_completion = *state->current_completion_)
current_id = current_completion->id_;
for (location* current_location = *state->current_location_;
current_location; current_location = current_location->next_)
{
write_line(
#if defined(BOOST_ASIO_WINDOWS)
"@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n",
#else // defined(BOOST_ASIO_WINDOWS)
"@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n",
#endif // defined(BOOST_ASIO_WINDOWS)
timestamp.seconds, timestamp.microseconds,
current_id, h.id_,
current_location == *state->current_location_ ? "in " : "called from ",
current_location->func_ ? "'" : "",
current_location->func_ ? current_location->func_ : "",
current_location->func_ ? "' " : "",
current_location->file_, current_location->line_);
}
write_line(
#if defined(BOOST_ASIO_WINDOWS)
"@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n",
@@ -328,7 +366,9 @@ void handler_tracking::write_line(const char* format, ...)
va_start(args, format);
char line[256] = "";
#if defined(BOOST_ASIO_HAS_SECURE_RTL)
#if defined(BOOST_ASIO_HAS_SNPRINTF)
int length = vsnprintf(line, sizeof(line), format, args);
#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
int length = vsprintf_s(line, sizeof(line), format, args);
#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
int length = vsprintf(line, format, args);

View File

@@ -0,0 +1,207 @@
//
// detail/impl/io_uring_descriptor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING)
#include <boost/asio/error.hpp>
#include <boost/asio/detail/io_uring_descriptor_service.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_descriptor_service::io_uring_descriptor_service(
execution_context& context)
: execution_context_service_base<io_uring_descriptor_service>(context),
io_uring_service_(boost::asio::use_service<io_uring_service>(context))
{
io_uring_service_.init_task();
}
void io_uring_descriptor_service::shutdown()
{
}
void io_uring_descriptor_service::construct(
io_uring_descriptor_service::implementation_type& impl)
{
impl.descriptor_ = -1;
impl.state_ = 0;
impl.io_object_data_ = 0;
}
void io_uring_descriptor_service::move_construct(
io_uring_descriptor_service::implementation_type& impl,
io_uring_descriptor_service::implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_descriptor_service::move_assign(
io_uring_descriptor_service::implementation_type& impl,
io_uring_descriptor_service& /*other_service*/,
io_uring_descriptor_service::implementation_type& other_impl)
{
destroy(impl);
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_descriptor_service::destroy(
io_uring_descriptor_service::implementation_type& impl)
{
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
boost::system::error_code ignored_ec;
descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
}
boost::system::error_code io_uring_descriptor_service::assign(
io_uring_descriptor_service::implementation_type& impl,
const native_handle_type& native_descriptor, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
io_uring_service_.register_io_object(impl.io_object_data_);
impl.descriptor_ = native_descriptor;
impl.state_ = descriptor_ops::possible_dup;
ec = success_ec_;
return ec;
}
boost::system::error_code io_uring_descriptor_service::close(
io_uring_descriptor_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
descriptor_ops::close(impl.descriptor_, impl.state_, ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
else
{
ec = success_ec_;
}
// The descriptor is closed by the OS even if close() returns an error.
//
// (Actually, POSIX says the state of the descriptor is unspecified. On
// Linux the descriptor is apparently closed anyway; e.g. see
// http://lkml.org/lkml/2005/9/10/129
construct(impl);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
io_uring_descriptor_service::native_handle_type
io_uring_descriptor_service::release(
io_uring_descriptor_service::implementation_type& impl)
{
native_handle_type descriptor = impl.descriptor_;
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "release"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
construct(impl);
}
return descriptor;
}
boost::system::error_code io_uring_descriptor_service::cancel(
io_uring_descriptor_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"descriptor", &impl, impl.descriptor_, "cancel"));
io_uring_service_.cancel_ops(impl.io_object_data_);
ec = success_ec_;
return ec;
}
void io_uring_descriptor_service::start_op(
io_uring_descriptor_service::implementation_type& impl,
int op_type, io_uring_operation* op, bool is_continuation, bool noop)
{
if (!noop)
{
io_uring_service_.start_op(op_type,
impl.io_object_data_, op, is_continuation);
}
else
{
io_uring_service_.post_immediate_completion(op, is_continuation);
}
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_DESCRIPTOR_SERVICE_IPP

View File

@@ -0,0 +1,142 @@
//
// detail/impl/io_uring_file_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_FILE) \
&& defined(BOOST_ASIO_HAS_IO_URING)
#include <cstring>
#include <sys/stat.h>
#include <boost/asio/detail/io_uring_file_service.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_file_service::io_uring_file_service(
execution_context& context)
: execution_context_service_base<io_uring_file_service>(context),
descriptor_service_(context)
{
}
void io_uring_file_service::shutdown()
{
descriptor_service_.shutdown();
}
boost::system::error_code io_uring_file_service::open(
io_uring_file_service::implementation_type& impl,
const char* path, file_base::flags open_flags,
boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
descriptor_ops::state_type state = 0;
int fd = descriptor_ops::open(path, static_cast<int>(open_flags), 0777, ec);
if (fd < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
// We're done. Take ownership of the serial port descriptor.
if (descriptor_service_.assign(impl, fd, ec))
{
boost::system::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
}
(void)::posix_fadvise(native_handle(impl), 0, 0,
impl.is_stream_ ? POSIX_FADV_SEQUENTIAL : POSIX_FADV_RANDOM);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
uint64_t io_uring_file_service::size(
const io_uring_file_service::implementation_type& impl,
boost::system::error_code& ec) const
{
struct stat s;
int result = ::fstat(native_handle(impl), &s);
descriptor_ops::get_last_error(ec, result != 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return !ec ? s.st_size : 0;
}
boost::system::error_code io_uring_file_service::resize(
io_uring_file_service::implementation_type& impl,
uint64_t n, boost::system::error_code& ec)
{
int result = ::ftruncate(native_handle(impl), n);
descriptor_ops::get_last_error(ec, result != 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
boost::system::error_code io_uring_file_service::sync_all(
io_uring_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
int result = ::fsync(native_handle(impl));
descriptor_ops::get_last_error(ec, result != 0);
return ec;
}
boost::system::error_code io_uring_file_service::sync_data(
io_uring_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
#if defined(_POSIX_SYNCHRONIZED_IO)
int result = ::fdatasync(native_handle(impl));
#else // defined(_POSIX_SYNCHRONIZED_IO)
int result = ::fsync(native_handle(impl));
#endif // defined(_POSIX_SYNCHRONIZED_IO)
descriptor_ops::get_last_error(ec, result != 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
uint64_t io_uring_file_service::seek(
io_uring_file_service::implementation_type& impl, int64_t offset,
file_base::seek_basis whence, boost::system::error_code& ec)
{
int64_t result = ::lseek(native_handle(impl), offset, whence);
descriptor_ops::get_last_error(ec, result < 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return !ec ? static_cast<uint64_t>(result) : 0;
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// && defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_FILE_SERVICE_IPP

View File

@@ -0,0 +1,114 @@
//
// detail/impl/io_uring_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#if defined(BOOST_ASIO_HAS_IO_URING)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void io_uring_service::post_immediate_completion(
operation* op, bool is_continuation)
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void io_uring_service::add_timer_queue(timer_queue<Time_Traits>& queue)
{
do_add_timer_queue(queue);
}
template <typename Time_Traits>
void io_uring_service::remove_timer_queue(timer_queue<Time_Traits>& queue)
{
do_remove_timer_queue(queue);
}
template <typename Time_Traits>
void io_uring_service::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
{
mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op);
scheduler_.work_started();
if (earliest)
{
update_timeout();
post_submit_sqes_op(lock);
}
}
template <typename Time_Traits>
std::size_t io_uring_service::cancel_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& timer,
std::size_t max_cancelled)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
scheduler_.post_deferred_completions(ops);
return n;
}
template <typename Time_Traits>
void io_uring_service::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void io_uring_service::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,
typename timer_queue<Time_Traits>::per_timer_data& source)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer(target, ops);
queue.move_timer(target, source);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_HPP

View File

@@ -0,0 +1,916 @@
//
// detail/impl/io_uring_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING)
#include <cstddef>
#include <sys/eventfd.h>
#include <boost/asio/detail/io_uring_service.hpp>
#include <boost/asio/detail/reactor_op.hpp>
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_service::io_uring_service(boost::asio::execution_context& ctx)
: execution_context_service_base<io_uring_service>(ctx),
scheduler_(use_service<scheduler>(ctx)),
mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
outstanding_work_(0),
submit_sqes_op_(this),
pending_sqes_(0),
pending_submit_sqes_op_(false),
shutdown_(false),
timeout_(),
registration_mutex_(mutex_.enabled()),
reactor_(use_service<reactor>(ctx)),
reactor_data_(),
event_fd_(-1)
{
reactor_.init_task();
init_ring();
register_with_reactor();
}
io_uring_service::~io_uring_service()
{
if (ring_.ring_fd != -1)
::io_uring_queue_exit(&ring_);
if (event_fd_ != -1)
::close(event_fd_);
}
void io_uring_service::shutdown()
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
op_queue<operation> ops;
// Cancel all outstanding operations.
while (io_object* io_obj = registered_io_objects_.first())
{
for (int i = 0; i < max_ops; ++i)
{
if (!io_obj->queues_[i].op_queue_.empty())
{
ops.push(io_obj->queues_[i].op_queue_);
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0);
}
}
io_obj->shutdown_ = true;
registered_io_objects_.free(io_obj);
}
// Cancel the timeout operation.
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &timeout_, IOSQE_IO_DRAIN);
submit_sqes();
// Wait for all completions to come back.
for (; outstanding_work_ > 0; --outstanding_work_)
{
::io_uring_cqe* cqe = 0;
if (::io_uring_wait_cqe(&ring_, &cqe) != 0)
break;
}
timer_queues_.get_all_timers(ops);
scheduler_.abandon_operations(ops);
}
void io_uring_service::notify_fork(
boost::asio::execution_context::fork_event fork_ev)
{
switch (fork_ev)
{
case boost::asio::execution_context::fork_prepare:
{
// Cancel all outstanding operations. They will be restarted
// after the fork completes.
mutex::scoped_lock registration_lock(registration_mutex_);
for (io_object* io_obj = registered_io_objects_.first();
io_obj != 0; io_obj = io_obj->next_)
{
mutex::scoped_lock io_object_lock(io_obj->mutex_);
for (int i = 0; i < max_ops; ++i)
{
if (!io_obj->queues_[i].op_queue_.empty()
&& !io_obj->queues_[i].cancel_requested_)
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0);
}
}
}
// Cancel the timeout operation.
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &timeout_, IOSQE_IO_DRAIN);
submit_sqes();
}
// Wait for all completions to come back, and post all completed I/O
// queues to the scheduler. Note that some operations may have already
// completed, or were explicitly cancelled. All others will be
// automatically restarted.
op_queue<operation> ops;
for (; outstanding_work_ > 0; --outstanding_work_)
{
::io_uring_cqe* cqe = 0;
if (::io_uring_wait_cqe(&ring_, &cqe) != 0)
break;
if (void* ptr = ::io_uring_cqe_get_data(cqe))
{
if (ptr != this && ptr != &timer_queues_ && ptr != &timeout_)
{
io_queue* io_q = static_cast<io_queue*>(ptr);
io_q->set_result(cqe->res);
ops.push(io_q);
}
}
}
scheduler_.post_deferred_completions(ops);
// Restart and eventfd operation.
register_with_reactor();
}
break;
case boost::asio::execution_context::fork_parent:
// Restart the timeout and eventfd operations.
update_timeout();
register_with_reactor();
break;
case boost::asio::execution_context::fork_child:
{
// The child process gets a new io_uring instance.
::io_uring_queue_exit(&ring_);
init_ring();
register_with_reactor();
}
break;
default:
break;
}
}
void io_uring_service::init_task()
{
scheduler_.init_task();
}
void io_uring_service::register_io_object(
io_uring_service::per_io_object_data& io_obj)
{
io_obj = allocate_io_object();
mutex::scoped_lock io_object_lock(io_obj->mutex_);
io_obj->service_ = this;
io_obj->shutdown_ = false;
for (int i = 0; i < max_ops; ++i)
{
io_obj->queues_[i].io_object_ = io_obj;
io_obj->queues_[i].cancel_requested_ = false;
}
}
void io_uring_service::register_internal_io_object(
io_uring_service::per_io_object_data& io_obj,
int op_type, io_uring_operation* op)
{
io_obj = allocate_io_object();
mutex::scoped_lock io_object_lock(io_obj->mutex_);
io_obj->service_ = this;
io_obj->shutdown_ = false;
for (int i = 0; i < max_ops; ++i)
{
io_obj->queues_[i].io_object_ = io_obj;
io_obj->queues_[i].cancel_requested_ = false;
}
io_obj->queues_[op_type].op_queue_.push(op);
io_object_lock.unlock();
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
op->prepare(sqe);
::io_uring_sqe_set_data(sqe, &io_obj->queues_[op_type]);
post_submit_sqes_op(lock);
}
else
{
boost::system::error_code ec(ENOBUFS,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_get_sqe");
}
}
void io_uring_service::register_buffers(const ::iovec* v, unsigned n)
{
int result = ::io_uring_register_buffers(&ring_, v, n);
if (result < 0)
{
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_register_buffers");
}
}
void io_uring_service::unregister_buffers()
{
(void)::io_uring_unregister_buffers(&ring_);
}
void io_uring_service::start_op(int op_type,
io_uring_service::per_io_object_data& io_obj,
io_uring_operation* op, bool is_continuation)
{
if (!io_obj)
{
op->ec_ = boost::asio::error::bad_descriptor;
post_immediate_completion(op, is_continuation);
return;
}
mutex::scoped_lock io_object_lock(io_obj->mutex_);
if (io_obj->shutdown_)
{
io_object_lock.unlock();
post_immediate_completion(op, is_continuation);
return;
}
if (io_obj->queues_[op_type].op_queue_.empty())
{
if (op->perform(false))
{
io_object_lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
}
else
{
io_obj->queues_[op_type].op_queue_.push(op);
io_object_lock.unlock();
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
op->prepare(sqe);
::io_uring_sqe_set_data(sqe, &io_obj->queues_[op_type]);
scheduler_.work_started();
post_submit_sqes_op(lock);
}
else
{
lock.unlock();
io_obj->queues_[op_type].set_result(-ENOBUFS);
post_immediate_completion(&io_obj->queues_[op_type], is_continuation);
}
}
}
else
{
io_obj->queues_[op_type].op_queue_.push(op);
scheduler_.work_started();
}
}
void io_uring_service::cancel_ops(io_uring_service::per_io_object_data& io_obj)
{
if (!io_obj)
return;
mutex::scoped_lock io_object_lock(io_obj->mutex_);
op_queue<operation> ops;
do_cancel_ops(io_obj, ops);
io_object_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void io_uring_service::cancel_ops_by_key(
io_uring_service::per_io_object_data& io_obj,
int op_type, void* cancellation_key)
{
if (!io_obj)
return;
mutex::scoped_lock io_object_lock(io_obj->mutex_);
bool first = true;
op_queue<operation> ops;
op_queue<io_uring_operation> other_ops;
while (io_uring_operation* op = io_obj->queues_[op_type].op_queue_.front())
{
io_obj->queues_[op_type].op_queue_.pop();
if (op->cancellation_key_ == cancellation_key)
{
if (first)
{
other_ops.push(op);
if (!io_obj->queues_[op_type].cancel_requested_)
{
io_obj->queues_[op_type].cancel_requested_ = true;
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_cancel(sqe, &io_obj->queues_[op_type], 0);
submit_sqes();
}
}
}
else
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
}
else
other_ops.push(op);
first = false;
}
io_obj->queues_[op_type].op_queue_.push(other_ops);
io_object_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void io_uring_service::deregister_io_object(
io_uring_service::per_io_object_data& io_obj)
{
if (!io_obj)
return;
mutex::scoped_lock io_object_lock(io_obj->mutex_);
if (!io_obj->shutdown_)
{
op_queue<operation> ops;
bool pending_cancelled_ops = do_cancel_ops(io_obj, ops);
io_obj->shutdown_ = true;
io_object_lock.unlock();
scheduler_.post_deferred_completions(ops);
if (pending_cancelled_ops)
{
// There are still pending operations. Prevent cleanup_io_object from
// freeing the I/O object and let the last operation to complete free it.
io_obj = 0;
}
else
{
// Leave io_obj set so that it will be freed by the subsequent call to
// cleanup_io_object.
}
}
else
{
// We are shutting down, so prevent cleanup_io_object from freeing
// the I/O object and let the destructor free it instead.
io_obj = 0;
}
}
void io_uring_service::cleanup_io_object(
io_uring_service::per_io_object_data& io_obj)
{
if (io_obj)
{
free_io_object(io_obj);
io_obj = 0;
}
}
void io_uring_service::run(long usec, op_queue<operation>& ops)
{
__kernel_timespec ts;
int local_ops = 0;
if (usec > 0)
{
ts.tv_sec = usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
++local_ops;
::io_uring_prep_timeout(sqe, &ts, 0, 0);
::io_uring_sqe_set_data(sqe, &ts);
submit_sqes();
}
}
::io_uring_cqe* cqe = 0;
int result = (usec == 0)
? ::io_uring_peek_cqe(&ring_, &cqe)
: ::io_uring_wait_cqe(&ring_, &cqe);
if (local_ops > 0)
{
if (result != 0 || ::io_uring_cqe_get_data(cqe) != &ts)
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
++local_ops;
::io_uring_prep_timeout_remove(sqe, reinterpret_cast<__u64>(&ts), 0);
::io_uring_sqe_set_data(sqe, &ts);
submit_sqes();
}
}
}
bool check_timers = false;
int count = 0;
while (result == 0 || local_ops > 0)
{
if (result == 0)
{
if (void* ptr = ::io_uring_cqe_get_data(cqe))
{
if (ptr == this)
{
// The io_uring service was interrupted.
}
else if (ptr == &timer_queues_)
{
check_timers = true;
}
else if (ptr == &timeout_)
{
check_timers = true;
timeout_.tv_sec = 0;
timeout_.tv_nsec = 0;
}
else if (ptr == &ts)
{
--local_ops;
}
else
{
io_queue* io_q = static_cast<io_queue*>(ptr);
io_q->set_result(cqe->res);
ops.push(io_q);
}
}
::io_uring_cqe_seen(&ring_, cqe);
++count;
}
result = (count < complete_batch_size || local_ops > 0)
? ::io_uring_peek_cqe(&ring_, &cqe) : -EAGAIN;
}
decrement(outstanding_work_, count);
if (check_timers)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.get_ready_timers(ops);
if (timeout_.tv_sec == 0 && timeout_.tv_nsec == 0)
{
timeout_ = get_timeout();
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_timeout(sqe, &timeout_, 0, 0);
::io_uring_sqe_set_data(sqe, &timeout_);
push_submit_sqes_op(ops);
}
}
}
}
void io_uring_service::interrupt()
{
mutex::scoped_lock lock(mutex_);
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_nop(sqe);
::io_uring_sqe_set_data(sqe, this);
}
submit_sqes();
}
void io_uring_service::init_ring()
{
int result = ::io_uring_queue_init(ring_size, &ring_, 0);
if (result < 0)
{
ring_.ring_fd = -1;
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_queue_init");
}
#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
event_fd_ = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (event_fd_ < 0)
{
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
::io_uring_queue_exit(&ring_);
boost::asio::detail::throw_error(ec, "eventfd");
}
result = ::io_uring_register_eventfd(&ring_, event_fd_);
if (result < 0)
{
::close(event_fd_);
::io_uring_queue_exit(&ring_);
boost::system::error_code ec(-result,
boost::asio::error::get_system_category());
boost::asio::detail::throw_error(ec, "io_uring_queue_init");
}
#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
class io_uring_service::event_fd_read_op :
public reactor_op
{
public:
event_fd_read_op(io_uring_service* s)
: reactor_op(boost::system::error_code(),
&event_fd_read_op::do_perform, event_fd_read_op::do_complete),
service_(s)
{
}
static status do_perform(reactor_op* base)
{
event_fd_read_op* o(static_cast<event_fd_read_op*>(base));
for (;;)
{
// Only perform one read. The kernel maintains an atomic counter.
uint64_t counter(0);
errno = 0;
int bytes_read = ::read(o->service_->event_fd_,
&counter, sizeof(uint64_t));
if (bytes_read < 0 && errno == EINTR)
continue;
break;
}
op_queue<operation> ops;
o->service_->run(0, ops);
o->service_->scheduler_.post_deferred_completions(ops);
return not_done;
}
static void do_complete(void* /*owner*/, operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
event_fd_read_op* o(static_cast<event_fd_read_op*>(base));
delete o;
}
private:
io_uring_service* service_;
};
#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
void io_uring_service::register_with_reactor()
{
#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.register_internal_descriptor(reactor::read_op,
event_fd_, reactor_data_, new event_fd_read_op(this));
#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
io_uring_service::io_object* io_uring_service::allocate_io_object()
{
mutex::scoped_lock registration_lock(registration_mutex_);
return registered_io_objects_.alloc(
BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, scheduler_.concurrency_hint()));
}
void io_uring_service::free_io_object(io_uring_service::io_object* io_obj)
{
mutex::scoped_lock registration_lock(registration_mutex_);
registered_io_objects_.free(io_obj);
}
bool io_uring_service::do_cancel_ops(
per_io_object_data& io_obj, op_queue<operation>& ops)
{
bool cancel_op = false;
for (int i = 0; i < max_ops; ++i)
{
if (io_uring_operation* first_op = io_obj->queues_[i].op_queue_.front())
{
cancel_op = true;
io_obj->queues_[i].op_queue_.pop();
while (io_uring_operation* op = io_obj->queues_[i].op_queue_.front())
{
op->ec_ = boost::asio::error::operation_aborted;
io_obj->queues_[i].op_queue_.pop();
ops.push(op);
}
io_obj->queues_[i].op_queue_.push(first_op);
}
}
if (cancel_op)
{
mutex::scoped_lock lock(mutex_);
for (int i = 0; i < max_ops; ++i)
{
if (!io_obj->queues_[i].op_queue_.empty()
&& !io_obj->queues_[i].cancel_requested_)
{
io_obj->queues_[i].cancel_requested_ = true;
if (::io_uring_sqe* sqe = get_sqe())
::io_uring_prep_cancel(sqe, &io_obj->queues_[i], 0);
}
}
submit_sqes();
}
return cancel_op;
}
void io_uring_service::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.insert(&queue);
}
void io_uring_service::do_remove_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(mutex_);
timer_queues_.erase(&queue);
}
void io_uring_service::update_timeout()
{
if (::io_uring_sqe* sqe = get_sqe())
{
::io_uring_prep_timeout_remove(sqe, reinterpret_cast<__u64>(&timeout_), 0);
::io_uring_sqe_set_data(sqe, &timer_queues_);
}
}
__kernel_timespec io_uring_service::get_timeout() const
{
__kernel_timespec ts;
long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
ts.tv_sec = usec / 1000000;
ts.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
return ts;
}
::io_uring_sqe* io_uring_service::get_sqe()
{
::io_uring_sqe* sqe = ::io_uring_get_sqe(&ring_);
if (!sqe)
{
submit_sqes();
sqe = ::io_uring_get_sqe(&ring_);
}
if (sqe)
{
::io_uring_sqe_set_data(sqe, 0);
++pending_sqes_;
}
return sqe;
}
void io_uring_service::submit_sqes()
{
if (pending_sqes_ != 0)
{
int result = ::io_uring_submit(&ring_);
if (result > 0)
{
pending_sqes_ -= result;
increment(outstanding_work_, result);
}
}
}
void io_uring_service::post_submit_sqes_op(mutex::scoped_lock& lock)
{
if (pending_sqes_ >= submit_batch_size)
{
submit_sqes();
}
else if (pending_sqes_ != 0 && !pending_submit_sqes_op_)
{
pending_submit_sqes_op_ = true;
lock.unlock();
scheduler_.post_immediate_completion(&submit_sqes_op_, false);
}
}
void io_uring_service::push_submit_sqes_op(op_queue<operation>& ops)
{
if (pending_sqes_ != 0 && !pending_submit_sqes_op_)
{
pending_submit_sqes_op_ = true;
ops.push(&submit_sqes_op_);
scheduler_.compensating_work_started();
}
}
io_uring_service::submit_sqes_op::submit_sqes_op(io_uring_service* s)
: operation(&io_uring_service::submit_sqes_op::do_complete),
service_(s)
{
}
void io_uring_service::submit_sqes_op::do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/)
{
if (owner)
{
submit_sqes_op* o = static_cast<submit_sqes_op*>(base);
mutex::scoped_lock lock(o->service_->mutex_);
o->service_->submit_sqes();
if (o->service_->pending_sqes_ != 0)
o->service_->scheduler_.post_immediate_completion(o, true);
else
o->service_->pending_submit_sqes_op_ = false;
}
}
io_uring_service::io_queue::io_queue()
: operation(&io_uring_service::io_queue::do_complete)
{
}
struct io_uring_service::perform_io_cleanup_on_block_exit
{
explicit perform_io_cleanup_on_block_exit(io_uring_service* s)
: service_(s), io_object_to_free_(0), first_op_(0)
{
}
~perform_io_cleanup_on_block_exit()
{
if (io_object_to_free_)
{
mutex::scoped_lock lock(service_->mutex_);
service_->free_io_object(io_object_to_free_);
}
if (first_op_)
{
// Post the remaining completed operations for invocation.
if (!ops_.empty())
service_->scheduler_.post_deferred_completions(ops_);
// A user-initiated operation has completed, but there's no need to
// explicitly call work_finished() here. Instead, we'll take advantage of
// the fact that the scheduler will call work_finished() once we return.
}
else
{
// No user-initiated operations have completed, so we need to compensate
// for the work_finished() call that the scheduler will make once this
// operation returns.
service_->scheduler_.compensating_work_started();
}
}
io_uring_service* service_;
io_object* io_object_to_free_;
op_queue<operation> ops_;
operation* first_op_;
};
operation* io_uring_service::io_queue::perform_io(int result)
{
perform_io_cleanup_on_block_exit io_cleanup(io_object_->service_);
mutex::scoped_lock io_object_lock(io_object_->mutex_);
if (result != -ECANCELED || cancel_requested_)
{
if (io_uring_operation* op = op_queue_.front())
{
if (result < 0)
{
op->ec_.assign(-result, boost::asio::error::get_system_category());
op->bytes_transferred_ = 0;
}
else
{
op->ec_.assign(0, op->ec_.category());
op->bytes_transferred_ = static_cast<std::size_t>(result);
}
}
while (io_uring_operation* op = op_queue_.front())
{
if (op->perform(io_cleanup.ops_.empty()))
{
op_queue_.pop();
io_cleanup.ops_.push(op);
}
else
break;
}
}
cancel_requested_ = false;
if (!op_queue_.empty())
{
io_uring_service* service = io_object_->service_;
mutex::scoped_lock lock(service->mutex_);
if (::io_uring_sqe* sqe = service->get_sqe())
{
op_queue_.front()->prepare(sqe);
::io_uring_sqe_set_data(sqe, this);
service->post_submit_sqes_op(lock);
}
else
{
lock.unlock();
while (io_uring_operation* op = op_queue_.front())
{
op->ec_ = boost::asio::error::no_buffer_space;
op_queue_.pop();
io_cleanup.ops_.push(op);
}
}
}
// The last operation to complete on a shut down object must free it.
if (io_object_->shutdown_)
{
io_cleanup.io_object_to_free_ = io_object_;
for (int i = 0; i < max_ops; ++i)
if (!io_object_->queues_[i].op_queue_.empty())
io_cleanup.io_object_to_free_ = 0;
}
// The first operation will be returned for completion now. The others will
// be posted for later by the io_cleanup object's destructor.
io_cleanup.first_op_ = io_cleanup.ops_.front();
io_cleanup.ops_.pop();
return io_cleanup.first_op_;
}
void io_uring_service::io_queue::do_complete(void* owner, operation* base,
const boost::system::error_code& ec, std::size_t bytes_transferred)
{
if (owner)
{
io_queue* io_q = static_cast<io_queue*>(base);
int result = static_cast<int>(bytes_transferred);
if (operation* op = io_q->perform_io(result))
{
op->complete(owner, ec, 0);
}
}
}
io_uring_service::io_object::io_object(bool locking)
: mutex_(locking)
{
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_SERVICE_IPP

View File

@@ -0,0 +1,251 @@
//
// detail/io_uring_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP
#define BOOST_ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING)
#include <boost/asio/detail/io_uring_socket_service_base.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
io_uring_socket_service_base::io_uring_socket_service_base(
execution_context& context)
: io_uring_service_(boost::asio::use_service<io_uring_service>(context))
{
io_uring_service_.init_task();
}
void io_uring_socket_service_base::base_shutdown()
{
}
void io_uring_socket_service_base::construct(
io_uring_socket_service_base::base_implementation_type& impl)
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.io_object_data_ = 0;
}
void io_uring_socket_service_base::base_move_construct(
io_uring_socket_service_base::base_implementation_type& impl,
io_uring_socket_service_base::base_implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_socket_service_base::base_move_assign(
io_uring_socket_service_base::base_implementation_type& impl,
io_uring_socket_service_base& /*other_service*/,
io_uring_socket_service_base::base_implementation_type& other_impl)
{
destroy(impl);
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
impl.state_ = other_impl.state_;
other_impl.state_ = 0;
impl.io_object_data_ = other_impl.io_object_data_;
other_impl.io_object_data_ = 0;
}
void io_uring_socket_service_base::destroy(
io_uring_socket_service_base::base_implementation_type& impl)
{
if (impl.socket_ != invalid_socket)
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
boost::system::error_code ignored_ec;
socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
}
boost::system::error_code io_uring_socket_service_base::close(
io_uring_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
{
if (is_open(impl))
{
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "close"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
socket_ops::close(impl.socket_, impl.state_, false, ec);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
}
else
{
ec = success_ec_;
}
// The descriptor is closed by the OS even if close() returns an error.
//
// (Actually, POSIX says the state of the descriptor is unspecified. On
// Linux the descriptor is apparently closed anyway; e.g. see
// http://lkml.org/lkml/2005/9/10/129
construct(impl);
return ec;
}
socket_type io_uring_socket_service_base::release(
io_uring_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
return invalid_socket;
}
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "release"));
io_uring_service_.deregister_io_object(impl.io_object_data_);
io_uring_service_.cleanup_io_object(impl.io_object_data_);
socket_type sock = impl.socket_;
construct(impl);
ec = success_ec_;
return sock;
}
boost::system::error_code io_uring_socket_service_base::cancel(
io_uring_socket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
return ec;
}
BOOST_ASIO_HANDLER_OPERATION((io_uring_service_.context(),
"socket", &impl, impl.socket_, "cancel"));
io_uring_service_.cancel_ops(impl.io_object_data_);
ec = success_ec_;
return ec;
}
boost::system::error_code io_uring_socket_service_base::do_open(
io_uring_socket_service_base::base_implementation_type& impl,
int af, int type, int protocol, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
return ec;
}
socket_holder sock(socket_ops::socket(af, type, protocol, ec));
if (sock.get() == invalid_socket)
return ec;
io_uring_service_.register_io_object(impl.io_object_data_);
impl.socket_ = sock.release();
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
ec = success_ec_;
return ec;
}
boost::system::error_code io_uring_socket_service_base::do_assign(
io_uring_socket_service_base::base_implementation_type& impl, int type,
const io_uring_socket_service_base::native_handle_type& native_socket,
boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
return ec;
}
io_uring_service_.register_io_object(impl.io_object_data_);
impl.socket_ = native_socket;
switch (type)
{
case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
default: impl.state_ = 0; break;
}
impl.state_ |= socket_ops::possible_dup;
ec = success_ec_;
return ec;
}
void io_uring_socket_service_base::start_op(
io_uring_socket_service_base::base_implementation_type& impl,
int op_type, io_uring_operation* op, bool is_continuation, bool noop)
{
if (!noop)
{
io_uring_service_.start_op(op_type,
impl.io_object_data_, op, is_continuation);
}
else
{
io_uring_service_.post_immediate_completion(op, is_continuation);
}
}
void io_uring_socket_service_base::start_accept_op(
io_uring_socket_service_base::base_implementation_type& impl,
io_uring_operation* op, bool is_continuation, bool peer_is_open)
{
if (!peer_is_open)
start_op(impl, io_uring_service::read_op, op, is_continuation, false);
else
{
op->ec_ = boost::asio::error::already_open;
io_uring_service_.post_immediate_completion(op, is_continuation);
}
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#endif // BOOST_ASIO_DETAIL_IMPL_IO_URING_SOCKET_SERVICE_BASE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/kqueue_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -20,12 +20,20 @@
#if defined(BOOST_ASIO_HAS_KQUEUE)
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void kqueue_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -71,6 +79,18 @@ std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void kqueue_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/kqueue_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -25,9 +25,13 @@
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#if defined(__NetBSD__)
# include <sys/param.h>
#endif
#include <boost/asio/detail/push_options.hpp>
#if defined(__NetBSD__)
#if defined(__NetBSD__) && __NetBSD_Version__ < 999001500
# define BOOST_ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
EV_SET(ev, ident, filt, flags, fflags, data, \
reinterpret_cast<intptr_t>(static_cast<void*>(udata)))
@@ -187,14 +191,23 @@ void kqueue_reactor::move_descriptor(socket_type,
source_descriptor_data = 0;
}
void kqueue_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const kqueue_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void kqueue_reactor::start_op(int op_type, socket_type descriptor,
kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
if (!descriptor_data)
{
op->ec_ = boost::asio::error::bad_descriptor;
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -202,7 +215,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
if (descriptor_data->shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -217,7 +230,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
if (op->perform())
{
descriptor_lock.unlock();
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -236,7 +249,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor,
{
op->ec_ = boost::system::error_code(errno,
boost::asio::error::get_system_category());
scheduler_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
}
@@ -283,6 +296,35 @@ void kqueue_reactor::cancel_ops(socket_type,
scheduler_.post_deferred_completions(ops);
}
void kqueue_reactor::cancel_ops_by_key(socket_type,
kqueue_reactor::per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key)
{
if (!descriptor_data)
return;
mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
op_queue<operation> ops;
op_queue<reactor_op> other_ops;
while (reactor_op* op = descriptor_data->op_queue_[op_type].front())
{
descriptor_data->op_queue_[op_type].pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
descriptor_data->op_queue_[op_type].push(other_ops);
descriptor_lock.unlock();
scheduler_.post_deferred_completions(ops);
}
void kqueue_reactor::deregister_descriptor(socket_type descriptor,
kqueue_reactor::per_descriptor_data& descriptor_data, bool closing)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/null_event.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/pipe_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -102,12 +102,17 @@ bool pipe_select_interrupter::reset()
{
char data[1024];
signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));
if (bytes_read < 0 && errno == EINTR)
if (bytes_read == sizeof(data))
continue;
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
if (bytes_read > 0)
return true;
if (bytes_read == 0)
return false;
if (errno == EINTR)
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN)
return true;
return false;
}
}

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_event.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -38,10 +38,14 @@ posix_event::posix_event()
#else // (defined(__MACH__) && defined(__APPLE__))
// || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
::pthread_condattr_t attr;
::pthread_condattr_init(&attr);
int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
int error = ::pthread_condattr_init(&attr);
if (error == 0)
error = ::pthread_cond_init(&cond_, &attr);
{
error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
if (error == 0)
error = ::pthread_cond_init(&cond_, &attr);
::pthread_condattr_destroy(&attr);
}
#endif // (defined(__MACH__) && defined(__APPLE__))
// || (defined(__ANDROID__) && (__ANDROID_API__ < 21))

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_mutex.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -1,16 +1,16 @@
//
// detail/impl/reactive_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// detail/impl/posix_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
@@ -22,7 +22,7 @@
#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
#include <cstring>
#include <boost/asio/detail/reactive_serial_port_service.hpp>
#include <boost/asio/detail/posix_serial_port_service.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -30,25 +30,26 @@ namespace boost {
namespace asio {
namespace detail {
reactive_serial_port_service::reactive_serial_port_service(
posix_serial_port_service::posix_serial_port_service(
execution_context& context)
: execution_context_service_base<reactive_serial_port_service>(context),
: execution_context_service_base<posix_serial_port_service>(context),
descriptor_service_(context)
{
}
void reactive_serial_port_service::shutdown()
void posix_serial_port_service::shutdown()
{
descriptor_service_.shutdown();
}
boost::system::error_code reactive_serial_port_service::open(
reactive_serial_port_service::implementation_type& impl,
boost::system::error_code posix_serial_port_service::open(
posix_serial_port_service::implementation_type& impl,
const std::string& device, boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -56,7 +57,10 @@ boost::system::error_code reactive_serial_port_service::open(
int fd = descriptor_ops::open(device.c_str(),
O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
if (fd < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
if (s >= 0)
@@ -65,13 +69,14 @@ boost::system::error_code reactive_serial_port_service::open(
{
boost::system::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
// Set up default serial port options.
termios ios;
errno = 0;
s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
s = ::tcgetattr(fd, &ios);
descriptor_ops::get_last_error(ec, s < 0);
if (s >= 0)
{
#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
@@ -86,13 +91,14 @@ boost::system::error_code reactive_serial_port_service::open(
#endif
ios.c_iflag |= IGNPAR;
ios.c_cflag |= CREAD | CLOCAL;
errno = 0;
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
s = ::tcsetattr(fd, TCSANOW, &ios);
descriptor_ops::get_last_error(ec, s < 0);
}
if (s < 0)
{
boost::system::error_code ignored_ec;
descriptor_ops::close(fd, state, ignored_ec);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -103,43 +109,53 @@ boost::system::error_code reactive_serial_port_service::open(
descriptor_ops::close(fd, state, ignored_ec);
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
boost::system::error_code reactive_serial_port_service::do_set_option(
reactive_serial_port_service::implementation_type& impl,
reactive_serial_port_service::store_function_type store,
boost::system::error_code posix_serial_port_service::do_set_option(
posix_serial_port_service::implementation_type& impl,
posix_serial_port_service::store_function_type store,
const void* option, boost::system::error_code& ec)
{
termios ios;
errno = 0;
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native_handle(impl), &ios), ec);
if (ec)
int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
descriptor_ops::get_last_error(ec, s < 0);
if (s < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
if (store(option, ios, ec))
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
errno = 0;
descriptor_ops::error_wrapper(::tcsetattr(
descriptor_service_.native_handle(impl), TCSANOW, &ios), ec);
s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios);
descriptor_ops::get_last_error(ec, s < 0);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
boost::system::error_code reactive_serial_port_service::do_get_option(
const reactive_serial_port_service::implementation_type& impl,
reactive_serial_port_service::load_function_type load,
boost::system::error_code posix_serial_port_service::do_get_option(
const posix_serial_port_service::implementation_type& impl,
posix_serial_port_service::load_function_type load,
void* option, boost::system::error_code& ec) const
{
termios ios;
errno = 0;
descriptor_ops::error_wrapper(::tcgetattr(
descriptor_service_.native_handle(impl), &ios), ec);
if (ec)
int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
descriptor_ops::get_last_error(ec, s < 0);
if (s < 0)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
return load(option, ios, ec);
load(option, ios, ec);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
} // namespace detail
@@ -151,4 +167,4 @@ boost::system::error_code reactive_serial_port_service::do_get_option(
#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT)
#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_SERIAL_PORT_SERVICE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_thread.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/posix_tss_ptr.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/reactive_descriptor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -19,7 +19,8 @@
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
&& !defined(__CYGWIN__) \
&& !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/error.hpp>
#include <boost/asio/detail/reactive_descriptor_service.hpp>
@@ -47,11 +48,13 @@ void reactive_descriptor_service::construct(
{
impl.descriptor_ = -1;
impl.state_ = 0;
impl.reactor_data_ = reactor::per_descriptor_data();
}
void reactive_descriptor_service::move_construct(
reactive_descriptor_service::implementation_type& impl,
reactive_descriptor_service::implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.descriptor_ = other_impl.descriptor_;
other_impl.descriptor_ = -1;
@@ -105,6 +108,7 @@ boost::system::error_code reactive_descriptor_service::assign(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -113,6 +117,7 @@ boost::system::error_code reactive_descriptor_service::assign(
{
ec = boost::system::error_code(err,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -151,6 +156,7 @@ boost::system::error_code reactive_descriptor_service::close(
// We'll just have to assume that other OSes follow the same behaviour.)
construct(impl);
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -180,6 +186,7 @@ boost::system::error_code reactive_descriptor_service::cancel(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -191,10 +198,10 @@ boost::system::error_code reactive_descriptor_service::cancel(
return ec;
}
void reactive_descriptor_service::start_op(
reactive_descriptor_service::implementation_type& impl,
int op_type, reactor_op* op, bool is_continuation,
bool is_non_blocking, bool noop)
void reactive_descriptor_service::do_start_op(implementation_type& impl,
int op_type, reactor_op* op, bool is_continuation, bool is_non_blocking,
bool noop, void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if (!noop)
{
@@ -202,13 +209,13 @@ void reactive_descriptor_service::start_op(
descriptor_ops::set_internal_non_blocking(
impl.descriptor_, impl.state_, true, op->ec_))
{
reactor_.start_op(op_type, impl.descriptor_,
impl.reactor_data_, op, is_continuation, is_non_blocking);
reactor_.start_op(op_type, impl.descriptor_, impl.reactor_data_, op,
is_continuation, is_non_blocking, on_immediate, immediate_arg);
return;
}
}
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
} // namespace detail
@@ -220,5 +227,6 @@ void reactive_descriptor_service::start_op(
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
// && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP

View File

@@ -2,7 +2,7 @@
// detail/reactive_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -18,7 +18,8 @@
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_HAS_IOCP) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME)
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/detail/reactive_socket_service_base.hpp>
@@ -44,11 +45,13 @@ void reactive_socket_service_base::construct(
{
impl.socket_ = invalid_socket;
impl.state_ = 0;
impl.reactor_data_ = reactor::per_descriptor_data();
}
void reactive_socket_service_base::base_move_construct(
reactive_socket_service_base::base_implementation_type& impl,
reactive_socket_service_base::base_implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
@@ -231,10 +234,11 @@ boost::system::error_code reactive_socket_service_base::do_assign(
return ec;
}
void reactive_socket_service_base::start_op(
reactive_socket_service_base::base_implementation_type& impl,
int op_type, reactor_op* op, bool is_continuation,
bool is_non_blocking, bool noop)
void reactive_socket_service_base::do_start_op(
reactive_socket_service_base::base_implementation_type& impl, int op_type,
reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop,
void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if (!noop)
{
@@ -242,32 +246,38 @@ void reactive_socket_service_base::start_op(
|| socket_ops::set_internal_non_blocking(
impl.socket_, impl.state_, true, op->ec_))
{
reactor_.start_op(op_type, impl.socket_,
impl.reactor_data_, op, is_continuation, is_non_blocking);
reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op,
is_continuation, is_non_blocking, on_immediate, immediate_arg);
return;
}
}
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
void reactive_socket_service_base::start_accept_op(
void reactive_socket_service_base::do_start_accept_op(
reactive_socket_service_base::base_implementation_type& impl,
reactor_op* op, bool is_continuation, bool peer_is_open)
reactor_op* op, bool is_continuation, bool peer_is_open,
void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if (!peer_is_open)
start_op(impl, reactor::read_op, op, is_continuation, true, false);
{
do_start_op(impl, reactor::read_op, op, is_continuation,
true, false, on_immediate, immediate_arg);
}
else
{
op->ec_ = boost::asio::error::already_open;
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
}
void reactive_socket_service_base::start_connect_op(
void reactive_socket_service_base::do_start_connect_op(
reactive_socket_service_base::base_implementation_type& impl,
reactor_op* op, bool is_continuation,
const socket_addr_type* addr, size_t addrlen)
reactor_op* op, bool is_continuation, const void* addr, size_t addrlen,
void (*on_immediate)(operation* op, bool, const void*),
const void* immediate_arg)
{
if ((impl.state_ & socket_ops::non_blocking)
|| socket_ops::set_internal_non_blocking(
@@ -279,14 +289,14 @@ void reactive_socket_service_base::start_connect_op(
|| op->ec_ == boost::asio::error::would_block)
{
op->ec_ = boost::system::error_code();
reactor_.start_op(reactor::connect_op, impl.socket_,
impl.reactor_data_, op, is_continuation, false);
reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_,
op, is_continuation, false, on_immediate, immediate_arg);
return;
}
}
}
reactor_.post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
}
} // namespace detail
@@ -297,5 +307,6 @@ void reactive_socket_service_base::start_connect_op(
#endif // !defined(BOOST_ASIO_HAS_IOCP)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/resolver_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -81,12 +81,10 @@ void resolver_service_base::base_notify_fork(
work_thread_->join();
work_thread_.reset();
}
else
{
work_scheduler_->restart();
work_thread_.reset(new boost::asio::detail::thread(
work_scheduler_runner(*work_scheduler_)));
}
}
else if (fork_ev != execution_context::fork_prepare)
{
work_scheduler_->restart();
}
}

View File

@@ -2,7 +2,7 @@
// detail/impl/scheduler.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -20,11 +20,16 @@
#include <boost/asio/detail/concurrency_hint.hpp>
#include <boost/asio/detail/event.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/detail/reactor.hpp>
#include <boost/asio/detail/scheduler.hpp>
#include <boost/asio/detail/scheduler_thread_info.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/io_uring_service.hpp>
#else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/reactor.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
@@ -105,7 +110,7 @@ struct scheduler::work_cleanup
};
scheduler::scheduler(boost::asio::execution_context& ctx,
int concurrency_hint, bool own_thread)
int concurrency_hint, bool own_thread, get_task_func_type get_task)
: boost::asio::detail::execution_context_service_base<scheduler>(ctx),
one_thread_(concurrency_hint == 1
|| !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
@@ -115,6 +120,7 @@ scheduler::scheduler(boost::asio::execution_context& ctx,
mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
SCHEDULER, concurrency_hint)),
task_(0),
get_task_(get_task),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
@@ -136,6 +142,10 @@ scheduler::~scheduler()
{
if (thread_)
{
mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_all_threads(lock);
lock.unlock();
thread_->join();
delete thread_;
}
@@ -175,7 +185,7 @@ void scheduler::init_task()
mutex::scoped_lock lock(mutex_);
if (!shutdown_ && !task_)
{
task_ = &use_service<reactor>(this->context());
task_ = get_task_(this->context());
op_queue_.push(&task_operation_);
wake_one_thread_and_unlock(lock);
}
@@ -318,9 +328,21 @@ void scheduler::restart()
void scheduler::compensating_work_started()
{
thread_info_base* this_thread = thread_call_stack::contains(this);
BOOST_ASIO_ASSUME(this_thread != 0); // Only called from inside scheduler.
++static_cast<thread_info*>(this_thread)->private_outstanding_work;
}
bool scheduler::can_dispatch()
{
return thread_call_stack::contains(this) != 0;
}
void scheduler::capture_current_exception()
{
if (thread_info_base* this_thread = thread_call_stack::contains(this))
this_thread->capture_current_exception();
}
void scheduler::post_immediate_completion(
scheduler::operation* op, bool is_continuation)
{
@@ -344,6 +366,30 @@ void scheduler::post_immediate_completion(
wake_one_thread_and_unlock(lock);
}
void scheduler::post_immediate_completions(std::size_t n,
op_queue<scheduler::operation>& ops, bool is_continuation)
{
#if defined(BOOST_ASIO_HAS_THREADS)
if (one_thread_ || is_continuation)
{
if (thread_info_base* this_thread = thread_call_stack::contains(this))
{
static_cast<thread_info*>(this_thread)->private_outstanding_work
+= static_cast<long>(n);
static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);
return;
}
}
#else // defined(BOOST_ASIO_HAS_THREADS)
(void)is_continuation;
#endif // defined(BOOST_ASIO_HAS_THREADS)
increment(outstanding_work_, static_cast<long>(n));
mutex::scoped_lock lock(mutex_);
op_queue_.push(ops);
wake_one_thread_and_unlock(lock);
}
void scheduler::post_deferred_completion(scheduler::operation* op)
{
#if defined(BOOST_ASIO_HAS_THREADS)
@@ -445,6 +491,7 @@ std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
// Complete the operation. May throw an exception. Deletes the object.
o->complete(this, ec, task_result);
this_thread.rethrow_pending_exception();
return 1;
}
@@ -525,6 +572,7 @@ std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,
// Complete the operation. May throw an exception. Deletes the object.
o->complete(this, ec, task_result);
this_thread.rethrow_pending_exception();
return 1;
}
@@ -579,6 +627,7 @@ std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock,
// Complete the operation. May throw an exception. Deletes the object.
o->complete(this, ec, task_result);
this_thread.rethrow_pending_exception();
return 1;
}
@@ -610,6 +659,15 @@ void scheduler::wake_one_thread_and_unlock(
}
}
scheduler_task* scheduler::get_default_task(boost::asio::execution_context& ctx)
{
#if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
return &use_service<io_uring_service>(ctx);
#else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
return &use_service<reactor>(ctx);
#endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
} // namespace detail
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/impl/select_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -23,12 +23,24 @@
&& !defined(BOOST_ASIO_HAS_KQUEUE) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME))
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_io_context.hpp>
#else // defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/scheduler.hpp>
#endif // defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
inline void select_reactor::post_immediate_completion(
operation* op, bool is_continuation) const
{
scheduler_.post_immediate_completion(op, is_continuation);
}
template <typename Time_Traits>
void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
{
@@ -74,6 +86,18 @@ std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
return n;
}
template <typename Time_Traits>
void select_reactor::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
scheduler_.post_deferred_completions(ops);
}
template <typename Time_Traits>
void select_reactor::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& target,

View File

@@ -2,7 +2,7 @@
// detail/impl/select_reactor.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -28,6 +28,12 @@
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_io_context.hpp>
#else // defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/scheduler.hpp>
#endif // defined(BOOST_ASIO_HAS_IOCP)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
@@ -61,6 +67,7 @@ select_reactor::select_reactor(boost::asio::execution_context& ctx)
#if defined(BOOST_ASIO_HAS_IOCP)
stop_thread_(false),
thread_(0),
restart_reactor_(this),
#endif // defined(BOOST_ASIO_HAS_IOCP)
shutdown_(false)
{
@@ -81,13 +88,14 @@ void select_reactor::shutdown()
shutdown_ = true;
#if defined(BOOST_ASIO_HAS_IOCP)
stop_thread_ = true;
if (thread_)
interrupter_.interrupt();
#endif // defined(BOOST_ASIO_HAS_IOCP)
lock.unlock();
#if defined(BOOST_ASIO_HAS_IOCP)
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
@@ -107,8 +115,12 @@ void select_reactor::shutdown()
void select_reactor::notify_fork(
boost::asio::execution_context::fork_event fork_ev)
{
#if defined(BOOST_ASIO_HAS_IOCP)
(void)fork_ev;
#else // defined(BOOST_ASIO_HAS_IOCP)
if (fork_ev == boost::asio::execution_context::fork_child)
interrupter_.recreate();
#endif // defined(BOOST_ASIO_HAS_IOCP)
}
void select_reactor::init_task()
@@ -140,15 +152,23 @@ void select_reactor::move_descriptor(socket_type,
{
}
void select_reactor::call_post_immediate_completion(
operation* op, bool is_continuation, const void* self)
{
static_cast<const select_reactor*>(self)->post_immediate_completion(
op, is_continuation);
}
void select_reactor::start_op(int op_type, socket_type descriptor,
select_reactor::per_descriptor_data&, reactor_op* op,
bool is_continuation, bool)
select_reactor::per_descriptor_data&, reactor_op* op, bool is_continuation,
bool, void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
post_immediate_completion(op, is_continuation);
on_immediate(op, is_continuation, immediate_arg);
return;
}
@@ -165,6 +185,19 @@ void select_reactor::cancel_ops(socket_type descriptor,
cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
}
void select_reactor::cancel_ops_by_key(socket_type descriptor,
select_reactor::per_descriptor_data&,
int op_type, void* cancellation_key)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
op_queue<operation> ops;
bool need_interrupt = op_queue_[op_type].cancel_operations_by_key(
descriptor, ops, cancellation_key, boost::asio::error::operation_aborted);
scheduler_.post_deferred_completions(ops);
if (need_interrupt)
interrupter_.interrupt();
}
void select_reactor::deregister_descriptor(socket_type descriptor,
select_reactor::per_descriptor_data&, bool)
{
@@ -240,7 +273,16 @@ void select_reactor::run(long usec, op_queue<operation>& ops)
// Reset the interrupter.
if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor()))
{
interrupter_.reset();
if (!interrupter_.reset())
{
lock.lock();
#if defined(BOOST_ASIO_HAS_IOCP)
stop_thread_ = true;
scheduler_.post_immediate_completion(&restart_reactor_, false);
#else // defined(BOOST_ASIO_HAS_IOCP)
interrupter_.recreate();
#endif // defined(BOOST_ASIO_HAS_IOCP)
}
--retval;
}
@@ -276,11 +318,36 @@ void select_reactor::run_thread()
{
lock.unlock();
op_queue<operation> ops;
run(true, ops);
run(-1, ops);
scheduler_.post_deferred_completions(ops);
lock.lock();
}
}
void select_reactor::restart_reactor::do_complete(void* owner, operation* base,
const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/)
{
if (owner)
{
select_reactor* reactor = static_cast<restart_reactor*>(base)->reactor_;
if (reactor->thread_)
{
reactor->thread_->join();
delete reactor->thread_;
reactor->thread_ = 0;
}
boost::asio::detail::mutex::scoped_lock lock(reactor->mutex_);
reactor->interrupter_.recreate();
reactor->stop_thread_ = false;
lock.unlock();
boost::asio::detail::signal_blocker sb;
reactor->thread_ =
new boost::asio::detail::thread(thread_function(reactor));
}
}
#endif // defined(BOOST_ASIO_HAS_IOCP)
void select_reactor::do_add_timer_queue(timer_queue_base& queue)

View File

@@ -2,7 +2,7 @@
// detail/impl/service_registry.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/service_registry.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/signal_set_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -19,12 +19,17 @@
#include <cstring>
#include <stdexcept>
#include <boost/asio/detail/reactor.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/signal_set_service.hpp>
#include <boost/asio/detail/static_mutex.hpp>
#include <boost/asio/detail/throw_exception.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/io_uring_service.hpp>
#else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/reactor.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
@@ -50,12 +55,16 @@ struct signal_state
// A count of the number of objects that are registered for each signal.
std::size_t registration_count_[max_signal_number];
// The flags used for each registered signal.
signal_set_base::flags_t flags_[max_signal_number];
};
signal_state* get_signal_state()
{
static signal_state state = {
BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };
BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0,
{ 0 }, { signal_set_base::flags_t() } };
return &state;
}
@@ -86,11 +95,45 @@ void boost_asio_signal_handler(int signal_number)
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
class signal_set_service::pipe_read_op : public reactor_op
class signal_set_service::pipe_read_op :
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
public io_uring_operation
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
public reactor_op
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
{
public:
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
pipe_read_op()
: reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
: io_uring_operation(boost::system::error_code(), &pipe_read_op::do_prepare,
&pipe_read_op::do_perform, pipe_read_op::do_complete)
{
}
static void do_prepare(io_uring_operation*, ::io_uring_sqe* sqe)
{
signal_state* state = get_signal_state();
int fd = state->read_descriptor_;
::io_uring_prep_poll_add(sqe, fd, POLLIN);
}
static bool do_perform(io_uring_operation*, bool)
{
signal_state* state = get_signal_state();
int fd = state->read_descriptor_;
int signal_number = 0;
while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
if (signal_number >= 0 && signal_number < max_signal_number)
signal_set_service::deliver_signal(signal_number);
return false;
}
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
pipe_read_op()
: reactor_op(boost::system::error_code(),
&pipe_read_op::do_perform, pipe_read_op::do_complete)
{
}
@@ -106,6 +149,7 @@ public:
return not_done;
}
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
static void do_complete(void* /*owner*/, operation* base,
const boost::system::error_code& /*ec*/,
@@ -125,7 +169,11 @@ signal_set_service::signal_set_service(execution_context& context)
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
io_uring_service_(boost::asio::use_service<io_uring_service>(context)),
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_(boost::asio::use_service<reactor>(context)),
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -137,7 +185,11 @@ signal_set_service::signal_set_service(execution_context& context)
#if !defined(BOOST_ASIO_WINDOWS) \
&& !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
&& !defined(__CYGWIN__)
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
io_uring_service_.init_task();
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.init_task();
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -187,8 +239,14 @@ void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = true;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
io_uring_service_.deregister_io_object(io_object_data_);
io_uring_service_.cleanup_io_object(io_object_data_);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);
reactor_.cleanup_descriptor_data(reactor_data_);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
break;
case execution_context::fork_parent:
@@ -197,8 +255,14 @@ void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = false;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
io_uring_service_.register_internal_io_object(io_object_data_,
io_uring_service::read_op, new pipe_read_op);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, reactor_data_, new pipe_read_op);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
break;
case execution_context::fork_child:
@@ -210,8 +274,14 @@ void signal_set_service::notify_fork(execution_context::fork_event fork_ev)
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = false;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
io_uring_service_.register_internal_io_object(io_object_data_,
io_uring_service::read_op, new pipe_read_op);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, reactor_data_, new pipe_read_op);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
}
break;
default:
@@ -241,8 +311,8 @@ void signal_set_service::destroy(
}
boost::system::error_code signal_set_service::add(
signal_set_service::implementation_type& impl,
int signal_number, boost::system::error_code& ec)
signal_set_service::implementation_type& impl, int signal_number,
signal_set_base::flags_t f, boost::system::error_code& ec)
{
// Check that the signal number is valid.
if (signal_number < 0 || signal_number >= max_signal_number)
@@ -251,6 +321,15 @@ boost::system::error_code signal_set_service::add(
return ec;
}
// Check that the specified flags are supported.
#if !defined(BOOST_ASIO_HAS_SIGACTION)
if (f != signal_set_base::flags::dont_care)
{
ec = boost::asio::error::operation_not_supported;
return ec;
}
#endif // !defined(BOOST_ASIO_HAS_SIGACTION)
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
@@ -278,6 +357,8 @@ boost::system::error_code signal_set_service::add(
memset(&sa, 0, sizeof(sa));
sa.sa_handler = boost_asio_signal_handler;
sigfillset(&sa.sa_mask);
if (f != signal_set_base::flags::dont_care)
sa.sa_flags = static_cast<int>(f);
if (::sigaction(signal_number, &sa, 0) == -1)
# else // defined(BOOST_ASIO_HAS_SIGACTION)
if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR)
@@ -292,7 +373,39 @@ boost::system::error_code signal_set_service::add(
delete new_registration;
return ec;
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
state->flags_[signal_number] = f;
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
// Otherwise check to see if the flags have changed.
else if (f != signal_set_base::flags::dont_care)
{
if (f != state->flags_[signal_number])
{
using namespace std; // For memset.
if (state->flags_[signal_number] != signal_set_base::flags::dont_care)
{
ec = boost::asio::error::invalid_argument;
delete new_registration;
return ec;
}
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = boost_asio_signal_handler;
sigfillset(&sa.sa_mask);
sa.sa_flags = static_cast<int>(f);
if (::sigaction(signal_number, &sa, 0) == -1)
{
ec = boost::system::error_code(errno,
boost::asio::error::get_system_category());
delete new_registration;
return ec;
}
state->flags_[signal_number] = f;
}
}
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
// Record the new registration in the set.
@@ -361,6 +474,9 @@ boost::system::error_code signal_set_service::remove(
# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
return ec;
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
state->flags_[signal_number] = signal_set_base::flags_t();
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
}
#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
@@ -415,6 +531,9 @@ boost::system::error_code signal_set_service::clear(
# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
return ec;
}
# if defined(BOOST_ASIO_HAS_SIGACTION)
state->flags_[reg->signal_number_] = signal_set_base::flags_t();
# endif // defined(BOOST_ASIO_HAS_SIGACTION)
}
#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION)
@@ -462,6 +581,33 @@ boost::system::error_code signal_set_service::cancel(
return ec;
}
void signal_set_service::cancel_ops_by_key(
signal_set_service::implementation_type& impl, void* cancellation_key)
{
op_queue<operation> ops;
{
op_queue<signal_op> other_ops;
signal_state* state = get_signal_state();
static_mutex::scoped_lock lock(state->mutex_);
while (signal_op* op = impl.queue_.front())
{
impl.queue_.pop();
if (op->cancellation_key_ == cancellation_key)
{
op->ec_ = boost::asio::error::operation_aborted;
ops.push(op);
}
else
other_ops.push(op);
}
impl.queue_.push(other_ops);
}
scheduler_.post_deferred_completions(ops);
}
void signal_set_service::deliver_signal(int signal_number)
{
signal_state* state = get_signal_state();
@@ -538,8 +684,14 @@ void signal_set_service::add_service(signal_set_service* service)
// Register for pipe readiness notifications.
int read_descriptor = state->read_descriptor_;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
service->io_uring_service_.register_internal_io_object(
service->io_object_data_, io_uring_service::read_op, new pipe_read_op);
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
service->reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, service->reactor_data_, new pipe_read_op);
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)
@@ -558,10 +710,17 @@ void signal_set_service::remove_service(signal_set_service* service)
// Disable the pipe readiness notifications.
int read_descriptor = state->read_descriptor_;
lock.unlock();
# if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
(void)read_descriptor;
service->io_uring_service_.deregister_io_object(service->io_object_data_);
service->io_uring_service_.cleanup_io_object(service->io_object_data_);
lock.lock();
# else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
service->reactor_.deregister_internal_descriptor(
read_descriptor, service->reactor_data_);
service->reactor_.cleanup_descriptor_data(service->reactor_data_);
lock.lock();
# endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
#endif // !defined(BOOST_ASIO_WINDOWS)
// && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
// && !defined(__CYGWIN__)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// detail/impl/socket_select_interrupter.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -61,11 +61,11 @@ void socket_select_interrupter::open_descriptors()
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
addr.sin_port = 0;
if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
if (socket_ops::bind(acceptor.get(), &addr,
addr_len, ec) == socket_error_retval)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
if (socket_ops::getsockname(acceptor.get(), &addr,
&addr_len, ec) == socket_error_retval)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
@@ -84,7 +84,7 @@ void socket_select_interrupter::open_descriptors()
if (client.get() == invalid_socket)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
if (socket_ops::connect(client.get(), &addr,
addr_len, ec) == socket_error_retval)
boost::asio::detail::throw_error(ec, "socket_select_interrupter");
@@ -156,11 +156,20 @@ bool socket_select_interrupter::reset()
socket_ops::buf b;
socket_ops::init_buf(b, data, sizeof(data));
boost::system::error_code ec;
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
return was_interrupted;
for (;;)
{
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
if (bytes_read == sizeof(data))
continue;
if (bytes_read > 0)
return true;
if (bytes_read == 0)
return false;
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
return true;
return false;
}
}
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_executor_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -15,11 +15,13 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/call_stack.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/recycling_allocator.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/defer.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -27,8 +29,132 @@ namespace boost {
namespace asio {
namespace detail {
template <typename F, typename Allocator>
class strand_executor_service::allocator_binder
{
public:
typedef Allocator allocator_type;
allocator_binder(BOOST_ASIO_MOVE_ARG(F) f, const Allocator& a)
: f_(BOOST_ASIO_MOVE_CAST(F)(f)),
allocator_(a)
{
}
allocator_binder(const allocator_binder& other)
: f_(other.f_),
allocator_(other.allocator_)
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
allocator_binder(allocator_binder&& other)
: f_(BOOST_ASIO_MOVE_CAST(F)(other.f_)),
allocator_(BOOST_ASIO_MOVE_CAST(allocator_type)(other.allocator_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
{
return allocator_;
}
void operator()()
{
f_();
}
private:
F f_;
allocator_type allocator_;
};
template <typename Executor>
class strand_executor_service::invoker
class strand_executor_service::invoker<Executor,
typename enable_if<
execution::is_executor<Executor>::value
>::type>
{
public:
invoker(const implementation_type& impl, Executor& ex)
: impl_(impl),
executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
invoker(const invoker& other)
: impl_(other.impl_),
executor_(other.executor_)
{
}
#if defined(BOOST_ASIO_HAS_MOVE)
invoker(invoker&& other)
: impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
{
}
#endif // defined(BOOST_ASIO_HAS_MOVE)
struct on_invoker_exit
{
invoker* this_;
~on_invoker_exit()
{
if (push_waiting_to_ready(this_->impl_))
{
recycling_allocator<void> allocator;
executor_type ex = this_->executor_;
#if defined(BOOST_ASIO_NO_DEPRECATED)
boost::asio::prefer(
boost::asio::require(
BOOST_ASIO_MOVE_CAST(executor_type)(ex),
execution::blocking.never),
execution::allocator(allocator)
).execute(BOOST_ASIO_MOVE_CAST(invoker)(*this_));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(
boost::asio::prefer(
boost::asio::require(
BOOST_ASIO_MOVE_CAST(executor_type)(ex),
execution::blocking.never),
execution::allocator(allocator)),
BOOST_ASIO_MOVE_CAST(invoker)(*this_));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
}
};
void operator()()
{
// Ensure the next handler, if any, is scheduled on block exit.
on_invoker_exit on_exit = { this };
(void)on_exit;
run_ready_handlers(impl_);
}
private:
typedef typename decay<
typename prefer_result<
Executor,
execution::outstanding_work_t::tracked_t
>::type
>::type executor_type;
implementation_type impl_;
executor_type executor_;
};
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename Executor>
class strand_executor_service::invoker<Executor,
typename enable_if<
!execution::is_executor<Executor>::value
>::type>
{
public:
invoker(const implementation_type& impl, Executor& ex)
@@ -57,13 +183,7 @@ public:
~on_invoker_exit()
{
this_->impl_->mutex_->lock();
this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);
bool more_handlers = this_->impl_->locked_ =
!this_->impl_->ready_queue_.empty();
this_->impl_->mutex_->unlock();
if (more_handlers)
if (push_waiting_to_ready(this_->impl_))
{
Executor ex(this_->work_.get_executor());
recycling_allocator<void> allocator;
@@ -74,21 +194,11 @@ public:
void operator()()
{
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl_.get());
// Ensure the next handler, if any, is scheduled on block exit.
on_invoker_exit on_exit = { this };
(void)on_exit;
// Run all ready handlers. No lock is required since the ready queue is
// accessed only within the strand.
boost::system::error_code ec;
while (scheduler_operation* o = impl_->ready_queue_.front())
{
impl_->ready_queue_.pop();
o->complete(impl_.get(), ec, 0);
}
run_ready_handlers(impl_);
}
private:
@@ -96,6 +206,72 @@ private:
executor_work_guard<Executor> work_;
};
#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
template <typename Executor, typename Function>
inline void strand_executor_service::execute(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
typename enable_if<
can_query<Executor, execution::allocator_t<void> >::value
>::type*)
{
return strand_executor_service::do_execute(impl, ex,
BOOST_ASIO_MOVE_CAST(Function)(function),
boost::asio::query(ex, execution::allocator));
}
template <typename Executor, typename Function>
inline void strand_executor_service::execute(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
typename enable_if<
!can_query<Executor, execution::allocator_t<void> >::value
>::type*)
{
return strand_executor_service::do_execute(impl, ex,
BOOST_ASIO_MOVE_CAST(Function)(function),
std::allocator<void>());
}
template <typename Executor, typename Function, typename Allocator>
void strand_executor_service::do_execute(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
{
typedef typename decay<Function>::type function_type;
// If the executor is not never-blocking, and we are already in the strand,
// then the function can run immediately.
if (boost::asio::query(ex, execution::blocking) != execution::blocking.never
&& running_in_this_thread(impl))
{
// Make a local, non-const copy of the function.
function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
fenced_block b(fenced_block::full);
boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
return;
}
// Allocate and construct an operation to wrap the function.
typedef executor_op<function_type, Allocator> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
"strand_executor", impl.get(), 0, "execute"));
// Add the function to the strand and schedule the strand if required.
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
{
#if defined(BOOST_ASIO_NO_DEPRECATED)
ex.execute(invoker<Executor>(impl, ex));
#else // defined(BOOST_ASIO_NO_DEPRECATED)
execution::execute(ex, invoker<Executor>(impl, ex));
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
}
}
template <typename Executor, typename Function, typename Allocator>
void strand_executor_service::dispatch(const implementation_type& impl,
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
@@ -103,7 +279,7 @@ void strand_executor_service::dispatch(const implementation_type& impl,
typedef typename decay<Function>::type function_type;
// If we are already in the strand then the function can run immediately.
if (call_stack<strand_impl>::contains(impl.get()))
if (running_in_this_thread(impl))
{
// Make a local, non-const copy of the function.
function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
@@ -125,7 +301,11 @@ void strand_executor_service::dispatch(const implementation_type& impl,
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
ex.dispatch(invoker<Executor>(impl, ex), a);
{
boost::asio::dispatch(ex,
allocator_binder<invoker<Executor>, Allocator>(
invoker<Executor>(impl, ex), a));
}
}
// Request invocation of the given function and return immediately.
@@ -147,7 +327,11 @@ void strand_executor_service::post(const implementation_type& impl,
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
ex.post(invoker<Executor>(impl, ex), a);
{
boost::asio::post(ex,
allocator_binder<invoker<Executor>, Allocator>(
invoker<Executor>(impl, ex), a));
}
}
// Request invocation of the given function and return immediately.
@@ -169,7 +353,11 @@ void strand_executor_service::defer(const implementation_type& impl,
bool first = enqueue(impl, p.p);
p.v = p.p = 0;
if (first)
ex.defer(invoker<Executor>(impl, ex), a);
{
boost::asio::defer(ex,
allocator_binder<invoker<Executor>, Allocator>(
invoker<Executor>(impl, ex), a));
}
}
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_executor_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -127,6 +127,30 @@ bool strand_executor_service::running_in_this_thread(
return !!call_stack<strand_impl>::contains(impl.get());
}
bool strand_executor_service::push_waiting_to_ready(implementation_type& impl)
{
impl->mutex_->lock();
impl->ready_queue_.push(impl->waiting_queue_);
bool more_handlers = impl->locked_ = !impl->ready_queue_.empty();
impl->mutex_->unlock();
return more_handlers;
}
void strand_executor_service::run_ready_handlers(implementation_type& impl)
{
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl.get());
// Run all ready handlers. No lock is required since the ready queue is
// accessed only within the strand.
boost::system::error_code ec;
while (scheduler_operation* o = impl->ready_queue_.front())
{
impl->ready_queue_.pop();
o->complete(impl.get(), ec, 0);
}
}
} // namespace detail
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -15,7 +15,6 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/call_stack.hpp>
#include <boost/asio/detail/completion_handler.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
@@ -34,29 +33,12 @@ inline strand_service::strand_impl::strand_impl()
{
}
struct strand_service::on_dispatch_exit
{
io_context_impl* io_context_;
strand_impl* impl_;
~on_dispatch_exit()
{
impl_->mutex_.lock();
impl_->ready_queue_.push(impl_->waiting_queue_);
bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
impl_->mutex_.unlock();
if (more_handlers)
io_context_->post_immediate_completion(impl_, false);
}
};
template <typename Handler>
void strand_service::dispatch(strand_service::implementation_type& impl,
Handler& handler)
{
// If we are already in the strand then the handler can run immediately.
if (call_stack<strand_impl>::contains(impl))
if (running_in_this_thread(impl))
{
fenced_block b(fenced_block::full);
boost_asio_handler_invoke_helpers::invoke(handler, handler);
@@ -64,30 +46,17 @@ void strand_service::dispatch(strand_service::implementation_type& impl,
}
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typedef completion_handler<Handler, io_context::executor_type> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_context_.get_executor());
BOOST_ASIO_HANDLER_CREATION((this->context(),
*p.p, "strand", impl, 0, "dispatch"));
bool dispatch_immediately = do_dispatch(impl, p.p);
operation* o = p.p;
p.v = p.p = 0;
if (dispatch_immediately)
{
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
on_dispatch_exit on_exit = { &io_context_, impl };
(void)on_exit;
completion_handler<Handler>::do_complete(
&io_context_, o, boost::system::error_code(), 0);
}
do_dispatch(impl, o);
}
// Request the io_context to invoke the given handler and return immediately.
@@ -99,10 +68,10 @@ void strand_service::post(strand_service::implementation_type& impl,
boost_asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef completion_handler<Handler> op;
typedef completion_handler<Handler, io_context::executor_type> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
p.p = new (p.v) op(handler, io_context_.get_executor());
BOOST_ASIO_HANDLER_CREATION((this->context(),
*p.p, "strand", impl, 0, "post"));

View File

@@ -2,7 +2,7 @@
// detail/impl/strand_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -44,7 +44,8 @@ struct strand_service::on_do_complete_exit
strand_service::strand_service(boost::asio::io_context& io_context)
: boost::asio::detail::service_base<strand_service>(io_context),
io_context_(boost::asio::use_service<io_context_impl>(io_context)),
io_context_(io_context),
io_context_impl_(boost::asio::use_service<io_context_impl>(io_context)),
mutex_(),
salt_(0)
{
@@ -91,18 +92,44 @@ bool strand_service::running_in_this_thread(
return call_stack<strand_impl>::contains(impl) != 0;
}
bool strand_service::do_dispatch(implementation_type& impl, operation* op)
struct strand_service::on_dispatch_exit
{
io_context_impl* io_context_impl_;
strand_impl* impl_;
~on_dispatch_exit()
{
impl_->mutex_.lock();
impl_->ready_queue_.push(impl_->waiting_queue_);
bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
impl_->mutex_.unlock();
if (more_handlers)
io_context_impl_->post_immediate_completion(impl_, false);
}
};
void strand_service::do_dispatch(implementation_type& impl, operation* op)
{
// If we are running inside the io_context, and no other handler already
// holds the strand lock, then the handler can run immediately.
bool can_dispatch = io_context_.can_dispatch();
bool can_dispatch = io_context_impl_.can_dispatch();
impl->mutex_.lock();
if (can_dispatch && !impl->locked_)
{
// Immediate invocation is allowed.
impl->locked_ = true;
impl->mutex_.unlock();
return true;
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl);
// Ensure the next handler, if any, is scheduled on block exit.
on_dispatch_exit on_exit = { &io_context_impl_, impl };
(void)on_exit;
op->complete(&io_context_impl_, boost::system::error_code(), 0);
return;
}
if (impl->locked_)
@@ -118,10 +145,8 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op)
impl->locked_ = true;
impl->mutex_.unlock();
impl->ready_queue_.push(op);
io_context_.post_immediate_completion(impl, false);
io_context_impl_.post_immediate_completion(impl, false);
}
return false;
}
void strand_service::do_post(implementation_type& impl,
@@ -141,7 +166,7 @@ void strand_service::do_post(implementation_type& impl,
impl->locked_ = true;
impl->mutex_.unlock();
impl->ready_queue_.push(op);
io_context_.post_immediate_completion(impl, is_continuation);
io_context_impl_.post_immediate_completion(impl, is_continuation);
}
}

View File

@@ -0,0 +1,37 @@
//
// detail/impl/thread_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP
#define BOOST_ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
thread_info_base* thread_context::top_of_thread_call_stack()
{
return thread_call_stack::top();
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_IMPL_THREAD_CONTEXT_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/throw_error.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -17,7 +17,6 @@
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/throw_exception.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/detail/push_options.hpp>
@@ -26,16 +25,21 @@ namespace boost {
namespace asio {
namespace detail {
void do_throw_error(const boost::system::error_code& err)
void do_throw_error(
const boost::system::error_code& err
BOOST_ASIO_SOURCE_LOCATION_PARAM)
{
boost::system::system_error e(err);
boost::asio::detail::throw_exception(e);
boost::asio::detail::throw_exception(e BOOST_ASIO_SOURCE_LOCATION_ARG);
}
void do_throw_error(const boost::system::error_code& err, const char* location)
void do_throw_error(
const boost::system::error_code& err,
const char* location
BOOST_ASIO_SOURCE_LOCATION_PARAM)
{
boost::system::system_error e(err, location);
boost::asio::detail::throw_exception(e);
boost::asio::detail::throw_exception(e BOOST_ASIO_SOURCE_LOCATION_ARG);
}
} // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/impl/timer_queue_ptime.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -76,6 +76,12 @@ std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
return impl_.cancel_timer(timer, ops, max_cancelled);
}
void timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer_by_key(
per_timer_data* timer, op_queue<operation>& ops, void* cancellation_key)
{
impl_.cancel_timer_by_key(timer, ops, cancellation_key);
}
void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer(
per_timer_data& target, per_timer_data& source)
{

View File

@@ -2,7 +2,7 @@
// detail/impl/timer_queue_set.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/win_event.ipp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -0,0 +1,267 @@
//
// detail/impl/win_iocp_file_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2023 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)
//
#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP
#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_FILE) \
&& defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
#include <cstring>
#include <sys/stat.h>
#include <boost/asio/detail/win_iocp_file_service.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
win_iocp_file_service::win_iocp_file_service(
execution_context& context)
: execution_context_service_base<win_iocp_file_service>(context),
handle_service_(context),
nt_flush_buffers_file_ex_(0)
{
if (FARPROC nt_flush_buffers_file_ex_ptr = ::GetProcAddress(
::GetModuleHandleA("NTDLL"), "NtFlushBuffersFileEx"))
{
nt_flush_buffers_file_ex_ = reinterpret_cast<nt_flush_buffers_file_ex_fn>(
reinterpret_cast<void*>(nt_flush_buffers_file_ex_ptr));
}
}
void win_iocp_file_service::shutdown()
{
handle_service_.shutdown();
}
boost::system::error_code win_iocp_file_service::open(
win_iocp_file_service::implementation_type& impl,
const char* path, file_base::flags open_flags,
boost::system::error_code& ec)
{
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
DWORD access = 0;
if ((open_flags & file_base::read_only) != 0)
access = GENERIC_READ;
else if ((open_flags & file_base::write_only) != 0)
access = GENERIC_WRITE;
else if ((open_flags & file_base::read_write) != 0)
access = GENERIC_READ | GENERIC_WRITE;
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD disposition = 0;
if ((open_flags & file_base::create) != 0)
{
if ((open_flags & file_base::exclusive) != 0)
disposition = CREATE_NEW;
else
disposition = OPEN_ALWAYS;
}
else
{
if ((open_flags & file_base::truncate) != 0)
disposition = TRUNCATE_EXISTING;
else
disposition = OPEN_EXISTING;
}
DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
if (impl.is_stream_)
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
else
flags |= FILE_FLAG_RANDOM_ACCESS;
if ((open_flags & file_base::sync_all_on_write) != 0)
flags |= FILE_FLAG_WRITE_THROUGH;
HANDLE handle = ::CreateFileA(path, access, share, 0, disposition, flags, 0);
if (handle != INVALID_HANDLE_VALUE)
{
if (disposition == OPEN_ALWAYS && (open_flags & file_base::truncate) != 0)
{
if (!::SetEndOfFile(handle))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
handle_service_.assign(impl, handle, ec);
if (ec)
::CloseHandle(handle);
impl.offset_ = 0;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
uint64_t win_iocp_file_service::size(
const win_iocp_file_service::implementation_type& impl,
boost::system::error_code& ec) const
{
LARGE_INTEGER result;
if (::GetFileSizeEx(native_handle(impl), &result))
{
boost::asio::error::clear(ec);
return static_cast<uint64_t>(result.QuadPart);
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
boost::system::error_code win_iocp_file_service::resize(
win_iocp_file_service::implementation_type& impl,
uint64_t n, boost::system::error_code& ec)
{
LARGE_INTEGER distance;
distance.QuadPart = n;
if (::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
{
BOOL result = ::SetEndOfFile(native_handle(impl));
DWORD last_error = ::GetLastError();
distance.QuadPart = static_cast<LONGLONG>(impl.offset_);
if (!::SetFilePointerEx(native_handle(impl), distance, 0, FILE_BEGIN))
{
result = FALSE;
last_error = ::GetLastError();
}
if (result)
boost::asio::error::clear(ec);
else
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
boost::system::error_code win_iocp_file_service::sync_all(
win_iocp_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
BOOL result = ::FlushFileBuffers(native_handle(impl));
if (result)
{
boost::asio::error::clear(ec);
return ec;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
}
boost::system::error_code win_iocp_file_service::sync_data(
win_iocp_file_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (nt_flush_buffers_file_ex_)
{
io_status_block status = {};
if (!nt_flush_buffers_file_ex_(native_handle(impl),
flush_flags_file_data_sync_only, 0, 0, &status))
{
boost::asio::error::clear(ec);
return ec;
}
}
return sync_all(impl, ec);
}
uint64_t win_iocp_file_service::seek(
win_iocp_file_service::implementation_type& impl, int64_t offset,
file_base::seek_basis whence, boost::system::error_code& ec)
{
DWORD method;
switch (whence)
{
case file_base::seek_set:
method = FILE_BEGIN;
break;
case file_base::seek_cur:
method = FILE_BEGIN;
offset = static_cast<int64_t>(impl.offset_) + offset;
break;
case file_base::seek_end:
method = FILE_END;
break;
default:
ec = boost::asio::error::invalid_argument;
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
LARGE_INTEGER distance, new_offset;
distance.QuadPart = offset;
if (::SetFilePointerEx(native_handle(impl), distance, &new_offset, method))
{
impl.offset_ = new_offset.QuadPart;
boost::asio::error::clear(ec);
return impl.offset_;
}
else
{
DWORD last_error = ::GetLastError();
ec.assign(last_error, boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// && defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_FILE_SERVICE_IPP

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_handle_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -69,6 +69,7 @@ public:
win_iocp_handle_service::win_iocp_handle_service(execution_context& context)
: execution_context_service_base<win_iocp_handle_service>(context),
iocp_service_(boost::asio::use_service<win_iocp_io_context>(context)),
nt_set_info_(0),
mutex_(),
impl_list_(0)
{
@@ -183,11 +184,15 @@ boost::system::error_code win_iocp_handle_service::assign(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
if (iocp_service_.register_handle(handle, ec))
{
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
impl.handle_ = handle;
ec = boost::system::error_code();
@@ -222,9 +227,47 @@ boost::system::error_code win_iocp_handle_service::close(
ec = boost::system::error_code();
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
win_iocp_handle_service::native_handle_type win_iocp_handle_service::release(
win_iocp_handle_service::implementation_type& impl,
boost::system::error_code& ec)
{
if (!is_open(impl))
return INVALID_HANDLE_VALUE;
cancel(impl, ec);
if (ec)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return INVALID_HANDLE_VALUE;
}
nt_set_info_fn fn = get_nt_set_info();
if (fn == 0)
{
ec = boost::asio::error::operation_not_supported;
BOOST_ASIO_ERROR_LOCATION(ec);
return INVALID_HANDLE_VALUE;
}
ULONG_PTR iosb[2] = { 0, 0 };
void* info[2] = { 0, 0 };
if (fn(impl.handle_, iosb, &info, sizeof(info),
61 /* FileReplaceCompletionInformation */))
{
ec = boost::asio::error::operation_not_supported;
BOOST_ASIO_ERROR_LOCATION(ec);
return INVALID_HANDLE_VALUE;
}
native_handle_type tmp = impl.handle_;
impl.handle_ = INVALID_HANDLE_VALUE;
return tmp;
}
boost::system::error_code win_iocp_handle_service::cancel(
win_iocp_handle_service::implementation_type& impl,
boost::system::error_code& ec)
@@ -232,6 +275,7 @@ boost::system::error_code win_iocp_handle_service::cancel(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -243,7 +287,8 @@ boost::system::error_code win_iocp_handle_service::cancel(
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(
reinterpret_cast<void*>(cancel_io_ex_ptr));
if (!cancel_io_ex(impl.handle_, 0))
{
DWORD last_error = ::GetLastError();
@@ -292,6 +337,7 @@ boost::system::error_code win_iocp_handle_service::cancel(
ec = boost::asio::error::operation_not_supported;
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -302,6 +348,7 @@ size_t win_iocp_handle_service::do_write(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -315,6 +362,7 @@ size_t win_iocp_handle_service::do_write(
overlapped_wrapper overlapped(ec);
if (ec)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -330,6 +378,7 @@ size_t win_iocp_handle_service::do_write(
{
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
@@ -343,6 +392,7 @@ size_t win_iocp_handle_service::do_write(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -394,6 +444,7 @@ size_t win_iocp_handle_service::do_read(
if (!is_open(impl))
{
ec = boost::asio::error::bad_descriptor;
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -407,6 +458,7 @@ size_t win_iocp_handle_service::do_read(
overlapped_wrapper overlapped(ec);
if (ec)
{
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
@@ -429,6 +481,7 @@ size_t win_iocp_handle_service::do_read(
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
}
BOOST_ASIO_ERROR_LOCATION(ec);
return 0;
}
}
@@ -449,6 +502,7 @@ size_t win_iocp_handle_service::do_read(
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
}
BOOST_ASIO_ERROR_LOCATION(ec);
return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;
}
@@ -515,6 +569,47 @@ void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
}
}
win_iocp_handle_service::nt_set_info_fn
win_iocp_handle_service::get_nt_set_info()
{
void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0);
if (!ptr)
{
if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL"))
ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile"));
// On failure, set nt_set_info_ to a special value to indicate that the
// NtSetInformationFile function is unavailable. That way we won't bother
// trying to look it up again.
interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this);
}
return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr);
}
void* win_iocp_handle_service::interlocked_compare_exchange_pointer(
void** dest, void* exch, void* cmp)
{
#if defined(_M_IX86)
return reinterpret_cast<void*>(InterlockedCompareExchange(
reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
reinterpret_cast<LONG>(cmp)));
#else
return InterlockedCompareExchangePointer(dest, exch, cmp);
#endif
}
void* win_iocp_handle_service::interlocked_exchange_pointer(
void** dest, void* val)
{
#if defined(_M_IX86)
return reinterpret_cast<void*>(InterlockedExchange(
reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
#else
return InterlockedExchangePointer(dest, val);
#endif
}
} // namespace detail
} // namespace asio
} // namespace boost

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_io_context.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -77,10 +77,27 @@ std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue,
mutex::scoped_lock lock(dispatch_mutex_);
op_queue<win_iocp_operation> ops;
std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
lock.unlock();
post_deferred_completions(ops);
return n;
}
template <typename Time_Traits>
void win_iocp_io_context::cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key)
{
// If the service has been shut down we silently ignore the cancellation.
if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
return;
mutex::scoped_lock lock(dispatch_mutex_);
op_queue<win_iocp_operation> ops;
queue.cancel_timer_by_key(timer, ops, cancellation_key);
lock.unlock();
post_deferred_completions(ops);
}
template <typename Time_Traits>
void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data& to,

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_io_context.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -52,7 +52,7 @@ struct win_iocp_io_context::thread_function
struct win_iocp_io_context::work_finished_on_block_exit
{
~work_finished_on_block_exit()
~work_finished_on_block_exit() BOOST_ASIO_NOEXCEPT_IF(false)
{
io_context_->work_finished();
}
@@ -114,6 +114,7 @@ win_iocp_io_context::~win_iocp_io_context()
{
if (thread_.get())
{
stop();
thread_->join();
thread_.reset();
}
@@ -132,6 +133,7 @@ void win_iocp_io_context::shutdown()
if (thread_.get())
{
stop();
thread_->join();
thread_.reset();
::InterlockedDecrement(&outstanding_work_);
@@ -167,7 +169,10 @@ void win_iocp_io_context::shutdown()
}
if (timer_thread_.get())
{
timer_thread_->join();
timer_thread_.reset();
}
}
boost::system::error_code win_iocp_io_context::register_handle(
@@ -199,7 +204,7 @@ size_t win_iocp_io_context::run(boost::system::error_code& ec)
thread_call_stack::context ctx(this, this_thread);
size_t n = 0;
while (do_one(INFINITE, ec))
while (do_one(INFINITE, this_thread, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
@@ -217,7 +222,7 @@ size_t win_iocp_io_context::run_one(boost::system::error_code& ec)
win_iocp_thread_info this_thread;
thread_call_stack::context ctx(this, this_thread);
return do_one(INFINITE, ec);
return do_one(INFINITE, this_thread, ec);
}
size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec)
@@ -232,7 +237,7 @@ size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec)
win_iocp_thread_info this_thread;
thread_call_stack::context ctx(this, this_thread);
return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec);
return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec);
}
size_t win_iocp_io_context::poll(boost::system::error_code& ec)
@@ -248,7 +253,7 @@ size_t win_iocp_io_context::poll(boost::system::error_code& ec)
thread_call_stack::context ctx(this, this_thread);
size_t n = 0;
while (do_one(0, ec))
while (do_one(0, this_thread, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
@@ -266,7 +271,7 @@ size_t win_iocp_io_context::poll_one(boost::system::error_code& ec)
win_iocp_thread_info this_thread;
thread_call_stack::context ctx(this, this_thread);
return do_one(0, ec);
return do_one(0, this_thread, ec);
}
void win_iocp_io_context::stop()
@@ -286,6 +291,17 @@ void win_iocp_io_context::stop()
}
}
bool win_iocp_io_context::can_dispatch()
{
return thread_call_stack::contains(this) != 0;
}
void win_iocp_io_context::capture_current_exception()
{
if (thread_info_base* this_thread = thread_call_stack::contains(this))
this_thread->capture_current_exception();
}
void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)
{
// Flag the operation as ready.
@@ -395,7 +411,8 @@ void win_iocp_io_context::on_completion(win_iocp_operation* op,
}
}
size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
size_t win_iocp_io_context::do_one(DWORD msec,
win_iocp_thread_info& this_thread, boost::system::error_code& ec)
{
for (;;)
{
@@ -457,6 +474,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
(void)on_exit;
op->complete(this, result_ec, bytes_transferred);
this_thread.rethrow_pending_exception();
ec = boost::system::error_code();
return 1;
}
@@ -513,6 +531,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
DWORD win_iocp_io_context::get_gqcs_timeout()
{
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
@@ -525,6 +544,9 @@ DWORD win_iocp_io_context::get_gqcs_timeout()
return INFINITE;
return default_gqcs_timeout;
#else // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)
return INFINITE;
#endif // !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)
}
void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue)

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_serial_port_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -47,6 +47,7 @@ boost::system::error_code win_iocp_serial_port_service::open(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -62,6 +63,7 @@ boost::system::error_code win_iocp_serial_port_service::open(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -76,21 +78,34 @@ boost::system::error_code win_iocp_serial_port_service::open(
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
// Set some default serial port parameters. This implementation does not
// support changing these, so they might as well be in a known state.
// support changing all of these, so they might as well be in a known state.
dcb.fBinary = TRUE; // Win32 only supports binary mode.
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE; // Do not ignore NULL characters.
dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
dcb.BaudRate = CBR_9600; // 9600 baud by default
dcb.ByteSize = 8; // 8 bit bytes
dcb.fOutxCtsFlow = FALSE; // No flow control
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fParity = FALSE; // No parity
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT; // One stop bit
if (!::SetCommState(handle, &dcb))
{
DWORD last_error = ::GetLastError();
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -109,6 +124,7 @@ boost::system::error_code win_iocp_serial_port_service::open(
::CloseHandle(handle);
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -133,6 +149,7 @@ boost::system::error_code win_iocp_serial_port_service::do_set_option(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -144,6 +161,7 @@ boost::system::error_code win_iocp_serial_port_service::do_set_option(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -166,6 +184,7 @@ boost::system::error_code win_iocp_serial_port_service::do_get_option(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}

View File

@@ -2,7 +2,7 @@
// detail/impl/win_iocp_socket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -73,6 +73,7 @@ void win_iocp_socket_service_base::construct(
void win_iocp_socket_service_base::base_move_construct(
win_iocp_socket_service_base::base_implementation_type& impl,
win_iocp_socket_service_base::base_implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.socket_ = other_impl.socket_;
other_impl.socket_ = invalid_socket;
@@ -250,7 +251,8 @@ boost::system::error_code win_iocp_socket_service_base::cancel(
{
// The version of Windows supports cancellation from any thread.
typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(
reinterpret_cast<void*>(cancel_io_ex_ptr));
socket_type sock = impl.socket_;
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
if (!cancel_io_ex(sock_as_handle, 0))
@@ -409,9 +411,8 @@ void win_iocp_socket_service_base::start_send_op(
void win_iocp_socket_service_base::start_send_to_op(
win_iocp_socket_service_base::base_implementation_type& impl,
WSABUF* buffers, std::size_t buffer_count,
const socket_addr_type* addr, int addrlen,
socket_base::message_flags flags, operation* op)
WSABUF* buffers, std::size_t buffer_count, const void* addr,
int addrlen, socket_base::message_flags flags, operation* op)
{
update_cancellation_thread_id(impl);
iocp_service_.work_started();
@@ -422,8 +423,8 @@ void win_iocp_socket_service_base::start_send_to_op(
{
DWORD bytes_transferred = 0;
int result = ::WSASendTo(impl.socket_, buffers,
static_cast<DWORD>(buffer_count),
&bytes_transferred, flags, addr, addrlen, op, 0);
static_cast<DWORD>(buffer_count), &bytes_transferred, flags,
static_cast<const socket_addr_type*>(addr), addrlen, op, 0);
DWORD last_error = ::WSAGetLastError();
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
@@ -465,29 +466,30 @@ void win_iocp_socket_service_base::start_receive_op(
}
}
void win_iocp_socket_service_base::start_null_buffers_receive_op(
int win_iocp_socket_service_base::start_null_buffers_receive_op(
win_iocp_socket_service_base::base_implementation_type& impl,
socket_base::message_flags flags, reactor_op* op)
socket_base::message_flags flags, reactor_op* op, operation* iocp_op)
{
if ((impl.state_ & socket_ops::stream_oriented) != 0)
{
// For stream sockets on Windows, we may issue a 0-byte overlapped
// WSARecv to wait until there is data available on the socket.
::WSABUF buf = { 0, 0 };
start_receive_op(impl, &buf, 1, flags, false, op);
start_receive_op(impl, &buf, 1, flags, false, iocp_op);
return -1;
}
else
{
start_reactor_op(impl,
(flags & socket_base::message_out_of_band)
? select_reactor::except_op : select_reactor::read_op,
op);
int op_type = (flags & socket_base::message_out_of_band)
? select_reactor::except_op : select_reactor::read_op;
start_reactor_op(impl, op_type, op);
return op_type;
}
}
void win_iocp_socket_service_base::start_receive_from_op(
win_iocp_socket_service_base::base_implementation_type& impl,
WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
WSABUF* buffers, std::size_t buffer_count, void* addr,
socket_base::message_flags flags, int* addrlen, operation* op)
{
update_cancellation_thread_id(impl);
@@ -500,8 +502,8 @@ void win_iocp_socket_service_base::start_receive_from_op(
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int result = ::WSARecvFrom(impl.socket_, buffers,
static_cast<DWORD>(buffer_count),
&bytes_transferred, &recv_flags, addr, addrlen, op, 0);
static_cast<DWORD>(buffer_count), &bytes_transferred, &recv_flags,
static_cast<socket_addr_type*>(addr), addrlen, op, 0);
DWORD last_error = ::WSAGetLastError();
if (last_error == ERROR_PORT_UNREACHABLE)
last_error = WSAECONNREFUSED;
@@ -546,11 +548,17 @@ void win_iocp_socket_service_base::start_accept_op(
void win_iocp_socket_service_base::restart_accept_op(
socket_type s, socket_holder& new_socket, int family, int type,
int protocol, void* output_buffer, DWORD address_length, operation* op)
int protocol, void* output_buffer, DWORD address_length,
long* cancel_requested, operation* op)
{
new_socket.reset();
iocp_service_.work_started();
// Check if we were cancelled after the first AcceptEx completed.
if (cancel_requested)
if (::InterlockedExchangeAdd(cancel_requested, 0) == 1)
iocp_service_.on_completion(op, boost::asio::error::operation_aborted);
boost::system::error_code ec;
new_socket.reset(socket_ops::socket(family, type, protocol, ec));
if (new_socket.get() == invalid_socket)
@@ -564,7 +572,19 @@ void win_iocp_socket_service_base::restart_accept_op(
if (!result && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error);
else
{
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
if (cancel_requested)
{
if (::InterlockedExchangeAdd(cancel_requested, 0) == 1)
{
HANDLE sock_as_handle = reinterpret_cast<HANDLE>(s);
::CancelIoEx(sock_as_handle, op);
}
}
#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
iocp_service_.on_pending(op);
}
}
}
@@ -586,10 +606,10 @@ void win_iocp_socket_service_base::start_reactor_op(
iocp_service_.post_immediate_completion(op, false);
}
void win_iocp_socket_service_base::start_connect_op(
int win_iocp_socket_service_base::start_connect_op(
win_iocp_socket_service_base::base_implementation_type& impl,
int family, int type, const socket_addr_type* addr,
std::size_t addrlen, win_iocp_socket_connect_op_base* op)
int family, int type, const void* addr, std::size_t addrlen,
win_iocp_socket_connect_op_base* op, operation* iocp_op)
{
// If ConnectEx is available, use that.
if (family == BOOST_ASIO_OS_DEF(AF_INET)
@@ -614,7 +634,7 @@ void win_iocp_socket_service_base::start_connect_op(
if (op->ec_ && op->ec_ != boost::asio::error::invalid_argument)
{
iocp_service_.post_immediate_completion(op, false);
return;
return -1;
}
op->connect_ex_ = true;
@@ -622,13 +642,14 @@ void win_iocp_socket_service_base::start_connect_op(
iocp_service_.work_started();
BOOL result = connect_ex(impl.socket_,
addr, static_cast<int>(addrlen), 0, 0, 0, op);
static_cast<const socket_addr_type*>(addr),
static_cast<int>(addrlen), 0, 0, 0, iocp_op);
DWORD last_error = ::WSAGetLastError();
if (!result && last_error != WSA_IO_PENDING)
iocp_service_.on_completion(op, last_error);
iocp_service_.on_completion(iocp_op, last_error);
else
iocp_service_.on_pending(op);
return;
iocp_service_.on_pending(iocp_op);
return -1;
}
}
@@ -648,12 +669,13 @@ void win_iocp_socket_service_base::start_connect_op(
op->ec_ = boost::system::error_code();
r.start_op(select_reactor::connect_op, impl.socket_,
impl.reactor_data_, op, false, false);
return;
return select_reactor::connect_op;
}
}
}
r.post_immediate_completion(op, false);
return -1;
}
void win_iocp_socket_service_base::close_for_destruction(

View File

@@ -2,7 +2,7 @@
// detail/impl/win_mutex.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/win_object_handle_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -214,6 +214,7 @@ boost::system::error_code win_object_handle_service::assign(
if (is_open(impl))
{
ec = boost::asio::error::already_open;
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -271,6 +272,7 @@ boost::system::error_code win_object_handle_service::close(
ec = boost::system::error_code();
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -313,6 +315,7 @@ boost::system::error_code win_object_handle_service::cancel(
ec = boost::asio::error::bad_descriptor;
}
BOOST_ASIO_ERROR_LOCATION(ec);
return ec;
}
@@ -327,6 +330,7 @@ void win_object_handle_service::wait(
DWORD last_error = ::GetLastError();
ec = boost::system::error_code(last_error,
boost::asio::error::get_system_category());
BOOST_ASIO_ERROR_LOCATION(ec);
break;
}
case WAIT_OBJECT_0:

View File

@@ -2,7 +2,7 @@
// detail/impl/win_static_mutex.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/win_thread.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/win_tss_ptr.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/winrt_ssocket_service_base.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)
@@ -67,6 +67,7 @@ void winrt_ssocket_service_base::construct(
void winrt_ssocket_service_base::base_move_construct(
winrt_ssocket_service_base::base_implementation_type& impl,
winrt_ssocket_service_base::base_implementation_type& other_impl)
BOOST_ASIO_NOEXCEPT
{
impl.socket_ = other_impl.socket_;
other_impl.socket_ = nullptr;
@@ -139,12 +140,8 @@ boost::system::error_code winrt_ssocket_service_base::close(
winrt_ssocket_service_base::base_implementation_type& impl,
boost::system::error_code& ec)
{
if (impl.socket_)
{
delete impl.socket_;
impl.socket_ = nullptr;
}
delete impl.socket_;
impl.socket_ = nullptr;
ec = boost::system::error_code();
return ec;
}
@@ -186,7 +183,7 @@ std::size_t winrt_ssocket_service_base::do_get_endpoint(
: impl.socket_->Information->RemotePort);
unsigned long scope = 0;
switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
switch (static_cast<const socket_addr_type*>(addr)->sa_family)
{
case BOOST_ASIO_OS_DEF(AF_INET):
if (addr_len < sizeof(sockaddr_in4_type))
@@ -355,7 +352,7 @@ boost::system::error_code winrt_ssocket_service_base::do_connect(
char addr_string[max_addr_v6_str_len];
unsigned short port;
switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
switch (static_cast<const socket_addr_type*>(addr)->sa_family)
{
case BOOST_ASIO_OS_DEF(AF_INET):
socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
@@ -405,7 +402,7 @@ void winrt_ssocket_service_base::start_connect_op(
char addr_string[max_addr_v6_str_len];
unsigned short port = 0;
switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
switch (static_cast<const socket_addr_type*>(addr)->sa_family)
{
case BOOST_ASIO_OS_DEF(AF_INET):
socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),

View File

@@ -2,7 +2,7 @@
// detail/impl/winrt_timer_scheduler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/winrt_timer_scheduler.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)

View File

@@ -2,7 +2,7 @@
// detail/impl/winsock_init.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2023 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)