Merge pull request #979 from shuffle2/fix-memcard-flush3

raw memcards: revert last change so flushes are still time-driven.
This commit is contained in:
shuffle2 2014-09-05 22:27:12 -07:00
commit a831121683
2 changed files with 35 additions and 44 deletions

View File

@ -12,8 +12,6 @@
#define SIZE_TO_Mb (1024 * 8 * 16) #define SIZE_TO_Mb (1024 * 8 * 16)
#define MC_HDR_SIZE 0xA000 #define MC_HDR_SIZE 0xA000
const std::chrono::seconds MemoryCard::s_flush_interval{ 15 };
MemoryCard::MemoryCard(std::string filename, int _card_index, u16 sizeMb) MemoryCard::MemoryCard(std::string filename, int _card_index, u16 sizeMb)
: MemoryCardBase(_card_index, sizeMb) : MemoryCardBase(_card_index, sizeMb)
, m_filename(filename) , m_filename(filename)
@ -46,7 +44,6 @@ MemoryCard::MemoryCard(std::string filename, int _card_index, u16 sizeMb)
// Class members (including inherited ones) have now been initialized, so // Class members (including inherited ones) have now been initialized, so
// it's safe to startup the flush thread (which reads them). // it's safe to startup the flush thread (which reads them).
m_last_flush = std::chrono::steady_clock::now();
m_flush_buffer = std::make_unique<u8[]>(memory_card_size); m_flush_buffer = std::make_unique<u8[]>(memory_card_size);
m_flush_thread = std::thread(&MemoryCard::FlushThread, this); m_flush_thread = std::thread(&MemoryCard::FlushThread, this);
} }
@ -55,13 +52,6 @@ MemoryCard::~MemoryCard()
{ {
if (m_flush_thread.joinable()) if (m_flush_thread.joinable())
{ {
// Update the flush buffer one last time, flush, and join.
{
std::unique_lock<std::mutex> l(m_flush_mutex);
memcpy(&m_flush_buffer[0], &m_memcard_data[0], memory_card_size);
}
m_is_exiting.Set();
m_flush_trigger.Set(); m_flush_trigger.Set();
m_flush_thread.join(); m_flush_thread.join();
@ -78,10 +68,21 @@ void MemoryCard::FlushThread()
Common::SetCurrentThreadName( Common::SetCurrentThreadName(
StringFromFormat("Memcard%x-Flush", card_index).c_str()); StringFromFormat("Memcard%x-Flush", card_index).c_str());
for (;;) const auto flush_interval = std::chrono::seconds(15);
while (true)
{ {
m_flush_trigger.Wait(); // If triggered, we're exiting.
bool do_exit = m_is_exiting.IsSet(); // If timed out, check if we need to flush.
bool do_exit = m_flush_trigger.WaitFor(flush_interval);
if (!do_exit)
{
bool is_dirty = m_dirty.TestAndClear();
if (!is_dirty)
{
continue;
}
}
// Opening the file is purposefully done each iteration to ensure the // Opening the file is purposefully done each iteration to ensure the
// file doesn't disappear out from under us after the first check. // file doesn't disappear out from under us after the first check.
@ -115,8 +116,9 @@ void MemoryCard::FlushThread()
{ {
std::unique_lock<std::mutex> l(m_flush_mutex); std::unique_lock<std::mutex> l(m_flush_mutex);
pFile.WriteBytes(&m_flush_buffer[0], memory_card_size); memcpy(&m_flush_buffer[0], &m_memcard_data[0], memory_card_size);
} }
pFile.WriteBytes(&m_flush_buffer[0], memory_card_size);
if (!do_exit) if (!do_exit)
{ {
@ -132,25 +134,9 @@ void MemoryCard::FlushThread()
} }
} }
// Attempt to update the flush buffer and trigger a flush. If we can't get a void MemoryCard::MakeDirty()
// lock in order to update the flush buffer, a write is in progress and a future
// write will take care of any changes to the memcard data, so nothing needs to
// be done now.
void MemoryCard::TryFlush()
{ {
auto now = std::chrono::steady_clock::now(); m_dirty.Set();
if (now - m_last_flush < s_flush_interval)
{
return;
}
m_last_flush = now;
if (m_flush_mutex.try_lock())
{
memcpy(&m_flush_buffer[0], &m_memcard_data[0], memory_card_size);
m_flush_mutex.unlock();
m_flush_trigger.Set();
}
} }
s32 MemoryCard::Read(u32 srcaddress, s32 length, u8 *destaddress) s32 MemoryCard::Read(u32 srcaddress, s32 length, u8 *destaddress)
@ -175,8 +161,11 @@ s32 MemoryCard::Write(u32 destaddress, s32 length, u8 *srcaddress)
return -1; return -1;
} }
memcpy(&m_memcard_data[destaddress], srcaddress, length); {
TryFlush(); std::unique_lock<std::mutex> l(m_flush_mutex);
memcpy(&m_memcard_data[destaddress], srcaddress, length);
}
MakeDirty();
return length; return length;
} }
@ -185,19 +174,24 @@ void MemoryCard::ClearBlock(u32 address)
if (address & (BLOCK_SIZE - 1) || !IsAddressInBounds(address)) if (address & (BLOCK_SIZE - 1) || !IsAddressInBounds(address))
{ {
PanicAlertT("MemoryCard: ClearBlock called on invalid address %x", PanicAlertT("MemoryCard: ClearBlock called on invalid address %x",
address); address);
return;
} }
else else
{ {
std::unique_lock<std::mutex> l(m_flush_mutex);
memset(&m_memcard_data[address], 0xFF, BLOCK_SIZE); memset(&m_memcard_data[address], 0xFF, BLOCK_SIZE);
TryFlush();
} }
MakeDirty();
} }
void MemoryCard::ClearAll() void MemoryCard::ClearAll()
{ {
memset(&m_memcard_data[0], 0xFF, memory_card_size); {
TryFlush(); std::unique_lock<std::mutex> l(m_flush_mutex);
memset(&m_memcard_data[0], 0xFF, memory_card_size);
}
MakeDirty();
} }
void MemoryCard::DoState(PointerWrap &p) void MemoryCard::DoState(PointerWrap &p)

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include <chrono>
#include <memory> #include <memory>
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/Flag.h" #include "Common/Flag.h"
@ -19,7 +18,7 @@ public:
MemoryCard(std::string filename, int _card_index, u16 sizeMb = MemCard2043Mb); MemoryCard(std::string filename, int _card_index, u16 sizeMb = MemCard2043Mb);
~MemoryCard(); ~MemoryCard();
void FlushThread(); void FlushThread();
void TryFlush(); void MakeDirty();
s32 Read(u32 address, s32 length, u8 *destaddress) override; s32 Read(u32 address, s32 length, u8 *destaddress) override;
s32 Write(u32 destaddress, s32 length, u8 *srcaddress) override; s32 Write(u32 destaddress, s32 length, u8 *srcaddress) override;
@ -30,11 +29,9 @@ public:
private: private:
std::string m_filename; std::string m_filename;
std::unique_ptr<u8[]> m_memcard_data; std::unique_ptr<u8[]> m_memcard_data;
std::unique_ptr<u8[]> m_flush_buffer;
std::thread m_flush_thread; std::thread m_flush_thread;
std::mutex m_flush_mutex; std::mutex m_flush_mutex;
Common::Event m_flush_trigger; Common::Event m_flush_trigger;
Common::Flag m_is_exiting; Common::Flag m_dirty;
std::unique_ptr<u8[]> m_flush_buffer;
std::chrono::steady_clock::time_point m_last_flush;
static const std::chrono::seconds s_flush_interval;
}; };