Fix Address Arbiter serialization
This commit is contained in:
		| @@ -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,19 +78,36 @@ 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); | ||||||
|     // Remove the newly-awakened thread from the Arbiter's waiting list. |     // Remove the newly-awakened thread from the Arbiter's waiting list. | ||||||
|     waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread), |     waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread), | ||||||
|                           waiting_threads.end()); |                             waiting_threads.end()); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| 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) | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user