123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- #include "Scheduler.hh"
- #include "Schedulable.hh"
- #include "Thread.hh"
- #include "MSXCPU.hh"
- #include "ranges.hh"
- #include "serialize.hh"
- #include "stl.hh"
- #include <cassert>
- #include <iterator> // for back_inserter
- namespace openmsx {
- struct EqualSchedulable {
- explicit EqualSchedulable(const Schedulable& schedulable_)
- : schedulable(schedulable_) {}
- bool operator()(const SynchronizationPoint& sp) const {
- return sp.getDevice() == &schedulable;
- }
- const Schedulable& schedulable;
- };
- Scheduler::~Scheduler()
- {
- assert(!cpu);
- auto copy = to_vector(queue);
- for (auto& s : copy) {
- s.getDevice()->schedulerDeleted();
- }
- assert(queue.empty());
- }
- void Scheduler::setSyncPoint(EmuTime::param time, Schedulable& device)
- {
- assert(Thread::isMainThread());
- assert(time >= scheduleTime);
- // Push sync point into queue.
- queue.insert(SynchronizationPoint(time, &device),
- [](SynchronizationPoint& sp) { sp.setTime(EmuTime::infinity()); },
- [](const SynchronizationPoint& x, const SynchronizationPoint& y) {
- return x.getTime() < y.getTime(); });
- if (!scheduleInProgress && cpu) {
- // only when scheduleHelper() is not being executed
- // otherwise getNext() doesn't return the correct time and
- // scheduleHelper() anyway calls setNextSyncPoint() at the end
- cpu->setNextSyncPoint(getNext());
- }
- }
- Scheduler::SyncPoints Scheduler::getSyncPoints(const Schedulable& device) const
- {
- SyncPoints result;
- ranges::copy_if(queue, back_inserter(result), EqualSchedulable(device));
- return result;
- }
- bool Scheduler::removeSyncPoint(Schedulable& device)
- {
- assert(Thread::isMainThread());
- return queue.remove(EqualSchedulable(device));
- }
- void Scheduler::removeSyncPoints(Schedulable& device)
- {
- assert(Thread::isMainThread());
- queue.remove_all(EqualSchedulable(device));
- }
- bool Scheduler::pendingSyncPoint(const Schedulable& device,
- EmuTime& result) const
- {
- assert(Thread::isMainThread());
- auto it = ranges::find_if(queue, EqualSchedulable(device));
- if (it != std::end(queue)) {
- result = it->getTime();
- return true;
- } else {
- return false;
- }
- }
- EmuTime::param Scheduler::getCurrentTime() const
- {
- assert(Thread::isMainThread());
- return scheduleTime;
- }
- void Scheduler::scheduleHelper(EmuTime::param limit, EmuTime next)
- {
- assert(!scheduleInProgress);
- scheduleInProgress = true;
- while (true) {
- assert(scheduleTime <= next);
- scheduleTime = next;
- const auto& sp = queue.front();
- auto* device = sp.getDevice();
- queue.remove_front();
- device->executeUntil(next);
- next = getNext();
- if (likely(next > limit)) break;
- }
- scheduleInProgress = false;
- cpu->setNextSyncPoint(next);
- }
- template <typename Archive>
- void SynchronizationPoint::serialize(Archive& ar, unsigned /*version*/)
- {
- // SynchronizationPoint is always serialized via Schedulable. A
- // Schedulable has a collection of SynchronizationPoints, all with the
- // same Schedulable. So there's no need to serialize 'device'.
- //Schedulable* device;
- ar.serialize("time", timeStamp);
- }
- INSTANTIATE_SERIALIZE_METHODS(SynchronizationPoint);
- template <typename Archive>
- void Scheduler::serialize(Archive& ar, unsigned /*version*/)
- {
- ar.serialize("currentTime", scheduleTime);
- // don't serialize 'queue', each Schedulable serializes its own
- // syncpoints
- }
- INSTANTIATE_SERIALIZE_METHODS(Scheduler);
- } // namespace openmsx
|