openMSX
Scheduler.cc
Go to the documentation of this file.
1 #include "Scheduler.hh"
2 #include "Schedulable.hh"
3 #include "Thread.hh"
4 #include "MSXCPU.hh"
5 #include "ranges.hh"
6 #include "serialize.hh"
7 #include "stl.hh"
8 #include <cassert>
9 #include <iterator> // for back_inserter
10 
11 namespace openmsx {
12 
14  explicit EqualSchedulable(const Schedulable& schedulable_)
15  : schedulable(schedulable_) {}
16  bool operator()(const SynchronizationPoint& sp) const {
17  return sp.getDevice() == &schedulable;
18  }
20 };
21 
22 
24 {
25  assert(!cpu);
26  auto copy = to_vector(queue);
27  for (auto& s : copy) {
28  s.getDevice()->schedulerDeleted();
29  }
30 
31  assert(queue.empty());
32 }
33 
34 void Scheduler::setSyncPoint(EmuTime::param time, Schedulable& device)
35 {
36  assert(Thread::isMainThread());
37  assert(time >= scheduleTime);
38 
39  // Push sync point into queue.
40  queue.insert(SynchronizationPoint(time, &device),
41  [](SynchronizationPoint& sp) { sp.setTime(EmuTime::infinity); },
42  [](const SynchronizationPoint& x, const SynchronizationPoint& y) {
43  return x.getTime() < y.getTime(); });
44 
45  if (!scheduleInProgress && cpu) {
46  // only when scheduleHelper() is not being executed
47  // otherwise getNext() doesn't return the correct time and
48  // scheduleHelper() anyway calls setNextSyncPoint() at the end
49  cpu->setNextSyncPoint(getNext());
50  }
51 }
52 
53 Scheduler::SyncPoints Scheduler::getSyncPoints(const Schedulable& device) const
54 {
55  SyncPoints result;
56  ranges::copy_if(queue, back_inserter(result), EqualSchedulable(device));
57  return result;
58 }
59 
60 bool Scheduler::removeSyncPoint(Schedulable& device)
61 {
62  assert(Thread::isMainThread());
63  return queue.remove(EqualSchedulable(device));
64 }
65 
66 void Scheduler::removeSyncPoints(Schedulable& device)
67 {
68  assert(Thread::isMainThread());
69  queue.remove_all(EqualSchedulable(device));
70 }
71 
72 bool Scheduler::pendingSyncPoint(const Schedulable& device,
73  EmuTime& result) const
74 {
75  assert(Thread::isMainThread());
76  auto it = ranges::find_if(queue, EqualSchedulable(device));
77  if (it != std::end(queue)) {
78  result = it->getTime();
79  return true;
80  } else {
81  return false;
82  }
83 }
84 
85 EmuTime::param Scheduler::getCurrentTime() const
86 {
87  assert(Thread::isMainThread());
88  return scheduleTime;
89 }
90 
91 void Scheduler::scheduleHelper(EmuTime::param limit, EmuTime next)
92 {
93  assert(!scheduleInProgress);
94  scheduleInProgress = true;
95  while (true) {
96  assert(scheduleTime <= next);
97  scheduleTime = next;
98 
99  const auto& sp = queue.front();
100  auto* device = sp.getDevice();
101 
102  queue.remove_front();
103 
104  device->executeUntil(next);
105 
106  next = getNext();
107  if (likely(next > limit)) break;
108  }
109  scheduleInProgress = false;
110 
111  cpu->setNextSyncPoint(next);
112 }
113 
114 
115 template <typename Archive>
116 void SynchronizationPoint::serialize(Archive& ar, unsigned /*version*/)
117 {
118  // SynchronizationPoint is always serialized via Schedulable. A
119  // Schedulable has a collection of SynchronizationPoints, all with the
120  // same Schedulable. So there's no need to serialize 'device'.
121  //Schedulable* device;
122  ar.serialize("time", timeStamp);
123 }
125 
126 template <typename Archive>
127 void Scheduler::serialize(Archive& ar, unsigned /*version*/)
128 {
129  ar.serialize("currentTime", scheduleTime);
130  // don't serialize 'queue', each Schedulable serializes its own
131  // syncpoints
132 }
134 
135 } // namespace openmsx
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:149
EqualSchedulable(const Schedulable &schedulable_)
Definition: Scheduler.cc:14
void serialize(Archive &ar, unsigned version)
Definition: Scheduler.cc:127
bool operator()(const SynchronizationPoint &sp) const
Definition: Scheduler.cc:16
SynchronizationPoint
Definition: Scheduler.cc:124
auto copy_if(InputRange &&range, OutputIter out, UnaryPredicate pred)
Definition: ranges.hh:155
Schedulable * getDevice() const
Definition: Scheduler.hh:22
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition: Scheduler.cc:85
auto find_if(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:113
void setTime(EmuTime::param time)
Definition: Scheduler.hh:21
Every class that wants to get scheduled at some point must inherit from this class.
Definition: Schedulable.hh:31
std::vector< SynchronizationPoint > SyncPoints
Definition: Scheduler.hh:36
EmuTime::param getTime() const
Definition: Scheduler.hh:20
void serialize(Archive &ar, unsigned version)
Definition: Scheduler.cc:116
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
const Schedulable & schedulable
Definition: Scheduler.cc:19
virtual void executeUntil(EmuTime::param time)=0
When the previously registered syncPoint is reached, this method gets called.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
#define likely(x)
Definition: likely.hh:14
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))>>
Definition: stl.hh:325
auto end(const string_view &x)
Definition: string_view.hh:153
bool isMainThread()
Returns true when called from the main thread.
Definition: Thread.cc:16