75.00% Lines (6/8) 100.00% Functions (1/1)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2026 Steve Gerbino 3   // Copyright (c) 2026 Steve Gerbino
4   // Copyright (c) 2026 Michael Vandeberg 4   // Copyright (c) 2026 Michael Vandeberg
5   // 5   //
6   // Distributed under the Boost Software License, Version 1.0. (See accompanying 6   // Distributed under the Boost Software License, Version 1.0. (See accompanying
7   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8   // 8   //
9   // Official repository: https://github.com/cppalliance/corosio 9   // Official repository: https://github.com/cppalliance/corosio
10   // 10   //
11   11  
12   #ifndef BOOST_COROSIO_NATIVE_DETAIL_MAKE_ERR_HPP 12   #ifndef BOOST_COROSIO_NATIVE_DETAIL_MAKE_ERR_HPP
13   #define BOOST_COROSIO_NATIVE_DETAIL_MAKE_ERR_HPP 13   #define BOOST_COROSIO_NATIVE_DETAIL_MAKE_ERR_HPP
14   14  
15   #include <boost/corosio/detail/config.hpp> 15   #include <boost/corosio/detail/config.hpp>
16   #include <boost/corosio/detail/platform.hpp> 16   #include <boost/corosio/detail/platform.hpp>
17   #include <boost/capy/error.hpp> 17   #include <boost/capy/error.hpp>
18   #include <system_error> 18   #include <system_error>
19   19  
20   #if BOOST_COROSIO_POSIX 20   #if BOOST_COROSIO_POSIX
21   #include <errno.h> 21   #include <errno.h>
22   #else 22   #else
23   #ifndef WIN32_LEAN_AND_MEAN 23   #ifndef WIN32_LEAN_AND_MEAN
24   #define WIN32_LEAN_AND_MEAN 24   #define WIN32_LEAN_AND_MEAN
25   #endif 25   #endif
26   #include <Windows.h> 26   #include <Windows.h>
27   #endif 27   #endif
28   28  
29   namespace boost::corosio::detail { 29   namespace boost::corosio::detail {
30   30  
31   #if BOOST_COROSIO_POSIX 31   #if BOOST_COROSIO_POSIX
32   32  
33   /** Convert a POSIX errno value to std::error_code. 33   /** Convert a POSIX errno value to std::error_code.
34   34  
35   Maps ECANCELED to capy::error::canceled. 35   Maps ECANCELED to capy::error::canceled.
36   36  
37   @param errn The errno value. 37   @param errn The errno value.
38   @return The corresponding std::error_code. 38   @return The corresponding std::error_code.
39   */ 39   */
40   inline std::error_code 40   inline std::error_code
HITCBC 41   221 make_err(int errn) noexcept 41   518 make_err(int errn) noexcept
42   { 42   {
HITCBC 43   221 if (errn == 0) 43   518 if (errn == 0)
MISUBC 44   return {}; 44   return {};
45   45  
HITCBC 46   221 if (errn == ECANCELED) 46   518 if (errn == ECANCELED)
MISUBC 47   return capy::error::canceled; 47   return capy::error::canceled;
48   48  
49   // Part of the portable wait contract; system_category's condition 49   // Part of the portable wait contract; system_category's condition
50   // mapping varies by C++ runtime. 50   // mapping varies by C++ runtime.
HITCBC 51   221 if (errn == ENOTSUP) 51   518 if (errn == ENOTSUP)
HITCBC 52   24 return std::make_error_code(std::errc::operation_not_supported); 52   24 return std::make_error_code(std::errc::operation_not_supported);
53   53  
HITCBC 54   197 return std::error_code(errn, std::system_category()); 54   494 return std::error_code(errn, std::system_category());
55   } 55   }
56   56  
57   #else 57   #else
58   58  
59   /** Convert a Windows error code to std::error_code. 59   /** Convert a Windows error code to std::error_code.
60   60  
61   Maps ERROR_OPERATION_ABORTED and ERROR_CANCELLED to 61   Maps ERROR_OPERATION_ABORTED and ERROR_CANCELLED to
62 - capy::error::canceled, and ERROR_HANDLE_EOF to capy::error::eof. 62 + capy::error::canceled, ERROR_HANDLE_EOF to capy::error::eof, and
63 - Every other code passes through std::system_category(). 63 + the contracted WSA/Win32 codes to the `std::errc` conditions the
  64 + library promises. Every other code passes through
  65 + std::system_category().
64   66  
65   ERROR_NETNAME_DELETED (64) is deliberately not mapped here: IOCP 67   ERROR_NETNAME_DELETED (64) is deliberately not mapped here: IOCP
66   delivers it both for a local closesocket() that cancels pending I/O 68   delivers it both for a local closesocket() that cancels pending I/O
67   and for a remote RST, so it can only be disambiguated per operation 69   and for a remote RST, so it can only be disambiguated per operation
68   kind at the IOCP decode sites (see iocp_make_err in win_overlapped_op). 70   kind at the IOCP decode sites (see iocp_make_err in win_overlapped_op).
69   71  
70   @param dwError The Windows error code (DWORD). 72   @param dwError The Windows error code (DWORD).
71   @return The corresponding std::error_code. 73   @return The corresponding std::error_code.
72   */ 74   */
73   inline std::error_code 75   inline std::error_code
74   make_err(unsigned long dwError) noexcept 76   make_err(unsigned long dwError) noexcept
75   { 77   {
76   if (dwError == 0) 78   if (dwError == 0)
77   return {}; 79   return {};
78   80  
79   if (dwError == ERROR_OPERATION_ABORTED || dwError == ERROR_CANCELLED) 81   if (dwError == ERROR_OPERATION_ABORTED || dwError == ERROR_CANCELLED)
80   return capy::error::canceled; 82   return capy::error::canceled;
81   83  
82   if (dwError == ERROR_HANDLE_EOF) 84   if (dwError == ERROR_HANDLE_EOF)
83   return capy::error::eof; 85   return capy::error::eof;
84   86  
85   // Part of the portable wait, adoption, bind, and seek contracts; 87   // Part of the portable wait, adoption, bind, and seek contracts;
86   // system_category's condition mapping for WSA codes varies by 88   // system_category's condition mapping for WSA codes varies by
87   // toolchain. 89   // toolchain.
88   if (dwError == WSAEOPNOTSUPP) 90   if (dwError == WSAEOPNOTSUPP)
89   return std::make_error_code(std::errc::operation_not_supported); 91   return std::make_error_code(std::errc::operation_not_supported);
90   if (dwError == WSAENOTSOCK) 92   if (dwError == WSAENOTSOCK)
91   return std::make_error_code(std::errc::not_a_socket); 93   return std::make_error_code(std::errc::not_a_socket);
92   if (dwError == WSAEAFNOSUPPORT) 94   if (dwError == WSAEAFNOSUPPORT)
93   return std::make_error_code( 95   return std::make_error_code(
94   std::errc::address_family_not_supported); 96   std::errc::address_family_not_supported);
95   if (dwError == WSAEPROTOTYPE) 97   if (dwError == WSAEPROTOTYPE)
96   return std::make_error_code(std::errc::wrong_protocol_type); 98   return std::make_error_code(std::errc::wrong_protocol_type);
97   if (dwError == WSAEADDRINUSE) 99   if (dwError == WSAEADDRINUSE)
98   return std::make_error_code(std::errc::address_in_use); 100   return std::make_error_code(std::errc::address_in_use);
99   if (dwError == WSAEADDRNOTAVAIL) 101   if (dwError == WSAEADDRNOTAVAIL)
100   return std::make_error_code(std::errc::address_not_available); 102   return std::make_error_code(std::errc::address_not_available);
101   if (dwError == ERROR_NEGATIVE_SEEK) 103   if (dwError == ERROR_NEGATIVE_SEEK)
102   return std::make_error_code(std::errc::invalid_argument); 104   return std::make_error_code(std::errc::invalid_argument);
  105 + // A thread the system will not give is the same retryable
  106 + // condition POSIX spells EAGAIN, which is what the contract
  107 + // promises; no toolchain maps the Win32 spelling to it.
  108 + if (dwError == ERROR_MAX_THRDS_REACHED)
  109 + return std::make_error_code(
  110 + std::errc::resource_unavailable_try_again);
103   111  
104   return std::error_code(static_cast<int>(dwError), std::system_category()); 112   return std::error_code(static_cast<int>(dwError), std::system_category());
105   } 113   }
106   114  
107   #endif 115   #endif
108   116  
109   } // namespace boost::corosio::detail 117   } // namespace boost::corosio::detail
110   118  
111   #endif 119   #endif