cesium-native  0.41.0
ImmediateScheduler.h
1 #pragma once
2 
3 #include "cesium-async++.h"
4 
5 #include <CesiumUtility/Assert.h>
6 
7 #include <spdlog/spdlog.h>
8 
9 namespace CesiumAsync {
10 namespace CesiumImpl {
11 
12 template <typename TScheduler> class ImmediateScheduler {
13 public:
14  explicit ImmediateScheduler(TScheduler* pScheduler) noexcept
15  : _pScheduler(pScheduler) {}
16 
17  void schedule(async::task_run_handle t) {
18  // Are we already in a suitable thread?
19  std::vector<TScheduler*>& inSuitable =
21  if (std::find(inSuitable.begin(), inSuitable.end(), this->_pScheduler) !=
22  inSuitable.end()) {
23  // Yes, run this task directly.
24  t.run();
25  } else {
26  // No, schedule this task with the deferred scheduler.
27  this->_pScheduler->schedule(std::move(t));
28  }
29  }
30 
32  public:
33  SchedulerScope(TScheduler* pScheduler = nullptr) : _pScheduler(pScheduler) {
34  if (this->_pScheduler) {
35  std::vector<TScheduler*>& inSuitable =
37  inSuitable.push_back(this->_pScheduler);
38  }
39  }
40 
41  ~SchedulerScope() noexcept { this->reset(); }
42 
43  SchedulerScope(SchedulerScope&& rhs) noexcept
44  : _pScheduler(rhs._pScheduler) {
45  rhs._pScheduler = nullptr;
46  }
47 
48  SchedulerScope& operator=(SchedulerScope&& rhs) noexcept {
49  std::swap(this->_pScheduler, rhs._pScheduler);
50  return *this;
51  }
52 
53  void reset() noexcept {
54  if (this->_pScheduler) {
55  std::vector<TScheduler*>& inSuitable =
57  CESIUM_ASSERT(!inSuitable.empty());
58  CESIUM_ASSERT(inSuitable.back() == this->_pScheduler);
59  inSuitable.pop_back();
60 
61  this->_pScheduler = nullptr;
62  }
63  }
64 
65  SchedulerScope(const SchedulerScope&) = delete;
66  SchedulerScope& operator=(const SchedulerScope&) = delete;
67 
68  private:
69  TScheduler* _pScheduler;
70  };
71 
72  SchedulerScope scope() { return SchedulerScope(this->_pScheduler); }
73 
74 private:
75  TScheduler* _pScheduler;
76 
77  // If a TScheduler instance is found in this thread-local vector, then the
78  // current thread has been dispatched by this scheduler and therefore we can
79  // dispatch immediately.
80  static std::vector<TScheduler*>&
81  getSchedulersCurrentlyDispatching() noexcept {
82  // We're using a static local here rather than a static field because, on
83  // at least some Linux systems (mine), with Clang 12, in a Debug build, a
84  // thread_local static field causes a SEGFAULT on access.
85  // I don't understand why (despite hours trying), but making it a static
86  // local instead solves the problem and is arguably cleaner, anyway.
87  static thread_local std::vector<TScheduler*> schedulersCurrentlyDispatching;
88  return schedulersCurrentlyDispatching;
89  }
90 };
91 
92 } // namespace CesiumImpl
93 } // namespace CesiumAsync
Classes that support asynchronous operations.