From 99276c2b05ebebe21362aba848784067b1122c3a Mon Sep 17 00:00:00 2001 From: Alexey Ozeritskiy Date: Wed, 12 Nov 2025 09:13:46 +0000 Subject: [PATCH] Better error handling --- coroio/socket.hpp | 59 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/coroio/socket.hpp b/coroio/socket.hpp index cbbf930..fe70044 100644 --- a/coroio/socket.hpp +++ b/coroio/socket.hpp @@ -128,8 +128,9 @@ class TSocketBase: public TSocketBase { /** * @brief Asynchronously reads data from the socket into the provided buffer. * - * When awaited, this method suspends the current coroutine until the read operation - * completes and then returns the number of bytes read. + * Semantics: returns bytes read (>0), 0 on closure, and a negative value + * (retry hint) for transient errors (e.g. EINTR/EAGAIN/EINPROGRESS). Non-retryable + * errors throw std::system_error. * * @param buf Pointer to the destination buffer. * @param size The number of bytes to read. @@ -150,8 +151,9 @@ class TSocketBase: public TSocketBase { /** * @brief Forces a read operation on the next event loop iteration. * - * Similar to @ref ReadSome(), but this variant ensures that the read is deferred - * to the next iteration of the event loop. + * Semantics: returns bytes read (>0), 0 on closure, and a negative value + * (retry hint) for transient errors (e.g. EINTR/EAGAIN/EINPROGRESS). Non-retryable + * errors throw std::system_error. * * @param buf Pointer to the buffer where data will be stored. * @param size Number of bytes to read. @@ -176,8 +178,9 @@ class TSocketBase: public TSocketBase { /** * @brief Asynchronously writes data from the provided buffer to the socket. * - * This method suspends the current coroutine until the data is written, and then returns - * the number of bytes successfully written. + * Semantics: returns bytes written (>0), 0 if nothing written, and a negative value + * (retry hint) for transient errors (e.g. EINTR/EAGAIN/EINPROGRESS). Non-retryable + * errors throw std::system_error. * * @param buf Pointer to the data to be written. * @param size The number of bytes to write. @@ -659,6 +662,17 @@ class TPollerDrivenSocket: public TSocket auto await_resume() { auto ret = poller->Result(); if (ret < 0) { +#ifdef _WIN32 + int err = -ret; + if (err == WSAEWOULDBLOCK || err == WSAEINTR || err == WSAEINPROGRESS) { + return ret; // retry hint + } +#else + int err = -ret; + if (err == EINTR || err == EAGAIN || err == EINPROGRESS) { + return ret; // retry hint + } +#endif throw std::system_error(-ret, std::generic_category()); } return ret; @@ -694,6 +708,17 @@ class TPollerDrivenSocket: public TSocket auto await_resume() { auto ret = poller->Result(); if (ret < 0) { +#ifdef _WIN32 + int err = -ret; + if (err == WSAEWOULDBLOCK || err == WSAEINTR || err == WSAEINPROGRESS) { + return ret; // retry hint + } +#else + int err = -ret; + if (err == EINTR || err == EAGAIN || err == EINPROGRESS) { + return ret; // retry hint + } +#endif throw std::system_error(-ret, std::generic_category()); } return ret; @@ -776,6 +801,17 @@ class TPollerDrivenFileHandle: public TFileHandle auto await_resume() { auto ret = poller->Result(); if (ret < 0) { +#ifdef _WIN32 + int err = -ret; + if (err == WSAEWOULDBLOCK || err == WSAEINTR || err == WSAEINPROGRESS) { + return ret; // retry hint + } +#else + int err = -ret; + if (err == EINTR || err == EAGAIN || err == EINPROGRESS) { + return ret; // retry hint + } +#endif throw std::system_error(-ret, std::generic_category()); } return ret; @@ -811,6 +847,17 @@ class TPollerDrivenFileHandle: public TFileHandle auto await_resume() { auto ret = poller->Result(); if (ret < 0) { +#ifdef _WIN32 + int err = -ret; + if (err == WSAEWOULDBLOCK || err == WSAEINTR || err == WSAEINPROGRESS) { + return ret; // retry hint + } +#else + int err = -ret; + if (err == EINTR || err == EAGAIN || err == EINPROGRESS) { + return ret; // retry hint + } +#endif throw std::system_error(-ret, std::generic_category()); } return ret;