Shaka Player Embedded
thread_event.h
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SHAKA_EMBEDDED_DEBUG_THREAD_EVENT_H_
16 #define SHAKA_EMBEDDED_DEBUG_THREAD_EVENT_H_
17 
18 #include <glog/logging.h>
19 
20 #include <atomic>
21 #include <future>
22 #include <string>
23 #include <utility>
24 
25 #include "src/debug/waitable.h"
27 #include "src/util/utils.h"
28 
29 namespace shaka {
30 
31 class Thread;
32 
37 class ThreadEventBase : public Waitable {
38  public:
39  explicit ThreadEventBase(const std::string& name);
40  ~ThreadEventBase() override;
41 
43  std::thread::id GetProvider() const override;
44 
49  void SetProvider(Thread* thread) {
50  provider_.store(thread, std::memory_order_release);
51 #ifdef DEBUG_DEADLOCKS
52  WaitingTracker::UpdateProvider(this);
53 #endif
54  }
55 
56  private:
57  const std::string name_;
58  std::atomic<Thread*> provider_;
59 };
60 
69 template <typename T>
70 class ThreadEvent final : public ThreadEventBase {
71  public:
72  explicit ThreadEvent(const std::string& name)
73  : ThreadEventBase(name), future_(promise_.get_future().share()) {}
74  ~ThreadEvent() override {}
75 
76  T GetValue() {
77  std::shared_future<T> future;
78  {
79  std::unique_lock<std::mutex> lock(mutex_);
80  future = future_;
81  }
82 
83 #ifdef DEBUG_DEADLOCKS
84  auto scope = WaitingTracker::ThreadWaiting(this);
85 #endif
86  return future.get();
87  }
88 
93  std::shared_future<T> future() {
94  std::unique_lock<std::mutex> lock(mutex_);
95  return future_;
96  }
97 
105  template <typename _Mutex>
106  T ResetAndWaitWhileUnlocked(std::unique_lock<_Mutex>& lock) { // NOLINT
107  DCHECK(lock.owns_lock());
108 
109  std::shared_future<T> future;
110  {
111  std::unique_lock<std::mutex> lock(mutex_);
112  ResetInternal();
113  future = future_;
114  }
115 
116  util::Unlocker<_Mutex> unlock(&lock);
117 #ifdef DEBUG_DEADLOCKS
118  auto scope = WaitingTracker::ThreadWaiting(this);
119 #endif
120  return future.get();
121  }
122 
124 
128  void SignalAll() {
129  CHECK(SignalAllIfNotSet());
130  }
131  template <typename U>
132  void SignalAll(U&& value) {
133  CHECK(SignalAllIfNotSet(std::forward<U>(value)));
134  }
135  // @}
136 
138 
144  // Don't signal with the lock held since once we signal, this object may be
145  // destroyed by thread we woke up.
146  std::promise<void> p;
147  {
148  std::unique_lock<std::mutex> lock(mutex_);
149  if (is_set_)
150  return false;
151  is_set_ = true;
152  p = std::move(promise_);
153  }
154  p.set_value();
155  return true;
156  }
157  template <typename U>
158  bool SignalAllIfNotSet(U&& value) {
159  std::promise<T> p;
160  {
161  std::unique_lock<std::mutex> lock(mutex_);
162  if (is_set_)
163  return false;
164  is_set_ = true;
165  p = std::move(promise_);
166  }
167  p.set_value(std::forward<U>(value));
168  return true;
169  }
170  // @}
171 
180  void Reset() {
181  std::unique_lock<std::mutex> lock(mutex_);
182  ResetInternal();
183  }
184 
185  private:
186  void ResetInternal() {
187 #ifdef DEBUG_DEADLOCKS
188  // Removing is the same as resetting.
189  WaitingTracker::RemoveWaitable(this);
190 #endif
191 
192  // When a std::promise is destroyed and its value hasn't been set, the
193  // promise should have its exception set to std::broken_promise. Some
194  // versions of the C++ library can't do this with no exceptions. Similarly,
195  // we can't set the exception to a value ourselves; but we can set the
196  // exception to the nullptr.
197  if (!is_set_)
198  promise_.set_exception(std::exception_ptr());
199 
200  is_set_ = false;
201  promise_ = std::promise<T>();
202  future_ = promise_.get_future().share();
203  }
204 
205  std::mutex mutex_;
206  std::promise<T> promise_;
207  std::shared_future<T> future_;
208  bool is_set_ = false;
209 };
210 
211 } // namespace shaka
212 
213 #endif // SHAKA_EMBEDDED_DEBUG_THREAD_EVENT_H_
~ThreadEventBase() override
Definition: thread_event.cc:24
std::shared_future< T > future()
Definition: thread_event.h:93
~ThreadEvent() override
Definition: thread_event.h:74
ThreadEvent(const std::string &name)
Definition: thread_event.h:72
void SignalAll(U &&value)
Definition: thread_event.h:132
std::string name() const
Definition: waitable.h:37
ThreadEventBase(const std::string &name)
Definition: thread_event.cc:21
T ResetAndWaitWhileUnlocked(std::unique_lock< _Mutex > &lock)
Definition: thread_event.h:106
bool SignalAllIfNotSet(U &&value)
Definition: thread_event.h:158
void SetProvider(Thread *thread)
Definition: thread_event.h:49
std::thread::id GetProvider() const override
Definition: thread_event.cc:26