LCOV - code coverage report
Current view: top level - capy/ex - work_guard.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 31 31
Test Date: 2026-02-17 18:14:47 Functions: 100.0 % 32 32

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       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/capy
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_CAPY_WORK_GUARD_HPP
      11                 : #define BOOST_CAPY_WORK_GUARD_HPP
      12                 : 
      13                 : #include <boost/capy/detail/config.hpp>
      14                 : #include <boost/capy/ex/execution_context.hpp>
      15                 : #include <boost/capy/concept/executor.hpp>
      16                 : 
      17                 : #include <utility>
      18                 : 
      19                 : namespace boost {
      20                 : namespace capy {
      21                 : 
      22                 : /** RAII guard that keeps an executor's context from completing.
      23                 : 
      24                 :     This class holds "work" on an executor, preventing the associated
      25                 :     execution context's `run()` function from returning due to lack of
      26                 :     work. It calls `on_work_started()` on construction and
      27                 :     `on_work_finished()` on destruction, ensuring proper work tracking.
      28                 : 
      29                 :     The guard is useful when you need to keep an execution context
      30                 :     running while waiting for external events or when work will be
      31                 :     posted later.
      32                 : 
      33                 :     @par RAII Semantics
      34                 : 
      35                 :     @li Construction calls `ex.on_work_started()`.
      36                 :     @li Destruction calls `ex.on_work_finished()` if `owns_work()`.
      37                 :     @li Copy construction creates a new work reference (calls
      38                 :         `on_work_started()` again).
      39                 :     @li Move construction transfers ownership without additional calls.
      40                 : 
      41                 :     @par Thread Safety
      42                 : 
      43                 :     Distinct objects may be accessed concurrently. Access to a single
      44                 :     object requires external synchronization.
      45                 : 
      46                 :     @par Example
      47                 :     @code
      48                 :     io_context ctx;
      49                 : 
      50                 :     // Keep context running while we set things up
      51                 :     auto guard = make_work_guard(ctx);
      52                 : 
      53                 :     std::thread t([&ctx]{ ctx.run(); });
      54                 : 
      55                 :     // ... post work to ctx ...
      56                 : 
      57                 :     // Allow context to complete when work is done
      58                 :     guard.reset();
      59                 : 
      60                 :     t.join();
      61                 :     @endcode
      62                 : 
      63                 :     @note The executor is returned by reference, allowing callers to
      64                 :     manage the executor's lifetime directly. This is essential in
      65                 :     coroutine-first designs where the executor often outlives individual
      66                 :     coroutine frames.
      67                 : 
      68                 :     @tparam Ex A type satisfying the Executor concept.
      69                 : 
      70                 :     @see make_work_guard, Executor
      71                 : */
      72                 : template<Executor Ex>
      73                 : class work_guard
      74                 : {
      75                 :     Ex ex_;
      76                 :     bool owns_;
      77                 : 
      78                 : public:
      79                 :     /** The underlying executor type. */
      80                 :     using executor_type = Ex;
      81                 : 
      82                 :     /** Construct a work guard.
      83                 : 
      84                 :         Calls `ex.on_work_started()` to inform the executor that
      85                 :         work is outstanding.
      86                 : 
      87                 :         @par Exception Safety
      88                 :         No-throw guarantee.
      89                 : 
      90                 :         @par Postconditions
      91                 :         @li `owns_work() == true`
      92                 :         @li `executor() == ex`
      93                 : 
      94                 :         @param ex The executor to hold work on. Moved into the guard.
      95                 :     */
      96                 :     explicit
      97 HIT        2914 :     work_guard(Ex ex) noexcept
      98            2914 :         : ex_(std::move(ex))
      99            2914 :         , owns_(true)
     100                 :     {
     101            2914 :         ex_.on_work_started();
     102            2914 :     }
     103                 : 
     104                 :     /** Copy constructor.
     105                 : 
     106                 :         Creates a new work guard holding work on the same executor.
     107                 :         Calls `on_work_started()` on the executor.
     108                 : 
     109                 :         @par Exception Safety
     110                 :         No-throw guarantee.
     111                 : 
     112                 :         @par Postconditions
     113                 :         @li `owns_work() == other.owns_work()`
     114                 :         @li `executor() == other.executor()`
     115                 : 
     116                 :         @param other The work guard to copy from.
     117                 :     */
     118               2 :     work_guard(work_guard const& other) noexcept
     119               2 :         : ex_(other.ex_)
     120               2 :         , owns_(other.owns_)
     121                 :     {
     122               2 :         if(owns_)
     123               1 :             ex_.on_work_started();
     124               2 :     }
     125                 : 
     126                 :     /** Move constructor.
     127                 : 
     128                 :         Transfers work ownership from `other` to `*this`. Does not
     129                 :         call `on_work_started()` or `on_work_finished()`.
     130                 : 
     131                 :         @par Exception Safety
     132                 :         No-throw guarantee.
     133                 : 
     134                 :         @par Postconditions
     135                 :         @li `owns_work()` equals the prior value of `other.owns_work()`
     136                 :         @li `other.owns_work() == false`
     137                 : 
     138                 :         @param other The work guard to move from.
     139                 :     */
     140               1 :     work_guard(work_guard&& other) noexcept
     141               1 :         : ex_(std::move(other.ex_))
     142               1 :         , owns_(other.owns_)
     143                 :     {
     144               1 :         other.owns_ = false;
     145               1 :     }
     146                 : 
     147                 :     /** Destructor.
     148                 : 
     149                 :         If `owns_work()` is `true`, calls `on_work_finished()` on
     150                 :         the executor.
     151                 : 
     152                 :         @par Exception Safety
     153                 :         No-throw guarantee.
     154                 :     */
     155            2917 :     ~work_guard()
     156                 :     {
     157            2917 :         if(owns_)
     158            2912 :             ex_.on_work_finished();
     159            2917 :     }
     160                 : 
     161                 :     work_guard& operator=(work_guard const&) = delete;
     162                 : 
     163                 :     /** Return the underlying executor by reference.
     164                 : 
     165                 :         The reference remains valid for the lifetime of this guard,
     166                 :         enabling callers to manage executor lifetime explicitly.
     167                 : 
     168                 :         @par Exception Safety
     169                 :         No-throw guarantee.
     170                 : 
     171                 :         @return A reference to the stored executor.
     172                 :     */
     173                 :     executor_type const&
     174            5815 :     executor() const noexcept
     175                 :     {
     176            5815 :         return ex_;
     177                 :     }
     178                 : 
     179                 :     /** Return whether the guard owns work.
     180                 : 
     181                 :         @par Exception Safety
     182                 :         No-throw guarantee.
     183                 : 
     184                 :         @return `true` if this guard will call `on_work_finished()`
     185                 :             on destruction, `false` otherwise.
     186                 :     */
     187                 :     bool
     188              12 :     owns_work() const noexcept
     189                 :     {
     190              12 :         return owns_;
     191                 :     }
     192                 : 
     193                 :     /** Release ownership of the work.
     194                 : 
     195                 :         If `owns_work()` is `true`, calls `on_work_finished()` on
     196                 :         the executor and sets ownership to `false`. Otherwise, has
     197                 :         no effect.
     198                 : 
     199                 :         @par Exception Safety
     200                 :         No-throw guarantee.
     201                 : 
     202                 :         @par Postconditions
     203                 :         @li `owns_work() == false`
     204                 :     */
     205                 :     void
     206               4 :     reset() noexcept
     207                 :     {
     208               4 :         if(owns_)
     209                 :         {
     210               3 :             ex_.on_work_finished();
     211               3 :             owns_ = false;
     212                 :         }
     213               4 :     }
     214                 : };
     215                 : 
     216                 : //------------------------------------------------
     217                 : 
     218                 : /** Create a work guard from an executor.
     219                 : 
     220                 :     @par Exception Safety
     221                 :     No-throw guarantee.
     222                 : 
     223                 :     @param ex The executor to create the guard for.
     224                 : 
     225                 :     @return A `work_guard` holding work on `ex`.
     226                 : 
     227                 :     @see work_guard
     228                 : */
     229                 : template<Executor Ex>
     230                 : work_guard<Ex>
     231               1 : make_work_guard(Ex ex)
     232                 : {
     233               1 :     return work_guard<Ex>(std::move(ex));
     234                 : }
     235                 : 
     236                 : } // capy
     237                 : } // boost
     238                 : 
     239                 : #endif
        

Generated by: LCOV version 2.3