Blame view

RIOT/sys/cpp11-compat/include/riot/condition_variable.hpp 4.15 KB
fb11e647   vrobic   reseau statique a...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  /*
   * Copyright (C) 2015 Hamburg University of Applied Sciences (HAW)
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @ingroup cpp11-compat
   * @{
   *
   * @file
   * @brief  C++11 condition variable drop in replacement
   * @see    <a href="http://en.cppreference.com/w/cpp/thread/condition_variable">
   *           std::condition_variable
   *         </a>
   *
   * @author Raphael Hiesgen <raphael.hiesgen (at) haw-hamburg.de>
   *
   * @}
   */
  
  #ifndef RIOT_CONDITION_VARIABLE_HPP
  #define RIOT_CONDITION_VARIABLE_HPP
  
  #include "sched.h"
  #include "xtimer.h"
  #include "priority_queue.h"
  
  #include "riot/mutex.hpp"
  #include "riot/chrono.hpp"
  
  namespace riot {
  
  enum class cv_status {
    no_timeout,
    timeout
  };
  
  /**
   * @brief C++11 complient implementation of condition variable, uses the time
   *              point implemented in our chrono replacement instead of the
   *              specified one
   * @see   <a href="http://en.cppreference.com/w/cpp/thread/condition_variable">
   *          std::condition_variable
   *        </a>
   */
  class condition_variable {
   public:
    using native_handle_type = priority_queue_t*;
  
    inline condition_variable() { m_queue.first = NULL; }
    ~condition_variable();
  
    void notify_one() noexcept;
    void notify_all() noexcept;
  
    void wait(unique_lock<mutex>& lock) noexcept;
    template <class Predicate>
    void wait(unique_lock<mutex>& lock, Predicate pred);
    cv_status wait_until(unique_lock<mutex>& lock,
                         const time_point& timeout_time);
    template <class Predicate>
    bool wait_until(unique_lock<mutex>& lock, const time_point& timeout_time,
                    Predicate pred);
  
    template <class Rep, class Period>
    cv_status wait_for(unique_lock<mutex>& lock,
                       const std::chrono::duration<Rep, Period>& rel_time);
    template <class Rep, class Period, class Predicate>
    bool wait_for(unique_lock<mutex>& lock,
                  const std::chrono::duration<Rep, Period>& rel_time,
                  Predicate pred);
  
    inline native_handle_type native_handle() { return &m_queue; }
  
   private:
    condition_variable(const condition_variable&);
    condition_variable& operator=(const condition_variable&);
  
    priority_queue_t m_queue;
  };
  
  template <class Predicate>
  void condition_variable::wait(unique_lock<mutex>& lock, Predicate pred) {
    while (!pred()) {
      wait(lock);
    }
  }
  
  template <class Predicate>
  bool condition_variable::wait_until(unique_lock<mutex>& lock,
                                      const time_point& timeout_time,
                                      Predicate pred) {
    while (!pred()) {
      if (wait_until(lock, timeout_time) == cv_status::timeout) {
        return pred();
      }
    }
    return true;
  }
  
  template <class Rep, class Period>
  cv_status condition_variable::wait_for(unique_lock<mutex>& lock,
                                         const std::chrono::duration
                                         <Rep, Period>& timeout_duration) {
    using namespace std::chrono;
    using std::chrono::duration;
    if (timeout_duration <= timeout_duration.zero()) {
      return cv_status::timeout;
    }
    timex_t timeout, before, after;
    auto s = duration_cast<seconds>(timeout_duration);
    timeout.seconds = s.count();
    timeout.microseconds
      = (duration_cast<microseconds>(timeout_duration - s)).count();
    xtimer_now_timex(&before);
    xtimer_t timer;
    xtimer_set_wakeup(&timer, timex_uint64(timeout), sched_active_pid);
    wait(lock);
    xtimer_now_timex(&after);
    xtimer_remove(&timer);
    auto passed = timex_sub(after, before);
    auto cmp = timex_cmp(passed, timeout);
    return cmp < 1 ? cv_status::no_timeout : cv_status::timeout;
  }
  
  template <class Rep, class Period, class Predicate>
  inline bool condition_variable::wait_for(unique_lock<mutex>& lock,
                                           const std::chrono::duration
                                           <Rep, Period>& timeout_duration,
                                           Predicate pred) {
    return wait_until(lock, std::chrono::steady_clock::now() + timeout_duration,
                      std::move(pred));
  }
  
  } // namespace riot
  
  #endif // RIOT_CONDITION_VARIABLE_HPP