Improve WII state saves by saving /tmp and IPC request/reply queues

mp3:c stores temporary files in /tmp and needs them restored to
resume properly.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7564 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
pierre 2011-05-27 19:55:07 +00:00
parent 5b5e8edb17
commit 3bcb406c46
9 changed files with 176 additions and 40 deletions

View File

@ -29,6 +29,7 @@
#include <map>
#include <vector>
#include <deque>
#include <string>
#include "Common.h"
@ -127,6 +128,18 @@ public:
DoArray(&x[0], vec_size);
}
// Store deques.
template<class T>
void Do(std::deque<T> &x)
{
u32 deq_size = (u32)x.size();
Do(deq_size);
x.resize(deq_size);
u32 i;
for(i = 0; i < deq_size; i++)
DoVoid(&x[i],sizeof(T));
}
// Store strings.
void Do(std::string &x)
{

View File

@ -71,7 +71,7 @@ typedef std::map<u32, std::string> TFileNameMap;
TFileNameMap g_FileNameMap;
u32 g_LastDeviceID;
typedef std::queue<u32> ipc_msg_queue;
typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue; // arm -> ppc
@ -120,8 +120,8 @@ void Reset(bool _bHard)
g_DeviceMap.erase(itr, g_DeviceMap.end());
g_FileNameMap.clear();
request_queue = std::queue<u32>();
reply_queue = std::queue<u32>();
request_queue.clear();
reply_queue.clear();
g_LastDeviceID = IPC_FIRST_FILEIO_ID;
}
@ -205,23 +205,20 @@ void DoState(PointerWrap &p)
{
p.Do(g_LastDeviceID);
// Currently only USB device needs to be saved
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("/dev/usb/oh1/57e/305")));
if (pDevice)
pDevice->DoState(p);
else
PanicAlert("WII_IPC_HLE: Save/Load State failed, Device /dev/usb/oh1/57e/305 doesn't exist!");
TFileNameMap::const_iterator itr;
if (p.GetMode() == PointerWrap::MODE_READ)
{
TFileNameMap::const_iterator itr;
// Delete file Handles
itr = g_FileNameMap.begin();
while (itr != g_FileNameMap.end())
{
if (g_DeviceMap[itr->first])
delete g_DeviceMap[itr->first];
TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first);
if (devitr != g_DeviceMap.end())
{
if (devitr->second)
delete devitr->second;
g_DeviceMap.erase(itr->first);
}
++itr;
}
// Load file names
@ -239,10 +236,26 @@ void DoState(PointerWrap &p)
p.Do(g_FileNameMap);
}
itr = g_FileNameMap.begin();
while (itr != g_FileNameMap.end())
p.Do(request_queue);
p.Do(reply_queue);
TDeviceMap::const_iterator itr;
//first, all the real devices
//(because we need fs to be deserialized first)
itr = g_DeviceMap.begin();
while (itr != g_DeviceMap.end())
{
g_DeviceMap[itr->first]->DoState(p);
if (itr->second->IsHardware())
itr->second->DoState(p);
++itr;
}
//then all the files
itr = g_DeviceMap.begin();
while (itr != g_DeviceMap.end())
{
if (!itr->second->IsHardware())
itr->second->DoState(p);
++itr;
}
}
@ -393,13 +406,13 @@ void ExecuteCommand(u32 _Address)
// Happens AS SOON AS IPC gets a new pointer!
void EnqRequest(u32 _Address)
{
request_queue.push(_Address);
request_queue.push_back(_Address);
}
// Called when IOS module has some reply
void EnqReply(u32 _Address)
{
reply_queue.push(_Address);
reply_queue.push_back(_Address);
}
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
@ -417,7 +430,7 @@ void Update()
INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
ExecuteCommand(request_queue.front());
request_queue.pop();
request_queue.pop_front();
#if MAX_LOGLEVEL >= DEBUG_LEVEL
Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
@ -428,7 +441,7 @@ void Update()
{
WII_IPCInterface::GenerateReply(reply_queue.front());
INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
reply_queue.pop();
reply_queue.pop_front();
}
}

View File

@ -87,7 +87,6 @@ CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std:
, m_pFileHandle(NULL)
, m_FileLength(0)
, m_Mode(0)
, m_Seek(0)
{
Common::ReadReplacements(replacements);
}
@ -104,10 +103,9 @@ bool CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bForce)
m_FileLength = 0;
m_Mode = 0;
m_Seek = 0;
// Close always return 0 for success
if (!_bForce)
if (_CommandAddress && !_bForce)
Memory::Write_U32(0, _CommandAddress + 4);
m_Active = false;
return true;
@ -121,7 +119,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
// close the file handle if we get a reopen
m_pFileHandle.Close();
const char* const Modes[] =
static const char* const Modes[] =
{
"Unk Mode",
"Read only",
@ -326,20 +324,24 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
{
if (p.GetMode() == PointerWrap::MODE_WRITE)
{
m_Seek = (m_pFileHandle) ? (s32)m_pFileHandle.Tell() : 0;
}
bool have_file_handle = m_pFileHandle;
s32 seek = (have_file_handle) ? (s32)m_pFileHandle.Tell() : 0;
p.Do(have_file_handle);
p.Do(m_Mode);
p.Do(m_Seek);
p.Do(seek);
if (p.GetMode() == PointerWrap::MODE_READ)
{
if (m_Mode)
if (have_file_handle)
{
Open(0, m_Mode);
m_pFileHandle.Seek(m_Seek, SEEK_SET);
_dbg_assert_msg_(WII_IPC_HLE, m_pFileHandle, "bad filehandle");
}
else
Close(0, true);
}
if (have_file_handle)
m_pFileHandle.Seek(seek, SEEK_SET);
}

View File

@ -76,7 +76,6 @@ private:
File::IOFile m_pFileHandle;
u32 m_FileLength;
u32 m_Mode;
s32 m_Seek;
std::string m_Filename;
};

