Changes in / [9fe2fd7:9fb280c] in mainline


Ignore:
Location:
uspace
Files:
1 added
9 deleted
13 edited

Legend:

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

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

    r9fe2fd7 r9fb280c  
    4747        src/mutex.cpp \
    4848        src/new.cpp \
    49         src/refcount_obj.cpp \
    5049        src/shared_mutex.cpp \
    5150        src/stdexcept.cpp \
     
    6463        src/__bits/test/deque.cpp \
    6564        src/__bits/test/functional.cpp \
    66         src/__bits/test/future.cpp \
    6765        src/__bits/test/list.cpp \
    6866        src/__bits/test/map.cpp \
  • TabularUnified uspace/lib/cpp/include/__bits/chrono.hpp

    r9fe2fd7 r9fb280c  
    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
  • TabularUnified uspace/lib/cpp/include/__bits/functional/functional.hpp

    r9fe2fd7 r9fb280c  
    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
  • TabularUnified uspace/lib/cpp/include/__bits/memory/shared_payload.hpp

    r9fe2fd7 r9fb280c  
    3030#define LIBCPP_BITS_MEMORY_SHARED_PAYLOAD
    3131
    32 #include <__bits/refcount_obj.hpp>
    3332#include <cinttypes>
    3433#include <utility>
     
    4443namespace std::aux
    4544{
     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
    4651    /**
    4752     * This allows us to construct shared_ptr from
     
    6166
    6267    template<class T>
    63     class shared_payload_base: public aux::refcount_obj
     68    class shared_payload_base
    6469    {
    6570        public:
     71            virtual void destroy() = 0;
    6672            virtual T* get() const noexcept = 0;
    6773
    6874            virtual uint8_t* deleter() const noexcept = 0;
    6975
     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;
    7083            virtual shared_payload_base* lock() noexcept = 0;
    7184
     
    7891        public:
    7992            shared_payload(T* ptr, D deleter = D{})
    80                 : data_{ptr}, deleter_{deleter}
     93                : data_{ptr}, deleter_{deleter},
     94                  refcount_{1}, weak_refcount_{1}
    8195            { /* DUMMY BODY */ }
    8296
     
    8498            shared_payload(Args&&... args)
    8599                : data_{new T{forward<Args>(args)...}},
    86                   deleter_{}
     100                  deleter_{}, refcount_{1}, weak_refcount_{1}
    87101            { /* DUMMY BODY */ }
    88102
     
    90104            shared_payload(allocator_arg_t, Alloc alloc, Args&&... args)
    91105                : data_{alloc.allocate(1)},
    92                   deleter_{}
     106                  deleter_{}, refcount_{1}, weak_refcount_{1}
    93107            {
    94108                alloc.construct(data_, forward<Args>(args)...);
     
    98112            shared_payload(D deleter, Alloc alloc, Args&&... args)
    99113                : data_{alloc.allocate(1)},
    100                   deleter_{deleter}
     114                  deleter_{deleter}, refcount_{1}, weak_refcount_{1}
    101115            {
    102116                alloc.construct(data_, forward<Args>(args)...);
     
    105119            void destroy() override
    106120            {
    107                 if (this->refs() == 0)
     121                if (refs() == 0)
    108122                {
    109123                    if (data_)
     
    113127                    }
    114128
    115                     if (this->weak_refs() == 0)
     129                    if (weak_refs() == 0)
    116130                        delete this;
    117131                }
     
    128142            }
    129143
     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
    130191            shared_payload_base<T>* lock() noexcept override
    131192            {
    132                 refcount_t rfs = this->refs();
     193                refcount_t rfs = refs();
    133194                while (rfs != 0L)
    134195                {
    135                     if (__atomic_compare_exchange_n(&this->refcount_, &rfs, rfs + 1,
     196                    if (__atomic_compare_exchange_n(&refcount_, &rfs, rfs + 1,
    136197                                                    true, __ATOMIC_RELAXED,
    137198                                                    __ATOMIC_RELAXED))
     
    147208            T* data_;
    148209            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_;
    149220    };
    150221}
  • TabularUnified uspace/lib/cpp/include/__bits/system_error.hpp

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

    r9fe2fd7 r9fb280c  
    11/*
    2  * Copyright (c) 2019 Jaroslav Jindrak
     2 * Copyright (c) 2018 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     };
    311297}
    312298
  • TabularUnified uspace/lib/cpp/include/__bits/thread/future.hpp

    r9fe2fd7 r9fb280c  
    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>
    3532#include <cassert>
     33#include <memory>
     34#include <system_error>
     35#include <type_traits>
    3636
    3737namespace std
    3838{
    3939    /**
    40      * 30.6.6, class template future:
     40     * 30.6, futures:
    4141     */
    4242
    43     namespace aux
     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
     49    };
     50
     51    enum class launch
    4452    {
    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 */ }
     53        async,
     54        deferred
     55    };
    5956
    60                 future_base(const future_base& rhs)
    61                     : state_{rhs.state_}
    62                 {
    63                     state_->increment();
    64                 }
     57    enum class future_status
     58    {
     59        ready,
     60        timeout,
     61        deferred
     62    };
    6563
    66                 future_base(future_base&& rhs) noexcept
    67                     : state_{move(rhs.state_)}
    68                 {
    69                     rhs.state_ = nullptr;
    70                 }
     64    /**
     65     * 30.6.2, error handling:
     66     */
    7167
    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                 }
     68    template<>
     69    struct is_error_code_enum<future_errc>: true_type
     70    { /* DUMMY BODY */ };
    8271
    83                 virtual ~future_base()
    84                 {
    85                     release_state_();
    86                 }
     72    error_code make_error_code(future_errc) noexcept;
     73    error_condition make_error_condition(future_errc) noexcept;
    8774
    88                 future_base& operator=(const future_base& rhs)
    89                 {
    90                     release_state_();
    91                     state_ = rhs.state_;
     75    const error_category& future_category() noexcept;
    9276
    93                     state_->increment();
     77    /**
     78     * 30.6.3, class future_error:
     79     */
    9480
    95                     return *this;
    96                 }
     81    class future_error: public logic_error
     82    {
     83        public:
     84            future_error(error_code ec);
    9785
    98                 future_base& operator=(future_base&& rhs) noexcept
    99                 {
    100                     release_state_();
    101                     state_ = move(rhs.state_);
    102                     rhs.state_ = nullptr;
     86            const error_code& code() const noexcept;
    10387
    104                     return *this;
    105                 }
     88        private:
     89            error_code code_;
     90    };
    10691
    107                 bool valid() const noexcept
    108                 {
    109                     return state_ != nullptr;
    110                 }
     92    /**
     93     * 30.6.4, shared state:
     94     */
    11195
    112                 void wait() const noexcept
    113                 {
    114                     assert(state_);
     96    template<class R>
     97    class promise
     98    {
     99    };
    115100
    116                     state_->wait();
    117                 }
     101    template<class R>
     102    class promise<R&>
     103    {
     104    };
    118105
    119                 template<class Rep, class Period>
    120                 future_status
    121                 wait_for(const chrono::duration<Rep, Period>& rel_time) const
    122                 {
    123                     assert(state_);
     106    template<>
     107    class promise<void>
     108    {
     109    };
    124110
    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         };
     111    template<class R>
     112    void swap(promise<R>& lhs, promise<R>& rhs) noexcept
     113    {
     114        lhs.swap(rhs);
    169115    }
    170116
    171     template<class R>
    172     class shared_future;
     117    template<class R, class Alloc>
     118    struct uses_allocator<promise<R>, Alloc>: true_type
     119    { /* DUMMY BODY */ };
    173120
    174121    template<class R>
    175     class future: public aux::future_base<aux::future_inner_t<R>>
     122    class future
    176123    {
    177         friend class shared_future<R>;
     124    };
    178125
    179         public:
    180             future() noexcept
    181                 : aux::future_base<aux::future_inner_t<R>>{}
    182             { /* DUMMY BODY */ }
     126    template<class R>
     127    class future<R&>
     128    {
     129    };
    183130
    184             future(const future&) = delete;
     131    template<>
     132    class future<void>
     133    {
     134    };
    185135
    186             future(future&& rhs) noexcept
    187                 : aux::future_base<aux::future_inner_t<R>>{move(rhs)}
    188             { /* DUMMY BODY */ }
     136    template<class R>
     137    class shared_future
     138    {
     139    };
    189140
    190             future(aux::shared_state<aux::future_inner_t<R>>* state)
    191                 : aux::future_base<aux::future_inner_t<R>>{state}
    192             { /* DUMMY BODY */ }
     141    template<class R>
     142    class shared_future<R&>
     143    {
     144    };
    193145
    194             future& operator=(const future&) = delete;
     146    template<>
     147    class shared_future<void>
     148    {
     149    };
    195150
    196             future& operator=(future&& rhs) noexcept = default;
     151    template<class>
     152    class packaged_task; // undefined
    197153
    198             shared_future<R> share()
    199             {
    200                 return shared_future<R>{move(*this)};
    201             }
     154    template<class R, class... Args>
     155    class packaged_task<R(Args...)>
     156    {
     157    };
    202158
    203             R get()
    204             {
    205                 assert(this->state_);
     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    };
    206164
    207                 this->wait();
     165    template<class R, class Alloc>
     166    struct uses_allocator<packaged_task<R>, Alloc>: true_type
     167    { /* DUMMY BODY */ };
    208168
    209                 if (this->state_->has_exception())
    210                     this->state_->throw_stored_exception();
     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    }
    211176
    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             }
    235     };
     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    }
    236184}
    237185
  • TabularUnified uspace/lib/cpp/include/__bits/trycatch.hpp

    r9fe2fd7 r9fb280c  
    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  */
    84 extern int __exception;
    85 
    86 /**
    8769 * These macros allow us to choose how the program
    8870 * should behave when an exception is thrown
     
    10587#define LIBCPP_EXCEPTION_IGNORE       /* IGNORE */
    10688#define LIBCPP_EXCEPTION_HANDLE_THROW LIBCPP_EXCEPTION_IGNORE
    107 #define LIBCPP_EXCEPTION_HANDLE_CATCH LIBCPP_EXCEPTION_ABORT
     89#define LIBCPP_EXCEPTION_HANDLE_CATCH LIBCPP_EXCEPTION_HANG
    10890
    10991#define try if constexpr (::std::aux::try_blocks_allowed)
  • TabularUnified uspace/lib/cpp/include/__bits/tuple/tuple.hpp

    r9fe2fd7 r9fb280c  
    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 
    454435    /**
    455436     * 20.4.2.7, relational operators:
  • TabularUnified uspace/lib/cpp/include/future

    r9fe2fd7 r9fb280c  
    2727 */
    2828
    29 #include <__bits/thread/async.hpp>
    3029#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>
  • TabularUnified uspace/lib/cpp/src/__bits/runtime.cpp

    r9fe2fd7 r9fb280c  
    2828
    2929#include <__bits/abi.hpp>
    30 #include <cassert>
    3130#include <cstdlib>
    3231#include <cstdint>
     
    208207    extern "C" void __cxa_end_cleanup()
    209208    { /* 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     }
    217209}
  • TabularUnified uspace/lib/cpp/src/future.cpp

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