diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 5074e352f..23a9bb8d1 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -16,8 +16,6 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace -SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter) - namespace Kernel { void AddressArbiter::WaitThread(std::shared_ptr thread, VAddr wait_address) { @@ -69,7 +67,8 @@ std::shared_ptr AddressArbiter::ResumeHighestPriorityThread(VAddr addres return thread; } -AddressArbiter::AddressArbiter(KernelSystem& kernel) : Object(kernel), kernel(kernel) {} +AddressArbiter::AddressArbiter(KernelSystem& kernel) + : Object(kernel), kernel(kernel), timeout_callback(std::make_shared(*this)) {} AddressArbiter::~AddressArbiter() {} std::shared_ptr KernelSystem::CreateAddressArbiter(std::string name) { @@ -80,6 +79,24 @@ std::shared_ptr KernelSystem::CreateAddressArbiter(std::string n return address_arbiter; } +class AddressArbiter::Callback : public WakeupCallback { +public: + explicit Callback(AddressArbiter& _parent) : parent(_parent) {} + AddressArbiter& parent; + + void WakeUp(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object) override { + parent.WakeUp(reason, std::move(thread), std::move(object)); + } + +private: + template + void serialize(Archive& ar, const unsigned int) { + ar& boost::serialization::base_object(*this); + } + friend class boost::serialization::access; +}; + void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object) { ASSERT(reason == ThreadWakeupReason::Timeout); @@ -90,9 +107,6 @@ void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr t ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr thread, ArbitrationType type, VAddr address, s32 value, u64 nanoseconds) { - - auto timeout_callback = std::dynamic_pointer_cast(shared_from_this()); - switch (type) { // Signal thread(s) waiting for arbitrate address... @@ -157,3 +171,23 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr thread, Arbi } } // namespace Kernel + +namespace boost::serialization { + +template +void save_construct_data(Archive& ar, const Kernel::AddressArbiter::Callback* t, + const unsigned int) { + ar << Kernel::SharedFrom(&t->parent); +} + +template +void load_construct_data(Archive& ar, Kernel::AddressArbiter::Callback* t, const unsigned int) { + std::shared_ptr parent; + ar >> parent; + ::new (t) Kernel::AddressArbiter::Callback(*parent); +} + +} // namespace boost::serialization + +SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter) +SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter::Callback) diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index c7a263d9e..4d8b12241 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -59,8 +59,7 @@ public: ResultCode ArbitrateAddress(std::shared_ptr thread, ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); - void WakeUp(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object); + class Callback; private: KernelSystem& kernel; @@ -78,20 +77,40 @@ private: /// Threads waiting for the address arbiter to be signaled. std::vector> waiting_threads; + std::shared_ptr timeout_callback; + + void WakeUp(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object); + + class DummyCallback : public WakeupCallback { + public: + void WakeUp(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object) override {} + }; + friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int file_version) { ar& boost::serialization::base_object(*this); - if (file_version > 0) { - ar& boost::serialization::base_object(*this); + if (file_version == 1) { + // 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(x); } ar& name; ar& waiting_threads; + if (file_version > 1) { + ar& timeout_callback; + } } }; } // namespace Kernel 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)