Changes in / [9fe2fd7:9fb280c] in mainline
- Location:
- uspace
- Files:
-
- 1 added
- 9 deleted
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified uspace/app/cpptest/main.cpp ¶
r9fe2fd7 r9fb280c 121 121 ts.add<std::test::functional_test>(); 122 122 ts.add<std::test::algorithm_test>(); 123 ts.add<std::test::future_test>();124 123 125 124 return ts.run(true) ? 0 : 1; -
TabularUnified uspace/lib/cpp/Makefile ¶
r9fe2fd7 r9fb280c 47 47 src/mutex.cpp \ 48 48 src/new.cpp \ 49 src/refcount_obj.cpp \50 49 src/shared_mutex.cpp \ 51 50 src/stdexcept.cpp \ … … 64 63 src/__bits/test/deque.cpp \ 65 64 src/__bits/test/functional.cpp \ 66 src/__bits/test/future.cpp \67 65 src/__bits/test/list.cpp \ 68 66 src/__bits/test/map.cpp \ -
TabularUnified uspace/lib/cpp/include/__bits/chrono.hpp ¶
r9fe2fd7 r9fb280c 331 331 { 332 332 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())); 334 334 } 335 335 -
TabularUnified uspace/lib/cpp/include/__bits/functional/functional.hpp ¶
r9fe2fd7 r9fb280c 46 46 decltype(auto) invoke(F&& f, Args&&... args) 47 47 { 48 return aux::INVOKE(forward<F>(f) ,forward<Args>(args)...);48 return aux::INVOKE(forward<F>(f)(forward<Args>(args)...)); 49 49 } 50 50 -
TabularUnified uspace/lib/cpp/include/__bits/memory/shared_payload.hpp ¶
r9fe2fd7 r9fb280c 30 30 #define LIBCPP_BITS_MEMORY_SHARED_PAYLOAD 31 31 32 #include <__bits/refcount_obj.hpp>33 32 #include <cinttypes> 34 33 #include <utility> … … 44 43 namespace std::aux 45 44 { 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 46 51 /** 47 52 * This allows us to construct shared_ptr from … … 61 66 62 67 template<class T> 63 class shared_payload_base : public aux::refcount_obj68 class shared_payload_base 64 69 { 65 70 public: 71 virtual void destroy() = 0; 66 72 virtual T* get() const noexcept = 0; 67 73 68 74 virtual uint8_t* deleter() const noexcept = 0; 69 75 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; 70 83 virtual shared_payload_base* lock() noexcept = 0; 71 84 … … 78 91 public: 79 92 shared_payload(T* ptr, D deleter = D{}) 80 : data_{ptr}, deleter_{deleter} 93 : data_{ptr}, deleter_{deleter}, 94 refcount_{1}, weak_refcount_{1} 81 95 { /* DUMMY BODY */ } 82 96 … … 84 98 shared_payload(Args&&... args) 85 99 : data_{new T{forward<Args>(args)...}}, 86 deleter_{} 100 deleter_{}, refcount_{1}, weak_refcount_{1} 87 101 { /* DUMMY BODY */ } 88 102 … … 90 104 shared_payload(allocator_arg_t, Alloc alloc, Args&&... args) 91 105 : data_{alloc.allocate(1)}, 92 deleter_{} 106 deleter_{}, refcount_{1}, weak_refcount_{1} 93 107 { 94 108 alloc.construct(data_, forward<Args>(args)...); … … 98 112 shared_payload(D deleter, Alloc alloc, Args&&... args) 99 113 : data_{alloc.allocate(1)}, 100 deleter_{deleter} 114 deleter_{deleter}, refcount_{1}, weak_refcount_{1} 101 115 { 102 116 alloc.construct(data_, forward<Args>(args)...); … … 105 119 void destroy() override 106 120 { 107 if ( this->refs() == 0)121 if (refs() == 0) 108 122 { 109 123 if (data_) … … 113 127 } 114 128 115 if ( this->weak_refs() == 0)129 if (weak_refs() == 0) 116 130 delete this; 117 131 } … … 128 142 } 129 143 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 130 191 shared_payload_base<T>* lock() noexcept override 131 192 { 132 refcount_t rfs = this->refs();193 refcount_t rfs = refs(); 133 194 while (rfs != 0L) 134 195 { 135 if (__atomic_compare_exchange_n(& this->refcount_, &rfs, rfs + 1,196 if (__atomic_compare_exchange_n(&refcount_, &rfs, rfs + 1, 136 197 true, __ATOMIC_RELAXED, 137 198 __ATOMIC_RELAXED)) … … 147 208 T* data_; 148 209 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_; 149 220 }; 150 221 } -
TabularUnified uspace/lib/cpp/include/__bits/system_error.hpp ¶
r9fe2fd7 r9fb280c 33 33 #include <__bits/string/stringfwd.hpp> 34 34 #include <stdexcept> 35 #include <type_traits>36 35 37 36 namespace std -
TabularUnified uspace/lib/cpp/include/__bits/test/tests.hpp ¶
r9fe2fd7 r9fb280c 1 1 /* 2 * Copyright (c) 201 9Jaroslav Jindrak2 * Copyright (c) 2018 Jaroslav Jindrak 3 3 * All rights reserved. 4 4 * … … 295 295 void test_mutating(); 296 296 }; 297 298 class future_test: public test_suite299 {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 };311 297 } 312 298 -
TabularUnified uspace/lib/cpp/include/__bits/thread/future.hpp ¶
r9fe2fd7 r9fb280c 30 30 #define LIBCPP_BITS_THREAD_FUTURE 31 31 32 #include <__bits/thread/future_common.hpp>33 #include <__bits/thread/shared_state.hpp>34 #include <__bits/utility/forward_move.hpp>35 32 #include <cassert> 33 #include <memory> 34 #include <system_error> 35 #include <type_traits> 36 36 37 37 namespace std 38 38 { 39 39 /** 40 * 30.6 .6, class template future:40 * 30.6, futures: 41 41 */ 42 42 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 44 52 { 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 }; 59 56 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 }; 65 63 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 */ 71 67 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 */ }; 82 71 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; 87 74 88 future_base& operator=(const future_base& rhs) 89 { 90 release_state_(); 91 state_ = rhs.state_; 75 const error_category& future_category() noexcept; 92 76 93 state_->increment(); 77 /** 78 * 30.6.3, class future_error: 79 */ 94 80 95 return *this; 96 } 81 class future_error: public logic_error 82 { 83 public: 84 future_error(error_code ec); 97 85 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; 103 87 104 return *this; 105 } 88 private: 89 error_code code_; 90 }; 106 91 107 bool valid() const noexcept 108 { 109 return state_ != nullptr; 110 } 92 /** 93 * 30.6.4, shared state: 94 */ 111 95 112 void wait() const noexcept 113 { 114 assert(state_); 96 template<class R> 97 class promise 98 { 99 }; 115 100 116 state_->wait(); 117 } 101 template<class R> 102 class promise<R&> 103 { 104 }; 118 105 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 }; 124 110 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); 169 115 } 170 116 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 */ }; 173 120 174 121 template<class R> 175 class future : public aux::future_base<aux::future_inner_t<R>>122 class future 176 123 { 177 friend class shared_future<R>;124 }; 178 125 179 public:180 future() noexcept181 : aux::future_base<aux::future_inner_t<R>>{}182 { /* DUMMY BODY */ }126 template<class R> 127 class future<R&> 128 { 129 }; 183 130 184 future(const future&) = delete; 131 template<> 132 class future<void> 133 { 134 }; 185 135 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 }; 189 140 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 }; 193 145 194 future& operator=(const future&) = delete; 146 template<> 147 class shared_future<void> 148 { 149 }; 195 150 196 future& operator=(future&& rhs) noexcept = default; 151 template<class> 152 class packaged_task; // undefined 197 153 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 }; 202 158 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 }; 206 164 207 this->wait(); 165 template<class R, class Alloc> 166 struct uses_allocator<packaged_task<R>, Alloc>: true_type 167 { /* DUMMY BODY */ }; 208 168 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 } 211 176 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 } 236 184 } 237 185 -
TabularUnified uspace/lib/cpp/include/__bits/trycatch.hpp ¶
r9fe2fd7 r9fb280c 67 67 68 68 /** 69 * The language allows us to odr-use a variable70 * that is not defined. We use this to support71 * macros redefining the catch keyword that are72 * followed by a block that uses that symbol.73 *74 * Normally, that would produce a compiler error75 * as the declaration of that variale would be removed76 * with the catch statement, but if we use the following77 * 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 using81 * the aux:: namespace because that cannot be used in82 * variable declaration.83 */84 extern int __exception;85 86 /**87 69 * These macros allow us to choose how the program 88 70 * should behave when an exception is thrown … … 105 87 #define LIBCPP_EXCEPTION_IGNORE /* IGNORE */ 106 88 #define LIBCPP_EXCEPTION_HANDLE_THROW LIBCPP_EXCEPTION_IGNORE 107 #define LIBCPP_EXCEPTION_HANDLE_CATCH LIBCPP_EXCEPTION_ ABORT89 #define LIBCPP_EXCEPTION_HANDLE_CATCH LIBCPP_EXCEPTION_HANG 108 90 109 91 #define try if constexpr (::std::aux::try_blocks_allowed) -
TabularUnified uspace/lib/cpp/include/__bits/tuple/tuple.hpp ¶
r9fe2fd7 r9fb280c 433 433 }; 434 434 435 template<>436 class tuple<>437 {438 /**439 * In some cases, e.g. for async() calls440 * without argument to the functors, we need441 * zero length tuples, which are provided by442 * the following specialization.443 * (Without it we get a resolution conflict between444 * the default constructor and the Ts... constructor445 * in the original tuple.)446 */447 448 tuple() = default;449 450 void swap(tuple&) noexcept451 { /* DUMMY BODY */ }452 };453 454 435 /** 455 436 * 20.4.2.7, relational operators: -
TabularUnified uspace/lib/cpp/include/future ¶
r9fe2fd7 r9fb280c 27 27 */ 28 28 29 #include <__bits/thread/async.hpp>30 29 #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 28 28 29 29 #include <__bits/abi.hpp> 30 #include <cassert>31 30 #include <cstdlib> 32 31 #include <cstdint> … … 208 207 extern "C" void __cxa_end_cleanup() 209 208 { /* DUMMY BODY */ } 210 211 extern "C" int __cxa_thread_atexit(void(*)(void*), void*, void*)212 {213 // TODO: needed for thread_local variables214 __unimplemented();215 return 0;216 }217 209 } -
TabularUnified uspace/lib/cpp/src/future.cpp ¶
r9fe2fd7 r9fb280c 81 81 return code_; 82 82 } 83 84 const char* future_error::what() const noexcept85 {86 return code().message().c_str();87 }88 83 }
Note:
See TracChangeset
for help on using the changeset viewer.