mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-15 11:30:07 +00:00
Fix Address Arbiter serialization
This commit is contained in:
parent
79a0cbbba8
commit
1fb3c9f08c
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user