LCOV - code coverage report
Current view: top level - corosio/native/detail/select - select_op.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 54.3 % 35 19 16
Test Date: 2026-03-13 23:11:04 Functions: 100.0 % 2 2

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Steve Gerbino
       3                 : //
       4                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6                 : //
       7                 : // Official repository: https://github.com/cppalliance/corosio
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_OP_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_OP_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/platform.hpp>
      14                 : 
      15                 : #if BOOST_COROSIO_HAS_SELECT
      16                 : 
      17                 : #include <boost/corosio/native/detail/reactor/reactor_op.hpp>
      18                 : #include <boost/corosio/native/detail/reactor/reactor_descriptor_state.hpp>
      19                 : 
      20                 : #include <errno.h>
      21                 : #include <fcntl.h>
      22                 : #include <sys/socket.h>
      23                 : #include <unistd.h>
      24                 : 
      25                 : /*
      26                 :     File descriptors are registered with the select scheduler once (via
      27                 :     select_descriptor_state) and stay registered until closed.
      28                 : 
      29                 :     select() is level-triggered but the descriptor_state pattern
      30                 :     (designed for edge-triggered) works correctly: is_enqueued_ CAS
      31                 :     prevents double-enqueue, add_ready_events is idempotent, and
      32                 :     EAGAIN ops stay parked until the next select() re-reports readiness.
      33                 : 
      34                 :     cancel() captures shared_from_this() into op.impl_ptr to prevent
      35                 :     use-after-free when the socket is closed with pending ops.
      36                 : 
      37                 :     Writes use sendmsg(MSG_NOSIGNAL) on Linux. On macOS/BSD where
      38                 :     MSG_NOSIGNAL may be absent, SO_NOSIGPIPE is set at socket creation
      39                 :     and accepted-socket setup instead.
      40                 : */
      41                 : 
      42                 : namespace boost::corosio::detail {
      43                 : 
      44                 : // Forward declarations
      45                 : class select_socket;
      46                 : class select_acceptor;
      47                 : struct select_op;
      48                 : 
      49                 : // Forward declaration
      50                 : class select_scheduler;
      51                 : 
      52                 : /// Per-descriptor state for persistent select registration.
      53                 : struct select_descriptor_state final : reactor_descriptor_state
      54                 : {};
      55                 : 
      56                 : /// select base operation — thin wrapper over reactor_op.
      57                 : struct select_op : reactor_op<select_socket, select_acceptor>
      58                 : {
      59                 :     void operator()() override;
      60                 : };
      61                 : 
      62                 : /// select connect operation.
      63                 : struct select_connect_op final : reactor_connect_op<select_op>
      64                 : {
      65                 :     void operator()() override;
      66                 :     void cancel() noexcept override;
      67                 : };
      68                 : 
      69                 : /// select scatter-read operation.
      70                 : struct select_read_op final : reactor_read_op<select_op>
      71                 : {
      72                 :     void cancel() noexcept override;
      73                 : };
      74                 : 
      75                 : /** Provides sendmsg() with EINTR retry for select writes.
      76                 : 
      77                 :     Uses MSG_NOSIGNAL where available (Linux). On platforms without
      78                 :     it (macOS/BSD), SO_NOSIGPIPE is set at socket creation time
      79                 :     and flags=0 is used here.
      80                 : */
      81                 : struct select_write_policy
      82                 : {
      83 HIT      126128 :     static ssize_t write(int fd, iovec* iovecs, int count) noexcept
      84                 :     {
      85          126128 :         msghdr msg{};
      86          126128 :         msg.msg_iov    = iovecs;
      87          126128 :         msg.msg_iovlen = static_cast<std::size_t>(count);
      88                 : 
      89                 : #ifdef MSG_NOSIGNAL
      90          126128 :         constexpr int send_flags = MSG_NOSIGNAL;
      91                 : #else
      92                 :         constexpr int send_flags = 0;
      93                 : #endif
      94                 : 
      95                 :         ssize_t n;
      96                 :         do
      97                 :         {
      98          126128 :             n = ::sendmsg(fd, &msg, send_flags);
      99                 :         }
     100          126128 :         while (n < 0 && errno == EINTR);
     101          126128 :         return n;
     102                 :     }
     103                 : };
     104                 : 
     105                 : /// select gather-write operation.
     106                 : struct select_write_op final : reactor_write_op<select_op, select_write_policy>
     107                 : {
     108                 :     void cancel() noexcept override;
     109                 : };
     110                 : 
     111                 : /** Provides accept() + fcntl(O_NONBLOCK|FD_CLOEXEC) with FD_SETSIZE check.
     112                 : 
     113                 :     Uses accept() instead of accept4() for broader POSIX compatibility.
     114                 : */
     115                 : struct select_accept_policy
     116                 : {
     117            3082 :     static int do_accept(int fd, sockaddr_storage& peer) noexcept
     118                 :     {
     119            3082 :         socklen_t addrlen = sizeof(peer);
     120                 :         int new_fd;
     121                 :         do
     122                 :         {
     123            3082 :             new_fd = ::accept(fd, reinterpret_cast<sockaddr*>(&peer), &addrlen);
     124                 :         }
     125            3082 :         while (new_fd < 0 && errno == EINTR);
     126                 : 
     127            3082 :         if (new_fd < 0)
     128 MIS           0 :             return new_fd;
     129                 : 
     130 HIT        3082 :         if (new_fd >= FD_SETSIZE)
     131                 :         {
     132 MIS           0 :             ::close(new_fd);
     133               0 :             errno = EINVAL;
     134               0 :             return -1;
     135                 :         }
     136                 : 
     137 HIT        3082 :         int flags = ::fcntl(new_fd, F_GETFL, 0);
     138            3082 :         if (flags == -1)
     139                 :         {
     140 MIS           0 :             int err = errno;
     141               0 :             ::close(new_fd);
     142               0 :             errno = err;
     143               0 :             return -1;
     144                 :         }
     145                 : 
     146 HIT        3082 :         if (::fcntl(new_fd, F_SETFL, flags | O_NONBLOCK) == -1)
     147                 :         {
     148 MIS           0 :             int err = errno;
     149               0 :             ::close(new_fd);
     150               0 :             errno = err;
     151               0 :             return -1;
     152                 :         }
     153                 : 
     154 HIT        3082 :         if (::fcntl(new_fd, F_SETFD, FD_CLOEXEC) == -1)
     155                 :         {
     156 MIS           0 :             int err = errno;
     157               0 :             ::close(new_fd);
     158               0 :             errno = err;
     159               0 :             return -1;
     160                 :         }
     161                 : 
     162                 : #ifdef SO_NOSIGPIPE
     163                 :         int one = 1;
     164                 :         if (::setsockopt(
     165                 :                 new_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one)) == -1)
     166                 :         {
     167                 :             int err = errno;
     168                 :             ::close(new_fd);
     169                 :             errno = err;
     170                 :             return -1;
     171                 :         }
     172                 : #endif
     173                 : 
     174 HIT        3082 :         return new_fd;
     175                 :     }
     176                 : };
     177                 : 
     178                 : /// select accept operation.
     179                 : struct select_accept_op final
     180                 :     : reactor_accept_op<select_op, select_accept_policy>
     181                 : {
     182                 :     void operator()() override;
     183                 :     void cancel() noexcept override;
     184                 : };
     185                 : 
     186                 : } // namespace boost::corosio::detail
     187                 : 
     188                 : #endif // BOOST_COROSIO_HAS_SELECT
     189                 : 
     190                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_OP_HPP
        

Generated by: LCOV version 2.3