OXYGENHUB
◆ main openmsx / src / Scheduler.cc
3.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "Scheduler.hh"
2
3
#include "MSXCPU.hh"
4
#include "Schedulable.hh"
5
#include "Thread.hh"
6
7
#include "serialize.hh"
8
#include "stl.hh"
9
10
#include <algorithm>
11
#include <cassert>
12
#include <iterator> // for back_inserter
13
14
namespace openmsx {
15
16
struct EqualSchedulable {
17
	explicit EqualSchedulable(const Schedulable& schedulable_)
18
		: schedulable(schedulable_) {}
19
	[[nodiscard]] bool operator()(const SynchronizationPoint& sp) const {
20
		return sp.getDevice() == &schedulable;
21
	}
22
	const Schedulable& schedulable;
23
};
24
25
26
Scheduler::~Scheduler()
27
{
28
	assert(!cpu);
29
	for (auto copy = to_vector(queue); auto& s : copy) {
30
		s.getDevice()->schedulerDeleted();
31
	}
32
	assert(queue.empty());
33
}
34
35
void Scheduler::setSyncPoint(EmuTime time, Schedulable& device)
36
{
37
	assert(Thread::isMainThread());
38
	assert(time >= scheduleTime);
39
40
	// Push sync point into queue.
41
	queue.insert(SynchronizationPoint(time, &device),
42
	             [](SynchronizationPoint& sp) { sp.setTime(EmuTime::infinity()); },
43
	             [](const SynchronizationPoint& x, const SynchronizationPoint& y) {
44
	                     return x.getTime() < y.getTime(); });
45
46
	if (!scheduleInProgress && cpu) {
47
		// only when scheduleHelper() is not being executed
48
		// otherwise getNext() doesn't return the correct time and
49
		// scheduleHelper() anyway calls setNextSyncPoint() at the end
50
		cpu->setNextSyncPoint(getNext());
51
	}
52
}
53
54
Scheduler::SyncPoints Scheduler::getSyncPoints(const Schedulable& device) const
55
{
56
	SyncPoints result;
57
	std::ranges::copy_if(queue, back_inserter(result), EqualSchedulable(device));
58
	return result;
59
}
60
61
bool Scheduler::removeSyncPoint(const Schedulable& device)
62
{
63
	assert(Thread::isMainThread());
64
	return queue.remove(EqualSchedulable(device));
65
}
66
67
void Scheduler::removeSyncPoints(const Schedulable& device)
68
{
69
	assert(Thread::isMainThread());
70
	queue.remove_all(EqualSchedulable(device));
71
}
72
73
std::optional<EmuTime> Scheduler::isPending(const Schedulable& device) const
74
{
75
	assert(Thread::isMainThread());
76
	if (auto it = std::ranges::find(queue, &device, &SynchronizationPoint::getDevice);
77
	    it != std::end(queue)) {
78
		return it->getTime();
79
	}
80
	return {};
81
}
82
83
EmuTime Scheduler::getCurrentTime() const
84
{
85
	assert(Thread::isMainThread());
86
	return scheduleTime;
87
}
88
89
void Scheduler::scheduleHelper(EmuTime limit, EmuTime next)
90
{
91
	assert(!scheduleInProgress);
92
	scheduleInProgress = true;
93
	while (true) {
94
		assert(scheduleTime <= next);
95
		scheduleTime = next;
96
97
		const auto& sp = queue.front();
98
		auto* device = sp.getDevice();
99
100
		queue.remove_front();
101
102
		device->executeUntil(next);
103
104
		next = getNext();
105
		if (next > limit) [[likely]] break;
106
	}
107
	scheduleInProgress = false;
108
109
	cpu->setNextSyncPoint(next);
110
}
111
112
113
template<typename Archive>
114
void SynchronizationPoint::serialize(Archive& ar, unsigned /*version*/)
115
{
116
	// SynchronizationPoint is always serialized via Schedulable. A
117
	// Schedulable has a collection of SynchronizationPoints, all with the
118
	// same Schedulable. So there's no need to serialize 'device'.
119
	//Schedulable* device;
120
	ar.serialize("time", timeStamp);
121
}
122
INSTANTIATE_SERIALIZE_METHODS(SynchronizationPoint);
123
124
template<typename Archive>
125
void Scheduler::serialize(Archive& ar, unsigned /*version*/)
126
{
127
	ar.serialize("currentTime", scheduleTime);
128
	// don't serialize 'queue', each Schedulable serializes its own
129
	// sync-points
130
}
131
INSTANTIATE_SERIALIZE_METHODS(Scheduler);
132
133
} // namespace openmsx