⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Conversation

@sgerbino
Copy link
Collaborator

@sgerbino sgerbino commented Jan 28, 2026

Summary by CodeRabbit

  • Refactor

    • Standardized platform/feature detection and centralized backend selection for clearer cross-platform builds.
  • New Features

    • Added complete async acceptor implementations for epoll and select backends, expanding native accept support across platforms.
  • Bug Fixes

    • Improved cancellation and error-handling behavior across asynchronous socket operations for more consistent and reliable I/O.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

Adds a platform feature-detection header exposing BOOST_COROSIO_HAS_IOCP/EPOLL/KQUEUE/SELECT and BOOST_COROSIO_POSIX, replaces OS-specific preprocessor guards across the codebase with these macros, and introduces/rewires select- and epoll-based acceptor implementations plus per-op cancellation semantics.

Changes

Cohort / File(s) Summary
Platform Detection Framework
include/boost/corosio/detail/platform.hpp
New header defining macros: BOOST_COROSIO_HAS_IOCP, BOOST_COROSIO_HAS_EPOLL, BOOST_COROSIO_HAS_KQUEUE, BOOST_COROSIO_HAS_SELECT, BOOST_COROSIO_POSIX.
Context & Backend Selection
include/boost/corosio/io_context.hpp, include/boost/corosio/iocp_context.hpp, include/boost/corosio/epoll_context.hpp, include/boost/corosio/select_context.hpp, src/corosio/src/*_context.cpp
Replaced platform guards with feature macros and added platform.hpp includes; backend aliasing now driven by BOOST_COROSIO_HAS_* macros.
Socket API & Endpoint Conversion
include/boost/corosio/socket.hpp, src/corosio/src/detail/endpoint_convert.hpp, src/corosio/src/socket.cpp
Switched _WIN32 / POSIX checks to feature macros; native_handle_type and system header includes gated by macros.
IOCP Backend
src/corosio/src/detail/iocp/* (completion_key.hpp, mutex.hpp, overlapped_op.hpp, resolver_service.{cpp,hpp}, scheduler.{cpp,hpp}, sockets.{cpp,hpp}, timers*, windows., wsa_init., etc.)
Replaced _WIN32 guards with BOOST_COROSIO_HAS_IOCP, added platform.hpp includes, and adjusted minor error-path defaults; no public API changes.
EPOLL Core & Refactor
src/corosio/src/detail/epoll/op.hpp, .../sockets.cpp, .../sockets.hpp, .../scheduler.*
Replaced __linux__ guards with BOOST_COROSIO_HAS_EPOLL; renamed op executor field dex; added pure-virtual cancel() to op base and cancel overrides; acceptor logic moved into new acceptors files.
EPOLL Acceptor (new)
src/corosio/src/detail/epoll/acceptors.hpp, src/corosio/src/detail/epoll/acceptors.cpp, src/corosio/src/epoll_context.cpp
New epoll-based acceptor_service, acceptor_impl, and accept_op with lifecycle, registration, cancellation, and endpoint handling; integrated into epoll context.
SELECT Core & Refactor
src/corosio/src/detail/select/op.hpp, .../sockets.cpp, .../sockets.hpp, .../scheduler.*
Replaced !_WIN32 guards with BOOST_COROSIO_HAS_SELECT; renamed op executor dex; added op cancel virtual and overrides; acceptor logic relocated to select acceptors files or removed from sockets.
SELECT Acceptor (new)
src/corosio/src/detail/select/acceptors.hpp, src/corosio/src/detail/select/acceptors.cpp, src/corosio/src/select_context.cpp
New select-based acceptor_service, acceptor_impl, and accept_op implementing FD management, non-blocking accept, cancellation, and endpoint caching.
POSIX / Resolver / Errors / Signals
src/corosio/src/detail/posix/*, src/corosio/src/detail/make_err.*, src/corosio/src/resolver.cpp, src/corosio/src/detail/win/*, examples/*
Replaced _WIN32/!_WIN32/__linux__ guards with BOOST_COROSIO_POSIX/feature macros; adjusted make_err signature/semantics and small example error-check style tweaks.

Sequence Diagram(s)

sequenceDiagram
  participant App as Acceptor (user)
  participant AcceptorSvc as Acceptors (epoll/select acceptor_service)
  participant Scheduler as Scheduler (epoll_scheduler / select_scheduler)
  participant Reactor as Kernel Reactor (epoll/select)
  participant SocketSvc as Socket Service
  participant Coroutine as Coroutine (awaiter)

  App->>AcceptorSvc: open_acceptor(bind, backlog)
  AcceptorSvc->>Scheduler: register fd for read
  note right of Scheduler: Scheduler integrates with Reactor

  Coroutine->>AcceptorSvc: async accept (co_await)
  AcceptorSvc->>Reactor: ensure fd monitored

  Reactor-->>Scheduler: readiness event (EPOLLIN/FD_SET)
  Scheduler->>AcceptorSvc: dispatch accept_op (op->operator())
  AcceptorSvc->>SocketSvc: create peer socket_impl
  AcceptorSvc->>AcceptorSvc: set endpoints, finalize
  AcceptorSvc->>Coroutine: resume with accepted socket / error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • vinniefalco

Poem

🐇 I hopped through macros, tidy and bright,

IOCP, EPOLL, SELECT — flags in sight,
Acceptors wake, ops learn to cancel and run,
Coroutines resume under kernel sun,
A carrot for builds now neatly done 🥕

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main objective: removing platform-dependent macros (_WIN32, linux, etc.) and replacing them with abstracted feature-detection macros (BOOST_COROSIO_HAS_IOCP, etc.).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@cppalliance-bot
Copy link

cppalliance-bot commented Jan 28, 2026

An automated preview of the documentation is available at https://88.corosio.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-01-28 17:18:20 UTC

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/corosio/src/detail/iocp/timers.cpp (1)

11-18: Add a brief implementation overview block after the includes.

This file contains backend-selection logic (NT timers first, thread fallback) but lacks the required high-level /* */ overview immediately after the includes.

