mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-11-03 23:28:48 +00:00 
			
		
		
		
	Fix Address Arbiter serialization
This commit is contained in:
		
							parent
							
								
									79a0cbbba8
								
							
						
					
					
						commit
						1fb3c9f08c
					
				
					 2 changed files with 53 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -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,19 +78,36 @@ 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);
 | 
			
		||||
    // 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.end());
 | 
			
		||||
                            waiting_threads.end());
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue