Mir
no_tls_future-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright © 2015 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17  */
18 
19 //Hybris and libc can have TLS collisions in the thread using OpenGL
20 //between std::promise and the GL dispatch.
21 //https://github.com/libhybris/libhybris/issues/212
22 //If this bug is resolved, switch to std::future and rm this file
23 
24 #ifndef MIR_CLIENT_NO_TLS_FUTURE_INL_H_
25 #define MIR_CLIENT_NO_TLS_FUTURE_INL_H_
26 
27 #include <memory>
28 #include <mutex>
29 #include <condition_variable>
30 #include <future>
31 
32 namespace mir
33 {
34 namespace client
35 {
36 template<typename T>
38 {
39 public:
40  template<class Rep, class Period>
41  std::future_status wait_for(std::chrono::duration<Rep, Period> const& timeout_duration) const
42  {
43  std::unique_lock<std::mutex> lk(mutex);
44  if (cv.wait_for(lk, timeout_duration, [this]{ return set || broken; }))
45  return std::future_status::ready;
46  return std::future_status::timeout;
47  }
48 
49  void set_value(T const& val)
50  {
51  std::lock_guard<std::mutex> lk(mutex);
52  set = true;
53  value = val;
54  cv.notify_all();
55  }
56 
57  void set_value(T && val)
58  {
59  std::lock_guard<std::mutex> lk(mutex);
60  set = true;
61  value = std::move(val);
62  cv.notify_all();
63  }
64 
66  {
67  std::unique_lock<std::mutex> lk(mutex);
68  cv.wait(lk, [this]{ return set || broken; });
69  if (broken)
70  throw std::future_error(std::future_errc::broken_promise);
71  return value;
72  }
73 
75  {
76  std::lock_guard<std::mutex> lk(mutex);
77  if (!set)
78  broken = true;
79  cv.notify_all();
80  }
81 
82  PromiseState() = default;
83  PromiseState(PromiseState const&) = delete;
84  PromiseState(PromiseState &&) = delete;
85  PromiseState& operator=(PromiseState const&) = delete;
86  PromiseState& operator=(PromiseState &&) = delete;
87 
88 private:
89  std::mutex mutable mutex;
90  std::condition_variable mutable cv;
91  bool set{false};
92  bool broken{false};
93  T value;
94 };
95 
96 template<typename T>
98 {
100  state(nullptr)
101  {
102  }
103 
104  NoTLSFuture(std::shared_ptr<PromiseState<T>> const& state) :
105  state(state)
106  {
107  }
108 
110  state(std::move(other.state))
111  {
112  }
113 
115  {
116  state = std::move(other.state);
117  return *this;
118  }
119 
120  NoTLSFuture(NoTLSFuture const&) = delete;
121  NoTLSFuture& operator=(NoTLSFuture const&) = delete;
122 
123  void validate_state() const
124  {
125  if (!valid())
126  throw std::logic_error("state was not valid");
127  }
128 
129  T get()
130  {
131  validate_state();
132  auto value = state->get_value();
133  state = nullptr;
134  return value;
135  }
136 
137  template<class Rep, class Period>
138  std::future_status wait_for(std::chrono::duration<Rep, Period> const& timeout_duration) const
139  {
140  validate_state();
141  return state->wait_for(timeout_duration);
142  }
143 
144  bool valid() const
145  {
146  return state != nullptr;
147  }
148 
149 private:
150  std::shared_ptr<PromiseState<T>> state;
151 };
152 
153 template<typename T>
155 {
156 public:
158  state(std::make_shared<PromiseState<T>>())
159  {
160  }
161 
163  {
164  if (state && !state.unique())
165  state->break_promise();
166  }
167 
169  state(std::move(other.state))
170  {
171  }
172 
174  {
175  state = std::move(other.state);
176  }
177 
178  NoTLSPromise(NoTLSPromise const&) = delete;
179  NoTLSPromise operator=(NoTLSPromise const&) = delete;
180 
181  void set_value(T value)
182  {
183  state->set_value(value);
184  }
185 
187  {
188  return NoTLSFuture<T>(state);
189  }
190 
191 private:
192  std::shared_ptr<PromiseState<T>> state;
193 };
194 }
195 }
196 #endif
void break_promise()
Definition: no_tls_future-inl.h:74
All things Mir.
Definition: atomic_callback.h:25
PromiseState & operator=(PromiseState const &)=delete
Definition: no_tls_future-inl.h:154
NoTLSPromise()
Definition: no_tls_future-inl.h:157
NoTLSFuture & operator=(NoTLSFuture &&other)
Definition: no_tls_future-inl.h:114
NoTLSPromise & operator=(NoTLSPromise &&other)
Definition: no_tls_future-inl.h:173
NoTLSFuture()
Definition: no_tls_future-inl.h:99
STL namespace.
bool valid() const
Definition: no_tls_future-inl.h:144
void validate_state() const
Definition: no_tls_future-inl.h:123
std::future_status wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Definition: no_tls_future-inl.h:138
void set_value(T &&val)
Definition: no_tls_future-inl.h:57
NoTLSFuture(std::shared_ptr< PromiseState< T >> const &state)
Definition: no_tls_future-inl.h:104
~NoTLSPromise()
Definition: no_tls_future-inl.h:162
Definition: no_tls_future-inl.h:37
void set_value(T value)
Definition: no_tls_future-inl.h:181
NoTLSFuture(NoTLSFuture &&other)
Definition: no_tls_future-inl.h:109
T get_value()
Definition: no_tls_future-inl.h:65
Definition: no_tls_future-inl.h:97
std::future_status wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Definition: no_tls_future-inl.h:41
void set_value(T const &val)
Definition: no_tls_future-inl.h:49
NoTLSFuture< T > get_future()
Definition: no_tls_future-inl.h:186
NoTLSPromise(NoTLSPromise &&other)
Definition: no_tls_future-inl.h:168

Copyright © 2012-2015 Canonical Ltd.
Generated on Thu Oct 8 16:20:16 UTC 2015