LCOV - code coverage report
Current view: top level - corosio/native/detail/posix - posix_fd_gate.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 93.8 % 48 45 3
Test Date: 2026-10-17 04:01:32 Functions: 100.0 % 8 8

           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_POSIX_POSIX_FD_GATE_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_POSIX_POSIX_FD_GATE_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/platform.hpp>
      14                 : 
      15                 : #if BOOST_COROSIO_POSIX
      16                 : 
      17                 : #include <mutex>
      18                 : #include <vector>
      19                 : 
      20                 : #include <unistd.h>
      21                 : 
      22                 : namespace boost::corosio::detail {
      23                 : 
      24                 : /** Keep a descriptor number allocated while pool workers use it.
      25                 : 
      26                 :     A worker copies the number when its operation is queued and calls
      27                 :     the kernel later, on another thread. Once the object closes the
      28                 :     descriptor, the number can be handed to any other open in the
      29                 :     process, and a worker still on its way to the kernel would then
      30                 :     transfer through an unrelated file. Workers enter the gate before
      31                 :     their system call and leave it after; closing while one is inside
      32                 :     defers the `::close` to the last one out, so the number stays
      33                 :     allocated to the file the worker meant.
      34                 : 
      35                 :     @par Thread Safety
      36                 :     Distinct objects: Safe.
      37                 :     Shared objects: Safe.
      38                 : */
      39                 : class posix_fd_gate
      40                 : {
      41                 :     std::mutex mutex_;
      42                 :     int fd_    = -1;
      43                 :     int users_ = 0;
      44                 :     std::vector<int> deferred_;
      45                 : 
      46                 : public:
      47                 :     /// Destroy the gate, closing any descriptor still deferred.
      48 HIT         939 :     ~posix_fd_gate()
      49                 :     {
      50             939 :         for (int fd : deferred_)
      51 MIS           0 :             ::close(fd);
      52 HIT         939 :     }
      53                 : 
      54             939 :     posix_fd_gate() = default;
      55                 :     posix_fd_gate(posix_fd_gate const&)            = delete;
      56                 :     posix_fd_gate& operator=(posix_fd_gate const&) = delete;
      57                 : 
      58                 :     /// Admit workers for @p fd, the descriptor the object now holds.
      59            1352 :     void open(int fd) noexcept
      60                 :     {
      61            1352 :         std::lock_guard<std::mutex> lock(mutex_);
      62            1352 :         fd_ = fd;
      63            1352 :     }
      64                 : 
      65                 :     /** Enter the gate for a system call on @p fd.
      66                 : 
      67                 :         @return False if the object no longer holds @p fd; the caller
      68                 :             must not use the number.
      69                 :     */
      70             607 :     bool enter(int fd) noexcept
      71                 :     {
      72             607 :         std::lock_guard<std::mutex> lock(mutex_);
      73             607 :         if (fd < 0 || fd != fd_)
      74 MIS           0 :             return false;
      75 HIT         607 :         ++users_;
      76             607 :         return true;
      77             607 :     }
      78                 : 
      79                 :     /// Leave the gate after a successful @ref enter.
      80             607 :     void leave() noexcept
      81                 :     {
      82             607 :         std::vector<int> close_now;
      83                 :         {
      84             607 :             std::lock_guard<std::mutex> lock(mutex_);
      85             607 :             if (--users_ == 0)
      86             607 :                 close_now.swap(deferred_);
      87             607 :         }
      88             623 :         for (int fd : close_now)
      89              16 :             ::close(fd);
      90             607 :     }
      91                 : 
      92                 :     /// Close the held descriptor once no worker is using it.
      93            4315 :     void close() noexcept
      94                 :     {
      95            4315 :         int fd = -1;
      96                 :         {
      97            4315 :             std::lock_guard<std::mutex> lock(mutex_);
      98            4315 :             fd  = fd_;
      99            4315 :             fd_ = -1;
     100            4315 :             if (fd >= 0 && users_ > 0)
     101                 :             {
     102              16 :                 deferred_.push_back(fd);
     103              16 :                 fd = -1;
     104                 :             }
     105            4315 :         }
     106            4315 :         if (fd >= 0)
     107            1327 :             ::close(fd);
     108            4315 :     }
     109                 : 
     110                 :     /** Stop admitting workers for the held descriptor, keeping it open.
     111                 : 
     112                 :         @return False, leaving the descriptor admitted, if a worker is
     113                 :             using it; the caller cannot take ownership of a number a
     114                 :             worker may still pass to the kernel.
     115                 :     */
     116               9 :     bool release() noexcept
     117                 :     {
     118               9 :         std::lock_guard<std::mutex> lock(mutex_);
     119               9 :         if (users_ > 0)
     120 MIS           0 :             return false;
     121 HIT           9 :         fd_ = -1;
     122               9 :         return true;
     123               9 :     }
     124                 : 
     125                 :     /// Return true if no descriptor is held and no worker is inside.
     126              64 :     bool idle() noexcept
     127                 :     {
     128              64 :         std::lock_guard<std::mutex> lock(mutex_);
     129              64 :         return fd_ == -1 && users_ == 0;
     130              64 :     }
     131                 : };
     132                 : 
     133                 : } // namespace boost::corosio::detail
     134                 : 
     135                 : #endif // BOOST_COROSIO_POSIX
     136                 : 
     137                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_POSIX_POSIX_FD_GATE_HPP
        

Generated by: LCOV version 2.3