📝 Suggested addition
 `#include` "src/detail/iocp/timers.hpp"
 `#include` "src/detail/iocp/timers_nt.hpp"
 `#include` "src/detail/iocp/timers_thread.hpp"
 
+/*
+    Overview: prefer the NT timer backend when available; otherwise
+    fall back to a dedicated thread-based timer implementation.
+*/
 namespace boost::corosio::detail {

As per coding guidelines: Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

🧹 Nitpick comments (4)
src/corosio/src/select_context.cpp (1)

10-17: Missing explicit platform.hpp include before using the feature macro.

BOOST_COROSIO_HAS_SELECT is used at line 13, but platform.hpp is not explicitly included in this file. The code relies on select_context.hpp to transitively include platform.hpp. This implicit dependency can break if header inclusion order changes or if select_context.hpp is refactored.

Other files in this PR (e.g., timers_thread.cpp, resolver_service.hpp) explicitly include platform.hpp before using the feature macros.

Suggested fix
 `#include` <boost/corosio/select_context.hpp>
 
+#include <boost/corosio/detail/platform.hpp>
 
 `#if` BOOST_COROSIO_HAS_SELECT
src/corosio/src/socket.cpp (1)

10-13: Add an implementation overview block after the includes.

Line 10-13: this file contains non-trivial implementation logic but lacks the required post-include /* */ overview comment. Please add a brief design/flow summary.

As per coding guidelines: “Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.”

src/corosio/src/detail/iocp/timers_nt.cpp (1)

11-13: Add an implementation overview block after the includes.

Line 11-13: this file contains non-trivial logic but lacks the required post-include /* */ overview comment.

As per coding guidelines: “Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.”

src/corosio/src/detail/epoll/sockets.cpp (1)

11-14: Add a brief implementation overview after the includes.
This file has substantial logic but lacks the required high-level /* */ overview comment immediately after the includes.

As per coding guidelines: Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

Also applies to: 720-720

@codecov
Copy link

codecov bot commented Jan 28, 2026

Codecov Report

❌ Patch coverage is 69.11197% with 160 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.30%. Comparing base (6c1e185) to head (921dc30).
⚠️ Report is 6 commits behind head on develop.

Files with missing lines Patch % Lines
src/corosio/src/detail/select/acceptors.cpp 63.56% 90 Missing ⚠️
src/corosio/src/detail/epoll/acceptors.cpp 73.36% 53 Missing ⚠️
src/corosio/src/detail/select/sockets.cpp 56.52% 10 Missing ⚠️
src/corosio/src/detail/epoll/sockets.cpp 69.56% 7 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop      #88      +/-   ##
===========================================
- Coverage    81.72%   81.30%   -0.43%     
===========================================
  Files           49       53       +4     
  Lines         4454     4492      +38     
===========================================
+ Hits          3640     3652      +12     
- Misses         814      840      +26     
Files with missing lines Coverage Δ
include/boost/corosio/socket.hpp 91.42% <ø> (ø)
src/corosio/src/acceptor.cpp 80.00% <ø> (ø)
src/corosio/src/detail/endpoint_convert.hpp 100.00% <ø> (ø)
src/corosio/src/detail/epoll/acceptors.hpp 100.00% <100.00%> (ø)
src/corosio/src/detail/epoll/op.hpp 83.92% <100.00%> (+0.14%) ⬆️
src/corosio/src/detail/epoll/scheduler.cpp 84.15% <ø> (-1.33%) ⬇️
src/corosio/src/detail/epoll/sockets.hpp 91.66% <ø> (-3.08%) ⬇️
src/corosio/src/detail/make_err.cpp 66.66% <100.00%> (ø)
src/corosio/src/detail/posix/resolver_service.cpp 83.05% <ø> (ø)
src/corosio/src/detail/posix/resolver_service.hpp 100.00% <ø> (ø)
... and 16 more

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6c1e185...921dc30. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/corosio/src/socket.cpp (1)

10-19: Add an implementation overview block comment after the includes.

This file has non-trivial backend selection logic; a brief /* ... */ overview right after the includes is required by guidelines.

💡 Example placement
 `#include` <boost/corosio/detail/except.hpp>
 `#include` <boost/corosio/detail/platform.hpp>
 
+/*
+ * Implementation overview:
+ * - Selects IOCP-backed socket implementation when BOOST_COROSIO_HAS_IOCP is set.
+ * - Falls back to POSIX socket_service-based backend otherwise.
+ */
+
 `#if` BOOST_COROSIO_HAS_IOCP
 `#include` "src/detail/iocp/sockets.hpp"

As per coding guidelines: Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

🤖 Fix all issues with AI agents
In `@src/corosio/src/detail/select/acceptors.cpp`:
- Around line 51-59: The success path currently leaves *ec_out untouched which
can leak a previous error; inside the existing ec_out check in acceptors.cpp,
when errn == 0 and cancelled.load(...) is false (i.e., success), explicitly
clear the caller's error by setting *ec_out = {} before the other branches; keep
the existing branches for cancelled (set to capy::error::canceled) and non-zero
errn (set to make_err(errn)), and ensure you only dereference ec_out after the
null check.
- Around line 169-172: The accept() call on the socket (acceptor code using fd_
and storing result in variable accepted) must be retried when it fails with
errno == EINTR; wrap the ::accept(fd_, reinterpret_cast<sockaddr*>(&addr),
&addrlen) invocation in a loop that repeats while accepted == -1 and errno ==
EINTR, and only treat other errno values as real errors (return/handle them).
Ensure you preserve errno for non-EINTR failures and use the same EINTR-handling
pattern already used elsewhere in the codebase.
🧹 Nitpick comments (7)
src/corosio/src/tcp_server.cpp (1)

39-42: Address the TODO: propagate listen() errors to the caller.

The TODO comment indicates that listen() should return an error_code, but currently any failure from listen() is silently ignored and bind() always returns success. This could mask binding failures (e.g., port already in use, permission denied).

Would you like me to generate a fix that captures and returns the error from listen(), or open a new issue to track this improvement?

src/corosio/src/detail/iocp/overlapped_op.hpp (1)

33-144: Consider adding a high-level implementation overview.

Per the coding guidelines, files with non-trivial implementation logic should include a block comment after the includes explaining how the implementation works. This struct manages Windows IOCP overlapped operations with cancellation support and stop_token integration—a brief overview would help maintainers understand the synchronization model (e.g., ready_ coordination with GQCS).

src/corosio/src/acceptor.cpp (1)

20-22: Consider adding a high-level implementation overview.

As per coding guidelines, files with non-trivial implementation logic should include a block comment after the includes explaining how the implementation works. A brief note about the IOCP vs POSIX backend selection model would help maintainers.

📝 Suggested overview
 `#include` <boost/corosio/detail/except.hpp>
 
+/*
+ * acceptor implementation
+ *
+ * Uses compile-time backend selection via BOOST_COROSIO_HAS_IOCP:
+ * - IOCP path: Direct integration with win_sockets service
+ * - POSIX path: Runtime polymorphism via acceptor_service interface
+ *   (concrete service installed by context constructor)
+ */
+
 namespace boost::corosio {
src/corosio/src/detail/epoll/sockets.cpp (1)

10-27: Add a brief file-level overview comment after the includes.

This file contains non-trivial lifecycle and cancellation logic; a short /* */ overview right after the includes would help maintainers.

As per coding guidelines: Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

src/corosio/src/detail/epoll/acceptors.cpp (1)

10-24: Add a brief file-level overview comment after the includes.

This new file has substantial control-flow and lifetime handling; a short /* */ overview would help future maintenance.

As per coding guidelines: Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

src/corosio/src/detail/select/acceptors.hpp (1)

17-30: Add explicit includes for std::coroutine_handle and std::stop_token.
Lines 52 and 54 use these types without explicitly including <coroutine> and <stop_token>. While they are available transitively through acceptor.hpp, adding explicit includes improves hygiene and avoids fragility.

♻️ Proposed fix
 `#include` <boost/corosio/detail/config.hpp>
 `#include` <boost/corosio/acceptor.hpp>
 `#include` <boost/capy/ex/executor_ref.hpp>
 `#include` <boost/capy/ex/execution_context.hpp>
 `#include` "src/detail/intrusive.hpp"
 `#include` "src/detail/socket_service.hpp"
 
 `#include` "src/detail/select/op.hpp"
 `#include` "src/detail/select/scheduler.hpp"
 
+#include <coroutine>
+#include <stop_token>
 `#include` <memory>
 `#include` <mutex>
 `#include` <unordered_map>
src/corosio/src/detail/select/acceptors.cpp (1)

14-24: Add a high-level implementation overview block comment.

This file contains non-trivial lifecycle and async accept logic but lacks the required /* */ overview after the includes. Please add a short high-level description of the control flow and tricky parts (registration/cancel paths, endpoint caching).

As per coding guidelines: Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

Comment on lines +169 to +172
sockaddr_in addr{};
socklen_t addrlen = sizeof(addr);
int accepted = ::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find and examine the specific file
fd -t f "acceptors.cpp" src/

Repository: cppalliance/corosio

Length of output: 149


🏁 Script executed:

# Read the specific lines mentioned in the review
sed -n '160,180p' src/corosio/src/detail/select/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 633


🏁 Script executed:

# Look for context around the accept call - get more lines
sed -n '165,185p' src/corosio/src/detail/select/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 686


🏁 Script executed:

# Search for other accept() calls in the codebase to see if EINTR is handled elsewhere
rg "::accept\(" src/

Repository: cppalliance/corosio

Length of output: 304


🏁 Script executed:

# Check for EINTR handling patterns in the same file
rg -i "eintr" src/corosio/src/detail/select/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 45


🏁 Script executed:

# Look for general error handling patterns in the file
sed -n '1,50p' src/corosio/src/detail/select/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 1354


🏁 Script executed:

# See the full error handling after accept()
sed -n '165,210p' src/corosio/src/detail/select/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 1491


🏁 Script executed:

# Check the other accept() call in op.hpp
sed -n '1,20p' src/corosio/src/detail/select/op.hpp

Repository: cppalliance/corosio

Length of output: 652


🏁 Script executed:

# Find the accept() call in op.hpp and see surrounding code
rg -B 5 -A 10 "::accept\(fd" src/corosio/src/detail/select/op.hpp

Repository: cppalliance/corosio

Length of output: 651


🏁 Script executed:

# Check if socket is set to non-blocking mode anywhere
rg -i "nonblock\|fcntl" src/corosio/src/detail/select/

Repository: cppalliance/corosio

Length of output: 45


🏁 Script executed:

# Look for any signal handling or EINTR patterns in similar async I/O libraries or boost
rg -i "EAGAIN\|EWOULDBLOCK" src/corosio/src/detail/select/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 45


🏁 Script executed:

# Search for EINTR handling patterns in the entire codebase
rg -i "EINTR" src/

Repository: cppalliance/corosio

Length of output: 234


🏁 Script executed:

# Check epoll implementation to see if it handles EINTR differently
rg -B 5 -A 10 "::accept\(" src/corosio/src/detail/epoll/

Repository: cppalliance/corosio

Length of output: 45


🏁 Script executed:

# Look for any retry patterns in the codebase
rg -i "do\s*\{|while.*errno|retry" src/corosio/src/detail/select/ | head -20

Repository: cppalliance/corosio

Length of output: 45


🏁 Script executed:

# Check epoll acceptors to see if they have different handling
cat src/corosio/src/detail/epoll/acceptors.cpp | grep -A 20 "::accept"

Repository: cppalliance/corosio

Length of output: 2121


🏁 Script executed:

# Look at the scheduler EINTR pattern more closely
rg -B 3 -A 3 "saved_errno != EINTR" src/corosio/src/detail/select/scheduler.cpp

Repository: cppalliance/corosio

Length of output: 305


Retry accept on EINTR.

The accept() call on a blocking socket can be interrupted by signals. Without retrying on EINTR, spurious failures occur. The codebase already distinguishes EINTR from real errors in scheduler contexts; apply the same pattern here.

Proposed fix
-    int accepted = ::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
+    int accepted;
+    do {
+        accepted = ::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
+    } while (accepted < 0 && errno == EINTR);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sockaddr_in addr{};
socklen_t addrlen = sizeof(addr);
int accepted = ::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
sockaddr_in addr{};
socklen_t addrlen = sizeof(addr);
int accepted;
do {
accepted = ::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
} while (accepted < 0 && errno == EINTR);
🤖 Prompt for AI Agents
In `@src/corosio/src/detail/select/acceptors.cpp` around lines 169 - 172, The
accept() call on the socket (acceptor code using fd_ and storing result in
variable accepted) must be retried when it fails with errno == EINTR; wrap the
::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen) invocation in a loop
that repeats while accepted == -1 and errno == EINTR, and only treat other errno
values as real errors (return/handle them). Ensure you preserve errno for
non-EINTR failures and use the same EINTR-handling pattern already used
elsewhere in the codebase.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/corosio/src/detail/epoll/acceptors.cpp`:
- Around line 171-186: accept4(fd_) can fail with errno == EINTR when
interrupted by signals; currently the code treats any non-EAGAIN/EWOULDBLOCK
error as permanent. Modify the accept loop around ::accept4 in the acceptor code
so that when errno == EINTR it retries the ::accept4 call (i.e., loop until
accepted >= 0 or errno is not EINTR), preserving the existing handling for
accepted >= 0 (set op.accepted_fd, op.complete, op.impl_ptr, svc_.post) and for
EAGAIN/EWOULDBLOCK. Ensure the retry logic is placed where ::accept4 is invoked
in this function so fd_, op and svc_ behavior remains unchanged.
🧹 Nitpick comments (4)
src/corosio/src/detail/epoll/sockets.cpp (1)

10-27: Add a brief file-level implementation overview.

This file has non-trivial cancellation and lifecycle logic; a short /* / overview after the includes would help maintainers. As per coding guidelines: Files containing non-trivial implementation logic should include a / */ block comment after the includes that provides a high-level overview of how the implementation works.

src/corosio/src/detail/epoll/acceptors.cpp (1)

10-24: Add a brief file-level implementation overview.

This new acceptor subsystem is non-trivial; a short /* / overview after the includes would aid maintainability. As per coding guidelines: Files containing non-trivial implementation logic should include a / */ block comment after the includes that provides a high-level overview of how the implementation works.

src/corosio/src/detail/select/acceptors.cpp (1)

10-24: Add a brief file-level implementation overview.

This file is non-trivial; a short /* / overview after the includes would help future maintenance. As per coding guidelines: Files containing non-trivial implementation logic should include a / */ block comment after the includes that provides a high-level overview of how the implementation works.

src/corosio/src/detail/select/sockets.cpp (1)

10-26: Add a brief file-level implementation overview.

This file contains non-trivial reactor/cancellation logic; a short /* / overview after the includes would help maintainability. As per coding guidelines: Files containing non-trivial implementation logic should include a / */ block comment after the includes that provides a high-level overview of how the implementation works.

Comment on lines +171 to +186
sockaddr_in addr{};
socklen_t addrlen = sizeof(addr);
int accepted = ::accept4(fd_, reinterpret_cast<sockaddr*>(&addr),
&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);

if (accepted >= 0)
{
op.accepted_fd = accepted;
op.complete(0, 0);
op.impl_ptr = shared_from_this();
svc_.post(&op);
return;
}

if (errno == EAGAIN || errno == EWOULDBLOCK)
{
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the full context of the acceptors.cpp file around the mentioned lines
fd src -t cpp -n acceptors | head -20

Repository: cppalliance/corosio

Length of output: 293


🏁 Script executed:

# Find the acceptors.cpp file
fd acceptors.cpp

Repository: cppalliance/corosio

Length of output: 149


🏁 Script executed:

# Get context around lines 171-186
wc -l src/corosio/src/detail/epoll/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 109


🏁 Script executed:

# View the relevant section and surrounding code
sed -n '160,200p' src/corosio/src/detail/epoll/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 1544


🏁 Script executed:

# Search for EINTR handling in the codebase
rg "EINTR" -B 2 -A 2

Repository: cppalliance/corosio

Length of output: 1163


🏁 Script executed:

# Check if there are similar socket operations that handle EINTR
rg "accept" -B 2 -A 4 --type cpp

Repository: cppalliance/corosio

Length of output: 50376


🌐 Web query:

POSIX accept4 EINTR specification signal interruption

💡 Result:

  • POSIX (accept): The POSIX accept() specification requires that accept() fail with -1 and set errno = EINTR if it is interrupted by a caught signal before a valid connection arrives. [1]
  • accept4 is not POSIX: accept4() is a non-POSIX extension (e.g., Linux provides it), so POSIX doesn’t standardize its behavior directly; in practice it follows the same interruption rule on systems that implement it. [2]
  • Linux (accept4 / accept) semantics: On Linux, accept4() (and accept()) can return EINTR when a signal is caught before a connection is accepted. [2]
  • Interaction with SA_RESTART / timeouts (Linux-specific): Linux documents that some “slow” syscalls may be restarted when SA_RESTART is used, but socket calls like accept() are not restarted (always return EINTR) if a receive timeout SO_RCVTIMEO is set. [3]

Practical takeaway: portable code should treat EINTR from accept()/accept4() as a normal interruption and usually retry in a loop, unless you intentionally want signals to break out.

Sources:
[1] POSIX/Open Group accept() specification (EINTR) https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html
[2] Linux accept4(2) man page (EINTR) https://man.archlinux.org/man/core/man-pages/accept4.2.en
[3] Linux signal(7) man page (restart rules; SO_RCVTIMEO exception) https://man.he.net/man7/signal


🏁 Script executed:

sed -n '165,195p' src/corosio/src/detail/epoll/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 1166


🏁 Script executed:

# Check the complete error handling flow after the accept4 call
sed -n '165,220p' src/corosio/src/detail/epoll/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 2084


🏁 Script executed:

# Also check the select backend acceptor for comparison
grep -A 20 "accept(" src/corosio/src/detail/select/acceptors.cpp | head -40

Repository: cppalliance/corosio

Length of output: 1206


🏁 Script executed:

# Check what happens after the EAGAIN/EWOULDBLOCK block to understand full error flow
sed -n '171,240p' src/corosio/src/detail/epoll/acceptors.cpp | tail -50

Repository: cppalliance/corosio

Length of output: 1714


🏁 Script executed:

# Verify if there's any EINTR handling elsewhere in the method
grep -n "EINTR" src/corosio/src/detail/epoll/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 45


🏁 Script executed:

# Confirm EINTR is not handled by looking at the complete error handling
sed -n '211,225p' src/corosio/src/detail/epoll/acceptors.cpp

Repository: cppalliance/corosio

Length of output: 384


Handle EINTR by retrying accept4 when interrupted by signals.

POSIX specifies that accept() (and by extension accept4()) can return -1 with errno == EINTR when a signal interrupts the call before a connection arrives. Without retry logic, spurious signal interruptions will propagate as errors rather than transparently handling the interruption.

🛠️ Proposed fix
-    int accepted = ::accept4(fd_, reinterpret_cast<sockaddr*>(&addr),
-                             &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
+    int accepted;
+    do {
+        accepted = ::accept4(fd_, reinterpret_cast<sockaddr*>(&addr),
+                             &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
+    } while (accepted < 0 && errno == EINTR);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sockaddr_in addr{};
socklen_t addrlen = sizeof(addr);
int accepted = ::accept4(fd_, reinterpret_cast<sockaddr*>(&addr),
&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (accepted >= 0)
{
op.accepted_fd = accepted;
op.complete(0, 0);
op.impl_ptr = shared_from_this();
svc_.post(&op);
return;
}
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
sockaddr_in addr{};
socklen_t addrlen = sizeof(addr);
int accepted;
do {
accepted = ::accept4(fd_, reinterpret_cast<sockaddr*>(&addr),
&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
} while (accepted < 0 && errno == EINTR);
if (accepted >= 0)
{
op.accepted_fd = accepted;
op.complete(0, 0);
op.impl_ptr = shared_from_this();
svc_.post(&op);
return;
}
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
🤖 Prompt for AI Agents
In `@src/corosio/src/detail/epoll/acceptors.cpp` around lines 171 - 186,
accept4(fd_) can fail with errno == EINTR when interrupted by signals; currently
the code treats any non-EAGAIN/EWOULDBLOCK error as permanent. Modify the accept
loop around ::accept4 in the acceptor code so that when errno == EINTR it
retries the ::accept4 call (i.e., loop until accepted >= 0 or errno is not
EINTR), preserving the existing handling for accepted >= 0 (set op.accepted_fd,
op.complete, op.impl_ptr, svc_.post) and for EAGAIN/EWOULDBLOCK. Ensure the
retry logic is placed where ::accept4 is invoked in this function so fd_, op and
svc_ behavior remains unchanged.

@sgerbino sgerbino merged commit fcfc8f3 into cppalliance:develop Jan 28, 2026
18 checks passed
@sgerbino sgerbino deleted the pr/clean-up branch January 28, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants