Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 9fe2fd7 in mainline


Ignore:
Timestamp:
2019-07-24T11:44:40Z (16 months ago)
Author:
GitHub <noreply@…>
Branches:
master
Children:
34b32a20, a448937, f42ee6f
Parents:
9fb280c (diff), 8c0b781 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jaroslav Jindrak <Dzejrou@…> (2019-07-24 11:44:40)
git-committer:
GitHub <noreply@…> (2019-07-24 11:44:40)
Message:

Merge pull request #171 from Dzejrou/hackweek

C++ stdlib: <future>

Location:
uspace
Files:
8 added
13 edited
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/app/cpptest/main.cpp

    r9fb280c r9fe2fd7  
    121121    ts.add<std::test::functional_test>();
    122122    ts.add<std::test::algorithm_test>();
     123    ts.add<std::test::future_test>();
    123124
    124125    return ts.run(true) ? 0 : 1;
  • uspace/lib/cpp/Makefile

    r9fb280c r9fe2fd7  
    4747        src/mutex.cpp \
    4848        src/new.cpp \
     49        src/refcount_obj.cpp \
    4950        src/shared_mutex.cpp \
    5051        src/stdexcept.cpp \
     
    6364        src/__bits/test/deque.cpp \
    6465        src/__bits/test/functional.cpp \
     66        src/__bits/test/future.cpp \
    6567        src/__bits/test/list.cpp \
    6668        src/__bits/test/map.cpp \
  • uspace/lib/cpp/include/__bits/chrono.hpp

    r9fb280c r9fe2fd7  
    331331    {
    332332        using CD = common_type_t<duration<Rep1, Period1>, duration<Rep2, Period2>>;
    333         return CD(CD(lhs.count()) + CD(rhs.count()));
     333        return CD(CD(lhs).count() + CD(rhs).count());
    334334    }
    335335
  • uspace/lib/cpp/include/__bits/functional/functional.hpp

    r9fb280c r9fe2fd7  
    4646    decltype(auto) invoke(F&& f, Args&&... args)
    4747    {
    48         return aux::INVOKE(forward<F>(f)(forward<Args>(args)...));
     48        return aux::INVOKE(forward<F>(f),forward<Args>(args)...);
    4949    }
    5050
  • uspace/lib/cpp/include/__bits/memory/shared_payload.hpp

    r9fb280c r9fe2fd7  
    3030#define LIBCPP_BITS_MEMORY_SHARED_PAYLOAD
    3131
     32#include <__bits/refcount_obj.hpp>
    3233#include <cinttypes>
    3334#include <utility>
     
    4344namespace std::aux
    4445{
    45     /**
    46      * At the moment we do not have atomics, change this
    47      * to std::atomic<long> once we do.
    48      */
    49     using refcount_t = long;
    50 
    5146    /**
    5247     * This allows us to construct shared_ptr from
     
    6661
    6762    template<class T>
    68     class shared_payload_base
     63    class shared_payload_base: public aux::refcount_obj
    6964    {
    7065        public:
    71             virtual void destroy() = 0;
    7266            virtual T* get() const noexcept = 0;
    7367
    7468            virtual uint8_t* deleter() const noexcept = 0;
    7569
    76             virtual void increment() noexcept = 0;
    77             virtual void increment_weak() noexcept = 0;
    78             virtual bool decrement() noexcept = 0;
    79             virtual bool decrement_weak() noexcept = 0;
    80             virtual refcount_t refs() const noexcept = 0;
    81             virtual refcount_t weak_refs() const noexcept = 0;
    82             virtual bool expired() const noexcept = 0;
    8370            virtual shared_payload_base* lock() noexcept = 0;
    8471
     
    9178        public:
    9279            shared_payload(T* ptr, D deleter = D{})
    93                 : data_{ptr}, deleter_{deleter},
    94                   refcount_{1}, weak_refcount_{1}
     80                : data_{ptr}, deleter_{deleter}
    9581            { /* DUMMY BODY */ }
    9682
     
    9884            shared_payload(Args&&... args)
    9985                : data_{new T{forward<Args>(args)...}},
    100                   deleter_{}, refcount_{1}, weak_refcount_{1}
     86                  deleter_{}
    10187            { /* DUMMY BODY */ }
    10288
     
    10490            shared_payload(allocator_arg_t, Alloc alloc, Args&&... args)
    10591                : data_{alloc.allocate(1)},
    106                   deleter_{}, refcount_{1}, weak_refcount_{1}
     92                  deleter_{}
    10793            {
    10894                alloc.construct(data_, forward<Args>(args)...);
     
    11298            shared_payload(D deleter, Alloc alloc, Args&&... args)
    11399                : data_{alloc.allocate(1)},
    114                   deleter_{deleter}, refcount_{1}, weak_refcount_{1}
     100                  deleter_{deleter}
    115101            {
    116102                alloc.construct(data_, forward<Args>(args)...);
     
    119105            void destroy() override
    120106            {
    121                 if (refs() == 0)
     107                if (this->refs() == 0)
    122108                {
    123109                    if (data_)
     
    127113                    }
    128114
    129                     if (weak_refs() == 0)
     115                    if (this->weak_refs() == 0)
    130116                        delete this;
    131117                }
     
    142128            }
    143129
    144             void increment() noexcept override
    145             {
    146                 __atomic_add_fetch(&refcount_, 1, __ATOMIC_ACQ_REL);
    147             }
    148 
    149             void increment_weak() noexcept override
    150             {
    151                 __atomic_add_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL);
    152             }
    153 
    154             bool decrement() noexcept override
    155             {
    156                 if (__atomic_sub_fetch(&refcount_, 1, __ATOMIC_ACQ_REL) == 0)
    157                 {
    158                     /**
    159                      * First call to destroy() will delete the held object,
    160                      * so it doesn't matter what the weak_refcount_ is,
    161                      * but we added one and we need to remove it now.
    162                      */
    163                     decrement_weak();
    164 
    165                     return true;
    166                 }
    167                 else
    168                     return false;
    169             }
    170 
    171             bool decrement_weak() noexcept override
    172             {
    173                 return __atomic_sub_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL) == 0 && refs() == 0;
    174             }
    175 
    176             refcount_t refs() const noexcept override
    177             {
    178                 return __atomic_load_n(&refcount_, __ATOMIC_RELAXED);
    179             }
    180 
    181             refcount_t weak_refs() const noexcept override
    182             {
    183                 return __atomic_load_n(&weak_refcount_, __ATOMIC_RELAXED);
    184             }
    185 
    186             bool expired() const noexcept override
    187             {
    188                 return refs() == 0;
    189             }
    190 
    191130            shared_payload_base<T>* lock() noexcept override
    192131            {
    193                 refcount_t rfs = refs();
     132                refcount_t rfs = this->refs();
    194133                while (rfs != 0L)
    195134                {
    196                     if (__atomic_compare_exchange_n(&refcount_, &rfs, rfs + 1,
     135                    if (__atomic_compare_exchange_n(&this->refcount_, &rfs, rfs + 1,
    197136                                                    true, __ATOMIC_RELAXED,
    198137                                                    __ATOMIC_RELAXED))
     
    208147            T* data_;
    209148            D deleter_;
    210 
    211             /**
    212              * We're using a trick where refcount_ > 0
    213              * means weak_refcount_ has 1 added to it,
    214              * this makes it easier for weak_ptrs that
    215              * can't decrement the weak_refcount_ to
    216              * zero with shared_ptrs using this object.
    217              */
    218             refcount_t refcount_;
    219             refcount_t weak_refcount_;
    220149    };
    221150}
  • uspace/lib/cpp/include/__bits/refcount_obj.hpp

    r9fb280c r9fe2fd7  
    11/*
    2  * Copyright (c) 2018 Jaroslav Jindrak
     2 * Copyright (c) 2019 Jaroslav Jindrak
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 #ifndef LIBCPP_BITS_RESULT_OF
    30 #define LIBCPP_BITS_RESULT_OF
     29#ifndef LIBCPP_BITS_REFCOUNT_OBJ
     30#define LIBCPP_BITS_REFCOUNT_OBJ
    3131
    32 /**
    33  * TODO: We have two implementations and I can't remember which
    34  *       one is the correnct one, investigate!
    35  */
    36 #include <__bits/invoke.hpp>
    37 
    38 namespace std
     32namespace std::aux
    3933{
    4034    /**
    41      * Note: This doesn't work, C++14 standard allows for F
    42      *       to be any complete type, our implementation
    43      *       currently works like the C++11 version where
    44      *       F has to be callable.
    45      * TODO: Fix this.
     35     * At the moment we do not have atomics, change this
     36     * to std::atomic<long> once we do.
    4637     */
     38    using refcount_t = long;
    4739
    48     template<class>
    49     struct result_of;
     40    class refcount_obj
     41    {
     42        public:
     43            refcount_obj() = default;
    5044
    51     template<class F, class... Args>
    52     class result_of<F(Args...)>: aux::type_is<
    53         decltype(aux::invoke(declval<F>(), declval<ArgTypes>()...))
    54     >
    55     { /* DUMMY BODY */ };
     45            void increment() noexcept;
     46            void increment_weak() noexcept;
     47            bool decrement() noexcept;
     48            bool decrement_weak() noexcept;
     49            refcount_t refs() const noexcept;
     50            refcount_t weak_refs() const noexcept;
     51            bool expired() const noexcept;
    5652
    57     template<class T>
    58     using result_of_t = typename result_of<T>::type;
     53            virtual ~refcount_obj() = default;
     54            virtual void destroy() = 0;
     55
     56        protected:
     57            /**
     58             * We're using a trick where refcount_ > 0
     59             * means weak_refcount_ has 1 added to it,
     60             * this makes it easier for weak_ptrs that
     61             * can't decrement the weak_refcount_ to
     62             * zero with shared_ptrs using this object.
     63             */
     64            refcount_t refcount_{1};
     65            refcount_t weak_refcount_{1};
     66    };
    5967}
    6068
  • uspace/lib/cpp/include/__bits/system_error.hpp

    r9fb280c r9fe2fd7  
    3333#include <__bits/string/stringfwd.hpp>
    3434#include <stdexcept>
     35#include <type_traits>
    3536
    3637namespace std
  • uspace/lib/cpp/include/__bits/test/tests.hpp

    r9fb280c r9fe2fd7  
    11/*
    2  * Copyright (c) 2018 Jaroslav Jindrak
     2 * Copyright (c) 2019 Jaroslav Jindrak
    33 * All rights reserved.
    44 *
     
    295295            void test_mutating();
    296296    };
     297
     298    class future_test: public test_suite
     299    {
     300        public:
     301            bool run(bool) override;
     302            const char* name() override;
     303        private:
     304            void test_future();
     305            void test_promise();
     306            void test_future_promise();
     307            void test_async();
     308            void test_packaged_task();
     309            void test_shared_future();
     310    };
    297311}
    298312
  • uspace/lib/cpp/include/__bits/thread/future.hpp

    r9fb280c r9fe2fd7  
    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 <type_traits>
    3636
    3737namespace std
    3838{
    3939    /**
    40      * 30.6, futures:
     40     * 30.6.6, class template future:
    4141     */
    4242
    43     enum class future_errc
    44     { // The 5001 start is to not collide with system_error's codes.
    45         broken_promise = 5001,
    46         future_already_retrieved,
    47         promise_already_satisfied,
    48         no_state
     43    namespace aux
     44    {
     45        /**
     46         * Note: Because of shared_future, this base class
     47         *       does implement copy constructor and copy
     48         *       assignment operator. This means that the
     49         *       children (std::future) need to delete this
     50         *       constructor and operator themselves.
     51         */
     52        template<class R>
     53        class future_base
     54        {
     55            public:
     56                future_base() noexcept
     57                    : state_{nullptr}
     58                { /* DUMMY BODY */ }
     59
     60                future_base(const future_base& rhs)
     61                    : state_{rhs.state_}
     62                {
     63                    state_->increment();
     64                }
     65
     66                future_base(future_base&& rhs) noexcept
     67                    : state_{move(rhs.state_)}
     68                {
     69                    rhs.state_ = nullptr;
     70                }
     71
     72                future_base(aux::shared_state<R>* state)
     73                    : state_{state}
     74                {
     75                    /**
     76                     * Note: This is a custom non-standard constructor that allows
     77                     *       us to create a future directly from a shared state. This
     78                     *       should never be a problem as aux::shared_state is a private
     79                     *       type and future has no constructor templates.
     80                     */
     81                }
     82
     83                virtual ~future_base()
     84                {
     85                    release_state_();
     86                }
     87
     88                future_base& operator=(const future_base& rhs)
     89                {
     90                    release_state_();
     91                    state_ = rhs.state_;
     92
     93                    state_->increment();
     94
     95                    return *this;
     96                }
     97
     98                future_base& operator=(future_base&& rhs) noexcept
     99                {
     100                    release_state_();
     101                    state_ = move(rhs.state_);
     102                    rhs.state_ = nullptr;
     103
     104                    return *this;
     105                }
     106
     107                bool valid() const noexcept
     108                {
     109                    return state_ != nullptr;
     110                }
     111
     112                void wait() const noexcept
     113                {
     114                    assert(state_);
     115
     116                    state_->wait();
     117                }
     118
     119                template<class Rep, class Period>
     120                future_status
     121                wait_for(const chrono::duration<Rep, Period>& rel_time) const
     122                {
     123                    assert(state_);
     124
     125                    return state_->wait_for(rel_time);
     126                }
     127
     128                template<class Clock, class Duration>
     129                future_status
     130                wait_until(
     131                    const chrono::time_point<Clock, Duration>& abs_time
     132                ) const
     133                {
     134                    assert(state_);
     135
     136                    return state_->wait_until(abs_time);
     137                }
     138
     139            protected:
     140                void release_state_()
     141                {
     142                    if (!state_)
     143                        return;
     144
     145                    /**
     146                     * Note: This is the 'release' move described in
     147                     *       30.6.4 (5).
     148                     * Last reference to state -> destroy state.
     149                     * Decrement refcount of state otherwise.
     150                     * Will not block, unless all following hold:
     151                     *  1) State was created by call to std::async.
     152                     *  2) State is not yet ready.
     153                     *  3) This was the last reference to the shared state.
     154                     */
     155                    if (state_->decrement())
     156                    {
     157                        /**
     158                         * The destroy call handles the special case
     159                         * when 1) - 3) hold.
     160                         */
     161                        state_->destroy();
     162                        delete state_;
     163                        state_ = nullptr;
     164                    }
     165                }
     166
     167                aux::shared_state<R>* state_;
     168        };
     169    }
     170
     171    template<class R>
     172    class shared_future;
     173
     174    template<class R>
     175    class future: public aux::future_base<aux::future_inner_t<R>>
     176    {
     177        friend class shared_future<R>;
     178
     179        public:
     180            future() noexcept
     181                : aux::future_base<aux::future_inner_t<R>>{}
     182            { /* DUMMY BODY */ }
     183
     184            future(const future&) = delete;
     185
     186            future(future&& rhs) noexcept
     187                : aux::future_base<aux::future_inner_t<R>>{move(rhs)}
     188            { /* DUMMY BODY */ }
     189
     190            future(aux::shared_state<aux::future_inner_t<R>>* state)
     191                : aux::future_base<aux::future_inner_t<R>>{state}
     192            { /* DUMMY BODY */ }
     193
     194            future& operator=(const future&) = delete;
     195
     196            future& operator=(future&& rhs) noexcept = default;
     197
     198            shared_future<R> share()
     199            {
     200                return shared_future<R>{move(*this)};
     201            }
     202
     203            R get()
     204            {
     205                assert(this->state_);
     206
     207                this->wait();
     208
     209                if (this->state_->has_exception())
     210                    this->state_->throw_stored_exception();
     211
     212                if constexpr (!is_same_v<R, void>)
     213                {
     214                    if constexpr (is_reference_v<R>)
     215                    {
     216                        assert(this->state_->get());
     217
     218                        return *this->state_->get();
     219                    }
     220                    else
     221                        return this->state_->get();
     222                }
     223            }
     224
     225            /**
     226             * Useful for testing as we can check some information
     227             * otherwise unavailable to us without waiting, e.g.
     228             * to check whether the state is ready, its reference
     229             * count etc.
     230             */
     231            aux::shared_state<aux::future_inner_t<R>>* __state() noexcept
     232            {
     233                return this->state_;
     234            }
    49235    };
    50 
    51     enum class launch
    52     {
    53         async,
    54         deferred
    55     };
    56 
    57     enum class future_status
    58     {
    59         ready,
    60         timeout,
    61         deferred
    62     };
    63 
    64     /**
    65      * 30.6.2, error handling:
    66      */
    67 
    68     template<>
    69     struct is_error_code_enum<future_errc>: true_type
    70     { /* DUMMY BODY */ };
    71 
    72     error_code make_error_code(future_errc) noexcept;
    73     error_condition make_error_condition(future_errc) noexcept;
    74 
    75     const error_category& future_category() noexcept;
    76 
    77     /**
    78      * 30.6.3, class future_error:
    79      */
    80 
    81     class future_error: public logic_error
    82     {
    83         public:
    84             future_error(error_code ec);
    85 
    86             const error_code& code() const noexcept;
    87 
    88         private:
    89             error_code code_;
    90     };
    91 
    92     /**
    93      * 30.6.4, shared state:
    94      */
    95 
    96     template<class R>
    97     class promise
    98     {
    99     };
    100 
    101     template<class R>
    102     class promise<R&>
    103     {
    104     };
    105 
    106     template<>
    107     class promise<void>
    108     {
    109     };
    110 
    111     template<class R>
    112     void swap(promise<R>& lhs, promise<R>& rhs) noexcept
    113     {
    114         lhs.swap(rhs);
    115     }
    116 
    117     template<class R, class Alloc>
    118     struct uses_allocator<promise<R>, Alloc>: true_type
    119     { /* DUMMY BODY */ };
    120 
    121     template<class R>
    122     class future
    123     {
    124     };
    125 
    126     template<class R>
    127     class future<R&>
    128     {
    129     };
    130 
    131     template<>
    132     class future<void>
    133     {
    134     };
    135 
    136     template<class R>
    137     class shared_future
    138     {
    139     };
    140 
    141     template<class R>
    142     class shared_future<R&>
    143     {
    144     };
    145 
    146     template<>
    147     class shared_future<void>
    148     {
    149     };
    150 
    151     template<class>
    152     class packaged_task; // undefined
    153 
    154     template<class R, class... Args>
    155     class packaged_task<R(Args...)>
    156     {
    157     };
    158 
    159     template<class R, class... Args>
    160     void swap(packaged_task<R(Args...)>& lhs, packaged_task<R(Args...)>& rhs) noexcept
    161     {
    162         lhs.swap(rhs);
    163     };
    164 
    165     template<class R, class Alloc>
    166     struct uses_allocator<packaged_task<R>, Alloc>: true_type
    167     { /* DUMMY BODY */ };
    168 
    169     template<class F, class... Args>
    170     future<result_of_t<decay_t<F>(decay_t<Args>...)>>
    171     async(F&& f, Args&&... args)
    172     {
    173         // TODO: implement
    174         __unimplemented();
    175     }
    176 
    177     template<class F, class... Args>
    178     future<result_of_t<decay_t<F>(decay_t<Args>...)>>
    179     async(launch, F&& f, Args&&... args)
    180     {
    181         // TODO: implement
    182         __unimplemented();
    183     }
    184236}
    185237
  • uspace/lib/cpp/include/__bits/trycatch.hpp

    r9fb280c r9fe2fd7  
    6767
    6868/**
     69 * The language allows us to odr-use a variable
     70 * that is not defined. We use this to support
     71 * macros redefining the catch keyword that are
     72 * followed by a block that uses that symbol.
     73 *
     74 * Normally, that would produce a compiler error
     75 * as the declaration of that variale would be removed
     76 * with the catch statement, but if we use the following
     77 * declaration's name as the name of the caught exception,
     78 * all will work well because of this extern declaration.
     79 *
     80 * Note: We do not follow our usual convention of using
     81 * the aux:: namespace because that cannot be used in
     82 * variable declaration.
     83 */
     84extern int __exception;
     85
     86/**
    6987 * These macros allow us to choose how the program
    7088 * should behave when an exception is thrown
     
    87105#define LIBCPP_EXCEPTION_IGNORE       /* IGNORE */
    88106#define LIBCPP_EXCEPTION_HANDLE_THROW LIBCPP_EXCEPTION_IGNORE
    89 #define LIBCPP_EXCEPTION_HANDLE_CATCH LIBCPP_EXCEPTION_HANG
     107#define LIBCPP_EXCEPTION_HANDLE_CATCH LIBCPP_EXCEPTION_ABORT
    90108
    91109#define try if constexpr (::std::aux::try_blocks_allowed)
  • uspace/lib/cpp/include/__bits/tuple/tuple.hpp

    r9fb280c r9fe2fd7  
    433433    };
    434434
     435    template<>
     436    class tuple<>
     437    {
     438        /**
     439         * In some cases, e.g. for async() calls
     440         * without argument to the functors, we need
     441         * zero length tuples, which are provided by
     442         * the following specialization.
     443         * (Without it we get a resolution conflict between
     444         * the default constructor and the Ts... constructor
     445         * in the original tuple.)
     446         */
     447
     448        tuple() = default;
     449
     450        void swap(tuple&) noexcept
     451        { /* DUMMY BODY */ }
     452    };
     453
    435454    /**
    436455     * 20.4.2.7, relational operators:
  • uspace/lib/cpp/include/future

    r9fb280c r9fe2fd7  
    2727 */
    2828
     29#include <__bits/thread/async.hpp>
    2930#include <__bits/thread/future.hpp>
     31#include <__bits/thread/future_common.hpp>
     32#include <__bits/thread/packaged_task.hpp>
     33#include <__bits/thread/promise.hpp>
     34#include <__bits/thread/shared_future.hpp>
     35#include <__bits/thread/shared_state.hpp>
  • uspace/lib/cpp/src/__bits/runtime.cpp

    r9fb280c r9fe2fd7  
    2828
    2929#include <__bits/abi.hpp>
     30#include <cassert>
    3031#include <cstdlib>
    3132#include <cstdint>
     
    207208    extern "C" void __cxa_end_cleanup()
    208209    { /* DUMMY BODY */ }
     210
     211    extern "C" int __cxa_thread_atexit(void(*)(void*), void*, void*)
     212    {
     213        // TODO: needed for thread_local variables
     214        __unimplemented();
     215        return 0;
     216    }
    209217}
  • uspace/lib/cpp/src/future.cpp

    r9fb280c r9fe2fd7  
    8181        return code_;
    8282    }
     83
     84    const char* future_error::what() const noexcept
     85    {
     86        return code().message().c_str();
     87    }
    8388}
Note: See TracChangeset for help on using the changeset viewer.