Merge pull request #1793 from LPFaint99/memcard
GCI folder: flush 1 second after last block is written
This commit is contained in:
commit
9eaae880e5
|
@ -2,9 +2,10 @@
|
||||||
// Licensed under GPLv2
|
// Licensed under GPLv2
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/FileSearch.h"
|
#include "Common/FileSearch.h"
|
||||||
|
#include "Common/StdMakeUnique.h"
|
||||||
|
#include "Common/Thread.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/HW/GCMemcardDirectory.h"
|
#include "Core/HW/GCMemcardDirectory.h"
|
||||||
|
@ -132,13 +133,14 @@ int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::IVolume::EC
|
||||||
}
|
}
|
||||||
|
|
||||||
GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 sizeMb, bool ascii, DiscIO::IVolume::ECountry card_region, int gameId)
|
GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 sizeMb, bool ascii, DiscIO::IVolume::ECountry card_region, int gameId)
|
||||||
: MemoryCardBase(slot, sizeMb)
|
: MemoryCardBase(slot, sizeMb)
|
||||||
, m_GameId(gameId)
|
, m_GameId(gameId)
|
||||||
, m_LastBlock(-1)
|
, m_LastBlock(-1)
|
||||||
, m_hdr(slot, sizeMb, ascii)
|
, m_hdr(slot, sizeMb, ascii)
|
||||||
, m_bat1(sizeMb)
|
, m_bat1(sizeMb)
|
||||||
, m_saves(0)
|
, m_saves(0)
|
||||||
, m_SaveDirectory(directory)
|
, m_SaveDirectory(directory)
|
||||||
|
, m_exiting(false)
|
||||||
{
|
{
|
||||||
// Use existing header data if available
|
// Use existing header data if available
|
||||||
if (File::Exists(m_SaveDirectory + MC_HDR))
|
if (File::Exists(m_SaveDirectory + MC_HDR))
|
||||||
|
@ -186,10 +188,51 @@ GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u
|
||||||
m_dir1.fixChecksums();
|
m_dir1.fixChecksums();
|
||||||
m_dir2 = m_dir1;
|
m_dir2 = m_dir1;
|
||||||
m_bat2 = m_bat1;
|
m_bat2 = m_bat1;
|
||||||
|
|
||||||
|
m_flush_thread = std::thread(&GCMemcardDirectory::FlushThread, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCMemcardDirectory::FlushThread()
|
||||||
|
{
|
||||||
|
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableMemcardSaving)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Common::SetCurrentThreadName(
|
||||||
|
StringFromFormat("Memcard%x-Flush", card_index).c_str());
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// no-op until signalled
|
||||||
|
m_flush_trigger.Wait();
|
||||||
|
|
||||||
|
if (m_exiting)
|
||||||
|
{
|
||||||
|
m_exiting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// no-op as long as signalled within flush_interval
|
||||||
|
while (m_flush_trigger.WaitFor(flush_interval))
|
||||||
|
{
|
||||||
|
if (m_exiting)
|
||||||
|
{
|
||||||
|
m_exiting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlushToFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GCMemcardDirectory::~GCMemcardDirectory()
|
GCMemcardDirectory::~GCMemcardDirectory()
|
||||||
{
|
{
|
||||||
|
m_exiting = true;
|
||||||
|
m_flush_trigger.Set();
|
||||||
|
m_flush_thread.join();
|
||||||
|
|
||||||
FlushToFile();
|
FlushToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +296,7 @@ s32 GCMemcardDirectory::Read(u32 address, s32 length, u8 *destaddress)
|
||||||
|
|
||||||
s32 GCMemcardDirectory::Write(u32 destaddress, s32 length, u8 *srcaddress)
|
s32 GCMemcardDirectory::Write(u32 destaddress, s32 length, u8 *srcaddress)
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_write_mutex);
|
||||||
if (length != 0x80)
|
if (length != 0x80)
|
||||||
INFO_LOG(EXPANSIONINTERFACE, "WRITING TO %x, len %x", destaddress, length);
|
INFO_LOG(EXPANSIONINTERFACE, "WRITING TO %x, len %x", destaddress, length);
|
||||||
s32 block = destaddress / BLOCK_SIZE;
|
s32 block = destaddress / BLOCK_SIZE;
|
||||||
|
@ -266,9 +310,8 @@ s32 GCMemcardDirectory::Write(u32 destaddress, s32 length, u8 *srcaddress)
|
||||||
|
|
||||||
// verify that we haven't calculated a length beyond BLOCK_SIZE
|
// verify that we haven't calculated a length beyond BLOCK_SIZE
|
||||||
_dbg_assert_msg_(EXPANSIONINTERFACE, (destaddress + length) % BLOCK_SIZE == 0,
|
_dbg_assert_msg_(EXPANSIONINTERFACE, (destaddress + length) % BLOCK_SIZE == 0,
|
||||||
"Memcard directory Write Logic Error");
|
"Memcard directory Write Logic Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_LastBlock != block)
|
if (m_LastBlock != block)
|
||||||
{
|
{
|
||||||
switch (block)
|
switch (block)
|
||||||
|
@ -310,8 +353,11 @@ s32 GCMemcardDirectory::Write(u32 destaddress, s32 length, u8 *srcaddress)
|
||||||
|
|
||||||
memcpy(m_LastBlockAddress + offset, srcaddress, length);
|
memcpy(m_LastBlockAddress + offset, srcaddress, length);
|
||||||
|
|
||||||
|
l.unlock();
|
||||||
if (extra)
|
if (extra)
|
||||||
extra = Write(destaddress + length, extra, srcaddress + length);
|
extra = Write(destaddress + length, extra, srcaddress + length);
|
||||||
|
if (offset + length == BLOCK_SIZE)
|
||||||
|
m_flush_trigger.Set();
|
||||||
return length + extra;
|
return length + extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,6 +552,7 @@ bool GCMemcardDirectory::SetUsedBlocks(int saveIndex)
|
||||||
|
|
||||||
void GCMemcardDirectory::FlushToFile()
|
void GCMemcardDirectory::FlushToFile()
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_write_mutex);
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
DEntry invalid;
|
DEntry invalid;
|
||||||
for (u16 i = 0; i < m_saves.size(); ++i)
|
for (u16 i = 0; i < m_saves.size(); ++i)
|
||||||
|
@ -585,6 +632,7 @@ void GCMemcardDirectory::FlushToFile()
|
||||||
|
|
||||||
void GCMemcardDirectory::DoState(PointerWrap &p)
|
void GCMemcardDirectory::DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_write_mutex);
|
||||||
m_LastBlock = -1;
|
m_LastBlock = -1;
|
||||||
m_LastBlockAddress = nullptr;
|
m_LastBlockAddress = nullptr;
|
||||||
p.Do(m_SaveDirectory);
|
p.Do(m_SaveDirectory);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common/Event.h"
|
||||||
#include "Core/HW/GCMemcard.h"
|
#include "Core/HW/GCMemcard.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ public:
|
||||||
DiscIO::IVolume::ECountry card_region = DiscIO::IVolume::COUNTRY_EUROPE, int gameId = 0);
|
DiscIO::IVolume::ECountry card_region = DiscIO::IVolume::COUNTRY_EUROPE, int gameId = 0);
|
||||||
~GCMemcardDirectory();
|
~GCMemcardDirectory();
|
||||||
void FlushToFile();
|
void FlushToFile();
|
||||||
|
void FlushThread();
|
||||||
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;
|
||||||
void ClearBlock(u32 address) override;
|
void ClearBlock(u32 address) override;
|
||||||
|
@ -44,4 +45,9 @@ private:
|
||||||
|
|
||||||
std::vector<std::string> m_loaded_saves;
|
std::vector<std::string> m_loaded_saves;
|
||||||
std::string m_SaveDirectory;
|
std::string m_SaveDirectory;
|
||||||
|
const std::chrono::seconds flush_interval = std::chrono::seconds(1);
|
||||||
|
Common::Event m_flush_trigger;
|
||||||
|
std::mutex m_write_mutex;
|
||||||
|
std::atomic<bool> m_exiting;
|
||||||
|
std::thread m_flush_thread;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue