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 <map>
#include <vector> #include <vector>
#include <deque>
#include <string> #include <string>
#include "Common.h" #include "Common.h"
@ -127,6 +128,18 @@ public:
DoArray(&x[0], vec_size); 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. // Store strings.
void Do(std::string &x) void Do(std::string &x)
{ {

View File

@ -71,7 +71,7 @@ typedef std::map<u32, std::string> TFileNameMap;
TFileNameMap g_FileNameMap; TFileNameMap g_FileNameMap;
u32 g_LastDeviceID; 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 request_queue; // ppc -> arm
static ipc_msg_queue reply_queue; // arm -> ppc static ipc_msg_queue reply_queue; // arm -> ppc
@ -120,8 +120,8 @@ void Reset(bool _bHard)
g_DeviceMap.erase(itr, g_DeviceMap.end()); g_DeviceMap.erase(itr, g_DeviceMap.end());
g_FileNameMap.clear(); g_FileNameMap.clear();
request_queue = std::queue<u32>(); request_queue.clear();
reply_queue = std::queue<u32>(); reply_queue.clear();
g_LastDeviceID = IPC_FIRST_FILEIO_ID; g_LastDeviceID = IPC_FIRST_FILEIO_ID;
} }
@ -205,23 +205,20 @@ void DoState(PointerWrap &p)
{ {
p.Do(g_LastDeviceID); 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) if (p.GetMode() == PointerWrap::MODE_READ)
{ {
TFileNameMap::const_iterator itr;
// Delete file Handles // Delete file Handles
itr = g_FileNameMap.begin(); itr = g_FileNameMap.begin();
while (itr != g_FileNameMap.end()) while (itr != g_FileNameMap.end())
{ {
if (g_DeviceMap[itr->first]) TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first);
delete g_DeviceMap[itr->first]; if (devitr != g_DeviceMap.end())
g_DeviceMap.erase(itr->first); {
if (devitr->second)
delete devitr->second;
g_DeviceMap.erase(itr->first);
}
++itr; ++itr;
} }
// Load file names // Load file names
@ -239,10 +236,26 @@ void DoState(PointerWrap &p)
p.Do(g_FileNameMap); p.Do(g_FileNameMap);
} }
itr = g_FileNameMap.begin(); p.Do(request_queue);
while (itr != g_FileNameMap.end()) 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; ++itr;
} }
} }
@ -393,13 +406,13 @@ void ExecuteCommand(u32 _Address)
// Happens AS SOON AS IPC gets a new pointer! // Happens AS SOON AS IPC gets a new pointer!
void EnqRequest(u32 _Address) void EnqRequest(u32 _Address)
{ {
request_queue.push(_Address); request_queue.push_back(_Address);
} }
// Called when IOS module has some reply // Called when IOS module has some reply
void EnqReply(u32 _Address) void EnqReply(u32 _Address)
{ {
reply_queue.push(_Address); reply_queue.push_back(_Address);
} }
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp // 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()); INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
ExecuteCommand(request_queue.front()); ExecuteCommand(request_queue.front());
request_queue.pop(); request_queue.pop_front();
#if MAX_LOGLEVEL >= DEBUG_LEVEL #if MAX_LOGLEVEL >= DEBUG_LEVEL
Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG); Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
@ -428,7 +441,7 @@ void Update()
{ {
WII_IPCInterface::GenerateReply(reply_queue.front()); WII_IPCInterface::GenerateReply(reply_queue.front());
INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", 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_pFileHandle(NULL)
, m_FileLength(0) , m_FileLength(0)
, m_Mode(0) , m_Mode(0)
, m_Seek(0)
{ {
Common::ReadReplacements(replacements); Common::ReadReplacements(replacements);
} }
@ -104,10 +103,9 @@ bool CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bForce)
m_FileLength = 0; m_FileLength = 0;
m_Mode = 0; m_Mode = 0;
m_Seek = 0;
// Close always return 0 for success // Close always return 0 for success
if (!_bForce) if (_CommandAddress && !_bForce)
Memory::Write_U32(0, _CommandAddress + 4); Memory::Write_U32(0, _CommandAddress + 4);
m_Active = false; m_Active = false;
return true; 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 // close the file handle if we get a reopen
m_pFileHandle.Close(); m_pFileHandle.Close();
const char* const Modes[] = static const char* const Modes[] =
{ {
"Unk Mode", "Unk Mode",
"Read only", "Read only",
@ -326,20 +324,24 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p) void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
{ {
if (p.GetMode() == PointerWrap::MODE_WRITE) bool have_file_handle = m_pFileHandle;
{ s32 seek = (have_file_handle) ? (s32)m_pFileHandle.Tell() : 0;
m_Seek = (m_pFileHandle) ? (s32)m_pFileHandle.Tell() : 0;
}
p.Do(have_file_handle);
p.Do(m_Mode); p.Do(m_Mode);
p.Do(m_Seek); p.Do(seek);
if (p.GetMode() == PointerWrap::MODE_READ) if (p.GetMode() == PointerWrap::MODE_READ)
{ {
if (m_Mode) if (have_file_handle)
{ {
Open(0, m_Mode); 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; File::IOFile m_pFileHandle;
u32 m_FileLength; u32 m_FileLength;
u32 m_Mode; u32 m_Mode;
s32 m_Seek;
std::string m_Filename; std::string m_Filename;
}; };

View File

@ -25,6 +25,7 @@
#include "FileSearch.h" #include "FileSearch.h"
#include "FileUtil.h" #include "FileUtil.h"
#include "NandPaths.h" #include "NandPaths.h"
#include "ChunkFile.h"
#include "../VolumeHandler.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; 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,7 +46,9 @@ public:
CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName); CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName);
virtual ~CWII_IPC_HLE_Device_fs(); virtual ~CWII_IPC_HLE_Device_fs();
virtual bool Open(u32 _CommandAddress, u32 _Mode); virtual void DoState(PointerWrap& p);
virtual bool Open(u32 _CommandAddress, u32 _Mode);
virtual bool Close(u32 _CommandAddress, bool _bForce); virtual bool Close(u32 _CommandAddress, bool _bForce);
virtual bool IOCtl(u32 _CommandAddress); virtual bool IOCtl(u32 _CommandAddress);

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) 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_CtrlSetup);
p.Do(m_ACLSetup); p.Do(m_ACLSetup);
p.Do(m_HCIEndpoint); p.Do(m_HCIEndpoint);
p.Do(m_ACLEndpoint); p.Do(m_ACLEndpoint);
p.Do(m_last_ticks); p.Do(m_last_ticks);
p.DoArray(m_PacketCount,4);
p.Do(m_ScanEnable);
m_acl_pool.DoState(p); m_acl_pool.DoState(p);
if (p.GetMode() == PointerWrap::MODE_READ) {
m_EventQueue.clear();
}
if (p.GetMode() == PointerWrap::MODE_READ && if (p.GetMode() == PointerWrap::MODE_READ &&
SConfig::GetInstance().m_WiimoteReconnectOnLoad) 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 " DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not "
"currently valid, queueing(%lu)...", "currently valid, queueing(%lu)...",
(unsigned long)m_EventQueue.size()); (unsigned long)m_EventQueue.size());
m_EventQueue.push(_event); m_EventQueue.push_back(_event);
const SQueuedEvent& event = m_EventQueue.front(); const SQueuedEvent& event = m_EventQueue.front();
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x " DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x "
"being written from queue(%lu) to %08x...", "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 // Send a reply to indicate HCI buffer is filled
WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address); WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address);
m_HCIEndpoint.Invalidate(); m_HCIEndpoint.Invalidate();
m_EventQueue.pop(); m_EventQueue.pop_front();
} }
} }
else else
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, " DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, "
"queueing(%lu)...", (unsigned long)m_EventQueue.size()); "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 // Send a reply to indicate HCI buffer is filled
WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address); WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address);
m_HCIEndpoint.Invalidate(); m_HCIEndpoint.Invalidate();
m_EventQueue.pop(); m_EventQueue.pop_front();
packet_transferred = true; packet_transferred = true;
} }

View File

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

View File

@ -65,7 +65,7 @@ static std::vector<u8> g_current_buffer;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // 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 struct StateHeader
{ {