citra-emu
/
citra-canary
Archived
1
0
Fork 0

Fix Address Arbiter serialization

This commit is contained in:
Hamish Milne 2020-04-18 15:10:54 +01:00
parent 79a0cbbba8
commit 1fb3c9f08c
2 changed files with 53 additions and 11 deletions

View File

@ -16,8 +16,6 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Kernel namespace // Kernel namespace
SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter)
namespace Kernel { namespace Kernel {
void AddressArbiter::WaitThread(std::shared_ptr<Thread> thread, VAddr wait_address) { void AddressArbiter::WaitThread(std::shared_ptr<Thread> thread, VAddr wait_address) {
@ -80,6 +78,26 @@ std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string n
return address_arbiter; return address_arbiter;
} }
class AddressArbiter::Callback : public WakeupCallback {
public:
Callback(AddressArbiter& _parent) : parent(SharedFrom(&_parent)) {}
std::shared_ptr<AddressArbiter> parent;
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) override {
parent->WakeUp(reason, thread, object);
}
private:
Callback() = default;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<WakeupCallback>(*this);
ar& parent;
}
friend class boost::serialization::access;
};
void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) { std::shared_ptr<WaitObject> object) {
ASSERT(reason == ThreadWakeupReason::Timeout); ASSERT(reason == ThreadWakeupReason::Timeout);
@ -90,9 +108,6 @@ void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> t
ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type,
VAddr address, s32 value, u64 nanoseconds) { VAddr address, s32 value, u64 nanoseconds) {
auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this());
switch (type) { switch (type) {
// Signal thread(s) waiting for arbitrate address... // Signal thread(s) waiting for arbitrate address...
@ -114,6 +129,9 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi
} }
break; break;
case ArbitrationType::WaitIfLessThanWithTimeout: case ArbitrationType::WaitIfLessThanWithTimeout:
if (!timeout_callback) {
timeout_callback = std::make_shared<Callback>(*this);
}
if ((s32)kernel.memory.Read32(address) < value) { if ((s32)kernel.memory.Read32(address) < value) {
thread->wakeup_callback = timeout_callback; thread->wakeup_callback = timeout_callback;
thread->WakeAfterDelay(nanoseconds); thread->WakeAfterDelay(nanoseconds);
@ -130,6 +148,9 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi
break; break;
} }
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: { case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: {
if (!timeout_callback) {
timeout_callback = std::make_shared<Callback>(*this);
}
s32 memory_value = kernel.memory.Read32(address); s32 memory_value = kernel.memory.Read32(address);
if (memory_value < value) { if (memory_value < value) {
// Only change the memory value if the thread should wait // Only change the memory value if the thread should wait
@ -157,3 +178,6 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi
} }
} // namespace Kernel } // namespace Kernel
SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter)
SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter::Callback)

View File

@ -59,8 +59,7 @@ public:
ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address, ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address,
s32 value, u64 nanoseconds); s32 value, u64 nanoseconds);
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, class Callback;
std::shared_ptr<WaitObject> object);
private: private:
KernelSystem& kernel; KernelSystem& kernel;
@ -78,20 +77,39 @@ private:
/// Threads waiting for the address arbiter to be signaled. /// Threads waiting for the address arbiter to be signaled.
std::vector<std::shared_ptr<Thread>> waiting_threads; std::vector<std::shared_ptr<Thread>> waiting_threads;
std::shared_ptr<Callback> timeout_callback;
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object);
class DummyCallback : public WakeupCallback {
public:
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) override {}
};
friend class boost::serialization::access; friend class boost::serialization::access;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) { void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this); ar& boost::serialization::base_object<Object>(*this);
if (file_version > 0) { if (file_version == 1) {
ar& boost::serialization::base_object<WakeupCallback>(*this); // This rigmarole is needed because in past versions, AddressArbiter inherited WakeupCallback
// But it turns out this breaks shared_from_this, so we split it out.
// Using a dummy class to deserialize a base_object allows compatibility to be maintained.
DummyCallback x;
ar& boost::serialization::base_object<WakeupCallback>(x);
} }
ar& name; ar& name;
ar& waiting_threads; ar& waiting_threads;
if (file_version > 1) {
ar& timeout_callback;
}
} }
}; };
} // namespace Kernel } // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter) BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter)
BOOST_CLASS_VERSION(Kernel::AddressArbiter, 1) BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter::Callback)
BOOST_CLASS_VERSION(Kernel::AddressArbiter, 2)
CONSTRUCT_KERNEL_OBJECT(Kernel::AddressArbiter) CONSTRUCT_KERNEL_OBJECT(Kernel::AddressArbiter)