Fix Address Arbiter serialization
This commit is contained in:
		| @@ -16,8 +16,6 @@ | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // Kernel namespace | ||||
|  | ||||
| SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter) | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| 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, | ||||
|                             std::shared_ptr<WaitObject> object) { | ||||
|     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, | ||||
|                                             VAddr address, s32 value, u64 nanoseconds) { | ||||
|  | ||||
|     auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this()); | ||||
|  | ||||
|     switch (type) { | ||||
|  | ||||
|     // Signal thread(s) waiting for arbitrate address... | ||||
| @@ -114,6 +129,9 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi | ||||
|         } | ||||
|         break; | ||||
|     case ArbitrationType::WaitIfLessThanWithTimeout: | ||||
|         if (!timeout_callback) { | ||||
|             timeout_callback = std::make_shared<Callback>(*this); | ||||
|         } | ||||
|         if ((s32)kernel.memory.Read32(address) < value) { | ||||
|             thread->wakeup_callback = timeout_callback; | ||||
|             thread->WakeAfterDelay(nanoseconds); | ||||
| @@ -130,6 +148,9 @@ ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, Arbi | ||||
|         break; | ||||
|     } | ||||
|     case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: { | ||||
|         if (!timeout_callback) { | ||||
|             timeout_callback = std::make_shared<Callback>(*this); | ||||
|         } | ||||
|         s32 memory_value = kernel.memory.Read32(address); | ||||
|         if (memory_value < value) { | ||||
|             // 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 | ||||
|  | ||||
| SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter) | ||||
| SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter::Callback) | ||||
|   | ||||
| @@ -59,8 +59,7 @@ public: | ||||
|     ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address, | ||||
|                                 s32 value, u64 nanoseconds); | ||||
|  | ||||
|     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, | ||||
|                 std::shared_ptr<WaitObject> object); | ||||
|     class Callback; | ||||
|  | ||||
| private: | ||||
|     KernelSystem& kernel; | ||||
| @@ -78,20 +77,39 @@ private: | ||||
|     /// Threads waiting for the address arbiter to be signaled. | ||||
|     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; | ||||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int file_version) { | ||||
|         ar& boost::serialization::base_object<Object>(*this); | ||||
|         if (file_version > 0) { | ||||
|             ar& boost::serialization::base_object<WakeupCallback>(*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<WakeupCallback>(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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user