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 "serialize.hh"
6 #include <cassert>
7 #include <algorithm>
8 #include <iterator> // for back_inserter
9 
10 namespace openmsx {
11 
13  explicit FindSchedulable(const Schedulable& schedulable_)
14  : schedulable(schedulable_) {}
15  bool operator()(const SynchronizationPoint& sp) const {
16  return sp.getDevice() == &schedulable;
17  }
19 };
20 
22  EqualSchedulable(const Schedulable& schedulable_, int userdata_)
23  : schedulable(schedulable_), userdata(userdata_) {}
24  bool operator()(const SynchronizationPoint& sp) const {
25  return (sp.getDevice() == &schedulable) &&
26  (sp.getUserData() == userdata);
27  }
29  int userdata;
30 };
31 
32 
34  : scheduleTime(EmuTime::zero)
35  , cpu(nullptr)
36  , scheduleInProgress(false)
37 {
38 }
39 
41 {
42  assert(!cpu);
43  SyncPoints copy(std::begin(queue), std::end(queue));
44  for (auto& s : copy) {
45  s.getDevice()->schedulerDeleted();
46  }
47 
48  assert(queue.empty());
49 }
50 
51 void Scheduler::setSyncPoint(EmuTime::param time, Schedulable& device, int userData)
52 {
53  assert(Thread::isMainThread());
54  assert(time >= scheduleTime);
55 
56  // Push sync point into queue.
57  queue.insert(SynchronizationPoint(time, &device, userData),
59  [](const SynchronizationPoint& x, const SynchronizationPoint& y) {
60  return x.getTime() < y.getTime(); });
61 
62  if (!scheduleInProgress && cpu) {
63  // only when scheduleHelper() is not being executed
64  // otherwise getNext() doesn't return the correct time and
65  // scheduleHelper() anyway calls setNextSyncPoint() at the end
66  cpu->setNextSyncPoint(getNext());
67  }
68 }
69 
70 Scheduler::SyncPoints Scheduler::getSyncPoints(const Schedulable& device) const
71 {
72  SyncPoints result;
73  copy_if(std::begin(queue), std::end(queue), back_inserter(result),
74  FindSchedulable(device));
75  return result;
76 }
77 
78 bool Scheduler::removeSyncPoint(Schedulable& device, int userData)
79 {
80  assert(Thread::isMainThread());
81  return queue.remove(EqualSchedulable(device, userData));
82 }
83 
84 void Scheduler::removeSyncPoints(Schedulable& device)
85 {
86  assert(Thread::isMainThread());
87  queue.remove_all(FindSchedulable(device));
88 }
89 
90 bool Scheduler::pendingSyncPoint(const Schedulable& device, int userData,
91  EmuTime& result) const
92 {
93  assert(Thread::isMainThread());
94  auto it = std::find_if(std::begin(queue), std::end(queue),
95  EqualSchedulable(device, userData));
96  if (it != std::end(queue)) {
97  result = it->getTime();
98  return true;
99  } else {
100  return false;
101  }
102 }
103 
105 {
106  assert(Thread::isMainThread());
107  return scheduleTime;
108 }
109 
110 void Scheduler::scheduleHelper(EmuTime::param limit, EmuTime next)
111 {
112  assert(!scheduleInProgress);
113  scheduleInProgress = true;
114  while (true) {
115  assert(scheduleTime <= next);
116  scheduleTime = next;
117 
118  const auto& sp = queue.front();
119  auto* device = sp.getDevice();
120  int userData = sp.getUserData();
121 
122  queue.remove_front();
123 
124  device->executeUntil(next, userData);
125 
126  next = getNext();
127  if (likely(next > limit)) break;
128  }
129  scheduleInProgress = false;
130 
131  cpu->setNextSyncPoint(next);
132 }
133 
134 
135 template <typename Archive>
136 void SynchronizationPoint::serialize(Archive& ar, unsigned /*version*/)
137 {
138  // SynchronizationPoint is always serialized via Schedulable. A
139  // Schedulable has a collection of SynchronizationPoints, all with the
140  // same Schedulable. So there's no need to serialize 'device'.
141  //Schedulable* device;
142  ar.serialize("time", timeStamp);
143  ar.serialize("type", userData);
144 }
146 
147 template <typename Archive>
148 void Scheduler::serialize(Archive& ar, unsigned /*version*/)
149 {
150  ar.serialize("currentTime", scheduleTime);
151  // don't serialize 'queue', each Schedulable serializes its own
152  // syncpoints
153 }
155 
156 } // namespace openmsx
string_ref::const_iterator end(const string_ref &x)
Definition: string_ref.hh:135
void serialize(Archive &ar, unsigned version)
Definition: Scheduler.cc:148
void setNextSyncPoint(EmuTime::param time)
Definition: MSXCPU.cc:175
bool operator()(const SynchronizationPoint &sp) const
Definition: Scheduler.cc:24
SynchronizationPoint
Definition: Scheduler.cc:145
EmuTime::param getNext() const
TODO.
Definition: Scheduler.hh:59
void setTime(EmuTime::param time)
Definition: Scheduler.hh:24
Every class that wants to get scheduled at some point must inherit from this class.
Definition: Schedulable.hh:16
Schedulable * getDevice() const
Definition: Scheduler.hh:25
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition: Scheduler.cc:104
void serialize(Archive &ar, unsigned version)
Definition: Scheduler.cc:136
static const EmuTime infinity
Definition: EmuTime.hh:58
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:7
const Schedulable & schedulable
Definition: Scheduler.cc:28
std::vector< SynchronizationPoint > SyncPoints
Definition: Scheduler.hh:41
FindSchedulable(const Schedulable &schedulable_)
Definition: Scheduler.cc:13
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:802
EqualSchedulable(const Schedulable &schedulable_, int userdata_)
Definition: Scheduler.cc:22
#define likely(x)
Definition: likely.hh:14
bool operator()(const SynchronizationPoint &sp) const
Definition: Scheduler.cc:15
string_ref::const_iterator begin(const string_ref &x)
Definition: string_ref.hh:134
const Schedulable & schedulable
Definition: Scheduler.cc:18
static bool isMainThread()
Returns true when called from the main thread.
Definition: Thread.cc:19