Ignore:
Timestamp:
2019-06-30T14:37:40Z (5 years ago)
Author:
Jaroslav Jindrak <dzejrou@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
3a29607
Parents:
d86c00f0
Message:

cpp: refactor future to avoid code duplication, fix wait_for and wait_until, synchronization and compilation

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/__bits/thread/future.hpp

    rd86c00f0 r6e97265  
    3030#define LIBCPP_BITS_THREAD_FUTURE
    3131
     32#include <__bits/thread/future_common.hpp>
     33#include <__bits/thread/shared_state.hpp>
     34#include <__bits/utility/forward_move.hpp>
    3235#include <cassert>
    33 #include <memory>
    34 #include <system_error>
    35 #include <thread>
    36 #include <tuple>
    37 #include <type_traits>
    38 #include <utility>
    3936
    4037namespace std
    4138{
    4239    /**
    43      * 30.6, futures:
    44      */
    45 
    46     enum class future_errc
    47     { // The 5001 start is to not collide with system_error's codes.
    48         broken_promise = 5001,
    49         future_already_retrieved,
    50         promise_already_satisfied,
    51         no_state
    52     };
    53 
    54     enum class future_status
    55     {
    56         ready,
    57         timeout,
    58         deferred
    59     };
    60 
    61     /**
    62      * 30.6.2, error handling:
    63      */
    64 
    65     template<>
    66     struct is_error_code_enum<future_errc>: true_type
    67     { /* DUMMY BODY */ };
    68 
    69     error_code make_error_code(future_errc) noexcept;
    70     error_condition make_error_condition(future_errc) noexcept;
    71 
    72     const error_category& future_category() noexcept;
    73 
    74     /**
    75      * 30.6.3, class future_error:
    76      */
    77 
    78     class future_error: public logic_error
    79     {
    80         public:
    81             future_error(error_code ec);
    82 
    83             const error_code& code() const noexcept;
    84             const char* what() const noexcept;
    85 
    86         private:
    87             error_code code_;
    88     };
    89 
    90     /**
    9140     * 30.6.6, class template future:
    9241     */
    9342
     43    namespace aux
     44    {
     45        template<class R>
     46        class future_base
     47        {
     48            public:
     49                future_base() noexcept
     50                    : state_{nullptr}
     51                { /* DUMMY BODY */ }
     52
     53                future_base(const future_base&) = delete;
     54
     55                future_base(future_base&& rhs) noexcept
     56                    : state_{std::move(rhs.state_)}
     57                {
     58                    rhs.state_ = nullptr;
     59                }
     60
     61                future_base(aux::shared_state<R>* state)
     62                    : state_{state}
     63                {
     64                    /**
     65                     * Note: This is a custom non-standard constructor that allows
     66                     *       us to create a future directly from a shared state. This
     67                     *       should never be a problem as aux::shared_state is a private
     68                     *       type and future has no constructor templates.
     69                     */
     70                }
     71
     72                virtual ~future_base()
     73                {
     74                    release_state_();
     75                }
     76
     77                future_base& operator=(const future_base&) = delete;
     78
     79                future_base& operator=(future_base&& rhs) noexcept
     80                {
     81                    release_state_();
     82                    state_ = std::move(rhs.state_);
     83                    rhs.state_ = nullptr;
     84                }
     85
     86                bool valid() const noexcept
     87                {
     88                    return state_ != nullptr;
     89                }
     90
     91                void wait() const noexcept
     92                {
     93                    assert(state_);
     94
     95                    state_->wait();
     96                }
     97
     98                template<class Rep, class Period>
     99                future_status
     100                wait_for(const chrono::duration<Rep, Period>& rel_time) const
     101                {
     102                    assert(state_);
     103
     104                    return state_->wait_for(rel_time);
     105                }
     106
     107                template<class Clock, class Duration>
     108                future_status
     109                wait_until(
     110                    const chrono::time_point<Clock, Duration>& abs_time
     111                ) const
     112                {
     113                    assert(state_);
     114
     115                    return state_->wait_until(abs_time);
     116                }
     117
     118            protected:
     119                void release_state_()
     120                {
     121                    if (!state_)
     122                        return;
     123
     124                    /**
     125                     * Note: This is the 'release' move described in
     126                     *       30.6.4 (5).
     127                     * Last reference to state -> destroy state.
     128                     * Decrement refcount of state otherwise.
     129                     * Will not block, unless all following hold:
     130                     *  1) State was created by call to std::async.
     131                     *  2) State is not yet ready.
     132                     *  3) This was the last reference to the shared state.
     133                     */
     134                    if (state_->decrement())
     135                    {
     136                        /**
     137                         * The destroy call handles the special case
     138                         * when 1) - 3) hold.
     139                         */
     140                        state_->destroy();
     141                        delete state_;
     142                        state_ = nullptr;
     143                    }
     144                }
     145
     146                aux::shared_state<R>* state_;
     147        };
     148    }
     149
    94150    template<class R>
    95151    class shared_future;
    96152
    97153    template<class R>
    98     class future
     154    class future: public aux::future_base<R>
    99155    {
    100156        public:
    101157            future() noexcept
    102                 : state_{nullptr}
     158                : aux::future_base<R>{}
    103159            { /* DUMMY BODY */ }
    104160
     
    106162
    107163            future(future&& rhs) noexcept
    108                 : state_{std::move(rhs.state_)}
    109             {
    110                 rhs.state_ = nullptr;
    111             }
     164                : aux::future_base<R>{std::move(rhs.state_)}
     165            { /* DUMMY BODY */ }
    112166
    113167            future(aux::shared_state<R>* state)
    114                 : state_{state}
    115             {
    116                 /**
    117                  * Note: This is a custom non-standard constructor that allows
    118                  *       us to create a future directly from a shared state. This
    119                  *       should never be a problem as aux::shared_state is a private
    120                  *       type and future has no constructor templates.
    121                  */
    122             }
    123 
    124             ~future()
    125             {
    126                 release_state_();
    127             }
    128 
    129             future& operator=(const future) = delete;
     168                : aux::future_base<R>{state}
     169            { /* DUMMY BODY */ }
     170
     171            future& operator=(const future&) = delete;
    130172
    131173            future& operator=(future&& rhs) noexcept
    132174            {
    133                 release_state_();
    134                 state_ = std::move(rhs.state_);
    135                 rhs.state_ = nullptr;
     175                return aux::future_base<R>::operator=(std::move(rhs));
    136176            }
    137177
     
    143183            R get()
    144184            {
    145                 assert(state_);
    146 
    147                 wait();
    148 
    149                 if (state_->has_exception())
    150                     state_->throw_stored_exception();
    151                 auto res = std::move(state_->get());
    152 
    153                 release_state_();
     185                assert(this->state_);
     186
     187                this->wait();
     188
     189                if (this->state_->has_exception())
     190                    this->state_->throw_stored_exception();
     191                auto res = std::move(this->state_->get());
     192
     193                this->release_state_();
    154194
    155195                return res;
    156196            }
    157 
    158             bool valid() const noexcept
    159             {
    160                 return state_ != nullptr;
    161             }
    162 
    163             void wait() const noexcept
    164             {
    165                 assert(state_);
    166 
    167                 state_->wait();
    168             }
    169 
    170             template<class Rep, class Period>
    171             future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const
    172             {
    173                 assert(state_);
    174 
    175                 return state_->wait_for(rel_time);
    176             }
    177 
    178             template<class Clock, class Duration>
    179             future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const
    180             {
    181                 assert(state_);
    182 
    183                 return state_->wait_until(abs_time);
    184             }
    185 
    186         private:
    187             void release_state_()
    188             {
    189                 if (!state_)
    190                     return;
    191 
    192                 /**
    193                  * Note: This is the 'release' move described in
    194                  *       30.6.4 (5).
    195                  * Last reference to state -> destroy state.
    196                  * Decrement refcount of state otherwise.
    197                  * Will not block, unless all following hold:
    198                  *  1) State was created by call to std::async.
    199                  *  2) State is not yet ready.
    200                  *  3) This was the last reference to the shared state.
    201                  */
    202                 if (state_->decrement())
    203                 {
    204                     /**
    205                      * The destroy call handles the special case
    206                      * when 1) - 3) hold.
    207                      */
    208                     state_->destroy();
    209                     delete state_;
    210                     state_ = nullptr;
    211                 }
    212             }
    213 
    214             aux::shared_state<R>* state_;
    215197    };
    216198
Note: See TracChangeset for help on using the changeset viewer.