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 
12 struct LessSyncPoint {
13  bool operator()(EmuTime::param time,
14  const SynchronizationPoint& sp) const;
15  bool operator()(const SynchronizationPoint& sp,
16  EmuTime::param time) const;
17  bool operator()(const SynchronizationPoint& lhs,
18  const SynchronizationPoint& rhs) const;
19 };
21  EmuTime::param time, const SynchronizationPoint& sp) const
22 {
23  return time < sp.getTime();
24 }
26  const SynchronizationPoint& sp, EmuTime::param time) const
27 {
28  return sp.getTime() < time;
29 }
31  const SynchronizationPoint& lhs, const SynchronizationPoint& rhs) const
32 {
33  // This method is needed for VC++ debug build (I'm not sure why).
34  return lhs.getTime() < rhs.getTime();
35 }
36 
37 
39  explicit FindSchedulable(const Schedulable& schedulable_)
40  : schedulable(schedulable_) {}
41  bool operator()(const SynchronizationPoint& sp) const {
42  return sp.getDevice() == &schedulable;
43  }
45 };
46 
48  EqualSchedulable(const Schedulable& schedulable_, int userdata_)
49  : schedulable(schedulable_), userdata(userdata_) {}
50  bool operator()(const SynchronizationPoint& sp) const {
51  return (sp.getDevice() == &schedulable) &&
52  (sp.getUserData() == userdata);
53  }
55  int userdata;
56 };
57 
58 
60  : scheduleTime(EmuTime::zero)
61  , cpu(nullptr)
62  , scheduleInProgress(false)
63 {
64 }
65 
67 {
68  assert(!cpu);
69  auto copy = syncPoints;
70  for (auto& s : copy) {
71  s.getDevice()->schedulerDeleted();
72  }
73 
74  assert(syncPoints.empty());
75 }
76 
77 void Scheduler::setSyncPoint(EmuTime::param time, Schedulable& device, int userData)
78 {
79  assert(Thread::isMainThread());
80  assert(time >= scheduleTime);
81 
82  // Push sync point into queue.
83  auto it = std::upper_bound(begin(syncPoints), end(syncPoints), time,
84  LessSyncPoint());
85  syncPoints.insert(it, SynchronizationPoint(time, &device, userData));
86 
87  if (!scheduleInProgress && cpu) {
88  // only when scheduleHelper() is not being executed
89  // otherwise getNext() doesn't return the correct time and
90  // scheduleHelper() anyway calls setNextSyncPoint() at the end
91  cpu->setNextSyncPoint(getNext());
92  }
93 }
94 
95 Scheduler::SyncPoints Scheduler::getSyncPoints(const Schedulable& device) const
96 {
97  SyncPoints result;
98  copy_if(begin(syncPoints), end(syncPoints), back_inserter(result),
99  FindSchedulable(device));
100  return result;
101 }
102 
103 bool Scheduler::removeSyncPoint(Schedulable& device, int userData)
104 {
105  assert(Thread::isMainThread());
106  auto it = find_if(begin(syncPoints), end(syncPoints),
107  EqualSchedulable(device, userData));
108  if (it != end(syncPoints)) {
109  syncPoints.erase(it);
110  return true;
111  } else {
112  return false;
113  }
114 }
115 
116 void Scheduler::removeSyncPoints(Schedulable& device)
117 {
118  assert(Thread::isMainThread());
119  syncPoints.erase(remove_if(begin(syncPoints), end(syncPoints),
120  FindSchedulable(device)),
121  end(syncPoints));
122 }
123 
124 bool Scheduler::pendingSyncPoint(const Schedulable& device, int userData) const
125 {
126  assert(Thread::isMainThread());
127  return find_if(begin(syncPoints), end(syncPoints),
128  EqualSchedulable(device, userData)) != end(syncPoints);
129 }
130 
132 {
133  assert(Thread::isMainThread());
134  return scheduleTime;
135 }
136 
137 void Scheduler::scheduleHelper(EmuTime::param limit)
138 {
139  assert(!scheduleInProgress);
140  scheduleInProgress = true;
141  while (true) {
142  // Get next sync point.
143  const auto& sp = syncPoints.front();
144  EmuTime time = sp.getTime();
145  if (time > limit) {
146  break;
147  }
148 
149  assert(scheduleTime <= time);
150  scheduleTime = time;
151 
152  Schedulable* device = sp.getDevice();
153  assert(device);
154  int userData = sp.getUserData();
155 
156  syncPoints.erase(begin(syncPoints));
157 
158  device->executeUntil(time, userData);
159  }
160  scheduleInProgress = false;
161 
162  cpu->setNextSyncPoint(getNext());
163 }
164 
165 
166 template <typename Archive>
167 void SynchronizationPoint::serialize(Archive& ar, unsigned /*version*/)
168 {
169  // SynchronizationPoint is always serialized via Schedulable. A
170  // Schedulable has a collection of SynchronizationPoints, all with the
171  // same Schedulable. So there's no need to serialize 'device'.
172  //Schedulable* device;
173  ar.serialize("time", timeStamp);
174  ar.serialize("type", userData);
175 }
177 
178 template <typename Archive>
179 void Scheduler::serialize(Archive& ar, unsigned /*version*/)
180 {
181  ar.serialize("currentTime", scheduleTime);
182  // don't serialize syncPoints, each Schedulable serializes its own
183  // syncpoints
184 }
186 
187 } // 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:179
void setNextSyncPoint(EmuTime::param time)
Definition: MSXCPU.cc:184
bool operator()(const SynchronizationPoint &sp) const
Definition: Scheduler.cc:50
SynchronizationPoint
Definition: Scheduler.cc:176
EmuTime::param getTime() const
Definition: Scheduler.hh:22
EmuTime::param getNext() const
TODO.
Definition: Scheduler.hh:57
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:23
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition: Scheduler.cc:131
void serialize(Archive &ar, unsigned version)
Definition: Scheduler.cc:167
const Schedulable & schedulable
Definition: Scheduler.cc:54
std::vector< SynchronizationPoint > SyncPoints
Definition: Scheduler.hh:39
friend class Schedulable
Definition: Scheduler.hh:77
FindSchedulable(const Schedulable &schedulable_)
Definition: Scheduler.cc:39
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:802
EqualSchedulable(const Schedulable &schedulable_, int userdata_)
Definition: Scheduler.cc:48
bool operator()(EmuTime::param time, const SynchronizationPoint &sp) const
Definition: Scheduler.cc:20
bool operator()(const SynchronizationPoint &sp) const
Definition: Scheduler.cc:41
string_ref::const_iterator begin(const string_ref &x)
Definition: string_ref.hh:134
const Schedulable & schedulable
Definition: Scheduler.cc:44
static bool isMainThread()
Returns true when called from the main thread.
Definition: Thread.cc:19