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 #include <boost/throw_exception.hpp>
32 
33 namespace mir
34 {
35 namespace client
36 {
37 template<typename T>
39 {
40 public:
41  template<class Rep, class Period>
42  std::future_status wait_for(std::chrono::duration<Rep, Period> const& timeout_duration) const
43  {
44  std::unique_lock<std::mutex> lk(mutex);
45  if (cv.wait_for(lk, timeout_duration, [this]{ return set || broken; }))
46  return std::future_status::ready;
47  return std::future_status::timeout;
48  }
49 
50  void set_value(T const& val)
51  {
52  std::lock_guard<std::mutex> lk(mutex);
53  set = true;
54  value = val;
55  cv.notify_all();
56  }
57 
58  void set_value(T && val)
59  {
60  std::lock_guard<std::mutex> lk(mutex);
61  set = true;
62  value = std::move(val);
63  cv.notify_all();
64  }
65 
67  {
68  std::unique_lock<std::mutex> lk(mutex);
69  cv.wait(lk, [this]{ return set || broken; });
70  if (broken)
71  {
72  //clang has problems with std::future_error::what() on vivid+overlay
73  BOOST_THROW_EXCEPTION(std::runtime_error("broken_promise"));
74  }
75  return value;
76  }
77 
79  {
80  std::lock_guard<std::mutex> lk(mutex);
81  if (!set)
82  broken = true;
83  cv.notify_all();
84  }
85 
86  PromiseState() = default;
87  PromiseState(PromiseState const&) = delete;
88  PromiseState(PromiseState &&) = delete;
89  PromiseState& operator=(PromiseState const&) = delete;
90  PromiseState& operator=(PromiseState &&) = delete;
91 
92 private:
93  std::mutex mutable mutex;
94  std::condition_variable mutable cv;
95  bool set{false};
96  bool broken{false};
97  T value;
98 };
99 
100 template<typename T>
102 {
104  state(nullptr)
105  {
106  }
107 
108  NoTLSFuture(std::shared_ptr<PromiseState<T>> const& state) :
109  state(state)
110  {
111  }
112 
114  state(std::move(other.state))
115  {
116  }
117 
119  {
120  state = std::move(other.state);
121  return *this;
122  }
123 
124  NoTLSFuture(NoTLSFuture const&) = delete;
125  NoTLSFuture& operator=(NoTLSFuture const&) = delete;
126 
127  void validate_state() const
128  {
129  if (!valid())
130  throw std::logic_error("state was not valid");
131  }
132 
133  T get()
134  {
135  validate_state();
136  auto value = state->get_value();
137  state = nullptr;
138  return value;
139  }
140 
141  template<class Rep, class Period>
142  std::future_status wait_for(std::chrono::duration<Rep, Period> const& timeout_duration) const
143  {
144  validate_state();
145  return state->wait_for(timeout_duration);
146  }
147 
148  bool valid() const
149  {
150  return state != nullptr;
151  }
152 
153 private:
154  std::shared_ptr<PromiseState<T>> state;
155 };
156 
157 template<typename T>
159 {
160 public:
162  state(std::make_shared<PromiseState<T>>())
163  {
164  }
165 
167  {
168  if (state && !state.unique())
169  state->break_promise();
170  }
171 
173  state(std::move(other.state))
174  {
175  }
176 
178  {
179  state = std::move(other.state);
180  }
181 
182  NoTLSPromise(NoTLSPromise const&) = delete;
183  NoTLSPromise operator=(NoTLSPromise const&) = delete;
184 
185  void set_value(T value)
186  {
187  state->set_value(value);
188  }
189 
191  {
192  return NoTLSFuture<T>(state);
193  }
194 
195 private:
196  std::shared_ptr<PromiseState<T>> state;
197 };
198 }
199 }
200 #endif
void break_promise()
Definition: no_tls_future-inl.h:78
All things Mir.
Definition: atomic_callback.h:25
PromiseState & operator=(PromiseState const &)=delete
Definition: no_tls_future-inl.h:158
NoTLSPromise()
Definition: no_tls_future-inl.h:161
NoTLSFuture & operator=(NoTLSFuture &&other)
Definition: no_tls_future-inl.h:118
NoTLSPromise & operator=(NoTLSPromise &&other)
Definition: no_tls_future-inl.h:177
NoTLSFuture()
Definition: no_tls_future-inl.h:103
STL namespace.
bool valid() const
Definition: no_tls_future-inl.h:148
void validate_state() const
Definition: no_tls_future-inl.h:127
std::future_status wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Definition: no_tls_future-inl.h:142
void set_value(T &&val)
Definition: no_tls_future-inl.h:58
NoTLSFuture(std::shared_ptr< PromiseState< T >> const &state)
Definition: no_tls_future-inl.h:108
~NoTLSPromise()
Definition: no_tls_future-inl.h:166
Definition: no_tls_future-inl.h:38
void set_value(T value)
Definition: no_tls_future-inl.h:185
NoTLSFuture(NoTLSFuture &&other)
Definition: no_tls_future-inl.h:113
T get_value()
Definition: no_tls_future-inl.h:66
Definition: no_tls_future-inl.h:101
std::future_status wait_for(std::chrono::duration< Rep, Period > const &timeout_duration) const
Definition: no_tls_future-inl.h:42
void set_value(T const &val)
Definition: no_tls_future-inl.h:50
NoTLSFuture< T > get_future()
Definition: no_tls_future-inl.h:190
NoTLSPromise(NoTLSPromise &&other)
Definition: no_tls_future-inl.h:172

Copyright © 2012-2015 Canonical Ltd.
Generated on Wed Mar 30 00:29:56 UTC 2016