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/shared_state.hpp

    rd86c00f0 r6e97265  
    3434 */
    3535
     36#include <__bits/exception.hpp>
    3637#include <__bits/functional/function.hpp>
    3738#include <__bits/functional/invoke.hpp>
    3839#include <__bits/refcount_obj.hpp>
     40#include <__bits/thread/future_common.hpp>
    3941#include <__bits/thread/threading.hpp>
     42#include <cerrno>
     43#include <thread>
     44#include <tuple>
     45
     46namespace std
     47{
     48    enum class future_status;
     49}
    4050
    4151namespace std::aux
     
    137147
    138148            template<class Rep, class Period>
    139             virtual future_status
     149            future_status
    140150            wait_for(const chrono::duration<Rep, Period>& rel_time)
    141151            {
    142152                aux::threading::mutex::lock(mutex_);
    143                 auto res = aux::threading::condvar::wait_for(
    144                     condvar_, mutex_,
     153                auto res = timed_wait_(
    145154                    aux::threading::time::convert(rel_time)
    146155                );
    147156                aux::threading::mutex::unlock(mutex_);
    148157
     158                return res;
     159            }
     160
     161            template<class Clock, class Duration>
     162            future_status
     163            wait_until(const chrono::time_point<Clock, Duration>& abs_time)
     164            {
     165                aux::threading::mutex::lock(mutex_);
     166                auto res = timed_wait_(
     167                    aux::threading::time(convert(abs_time - Clock::now()))
     168                );
     169                aux::threading::mutex::unlock(mutex_);
     170
     171                return res;
     172            }
     173
     174            ~shared_state() override = default;
     175
     176        protected:
     177            aux::mutex_t mutex_;
     178            aux::condvar_t condvar_;
     179
     180            R value_;
     181            bool value_set_;
     182
     183            exception_ptr exception_;
     184            bool has_exception_;
     185
     186            /**
     187             * Note: wait_for and wait_until are templates and as such
     188             *       cannot be virtual and overriden by the deferred_ and
     189             *       async_ children. However, we are using aux::time_unit_t
     190             *       in the end anyway, so we can work around that
     191             *       by using the 'template method' design pattern
     192             *       (i.e. by providing a virtual function called by these
     193             *       templates and then overriding that function in the
     194             *       children).
     195             */
     196            virtual future_status timed_wait_(aux::time_unit_t time)
     197            {
     198                auto res = aux::threading::condvar::wait_for(
     199                    condvar_, mutex_, time
     200                );
     201
    149202                return res == ETIMEOUT ? future_status::timeout
    150203                                       : future_status::ready;
    151204            }
    152 
    153             template<class Clock, class Duration>
    154             virtual future_status
    155             wait_until(const chrono::time_point<Clock, Duration>& abs_time)
    156             {
    157                 aux::threading::mutex::lock(mutex_);
    158                 auto res = aux::threading::condvar::wait_for(
    159                     condvar_, mutex_,
    160                     aux::threading::time::convert(abs_time - Clock::now())
    161                 );
    162                 aux::threading::mutex::unlock(mutex_);
    163 
    164                 return res == ETIMEOUT ? future_status::timeout
    165                                        : future_status::ready;
    166             }
    167 
    168             ~shared_state() override = default;
    169 
    170         private:
    171             aux::mutex_t mutex_;
    172             aux::condvar_t condvar_;
    173 
    174             R value_;
    175             bool value_set_;
    176 
    177             exception_ptr exception_;
    178             bool has_exception_;
    179205    };
    180206
     
    224250            }
    225251
    226             template<class Rep, class Period>
    227             future_status
    228             wait_for(const chrono::duration<Rep, Period>&) override
     252            ~async_shared_state() override
     253            {
     254                destroy();
     255            }
     256
     257        protected:
     258            future_status timed_wait_(aux::time_unit_t) override
    229259            {
    230260                // TODO: have to sleep and check
    231                 return future_status::ready;
    232             }
    233 
    234             template<class Clock, class Duration>
    235             future_status
    236             wait_until(const chrono::time_point<Clock, Duration>&) override
    237             {
    238                 // TODO: have to sleep and check
    239                 return future_status::ready;
    240             }
    241 
    242             ~async_shared_state() override
    243             {
    244                 destroy();
     261                return future_status::timeout;
    245262            }
    246263
     
    261278            void destroy() override
    262279            {
    263                 aux::threading::mutex::lock(mutex_);
     280                aux::threading::mutex::lock(this->mutex_);
    264281                if (!this->is_set())
    265282                    invoke_(make_index_sequence<sizeof...(Args)>{});
    266                 aux::threading::mutex::unlock(mutex_);
     283                aux::threading::mutex::unlock(this->mutex_);
    267284            }
    268285
    269286            void wait() override
    270287            {
    271                 aux::threading::mutex::lock(mutex_);
     288                /**
     289                 * Note: Synchronization done in invoke_ -> set_value.
     290                 */
    272291                if (!this->is_set())
    273292                    invoke_(make_index_sequence<sizeof...(Args)>{});
    274                 aux::threading::mutex::unlock(mutex_);
    275             }
    276 
    277             template<class Rep, class Period>
    278             future_status
    279             wait_for(const chrono::duration<Rep, Period>&) override
    280             {
    281                 /**
    282                  * Note: Neither of the wait_ functions has any effect
    283                  *       for deferred functions spawned by async (which
    284                  *       are the only users of this state type).
    285                  */
    286                 return future_status::deferred;
    287             }
    288 
    289             template<class Clock, class Duration>
    290             future_status
    291             wait_until(const chrono::time_point<Clock, Duration>&) override
    292             {
    293                 return future_status::deferred;
    294293            }
    295294
     
    299298            }
    300299
    301         private:
     300        protected:
    302301            function<R(decay_t<Args>...)> func_;
    303302            tuple<decay_t<Args>...> args_;
     
    315314                }
    316315            }
     316
     317            future_status timed_wait_(aux::time_unit_t) override
     318            {
     319                /**
     320                 * Note: Neither of the wait_ functions has any effect
     321                 *       for deferred functions spawned by async (which
     322                 *       are the only users of this state type).
     323                 */
     324                return future_status::deferred;
     325            }
    317326    };
    318327}
Note: See TracChangeset for help on using the changeset viewer.