mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-24 07:26:34 +00:00
Change stream I/O behaviour around sockets
* Previously each read and write would 1:1 become a send or recv call. * Now we buffer writes and send in batch (or when a chunk finishes), and every time we read we try to non-blocking read more data to fill the buffer, to allow batching reads where possible without blocking on data that will never come.
This commit is contained in:
+460
-467
@@ -215,525 +215,518 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
|
||||
if(threadData->killThread)
|
||||
break;
|
||||
|
||||
Threading::Sleep(4);
|
||||
// this will block until a packet comes in.
|
||||
RemoteServerPacket type = reader.ReadChunk<RemoteServerPacket>();
|
||||
|
||||
if(client->IsRecvDataWaiting())
|
||||
if(reader.IsErrored() || writer.IsErrored())
|
||||
break;
|
||||
|
||||
if(client == NULL)
|
||||
continue;
|
||||
|
||||
if(type == eRemoteServer_Ping)
|
||||
{
|
||||
RemoteServerPacket type = reader.ReadChunk<RemoteServerPacket>();
|
||||
reader.EndChunk();
|
||||
|
||||
if(reader.IsErrored() || writer.IsErrored())
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping);
|
||||
}
|
||||
else if(type == eRemoteServer_RemoteDriverList)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
std::map<RDCDriver, std::string> drivers = RenderDoc::Inst().GetRemoteDrivers();
|
||||
uint32_t count = (uint32_t)drivers.size();
|
||||
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_RemoteDriverList);
|
||||
SERIALISE_ELEMENT(count);
|
||||
|
||||
for(auto it = drivers.begin(); it != drivers.end(); ++it)
|
||||
{
|
||||
RDCDriver driverType = it->first;
|
||||
const std::string &driverName = it->second;
|
||||
|
||||
SERIALISE_ELEMENT(driverType);
|
||||
SERIALISE_ELEMENT(driverName);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_HomeDir)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
std::string home = FileIO::GetHomeFolderFilename();
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_HomeDir);
|
||||
SERIALISE_ELEMENT(home);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_ListDir)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
std::vector<PathEntry> files = FileIO::GetFilesInDirectory(path.c_str());
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ListDir);
|
||||
SERIALISE_ELEMENT(files);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_CopyCaptureFromRemote)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureFromRemote);
|
||||
|
||||
StreamReader fileStream(FileIO::fopen(path.c_str(), "rb"));
|
||||
ser.SerialiseStream(path, fileStream);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_CopyCaptureToRemote)
|
||||
{
|
||||
std::string path;
|
||||
std::string dummy, dummy2;
|
||||
FileIO::GetDefaultFiles("remotecopy", path, dummy, dummy2);
|
||||
|
||||
RDCLOG("Copying file to local path '%s'.", path.c_str());
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
|
||||
StreamWriter streamWriter(FileIO::fopen(path.c_str(), "wb"), Ownership::Stream);
|
||||
|
||||
ser.SerialiseStream(path.c_str(), streamWriter, NULL);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
FileIO::Delete(path.c_str());
|
||||
|
||||
RDCERR("Network error receiving file");
|
||||
break;
|
||||
}
|
||||
|
||||
if(client == NULL)
|
||||
continue;
|
||||
RDCLOG("File received.");
|
||||
|
||||
tempFiles.push_back(path);
|
||||
|
||||
if(type == eRemoteServer_Ping)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping);
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureToRemote);
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
else if(type == eRemoteServer_RemoteDriverList)
|
||||
}
|
||||
else if(type == eRemoteServer_TakeOwnershipCapture)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
{
|
||||
reader.EndChunk();
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
std::map<RDCDriver, std::string> drivers = RenderDoc::Inst().GetRemoteDrivers();
|
||||
uint32_t count = (uint32_t)drivers.size();
|
||||
reader.EndChunk();
|
||||
|
||||
RDCLOG("Taking ownership of '%s'.", path.c_str());
|
||||
|
||||
tempFiles.push_back(path);
|
||||
}
|
||||
else if(type == eRemoteServer_ShutdownServer)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
RDCLOG("Requested to shut down.");
|
||||
|
||||
threadData->killServer = true;
|
||||
threadData->killThread = true;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_RemoteDriverList);
|
||||
SERIALISE_ELEMENT(count);
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ShutdownServer);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_OpenLog)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
for(auto it = drivers.begin(); it != drivers.end(); ++it)
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
RDCASSERT(driver == NULL && proxy == NULL && rdc == NULL);
|
||||
ReplayStatus status = ReplayStatus::InternalError;
|
||||
|
||||
rdc = new RDCFile();
|
||||
rdc->Open(path.c_str());
|
||||
|
||||
if(rdc->ErrorCode() != ContainerError::NoError)
|
||||
{
|
||||
RDCERR("Failed to open '%s': %d", path.c_str(), rdc->ErrorCode());
|
||||
|
||||
switch(rdc->ErrorCode())
|
||||
{
|
||||
RDCDriver driverType = it->first;
|
||||
const std::string &driverName = it->second;
|
||||
|
||||
SERIALISE_ELEMENT(driverType);
|
||||
SERIALISE_ELEMENT(driverName);
|
||||
case ContainerError::FileNotFound: status = ReplayStatus::FileNotFound; break;
|
||||
case ContainerError::FileIO: status = ReplayStatus::FileIOFailed; break;
|
||||
case ContainerError::Corrupt: status = ReplayStatus::FileCorrupted; break;
|
||||
case ContainerError::UnsupportedVersion:
|
||||
status = ReplayStatus::FileIncompatibleVersion;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_HomeDir)
|
||||
else
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
std::string home = FileIO::GetHomeFolderFilename();
|
||||
|
||||
if(RenderDoc::Inst().HasRemoteDriver(rdc->GetDriver()))
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_HomeDir);
|
||||
SERIALISE_ELEMENT(home);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_ListDir)
|
||||
{
|
||||
std::string path;
|
||||
bool kill = false;
|
||||
float progress = 0.0f;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
RenderDoc::Inst().SetProgressPtr(&progress);
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
std::vector<PathEntry> files = FileIO::GetFilesInDirectory(path.c_str());
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ListDir);
|
||||
SERIALISE_ELEMENT(files);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_CopyCaptureFromRemote)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureFromRemote);
|
||||
|
||||
StreamReader fileStream(FileIO::fopen(path.c_str(), "rb"));
|
||||
ser.SerialiseStream(path, fileStream);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_CopyCaptureToRemote)
|
||||
{
|
||||
std::string path;
|
||||
std::string dummy, dummy2;
|
||||
FileIO::GetDefaultFiles("remotecopy", path, dummy, dummy2);
|
||||
|
||||
RDCLOG("Copying file to local path '%s'.", path.c_str());
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
|
||||
StreamWriter streamWriter(FileIO::fopen(path.c_str(), "wb"), Ownership::Stream);
|
||||
|
||||
ser.SerialiseStream(path.c_str(), streamWriter, NULL);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
FileIO::Delete(path.c_str());
|
||||
|
||||
RDCERR("Network error receiving file");
|
||||
break;
|
||||
}
|
||||
|
||||
RDCLOG("File received.");
|
||||
|
||||
tempFiles.push_back(path);
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureToRemote);
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_TakeOwnershipCapture)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
RDCLOG("Taking ownership of '%s'.", path.c_str());
|
||||
|
||||
tempFiles.push_back(path);
|
||||
}
|
||||
else if(type == eRemoteServer_ShutdownServer)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
RDCLOG("Requested to shut down.");
|
||||
|
||||
threadData->killServer = true;
|
||||
threadData->killThread = true;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ShutdownServer);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_OpenLog)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(path);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
RDCASSERT(driver == NULL && proxy == NULL && rdc == NULL);
|
||||
ReplayStatus status = ReplayStatus::InternalError;
|
||||
|
||||
rdc = new RDCFile();
|
||||
rdc->Open(path.c_str());
|
||||
|
||||
if(rdc->ErrorCode() != ContainerError::NoError)
|
||||
{
|
||||
RDCERR("Failed to open '%s': %d", path.c_str(), rdc->ErrorCode());
|
||||
|
||||
switch(rdc->ErrorCode())
|
||||
{
|
||||
case ContainerError::FileNotFound: status = ReplayStatus::FileNotFound; break;
|
||||
case ContainerError::FileIO: status = ReplayStatus::FileIOFailed; break;
|
||||
case ContainerError::Corrupt: status = ReplayStatus::FileCorrupted; break;
|
||||
case ContainerError::UnsupportedVersion:
|
||||
status = ReplayStatus::FileIncompatibleVersion;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(RenderDoc::Inst().HasRemoteDriver(rdc->GetDriver()))
|
||||
{
|
||||
bool kill = false;
|
||||
float progress = 0.0f;
|
||||
|
||||
RenderDoc::Inst().SetProgressPtr(&progress);
|
||||
|
||||
Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &kill, &progress]() {
|
||||
while(!kill)
|
||||
{
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpenProgress);
|
||||
SERIALISE_ELEMENT(progress);
|
||||
}
|
||||
Threading::Sleep(100);
|
||||
}
|
||||
});
|
||||
|
||||
status = RenderDoc::Inst().CreateRemoteDriver(rdc, &driver);
|
||||
|
||||
if(status != ReplayStatus::Succeeded || driver == NULL)
|
||||
Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &kill, &progress]() {
|
||||
while(!kill)
|
||||
{
|
||||
RDCERR("Failed to create remote driver for driver '%s'", rdc->GetDriverName().c_str());
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpenProgress);
|
||||
SERIALISE_ELEMENT(progress);
|
||||
}
|
||||
Threading::Sleep(100);
|
||||
}
|
||||
});
|
||||
|
||||
status = RenderDoc::Inst().CreateRemoteDriver(rdc, &driver);
|
||||
|
||||
if(status != ReplayStatus::Succeeded || driver == NULL)
|
||||
{
|
||||
RDCERR("Failed to create remote driver for driver '%s'", rdc->GetDriverName().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
status = driver->ReadLogInitialisation(rdc, false);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
RDCERR("Failed to initialise remote driver.");
|
||||
|
||||
driver->Shutdown();
|
||||
driver = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = driver->ReadLogInitialisation(rdc, false);
|
||||
RenderDoc::Inst().SetProgressPtr(NULL);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
RDCERR("Failed to initialise remote driver.");
|
||||
kill = true;
|
||||
Threading::JoinThread(ticker);
|
||||
Threading::CloseThread(ticker);
|
||||
|
||||
driver->Shutdown();
|
||||
driver = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderDoc::Inst().SetProgressPtr(NULL);
|
||||
|
||||
kill = true;
|
||||
Threading::JoinThread(ticker);
|
||||
Threading::CloseThread(ticker);
|
||||
|
||||
proxy = new ReplayProxy(reader, writer, driver);
|
||||
}
|
||||
proxy = new ReplayProxy(reader, writer, driver);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("File needs driver for '%s' which isn't supported!", rdc->GetDriverName().c_str());
|
||||
|
||||
status = ReplayStatus::APIUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpened);
|
||||
SERIALISE_ELEMENT(status);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_HasCallstacks)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
bool HasCallstacks = rdc && rdc->SectionIndex(SectionType::ResolveDatabase) >= 0;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_HasCallstacks);
|
||||
SERIALISE_ELEMENT(HasCallstacks);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_InitResolver)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
bool success = false;
|
||||
|
||||
int sectionIndex = rdc ? rdc->SectionIndex(SectionType::ResolveDatabase) : -1;
|
||||
|
||||
SAFE_DELETE(resolver);
|
||||
if(sectionIndex >= 0)
|
||||
{
|
||||
StreamReader *sectionReader = rdc->ReadSection(sectionIndex);
|
||||
|
||||
std::vector<byte> buf;
|
||||
buf.resize((size_t)sectionReader->GetSize());
|
||||
success = sectionReader->Read(buf.data(), sectionReader->GetSize());
|
||||
|
||||
delete sectionReader;
|
||||
|
||||
if(success)
|
||||
{
|
||||
float progress = 0.0f;
|
||||
|
||||
Threading::ThreadHandle ticker =
|
||||
Threading::CreateThread([&writer, &resolver, &progress]() {
|
||||
while(!resolver)
|
||||
{
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ResolverProgress);
|
||||
SERIALISE_ELEMENT(progress);
|
||||
}
|
||||
Threading::Sleep(100);
|
||||
}
|
||||
});
|
||||
|
||||
resolver = Callstack::MakeResolver(buf.data(), buf.size(), &progress, NULL);
|
||||
|
||||
Threading::JoinThread(ticker);
|
||||
Threading::CloseThread(ticker);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Failed to read resolve database.");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_InitResolver);
|
||||
SERIALISE_ELEMENT(success);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_GetResolve)
|
||||
{
|
||||
rdcarray<uint64_t> StackAddresses;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(StackAddresses);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
rdcarray<rdcstr> StackFrames;
|
||||
|
||||
if(resolver)
|
||||
{
|
||||
StackFrames.reserve(StackAddresses.size());
|
||||
for(uint64_t frame : StackAddresses)
|
||||
{
|
||||
Callstack::AddressDetails info = resolver->GetAddr(frame);
|
||||
StackFrames.push_back(info.formattedString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StackFrames = {""};
|
||||
}
|
||||
RDCERR("File needs driver for '%s' which isn't supported!", rdc->GetDriverName().c_str());
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_GetResolve);
|
||||
SERIALISE_ELEMENT(StackFrames);
|
||||
status = ReplayStatus::APIUnsupported;
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_FindSectionByName)
|
||||
|
||||
{
|
||||
std::string name;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(name);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
int index = rdc ? rdc->SectionIndex(name.c_str()) : -1;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByName);
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpened);
|
||||
SERIALISE_ELEMENT(status);
|
||||
}
|
||||
else if(type == eRemoteServer_FindSectionByType)
|
||||
}
|
||||
else if(type == eRemoteServer_HasCallstacks)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
bool HasCallstacks = rdc && rdc->SectionIndex(SectionType::ResolveDatabase) >= 0;
|
||||
|
||||
{
|
||||
SectionType sectionType;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(sectionType);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
int index = rdc ? rdc->SectionIndex(sectionType) : -1;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByType);
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_HasCallstacks);
|
||||
SERIALISE_ELEMENT(HasCallstacks);
|
||||
}
|
||||
else if(type == eRemoteServer_GetSectionProperties)
|
||||
}
|
||||
else if(type == eRemoteServer_InitResolver)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
bool success = false;
|
||||
|
||||
int sectionIndex = rdc ? rdc->SectionIndex(SectionType::ResolveDatabase) : -1;
|
||||
|
||||
SAFE_DELETE(resolver);
|
||||
if(sectionIndex >= 0)
|
||||
{
|
||||
int index = -1;
|
||||
StreamReader *sectionReader = rdc->ReadSection(sectionIndex);
|
||||
|
||||
std::vector<byte> buf;
|
||||
buf.resize((size_t)sectionReader->GetSize());
|
||||
success = sectionReader->Read(buf.data(), sectionReader->GetSize());
|
||||
|
||||
delete sectionReader;
|
||||
|
||||
if(success)
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
float progress = 0.0f;
|
||||
|
||||
reader.EndChunk();
|
||||
Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &resolver, &progress]() {
|
||||
while(!resolver)
|
||||
{
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ResolverProgress);
|
||||
SERIALISE_ELEMENT(progress);
|
||||
}
|
||||
Threading::Sleep(100);
|
||||
}
|
||||
});
|
||||
|
||||
SectionProperties props;
|
||||
if(rdc && index >= 0 && index < rdc->NumSections())
|
||||
props = rdc->GetSectionProperties(index);
|
||||
resolver = Callstack::MakeResolver(buf.data(), buf.size(), &progress, NULL);
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionProperties);
|
||||
SERIALISE_ELEMENT(props);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_GetSectionContents)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
bytebuf contents;
|
||||
|
||||
if(rdc && index >= 0 && index < rdc->NumSections())
|
||||
{
|
||||
StreamReader *sectionReader = rdc->ReadSection(index);
|
||||
|
||||
contents.resize((size_t)sectionReader->GetSize());
|
||||
bool success = sectionReader->Read(contents.data(), sectionReader->GetSize());
|
||||
|
||||
if(!success)
|
||||
contents.clear();
|
||||
|
||||
delete sectionReader;
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionContents);
|
||||
SERIALISE_ELEMENT(contents);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_WriteSection)
|
||||
{
|
||||
SectionProperties props;
|
||||
bytebuf contents;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(props);
|
||||
SERIALISE_ELEMENT(contents);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
if(rdc)
|
||||
{
|
||||
StreamWriter *sectionWriter = rdc->WriteSection(props);
|
||||
|
||||
if(sectionWriter)
|
||||
{
|
||||
sectionWriter->Write(contents.data(), contents.size());
|
||||
delete sectionWriter;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_CloseLog)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
if(driver)
|
||||
driver->Shutdown();
|
||||
driver = NULL;
|
||||
|
||||
SAFE_DELETE(proxy);
|
||||
SAFE_DELETE(rdc);
|
||||
SAFE_DELETE(resolver);
|
||||
}
|
||||
else if(type == eRemoteServer_ExecuteAndInject)
|
||||
{
|
||||
std::string app, workingDir, cmdLine, logfile;
|
||||
CaptureOptions opts;
|
||||
rdcarray<EnvironmentModification> env;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(app);
|
||||
SERIALISE_ELEMENT(workingDir);
|
||||
SERIALISE_ELEMENT(cmdLine);
|
||||
SERIALISE_ELEMENT(opts);
|
||||
SERIALISE_ELEMENT(env);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
uint32_t ident = 0;
|
||||
|
||||
if(threadData->allowExecution)
|
||||
{
|
||||
ident = Process::LaunchAndInjectIntoProcess(app.c_str(), workingDir.c_str(),
|
||||
cmdLine.c_str(), env, "", opts, false);
|
||||
Threading::JoinThread(ticker);
|
||||
Threading::CloseThread(ticker);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCWARN("Requested to execute program - disallowing based on configuration");
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject);
|
||||
SERIALISE_ELEMENT(ident);
|
||||
RDCERR("Failed to read resolve database.");
|
||||
}
|
||||
}
|
||||
else if((int)type >= eReplayProxy_First && proxy)
|
||||
|
||||
{
|
||||
bool ok = proxy->Tick(type);
|
||||
|
||||
if(!ok)
|
||||
break;
|
||||
|
||||
continue;
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_InitResolver);
|
||||
SERIALISE_ELEMENT(success);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_GetResolve)
|
||||
{
|
||||
rdcarray<uint64_t> StackAddresses;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(StackAddresses);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
rdcarray<rdcstr> StackFrames;
|
||||
|
||||
if(resolver)
|
||||
{
|
||||
StackFrames.reserve(StackAddresses.size());
|
||||
for(uint64_t frame : StackAddresses)
|
||||
{
|
||||
Callstack::AddressDetails info = resolver->GetAddr(frame);
|
||||
StackFrames.push_back(info.formattedString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StackFrames = {""};
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_GetResolve);
|
||||
SERIALISE_ELEMENT(StackFrames);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_FindSectionByName)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(name);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
int index = rdc ? rdc->SectionIndex(name.c_str()) : -1;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByName);
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_FindSectionByType)
|
||||
{
|
||||
SectionType sectionType;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(sectionType);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
int index = rdc ? rdc->SectionIndex(sectionType) : -1;
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByType);
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_GetSectionProperties)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
SectionProperties props;
|
||||
if(rdc && index >= 0 && index < rdc->NumSections())
|
||||
props = rdc->GetSectionProperties(index);
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionProperties);
|
||||
SERIALISE_ELEMENT(props);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_GetSectionContents)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(index);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
bytebuf contents;
|
||||
|
||||
if(rdc && index >= 0 && index < rdc->NumSections())
|
||||
{
|
||||
StreamReader *sectionReader = rdc->ReadSection(index);
|
||||
|
||||
contents.resize((size_t)sectionReader->GetSize());
|
||||
bool success = sectionReader->Read(contents.data(), sectionReader->GetSize());
|
||||
|
||||
if(!success)
|
||||
contents.clear();
|
||||
|
||||
delete sectionReader;
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionContents);
|
||||
SERIALISE_ELEMENT(contents);
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_WriteSection)
|
||||
{
|
||||
SectionProperties props;
|
||||
bytebuf contents;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(props);
|
||||
SERIALISE_ELEMENT(contents);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
if(rdc)
|
||||
{
|
||||
StreamWriter *sectionWriter = rdc->WriteSection(props);
|
||||
|
||||
if(sectionWriter)
|
||||
{
|
||||
sectionWriter->Write(contents.data(), contents.size());
|
||||
delete sectionWriter;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type == eRemoteServer_CloseLog)
|
||||
{
|
||||
reader.EndChunk();
|
||||
|
||||
if(driver)
|
||||
driver->Shutdown();
|
||||
driver = NULL;
|
||||
|
||||
SAFE_DELETE(proxy);
|
||||
SAFE_DELETE(rdc);
|
||||
SAFE_DELETE(resolver);
|
||||
}
|
||||
else if(type == eRemoteServer_ExecuteAndInject)
|
||||
{
|
||||
std::string app, workingDir, cmdLine, logfile;
|
||||
CaptureOptions opts;
|
||||
rdcarray<EnvironmentModification> env;
|
||||
|
||||
{
|
||||
READ_DATA_SCOPE();
|
||||
SERIALISE_ELEMENT(app);
|
||||
SERIALISE_ELEMENT(workingDir);
|
||||
SERIALISE_ELEMENT(cmdLine);
|
||||
SERIALISE_ELEMENT(opts);
|
||||
SERIALISE_ELEMENT(env);
|
||||
}
|
||||
|
||||
reader.EndChunk();
|
||||
|
||||
uint32_t ident = 0;
|
||||
|
||||
if(threadData->allowExecution)
|
||||
{
|
||||
ident = Process::LaunchAndInjectIntoProcess(app.c_str(), workingDir.c_str(),
|
||||
cmdLine.c_str(), env, "", opts, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCWARN("Requested to execute program - disallowing based on configuration");
|
||||
}
|
||||
|
||||
{
|
||||
WRITE_DATA_SCOPE();
|
||||
SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject);
|
||||
SERIALISE_ELEMENT(ident);
|
||||
}
|
||||
}
|
||||
else if((int)type >= eReplayProxy_First && proxy)
|
||||
{
|
||||
bool ok = proxy->Tick(type);
|
||||
|
||||
if(!ok)
|
||||
break;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(client->IsRecvDataWaiting())
|
||||
if(client->IsRecvDataWaiting() || !reader.GetReader()->AtEnd())
|
||||
{
|
||||
PacketType type = reader.ReadChunk<PacketType>();
|
||||
|
||||
@@ -533,7 +533,7 @@ public:
|
||||
return msg;
|
||||
}
|
||||
|
||||
if(!m_Socket->IsRecvDataWaiting())
|
||||
if(!m_Socket->IsRecvDataWaiting() && reader.GetReader()->AtEnd())
|
||||
{
|
||||
if(!m_Socket->Connected())
|
||||
{
|
||||
|
||||
@@ -404,6 +404,8 @@ void Serialiser<SerialiserMode::Writing>::EndChunk()
|
||||
m_Write->AlignTo<ChunkAlignment>();
|
||||
|
||||
m_ChunkMetadata = SDChunkMetaData();
|
||||
|
||||
m_Write->Flush();
|
||||
}
|
||||
|
||||
template <>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "streamio.h"
|
||||
#include <errno.h>
|
||||
#include "common/timing.h"
|
||||
|
||||
Compressor::~Compressor()
|
||||
{
|
||||
@@ -76,11 +77,12 @@ StreamReader::StreamReader(Network::Socket *sock, Ownership own)
|
||||
{
|
||||
m_Sock = sock;
|
||||
|
||||
m_InputSize = m_BufferSize = initialBufferSize;
|
||||
m_BufferSize = initialBufferSize;
|
||||
m_BufferBase = AllocAlignedBuffer(m_BufferSize);
|
||||
// place head at the *end* of the buffer, because for sockets we pretend the buffer is constantly
|
||||
// exhausted, and just do a read of the minimum number of bytes each time to satisfy each read
|
||||
m_BufferHead = m_BufferBase + m_BufferSize;
|
||||
m_BufferHead = m_BufferBase;
|
||||
|
||||
// for sockets we use m_InputSize to indicate how much data has been read into the buffer.
|
||||
m_InputSize = 0;
|
||||
|
||||
m_Ownership = own;
|
||||
}
|
||||
@@ -189,25 +191,7 @@ void StreamReader::SetOffset(uint64_t offs)
|
||||
|
||||
bool StreamReader::Reserve(uint64_t numBytes)
|
||||
{
|
||||
if(m_Sock)
|
||||
{
|
||||
// if we're reading more bytes than our buffer size, resize up
|
||||
if(numBytes > m_BufferSize)
|
||||
{
|
||||
FreeAlignedBuffer(m_BufferBase);
|
||||
m_InputSize = m_BufferSize = AlignUp<uint64_t>(numBytes, 256ULL);
|
||||
m_BufferBase = AllocAlignedBuffer(m_BufferSize);
|
||||
m_BufferHead = m_BufferBase + m_BufferSize;
|
||||
}
|
||||
|
||||
m_ReadOffset += numBytes;
|
||||
|
||||
// read into the end of the buffer, so that the subsequent read re-exhausts the buffer
|
||||
m_BufferHead = m_BufferBase + m_BufferSize - numBytes;
|
||||
return ReadFromExternal(m_BufferSize - numBytes, numBytes);
|
||||
}
|
||||
|
||||
RDCASSERT(m_File || m_Decompressor);
|
||||
RDCASSERT(m_Sock || m_File || m_Decompressor);
|
||||
|
||||
// store old buffer and the read data, so we can move it into the new buffer
|
||||
byte *oldBuffer = m_BufferBase;
|
||||
@@ -218,6 +202,9 @@ bool StreamReader::Reserve(uint64_t numBytes)
|
||||
byte *currentData = m_BufferHead - backwardsWindow;
|
||||
uint64_t currentDataSize = m_BufferSize - (m_BufferHead - m_BufferBase) + backwardsWindow;
|
||||
|
||||
if(m_Sock)
|
||||
currentDataSize = m_InputSize - (m_BufferHead - m_BufferBase) + backwardsWindow;
|
||||
|
||||
uint64_t BufferOffset = m_BufferHead - m_BufferBase;
|
||||
|
||||
// if we are reading more than our current buffer size, expand the buffer size
|
||||
@@ -243,11 +230,21 @@ bool StreamReader::Reserve(uint64_t numBytes)
|
||||
m_BufferHead = m_BufferBase + BufferOffset;
|
||||
}
|
||||
|
||||
if(m_Sock)
|
||||
m_InputSize = currentDataSize;
|
||||
|
||||
// if there's anything left of the file to read in, do so now
|
||||
bool ret = false;
|
||||
|
||||
ret = ReadFromExternal(currentDataSize, RDCMIN(m_BufferSize - currentDataSize,
|
||||
m_InputSize - m_ReadOffset - currentDataSize));
|
||||
uint64_t readSize =
|
||||
RDCMIN(m_BufferSize - currentDataSize, m_InputSize - m_ReadOffset - currentDataSize);
|
||||
|
||||
// we'll read as much as possible anyway using m_BufferSize, but we need to know how much we
|
||||
// *must* read.
|
||||
if(m_Sock)
|
||||
readSize = numBytes - Available();
|
||||
|
||||
ret = ReadFromExternal(currentDataSize, readSize);
|
||||
|
||||
if(oldBuffer != m_BufferBase && m_BufferBase)
|
||||
FreeAlignedBuffer(oldBuffer);
|
||||
@@ -276,7 +273,24 @@ bool StreamReader::ReadFromExternal(uint64_t bufferOffs, uint64_t length)
|
||||
}
|
||||
else
|
||||
{
|
||||
success = m_Sock->RecvDataBlocking(m_BufferBase + bufferOffs, (uint32_t)length);
|
||||
// first get the required data blocking (this will sleep the thread until it comes in).
|
||||
byte *readDest = m_BufferBase + bufferOffs;
|
||||
|
||||
success = m_Sock->RecvDataBlocking(readDest, (uint32_t)length);
|
||||
|
||||
if(success)
|
||||
{
|
||||
m_InputSize += length;
|
||||
readDest += length;
|
||||
|
||||
uint32_t bufSize = uint32_t(m_BufferSize - m_InputSize);
|
||||
|
||||
// now read more, as much as possible, to try and batch future reads
|
||||
success = m_Sock->RecvDataNonBlocking(readDest, bufSize);
|
||||
|
||||
if(success)
|
||||
m_InputSize += bufSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -344,7 +358,8 @@ StreamWriter::StreamWriter(StreamInvalidType)
|
||||
|
||||
StreamWriter::StreamWriter(Network::Socket *sock, Ownership own)
|
||||
{
|
||||
m_BufferBase = m_BufferHead = m_BufferEnd = NULL;
|
||||
m_BufferBase = m_BufferHead = AllocAlignedBuffer(initialBufferSize);
|
||||
m_BufferEnd = m_BufferBase + initialBufferSize;
|
||||
|
||||
m_Sock = sock;
|
||||
|
||||
@@ -389,6 +404,56 @@ StreamWriter::~StreamWriter()
|
||||
}
|
||||
}
|
||||
|
||||
bool StreamWriter::SendSocketData(const void *data, uint64_t numBytes)
|
||||
{
|
||||
// try to coalesce small writes without doing blocking sends, at least until we're flushed.
|
||||
// if the buffer is already full, flush it.
|
||||
if(m_BufferHead + numBytes >= m_BufferEnd)
|
||||
{
|
||||
bool success = FlushSocketData();
|
||||
if(!success)
|
||||
{
|
||||
HandleError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's larger than our buffer (even after flushing) just write directly
|
||||
if(m_BufferHead + numBytes >= m_BufferEnd)
|
||||
{
|
||||
bool success = m_Sock->SendDataBlocking(data, (uint32_t)numBytes);
|
||||
if(!success)
|
||||
{
|
||||
HandleError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, write it into the in-memory buffer
|
||||
memcpy(m_BufferHead, data, (size_t)numBytes);
|
||||
m_BufferHead += numBytes;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StreamWriter::FlushSocketData()
|
||||
{
|
||||
// send out what we have buffered up
|
||||
bool success = m_Sock->SendDataBlocking(m_BufferBase, uint32_t(m_BufferHead - m_BufferBase));
|
||||
if(!success)
|
||||
{
|
||||
HandleError();
|
||||
return false;
|
||||
}
|
||||
|
||||
// reset buffer to the start
|
||||
m_BufferHead = m_BufferBase;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StreamWriter::HandleError()
|
||||
{
|
||||
if(m_File)
|
||||
|
||||
@@ -91,7 +91,12 @@ public:
|
||||
|
||||
inline uint64_t GetOffset() { return m_BufferHead - m_BufferBase + m_ReadOffset; }
|
||||
inline uint64_t GetSize() { return m_InputSize; }
|
||||
inline bool AtEnd() { return GetOffset() >= GetSize(); }
|
||||
inline bool AtEnd()
|
||||
{
|
||||
if(m_Sock)
|
||||
return Available() == 0;
|
||||
return GetOffset() >= GetSize();
|
||||
}
|
||||
template <uint64_t alignment>
|
||||
bool AlignTo()
|
||||
{
|
||||
@@ -189,7 +194,7 @@ private:
|
||||
inline uint64_t Available()
|
||||
{
|
||||
if(m_Sock)
|
||||
return 0;
|
||||
return m_InputSize - (m_BufferHead - m_BufferBase);
|
||||
return m_BufferSize - (m_BufferHead - m_BufferBase);
|
||||
}
|
||||
bool Reserve(uint64_t numBytes);
|
||||
@@ -327,14 +332,7 @@ public:
|
||||
}
|
||||
else if(m_Sock)
|
||||
{
|
||||
bool success = m_Sock->SendDataBlocking(data, (uint32_t)numBytes);
|
||||
if(!success)
|
||||
{
|
||||
HandleError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return SendSocketData(data, numBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -396,6 +394,18 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Flush()
|
||||
{
|
||||
if(m_Compressor)
|
||||
return true;
|
||||
else if(m_File)
|
||||
return FileIO::fflush(m_File);
|
||||
else if(m_Sock)
|
||||
return FlushSocketData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Finish()
|
||||
{
|
||||
if(m_Compressor)
|
||||
@@ -437,6 +447,9 @@ private:
|
||||
|
||||
void HandleError();
|
||||
|
||||
bool SendSocketData(const void *data, uint64_t numBytes);
|
||||
bool FlushSocketData();
|
||||
|
||||
// used for aligned writes
|
||||
static const byte empty[128];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user