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) const
91 {
92  assert(Thread::isMainThread());
93  return std::find_if(std::begin(queue), std::end(queue),
94  EqualSchedulable(device, userData)) != std::end(queue);
95 }
96 
98 {
99  assert(Thread::isMainThread());
100  return scheduleTime;
101 }
102 
103 void Scheduler::scheduleHelper(EmuTime::param limit, EmuTime next)
104 {
105  assert(!scheduleInProgress);
106  scheduleInProgress = true;
107  while (true) {
108  assert(scheduleTime <= next);
109  scheduleTime = next;
110 
111  const auto& sp = queue.front();
112  auto* device = sp.getDevice();
113  int userData = sp.getUserData();
114 
115  queue.remove_front();
116 
117  device->executeUntil(next, userData);
118 
119  next = getNext();
120  if (likely(next > limit)) break;
121  }
122  scheduleInProgress = false;
123 
124  cpu->setNextSyncPoint(next);
125 }
126 
127 
128 template <typename Archive>
129 void SynchronizationPoint::serialize(Archive& ar, unsigned /*version*/)
130 {
131  // SynchronizationPoint is always serialized via Schedulable. A
132  // Schedulable has a collection of SynchronizationPoints, all with the
133  // same Schedulable. So there's no need to serialize 'device'.
134  //Schedulable* device;
135  ar.serialize("time", timeStamp);
136  ar.serialize("type", userData);
137 }
139 
140 template <typename Archive>
141 void Scheduler::serialize(Archive& ar, unsigned /*version*/)
142 {
143  ar.serialize("currentTime", scheduleTime);
144  // don't serialize 'queue', each Schedulable serializes its own
145  // syncpoints
146 }
148 
149 } // 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:141
void setNextSyncPoint(EmuTime::param time)
Definition: MSXCPU.cc:184
bool operator()(const SynchronizationPoint &sp) const
Definition: Scheduler.cc:24
SynchronizationPoint
Definition: Scheduler.cc:138
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:97
void serialize(Archive &ar, unsigned version)
Definition: Scheduler.cc:129
static const EmuTime infinity
Definition: EmuTime.hh:58
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