View File

@ -25,6 +25,7 @@
#include "FileSearch.h"
#include "FileUtil.h"
#include "NandPaths.h"
#include "ChunkFile.h"
#include "../VolumeHandler.h"
@ -484,3 +485,96 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B
return FS_RESULT_FATAL;
}
void CWII_IPC_HLE_Device_fs::DoState(PointerWrap& p)
{
// handle /tmp
std::string Path = File::GetUserPath(D_WIIUSER_IDX) + "tmp";
if (p.GetMode() == PointerWrap::MODE_READ)
{
File::DeleteDirRecursively(Path);
File::CreateDir(Path.c_str());
//now restore from the stream
while(1) {
char type;
p.Do(type);
if (!type)
break;
std::string filename;
p.Do(filename);
std::string name = Path + DIR_SEP + filename;
switch(type)
{
case 'd':
{
File::CreateDir(name.c_str());
break;
}
case 'f':
{
u32 size;
p.Do(size);
File::IOFile handle(name, "wb");
char buf[65536];
u32 count = size;
while(count > 65536) {
p.DoArray(&buf[0], 65536);
handle.WriteArray(&buf[0], 65536);
count -= 65536;
}
p.DoArray(&buf[0], count);
handle.WriteArray(&buf[0], count);
break;
}
}
}
}
else
{
//recurse through tmp and save dirs and files
File::FSTEntry parentEntry;
File::ScanDirectoryTree(Path, parentEntry);
std::deque<File::FSTEntry> todo;
todo.insert(todo.end(), parentEntry.children.begin(),
parentEntry.children.end());
while(!todo.empty())
{
File::FSTEntry &entry = todo.front();
std::string name = entry.physicalName;
name.erase(0,Path.length()+1);
char type = entry.isDirectory?'d':'f';
p.Do(type);
p.Do(name);
if (entry.isDirectory)
{
todo.insert(todo.end(), entry.children.begin(),
entry.children.end());
}
else
{
u32 size = entry.size;
p.Do(size);
File::IOFile handle(entry.physicalName, "rb");
char buf[65536];
u32 count = size;
while(count > 65536) {
handle.ReadArray(&buf[0], 65536);
p.DoArray(&buf[0], 65536);
count -= 65536;
}
handle.ReadArray(&buf[0], count);
p.DoArray(&buf[0], count);
}
todo.pop_front();
}
char type = 0;
p.Do(type);
}
}

View File

@ -46,6 +46,8 @@ public:
CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName);
virtual ~CWII_IPC_HLE_Device_fs();
virtual void DoState(PointerWrap& p);
virtual bool Open(u32 _CommandAddress, u32 _Mode);
virtual bool Close(u32 _CommandAddress, bool _bForce);

View File

@ -106,13 +106,26 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305()
void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
{
/*
//things that do not get saved:
std::vector<CWII_IPC_HLE_WiiMote> m_WiiMotes;
std::deque<SQueuedEvent> m_EventQueue;
*/
p.Do(m_CtrlSetup);
p.Do(m_ACLSetup);
p.Do(m_HCIEndpoint);
p.Do(m_ACLEndpoint);
p.Do(m_last_ticks);
p.DoArray(m_PacketCount,4);
p.Do(m_ScanEnable);
m_acl_pool.DoState(p);
if (p.GetMode() == PointerWrap::MODE_READ) {
m_EventQueue.clear();
}
if (p.GetMode() == PointerWrap::MODE_READ &&
SConfig::GetInstance().m_WiimoteReconnectOnLoad)
{
@ -397,7 +410,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not "
"currently valid, queueing(%lu)...",
(unsigned long)m_EventQueue.size());
m_EventQueue.push(_event);
m_EventQueue.push_back(_event);
const SQueuedEvent& event = m_EventQueue.front();
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x "
"being written from queue(%lu) to %08x...",
@ -409,14 +422,14 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
// Send a reply to indicate HCI buffer is filled
WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address);
m_HCIEndpoint.Invalidate();
m_EventQueue.pop();
m_EventQueue.pop_front();
}
}
else
{
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, "
"queueing(%lu)...", (unsigned long)m_EventQueue.size());
m_EventQueue.push(_event);
m_EventQueue.push_back(_event);
}
}
@ -439,7 +452,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
// Send a reply to indicate HCI buffer is filled
WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address);
m_HCIEndpoint.Invalidate();
m_EventQueue.pop();
m_EventQueue.pop_front();
packet_transferred = true;
}

View File

@ -152,7 +152,7 @@ private:
SHCICommandMessage m_CtrlSetup;
CtrlBuffer m_HCIEndpoint;
std::queue<SQueuedEvent> m_EventQueue;
std::deque<SQueuedEvent> m_EventQueue;
u32 m_ACLSetup;
CtrlBuffer m_ACLEndpoint;

View File

@ -65,7 +65,7 @@ static std::vector<u8> g_current_buffer;
static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system
static const int STATE_VERSION = 4;
static const int STATE_VERSION = 5;
struct StateHeader
{