Refactor RemoteHost to be copyable with shared storage

* This allows RemoteHost handles to still be valid and usable (if returning
  empty data) when they are deleted/removed if the device is disconnected, as
  well as providing better multi-thread access (they lock internally)
This commit is contained in:
baldurk
2019-07-31 17:51:12 +01:00
parent da289fdbcc
commit 06f2e61b8f
15 changed files with 626 additions and 355 deletions
+89 -46
View File
@@ -25,6 +25,7 @@
#include <QApplication>
#include <QDebug>
#include <QDir>
#include <QMutexLocker>
#include <QStandardPaths>
#include "Code/QRDUtils.h"
#include "Styles/StyleData.h"
@@ -194,34 +195,78 @@ void PersistantConfig::applyValues(const QVariantMap &values)
RENAMED_SETTING(QVariantList, SPIRVDisassemblers, ShaderProcessors);
}
int PersistantConfig::RemoteHostCount()
static QMutex RemoteHostLock;
rdcarray<RemoteHost> PersistantConfig::GetRemoteHosts()
{
return RemoteHosts.count();
QMutexLocker autolock(&RemoteHostLock);
return RemoteHostList;
}
RemoteHost *PersistantConfig::GetRemoteHost(int index)
RemoteHost PersistantConfig::GetRemoteHost(const rdcstr &hostname)
{
if(index < 0 || index >= RemoteHostCount())
return NULL;
return RemoteHosts[index];
RemoteHost ret;
{
QMutexLocker autolock(&RemoteHostLock);
for(size_t i = 0; i < RemoteHostList.size(); i++)
{
if(RemoteHostList[i].Hostname() == hostname)
{
ret = RemoteHostList[i];
break;
}
}
}
return ret;
}
void PersistantConfig::AddRemoteHost(RemoteHost host)
{
RemoteHosts.push_back(new RemoteHost(host));
if(!host.IsValid())
return;
QMutexLocker autolock(&RemoteHostLock);
// don't add duplicates
for(size_t i = 0; i < RemoteHostList.size(); i++)
{
if(RemoteHostList[i] == host)
{
RemoteHostList[i] = host;
return;
}
}
RemoteHostList.push_back(host);
}
void PersistantConfig::RemoveRemoteHost(RemoteHost host)
{
if(!host.IsValid())
return;
QMutexLocker autolock(&RemoteHostLock);
for(size_t i = 0; i < RemoteHostList.size(); i++)
{
if(RemoteHostList[i] == host)
{
RemoteHostList.takeAt(i);
break;
}
}
}
void PersistantConfig::AddAndroidHosts()
{
QMap<rdcstr, RemoteHost *> oldHosts;
for(int i = RemoteHosts.count() - 1; i >= 0; i--)
{
if(RemoteHosts[i]->IsADB())
{
RemoteHost *host = RemoteHosts.takeAt(i);
oldHosts[host->hostname] = host;
}
}
QMutexLocker autolock(&RemoteHostLock);
QMap<rdcstr, RemoteHost> oldHosts;
for(int i = RemoteHostList.count() - 1; i >= 0; i--)
if(RemoteHostList[i].IsADB())
oldHosts[RemoteHostList[i].Hostname()] = RemoteHostList.takeAt(i);
QString androidSDKPath = (!Android_SDKPath.isEmpty() && QFile::exists(Android_SDKPath))
? QString(Android_SDKPath)
@@ -242,28 +287,25 @@ void PersistantConfig::AddAndroidHosts()
for(const QString &hostName :
QString(androidHosts).split(QLatin1Char(','), QString::SkipEmptyParts))
{
RemoteHost *host = NULL;
RemoteHost host((rdcstr)hostName);
if(oldHosts.contains(hostName))
host = oldHosts.take(hostName);
else
host = new RemoteHost();
host->hostname = hostName;
rdcstr friendly;
RENDERDOC_GetAndroidFriendlyName(hostName.toUtf8().data(), friendly);
host->friendlyName = friendly;
host.SetFriendlyName(friendly);
// Just a command to display in the GUI and allow Launch() to be called.
host->runCommand = lit("Automatically handled");
RemoteHosts.push_back(host);
host.SetRunCommand("Automatically handled");
RemoteHostList.push_back(host);
}
// delete any leftovers
QMapIterator<rdcstr, RemoteHost *> i(oldHosts);
QMutableMapIterator<rdcstr, RemoteHost> i(oldHosts);
while(i.hasNext())
{
i.next();
delete i.value();
i.value().SetShutdown();
}
}
@@ -288,8 +330,6 @@ bool PersistantConfig::SetStyle()
PersistantConfig::~PersistantConfig()
{
for(RemoteHost *h : RemoteHosts)
delete h;
}
bool PersistantConfig::Load(const rdcstr &filename)
@@ -309,24 +349,32 @@ bool PersistantConfig::Load(const rdcstr &filename)
RDDialog::DefaultBrowsePath = LastFileBrowsePath;
// localhost should always be available as a remote host
bool foundLocalhost = false;
for(RemoteHost host : RemoteHostList)
{
if(host.hostname.isEmpty())
continue;
QMutexLocker autolock(&RemoteHostLock);
RemoteHosts.push_back(new RemoteHost(host));
bool foundLocalhost = false;
if(host.IsLocalhost())
foundLocalhost = true;
}
rdcarray<RemoteHost> hosts;
hosts.swap(RemoteHostList);
if(!foundLocalhost)
{
RemoteHost *host = new RemoteHost();
host->hostname = "localhost";
RemoteHosts.insert(0, host);
for(RemoteHost host : hosts)
{
// skip invalid hosts
if(!host.IsValid())
continue;
RemoteHostList.push_back(host);
if(host.IsLocalhost())
foundLocalhost = true;
}
if(!foundLocalhost)
{
RemoteHost host;
host.m_hostname = "localhost";
RemoteHostList.insert(0, host);
}
}
bool tools[arraydim<KnownShaderTool>()] = {};
@@ -427,11 +475,6 @@ bool PersistantConfig::Save()
if(m_Filename.isEmpty())
return true;
// update serialize list
RemoteHostList.clear();
for(RemoteHost *host : RemoteHosts)
RemoteHostList.push_back(*host);
RENDERDOC_SetConfigSetting("Disassembly_FriendlyNaming", ShaderViewer_FriendlyNaming ? "1" : "0");
RENDERDOC_SetConfigSetting("ExternalTool_RGPIntegration", ExternalTool_RGPIntegration ? "1" : "0");
+14 -21
View File
@@ -28,6 +28,8 @@
#include "QRDInterface.h"
#include "RemoteHost.h"
class QMutex;
DOCUMENT(R"(Identifies a particular known tool used for shader processing.
.. data:: Unknown
@@ -766,38 +768,29 @@ For more information about some of these settings that are user-facing see
class PersistantConfig
{
public:
// don't allow SWIG direct access to the RemoteHosts since they're an array of references and our
// bindings can't handle that properly
#if !defined(SWIG)
// Runtime list of dynamically allocated hosts.
// Saved to/from private RemoteHostList in CONFIG_SETTINGS()
// This is documented above in the docstring, similar to the values in CONFIG_SETTINGS()
// This must only be accessed on the UI thread to prevent races. For access on other threads (e.g.
// a background/asynchronous update), take a copy on the UI thread, update it in the background,
// then apply the updates.
DOCUMENT("");
rdcarray<RemoteHost *> RemoteHosts;
#endif
DOCUMENT(R"(Returns a list of all remote hosts.
DOCUMENT(R"(Returns the number of remote hosts currently registered.
:return: The number of remote hosts.
:rtype: ``int``
:return: The remote host list
:rtype: ``list`` of ``RemoteHost``
)");
int RemoteHostCount();
DOCUMENT(R"(Returns a given remote host at an index.
rdcarray<RemoteHost> GetRemoteHosts();
DOCUMENT(R"(Look up a remote host by hostname.
:param int index: The index of the remote host to retrieve
:return: The remote host specified, or ``None`` if an invalid index was passed
:return: The remote host for the given hostname, or an invalid ``RemoteHost`` if no such exists.
:rtype: ``RemoteHost``
)");
RemoteHost *GetRemoteHost(int index);
RemoteHost GetRemoteHost(const rdcstr &hostname);
DOCUMENT(R"(Adds a new remote host.
:param RemoteHost host: The remote host to add.
R)");
void AddRemoteHost(RemoteHost host);
DOCUMENT(R"(Removes an existing remote host.
:param RemoteHost host: The remote host to remove.
R)");
void RemoveRemoteHost(RemoteHost host);
DOCUMENT("If configured, queries ``adb`` to add android hosts to :data:`RemoteHosts`.");
void AddAndroidHosts();
+3 -3
View File
@@ -735,7 +735,7 @@ struct IReplayManager
:return: Whether or not the connection was successful.
:rtype: ~renderdoc.ReplayStatus
)");
virtual ReplayStatus ConnectToRemoteServer(RemoteHost *host) = 0;
virtual ReplayStatus ConnectToRemoteServer(RemoteHost host) = 0;
DOCUMENT("Disconnect from the server the manager is currently connected to.");
virtual void DisconnectFromRemoteServer() = 0;
@@ -751,10 +751,10 @@ struct IReplayManager
DOCUMENT(R"(Retrieves the host that the manager is currently connected to.
:return: The host connected to, or ``None`` if no connection is active.
:return: The host connected to, or an invalid RemoteHost if no connection is active.
:rtype: RemoteHost
)");
virtual RemoteHost *CurrentRemote() = 0;
virtual RemoteHost CurrentRemote() = 0;
DOCUMENT(R"(Retrieves the capture file handle for the currently open file.
+186 -41
View File
@@ -22,80 +22,158 @@
* THE SOFTWARE.
******************************************************************************/
#include <QAtomicInt>
#include <QMutex>
#include <QMutexLocker>
#include <QProcess>
#include <QThread>
#include "Code/QRDUtils.h"
#include "QRDInterface.h"
RemoteHost::RemoteHost()
struct RemoteHostData
{
serverRunning = connected = busy = versionMismatch = false;
}
QAtomicInt refcount;
QMutex mutex;
void ref() { refcount.ref(); }
void deref()
{
if(!refcount.deref())
delete this;
}
RemoteHostData() : refcount(1) {}
rdcstr m_friendlyName, m_runCommand, m_lastCapturePath;
bool m_serverRunning = false, m_connected = false, m_busy = false, m_versionMismatch = false;
};
RemoteHost::RemoteHost(const QVariant &var)
{
m_data = new RemoteHostData();
QVariantMap map = var.toMap();
if(map.contains(lit("hostname")))
hostname = map[lit("hostname")].toString();
m_hostname = map[lit("hostname")].toString();
if(map.contains(lit("friendlyName")))
friendlyName = map[lit("friendlyName")].toString();
m_data->m_friendlyName = map[lit("friendlyName")].toString();
if(map.contains(lit("runCommand")))
runCommand = map[lit("runCommand")].toString();
m_data->m_runCommand = map[lit("runCommand")].toString();
if(map.contains(lit("lastCapturePath")))
lastCapturePath = map[lit("lastCapturePath")].toString();
m_data->m_lastCapturePath = map[lit("lastCapturePath")].toString();
}
serverRunning = connected = busy = versionMismatch = false;
RemoteHost::RemoteHost()
{
m_data = new RemoteHostData();
}
RemoteHost::RemoteHost(const rdcstr &host)
{
// create a new host
m_hostname = host;
m_data = new RemoteHostData();
}
RemoteHost::RemoteHost(const RemoteHost &o)
{
*this = o;
}
RemoteHost &RemoteHost::operator=(const RemoteHost &o)
{
m_hostname = o.m_hostname;
// deref old data
if(m_data)
m_data->deref();
// point to new data
m_data = o.m_data;
// get a ref on it
m_data->ref();
return *this;
}
RemoteHost::~RemoteHost()
{
m_data->deref();
}
RemoteHost::operator QVariant() const
{
QVariantMap map;
map[lit("hostname")] = hostname;
map[lit("friendlyName")] = friendlyName;
map[lit("runCommand")] = runCommand;
map[lit("lastCapturePath")] = lastCapturePath;
m_data->mutex.lock();
map[lit("hostname")] = m_hostname;
map[lit("friendlyName")] = m_data->m_friendlyName;
map[lit("runCommand")] = m_data->m_runCommand;
map[lit("lastCapturePath")] = m_data->m_lastCapturePath;
m_data->mutex.unlock();
return map;
}
void RemoteHost::CheckStatus()
{
// special case - this is the local context
if(hostname == "localhost")
if(m_hostname == "localhost")
{
serverRunning = false;
versionMismatch = busy = false;
QMutexLocker autolock(&m_data->mutex);
m_data->m_serverRunning = m_data->m_versionMismatch = m_data->m_busy = false;
return;
}
// to avoid doing complex work while holding the remote host lock, we check the status here then
// call into the internal function that will propagate that data to the proper storage if needed.
IRemoteServer *rend = NULL;
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(hostname.c_str(), 0, &rend);
if(status == ReplayStatus::Succeeded)
{
serverRunning = true;
versionMismatch = busy = false;
}
else if(status == ReplayStatus::NetworkRemoteBusy)
{
serverRunning = true;
busy = true;
versionMismatch = false;
}
else if(status == ReplayStatus::NetworkVersionMismatch)
{
serverRunning = true;
busy = true;
versionMismatch = true;
}
else
{
serverRunning = false;
versionMismatch = busy = false;
}
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(m_hostname.c_str(), 0, &rend);
if(rend)
rend->ShutdownConnection();
UpdateStatus(status);
}
void RemoteHost::SetConnected(bool connected)
{
QMutexLocker autolock(&m_data->mutex);
m_data->m_connected = connected;
}
void RemoteHost::SetShutdown()
{
QMutexLocker autolock(&m_data->mutex);
m_data->m_connected = false;
m_data->m_serverRunning = false;
m_data->m_busy = false;
}
void RemoteHost::UpdateStatus(ReplayStatus status)
{
{
QMutexLocker autolock(&m_data->mutex);
if(status == ReplayStatus::Succeeded)
{
m_data->m_serverRunning = true;
m_data->m_versionMismatch = m_data->m_busy = false;
}
else if(status == ReplayStatus::NetworkRemoteBusy)
{
m_data->m_serverRunning = true;
m_data->m_busy = true;
m_data->m_versionMismatch = false;
}
else if(status == ReplayStatus::NetworkVersionMismatch)
{
m_data->m_serverRunning = true;
m_data->m_busy = true;
m_data->m_versionMismatch = true;
}
else
{
m_data->m_serverRunning = false;
m_data->m_versionMismatch = m_data->m_busy = false;
}
}
// since we can only have one active client at once on a remote server, we need
// to avoid DDOS'ing by doing multiple CheckStatus() one after the other so fast
// that the active client can't be properly shut down. Sleeping here for a short
@@ -113,15 +191,82 @@ ReplayStatus RemoteHost::Launch()
if(IsADB())
{
status = RENDERDOC_StartAndroidRemoteServer(hostname.c_str());
status = RENDERDOC_StartAndroidRemoteServer(m_hostname.c_str());
QThread::msleep(WAIT_TIME);
return status;
}
rdcstr run;
{
QMutexLocker autolock(&m_data->mutex);
run = RunCommand();
}
RDProcess process;
process.start(runCommand);
process.start(run);
process.waitForFinished(WAIT_TIME);
process.detach();
return status;
}
bool RemoteHost::IsServerRunning() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_serverRunning;
}
bool RemoteHost::IsConnected() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_connected;
}
bool RemoteHost::IsBusy() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_busy;
}
bool RemoteHost::IsVersionMismatch() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_versionMismatch;
}
rdcstr RemoteHost::FriendlyName() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_friendlyName;
}
void RemoteHost::SetFriendlyName(const rdcstr &name)
{
QMutexLocker autolock(&m_data->mutex);
m_data->m_friendlyName = name;
}
rdcstr RemoteHost::RunCommand() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_runCommand;
}
void RemoteHost::SetRunCommand(const rdcstr &cmd)
{
QMutexLocker autolock(&m_data->mutex);
m_data->m_runCommand = cmd;
}
rdcstr RemoteHost::LastCapturePath() const
{
QMutexLocker autolock(&m_data->mutex);
return m_data->m_lastCapturePath;
}
void RemoteHost::SetLastCapturePath(const rdcstr &path)
{
QMutexLocker autolock(&m_data->mutex);
m_data->m_lastCapturePath = path;
}
+68 -21
View File
@@ -29,22 +29,33 @@ class RemoteHost;
// do not include any headers here, they must all be in QRDInterface.h
#include "QRDInterface.h"
class PersistantConfig;
class ReplayManager;
struct RemoteHostData;
// to enable easy copying around of these hosts as well as allowing graceful behaviour when hosts
// are unexpectedly removed (such as disconnecting an auto-populated device) these structs are
// copied around and they have a shared locked data pointer. All accessors then lock and look up the
// data there to fetch or modify
DOCUMENT("A handle for interacting with a remote server on a given host.");
class RemoteHost
{
public:
DOCUMENT("");
RemoteHost();
RemoteHost(const rdcstr &host);
RemoteHost(const RemoteHost &o);
#if !defined(SWIG)
RemoteHost &operator=(const RemoteHost &o);
#endif
~RemoteHost();
VARIANT_CAST(RemoteHost);
DOCUMENT("");
bool operator==(const RemoteHost &o) const
{
return hostname == o.hostname && friendlyName == o.friendlyName && runCommand == o.runCommand &&
serverRunning == o.serverRunning && connected == o.connected && busy == o.busy &&
versionMismatch == o.versionMismatch;
}
bool operator==(const RemoteHost &o) const { return m_hostname == o.m_hostname; }
bool operator!=(const RemoteHost &o) const { return !(*this == o); }
bool operator<(const RemoteHost &o) const { return m_hostname < o.m_hostname; }
DOCUMENT(
"Ping the host to check current status - if the server is running, connection status, etc.");
void CheckStatus();
@@ -54,36 +65,72 @@ public:
ReplayStatus Launch();
DOCUMENT("``True`` if a remote server is currently running on this host.");
bool serverRunning : 1;
bool IsServerRunning() const;
DOCUMENT("``True`` if an active connection exists to this remote server.");
bool connected : 1;
bool IsConnected() const;
DOCUMENT("``True`` if someone else is currently connected to this server.");
bool busy : 1;
bool IsBusy() const;
DOCUMENT("``True`` if there is a code version mismatch with this server.");
bool versionMismatch : 1;
bool IsVersionMismatch() const;
DOCUMENT("The hostname of this host.");
rdcstr hostname;
const rdcstr &Hostname() const { return m_hostname; }
DOCUMENT("The friendly name for this host, if available (if empty, the Hostname is used).");
rdcstr friendlyName;
rdcstr FriendlyName() const;
DOCUMENT("The command to run locally to try to launch the server remotely.");
rdcstr runCommand;
rdcstr RunCommand() const;
DOCUMENT(R"(Sets the run command. See :meth:`RunCommand`.
DOCUMENT("The last folder browser to on this host, to provide a reasonable default path.");
rdcstr lastCapturePath;
:param str cmd: The new command to set.
)");
void SetRunCommand(const rdcstr &cmd);
DOCUMENT("The last folder browsed to on this host, to provide a reasonable default path.");
rdcstr LastCapturePath() const;
DOCUMENT(R"(Sets the last folder browsed to. See :meth:`LastCapturePath`.
:param str path: The new path to set.
)");
void SetLastCapturePath(const rdcstr &path);
DOCUMENT(R"(
Returns the name to display for this host in the UI, either :data:`friendlyName` or :data:`hostname`
Returns the name to display for this host in the UI, either :meth:`FriendlyName` if it is valid, or
:meth:`Hostname` if not.
)");
const rdcstr &Name() const { return !friendlyName.isEmpty() ? friendlyName : hostname; }
rdcstr Name() const
{
rdcstr friendlyName = FriendlyName();
return !friendlyName.isEmpty() ? friendlyName : m_hostname;
}
DOCUMENT("Returns ``True`` if this host represents a connected ADB (Android) device.");
bool IsADB() const
{
return hostname.count() > 4 && hostname[0] == 'a' && hostname[1] == 'd' && hostname[2] == 'b' &&
hostname[3] == ':';
return m_hostname.count() > 4 && m_hostname[0] == 'a' && m_hostname[1] == 'd' &&
m_hostname[2] == 'b' && m_hostname[3] == ':';
}
DOCUMENT("Returns ``True`` if this host represents the special localhost device.");
bool IsLocalhost() const { return hostname == "localhost"; }
bool IsLocalhost() const { return m_hostname == "localhost"; }
DOCUMENT("Returns ``True`` if this host represents a valid remote host.");
bool IsValid() const { return m_data && !m_hostname.isEmpty(); }
private:
// this is immutable and is used as a key to look up data, it's always valid as RemoteHost objects
// are created with it
rdcstr m_hostname;
// self-deleting shared and locked data store
RemoteHostData *m_data = NULL;
// allow config to set our data
friend class PersistantConfig;
void SetFriendlyName(const rdcstr &name);
// allow ReplayManager to call these functions to change the status. Otherwise they are read-only
// except by calling CheckStatus()
friend class ReplayManager;
void SetConnected(bool connected);
void SetShutdown();
void UpdateStatus(ReplayStatus status);
};
DECLARE_REFLECTION_STRUCT(RemoteHost);
+9 -8
View File
@@ -305,11 +305,11 @@ void ReplayManager::CloseThread()
m_Thread = NULL;
}
ReplayStatus ReplayManager::ConnectToRemoteServer(RemoteHost *host)
ReplayStatus ReplayManager::ConnectToRemoteServer(RemoteHost host)
{
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(host->hostname.c_str(), 0, &m_Remote);
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(host.Hostname().c_str(), 0, &m_Remote);
if(host->IsADB())
if(host.IsADB())
{
ANALYTIC_SET(UIFeatures.AndroidRemoteReplay, true);
}
@@ -322,7 +322,7 @@ ReplayStatus ReplayManager::ConnectToRemoteServer(RemoteHost *host)
if(status == ReplayStatus::Succeeded)
{
m_RemoteHost->connected = true;
m_RemoteHost.SetConnected(true);
return status;
}
@@ -331,8 +331,7 @@ ReplayStatus ReplayManager::ConnectToRemoteServer(RemoteHost *host)
void ReplayManager::DisconnectFromRemoteServer()
{
if(m_RemoteHost)
m_RemoteHost->connected = false;
m_RemoteHost.SetConnected(false);
if(m_Remote)
{
@@ -340,12 +339,14 @@ void ReplayManager::DisconnectFromRemoteServer()
m_Remote->ShutdownConnection();
}
m_RemoteHost = NULL;
m_RemoteHost = RemoteHost();
m_Remote = NULL;
}
void ReplayManager::ShutdownServer()
{
m_RemoteHost.SetShutdown();
if(m_Remote)
{
QMutexLocker autolock(&m_RemoteLock);
@@ -365,7 +366,7 @@ void ReplayManager::PingRemote()
if(!IsRunning() || m_Thread->isCurrentThread())
{
if(!m_Remote->Ping())
m_RemoteHost->serverRunning = false;
m_RemoteHost.SetShutdown();
}
m_RemoteLock.unlock();
}
+3 -3
View File
@@ -68,7 +68,7 @@ public:
void CloseThread();
ReplayStatus ConnectToRemoteServer(RemoteHost *host);
ReplayStatus ConnectToRemoteServer(RemoteHost host);
void DisconnectFromRemoteServer();
void ShutdownServer();
void PingRemote();
@@ -86,7 +86,7 @@ public:
// work whether local or remote.
ICaptureFile *GetCaptureFile() { return m_CaptureFile; }
void ReopenCaptureFile(const QString &path);
RemoteHost *CurrentRemote() { return m_RemoteHost; }
RemoteHost CurrentRemote() { return m_RemoteHost; }
ExecuteResult ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, const rdcstr &cmdLine,
const rdcarray<EnvironmentModification> &env,
const rdcstr &capturefile, CaptureOptions opts);
@@ -128,7 +128,7 @@ private:
void PushInvoke(InvokeHandle *cmd);
QMutex m_RemoteLock;
RemoteHost *m_RemoteHost = NULL;
RemoteHost m_RemoteHost;
IRemoteServer *m_Remote = NULL;
volatile bool m_Running;
+1
View File
@@ -86,6 +86,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, rdcstrpair)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, BugReport)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ExtensionMetadata)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, DialogButton)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, RemoteHost)
TEMPLATE_ARRAY_INSTANTIATE_PTR(rdcarray, ICaptureViewer)
// unignore the function from above
@@ -125,20 +125,24 @@ void PersistantConfig::Close()
{
}
int PersistantConfig::RemoteHostCount()
rdcarray<RemoteHost> PersistantConfig::GetRemoteHosts()
{
return 0;
return {};
}
RemoteHost *PersistantConfig::GetRemoteHost(int index)
RemoteHost PersistantConfig::GetRemoteHost(const rdcstr &)
{
return NULL;
return RemoteHost();
}
void PersistantConfig::AddRemoteHost(RemoteHost host)
{
}
void PersistantConfig::RemoveRemoteHost(RemoteHost host)
{
}
void PersistantConfig::AddAndroidHosts()
{
}
@@ -166,7 +170,23 @@ rdcstr PersistantConfig::GetConfigSetting(const rdcstr &name)
RemoteHost::RemoteHost()
{
serverRunning = connected = busy = versionMismatch = false;
}
RemoteHost::RemoteHost(const rdcstr &host)
{
}
RemoteHost::RemoteHost(const RemoteHost &o)
{
}
RemoteHost &RemoteHost::operator=(const RemoteHost &o)
{
return *this;
}
RemoteHost::~RemoteHost()
{
}
void RemoteHost::CheckStatus()
@@ -177,3 +197,58 @@ ReplayStatus RemoteHost::Launch()
{
return ReplayStatus::Succeeded;
}
bool RemoteHost::IsServerRunning() const
{
return false;
}
bool RemoteHost::IsConnected() const
{
return false;
}
bool RemoteHost::IsBusy() const
{
return false;
}
bool RemoteHost::IsVersionMismatch() const
{
return false;
}
rdcstr RemoteHost::FriendlyName() const
{
return rdcstr();
}
void RemoteHost::SetFriendlyName(const rdcstr &name)
{
}
rdcstr RemoteHost::RunCommand() const
{
return rdcstr();
}
void RemoteHost::SetRunCommand(const rdcstr &cmd)
{
}
rdcstr RemoteHost::LastCapturePath() const
{
return rdcstr();
}
void RemoteHost::SetLastCapturePath(const rdcstr &path)
{
}
void RemoteHost::SetConnected(bool connected)
{
}
void RemoteHost::SetShutdown()
{
}
+4 -3
View File
@@ -312,10 +312,11 @@ int main(int argc, char *argv[])
int replayHostIndex = -1;
if(parser.isSet(replayhost))
{
QString replayHost = parser.value(replayhost);
for(int i = 0; i < config.RemoteHosts.count(); i++)
rdcstr replayHost = parser.value(replayhost);
rdcarray<RemoteHost> hosts = config.GetRemoteHosts();
for(int i = 0; i < hosts.count(); i++)
{
if(QString(config.RemoteHosts[i]->hostname) == replayHost)
if(hosts[i].Hostname() == replayHost)
{
replayHostIndex = i;
break;
+18 -20
View File
@@ -300,7 +300,7 @@ void CaptureDialog::on_exePath_textChanged(const QString &text)
{
QString path = dir.absolutePath();
if(!m_Ctx.Replay().CurrentRemote())
if(!m_Ctx.Replay().CurrentRemote().IsValid())
path = QDir::toNativeSeparators(path);
// match the path separators from the path
@@ -503,7 +503,7 @@ void CaptureDialog::CheckAndroidSetup(QString &filename)
LambdaThread *scan = new LambdaThread([this, filename]() {
rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
rdcstr host = m_Ctx.Replay().CurrentRemote().Hostname();
RENDERDOC_CheckAndroidPackage(host.c_str(), filename.toUtf8().data(), &m_AndroidFlags);
const bool debuggable = bool(m_AndroidFlags & AndroidFlags::Debuggable);
@@ -535,9 +535,9 @@ void CaptureDialog::androidWarn_mouseClick()
{
QString exe = ui->exePath->text();
const RemoteHost *remote = m_Ctx.Replay().CurrentRemote();
RemoteHost remote = m_Ctx.Replay().CurrentRemote();
if(!remote)
if(!remote.IsValid())
{
RDDialog::critical(this, tr("Android server disconnected"),
tr("You've been disconnected from the android server.\n\n"
@@ -545,7 +545,7 @@ void CaptureDialog::androidWarn_mouseClick()
return;
}
rdcstr host = remote->hostname;
rdcstr host = remote.Hostname();
QString caption = tr("Application is not debuggable");
@@ -650,9 +650,9 @@ void CaptureDialog::on_exePathBrowse_clicked()
initDir = dir.absolutePath();
initExe = f.fileName();
}
else if(m_Ctx.Replay().CurrentRemote())
else if(m_Ctx.Replay().CurrentRemote().IsValid())
{
initDir = m_Ctx.Replay().CurrentRemote()->lastCapturePath;
initDir = m_Ctx.Replay().CurrentRemote().LastCapturePath();
}
else if(!m_Ctx.Config().LastCapturePath.isEmpty())
{
@@ -663,7 +663,7 @@ void CaptureDialog::on_exePathBrowse_clicked()
QString filename;
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
{
VirtualFileDialog vfd(m_Ctx, initDir, this);
RDDialog::show(&vfd);
@@ -678,7 +678,7 @@ void CaptureDialog::on_exePathBrowse_clicked()
{
SetExecutableFilename(filename);
if(m_Ctx.Replay().CurrentRemote() && m_Ctx.Replay().CurrentRemote()->IsADB())
if(m_Ctx.Replay().CurrentRemote().IsADB())
{
CheckAndroidSetup(filename);
}
@@ -691,9 +691,9 @@ void CaptureDialog::on_workDirBrowse_clicked()
if(initDir.isEmpty())
{
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
{
initDir = m_Ctx.Replay().CurrentRemote()->lastCapturePath;
initDir = m_Ctx.Replay().CurrentRemote().LastCapturePath();
}
else if(!QDir(initDir).exists())
{
@@ -709,7 +709,7 @@ void CaptureDialog::on_workDirBrowse_clicked()
QString dir;
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
{
VirtualFileDialog vfd(m_Ctx, initDir, this);
vfd.setDirBrowse();
@@ -1021,12 +1021,12 @@ void CaptureDialog::SetExecutableFilename(const rdcstr &filename)
{
QString fn = filename;
if(!m_Ctx.Replay().CurrentRemote())
if(!m_Ctx.Replay().CurrentRemote().IsValid())
fn = QDir::toNativeSeparators(QFileInfo(fn).absoluteFilePath());
ui->exePath->setText(fn);
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
{
// remove the filename itself before setting the last capture path. Try /, then \ as path
// separator. If no separators are found, there is no path to set.
@@ -1045,7 +1045,7 @@ void CaptureDialog::SetExecutableFilename(const rdcstr &filename)
fn = QString();
}
m_Ctx.Replay().CurrentRemote()->lastCapturePath = fn;
m_Ctx.Replay().CurrentRemote().SetLastCapturePath(fn);
}
else
{
@@ -1122,9 +1122,7 @@ void CaptureDialog::UpdateGlobalHook()
void CaptureDialog::UpdateRemoteHost()
{
const RemoteHost *host = m_Ctx.Replay().CurrentRemote();
if(host && host->IsADB())
if(m_Ctx.Replay().CurrentRemote().IsADB())
ui->cmdLineLabel->setText(tr("Intent Arguments"));
else
ui->cmdLineLabel->setText(tr("Command-line Arguments"));
@@ -1188,7 +1186,7 @@ void CaptureDialog::TriggerCapture()
}
// for non-remote captures, check the executable locally
if(!m_Ctx.Replay().CurrentRemote())
if(!m_Ctx.Replay().CurrentRemote().IsValid())
{
if(!QFileInfo::exists(exe))
{
@@ -1201,7 +1199,7 @@ void CaptureDialog::TriggerCapture()
QString workingDir;
// for non-remote captures, check the directory locally
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
{
workingDir = ui->workDirPath->text();
}
+4 -12
View File
@@ -705,9 +705,7 @@ bool LiveCapture::checkAllowClose()
// we either have to save or delete the capture. Make sure that if it's remote that we are able
// to by having an active connection or replay context on that host.
if(suppressRemoteWarning == false && (!m_Connection || !m_Connection->Connected()) &&
!cap->local && (!m_Ctx.Replay().CurrentRemote() ||
QString(m_Ctx.Replay().CurrentRemote()->hostname) != m_Hostname ||
!m_Ctx.Replay().CurrentRemote()->connected))
!cap->local && m_Ctx.Replay().CurrentRemote().Hostname() != rdcstr(m_Hostname))
{
QMessageBox::StandardButton res2 = RDDialog::question(
this, tr("No active replay context"),
@@ -752,9 +750,7 @@ void LiveCapture::openCapture(Capture *cap)
{
cap->opened = true;
if(!cap->local && (!m_Ctx.Replay().CurrentRemote() ||
QString(m_Ctx.Replay().CurrentRemote()->hostname) != m_Hostname ||
!m_Ctx.Replay().CurrentRemote()->connected))
if(!cap->local && m_Ctx.Replay().CurrentRemote().Hostname() != rdcstr(m_Hostname))
{
RDDialog::critical(
this, tr("No active replay context"),
@@ -821,9 +817,7 @@ bool LiveCapture::saveCapture(Capture *cap, QString path)
}
else
{
if(!m_Ctx.Replay().CurrentRemote() ||
QString(m_Ctx.Replay().CurrentRemote()->hostname) != m_Hostname ||
!m_Ctx.Replay().CurrentRemote()->connected)
if(m_Ctx.Replay().CurrentRemote().Hostname() != rdcstr(m_Hostname))
{
RDDialog::critical(this, tr("No active replay context"),
tr("This capture is on remote host %1 and there is no active replay "
@@ -1054,9 +1048,7 @@ void LiveCapture::connectionClosed()
// to this machine as a remote context
if(!cap->local)
{
if(!m_Ctx.Replay().CurrentRemote() ||
QString(m_Ctx.Replay().CurrentRemote()->hostname) != m_Hostname ||
!m_Ctx.Replay().CurrentRemote()->connected)
if(m_Ctx.Replay().CurrentRemote().Hostname() != rdcstr(m_Hostname))
return;
}
+76 -84
View File
@@ -58,25 +58,16 @@ static RemoteConnect getRemoteConnect(RDTreeWidgetItem *item)
return item->tag().value<RemoteConnect>();
}
static void setRemoteHost(RDTreeWidgetItem *item, RemoteHost *host)
static void setRemoteHost(RDTreeWidgetItem *item, RemoteHost host)
{
if(!item)
return;
item->setTag(QVariant::fromValue((uintptr_t)host));
}
static RemoteHost *getRemoteHost(RDTreeWidgetItem *item)
{
if(!item)
return NULL;
return (RemoteHost *)item->tag().value<uintptr_t>();
item->setTag(host.Hostname());
}
void deleteItemAndHost(RDTreeWidgetItem *item)
{
delete getRemoteHost(item);
delete item;
}
@@ -116,7 +107,7 @@ RemoteManager::RemoteManager(ICaptureContext &ctx, MainWindow *main)
m_Ctx.Config().AddAndroidHosts();
for(RemoteHost *h : m_Ctx.Config().RemoteHosts)
for(RemoteHost h : m_Ctx.Config().GetRemoteHosts())
addHost(h);
on_hosts_itemSelectionChanged();
@@ -125,10 +116,18 @@ RemoteManager::RemoteManager(ICaptureContext &ctx, MainWindow *main)
RemoteManager::~RemoteManager()
{
for(RDTreeWidgetItem *item : m_QueuedDeletes)
deleteItemAndHost(item);
delete item;
delete ui;
}
RemoteHost RemoteManager::getRemoteHost(RDTreeWidgetItem *item)
{
if(!item)
return RemoteHost();
return m_Ctx.Config().GetRemoteHost(item->tag().toString());
}
void RemoteManager::closeWhenFinished()
{
m_ExternalRef.acquire(1);
@@ -137,15 +136,12 @@ void RemoteManager::closeWhenFinished()
void RemoteManager::setRemoteServerLive(RDTreeWidgetItem *node, bool live, bool busy)
{
RemoteHost *host = getRemoteHost(node);
RemoteHost host = getRemoteHost(node);
if(!host)
if(!host.IsValid())
return;
host->serverRunning = live;
host->busy = busy;
if(host->IsLocalhost())
if(host.IsLocalhost())
{
node->setIcon(0, QIcon());
node->setText(1, QString());
@@ -154,11 +150,11 @@ void RemoteManager::setRemoteServerLive(RDTreeWidgetItem *node, bool live, bool
{
QString text = live ? tr("Remote server running") : tr("No remote server");
if(host->connected)
if(host.IsConnected())
text += tr(" (Active Context)");
else if(host->versionMismatch)
else if(host.IsVersionMismatch())
text += tr(" (Version Mismatch)");
else if(host->busy)
else if(host.IsBusy())
text += tr(" (Busy)");
node->setText(1, text);
@@ -167,15 +163,9 @@ void RemoteManager::setRemoteServerLive(RDTreeWidgetItem *node, bool live, bool
}
}
bool RemoteManager::isRemoteServerLive(RDTreeWidgetItem *node)
void RemoteManager::addHost(RemoteHost host)
{
RemoteHost *host = getRemoteHost(node);
return host && host->serverRunning;
}
void RemoteManager::addHost(RemoteHost *host)
{
RDTreeWidgetItem *node = new RDTreeWidgetItem({host->Name(), lit("...")});
RDTreeWidgetItem *node = new RDTreeWidgetItem({host.Name(), lit("...")});
node->setItalic(true);
node->setIcon(0, Icons::hourglass());
@@ -200,15 +190,15 @@ void RemoteManager::updateLookupsStatus()
void RemoteManager::runRemoteServer(RDTreeWidgetItem *node)
{
RemoteHost *host = getRemoteHost(node);
RemoteHost host = getRemoteHost(node);
if(!host)
if(!host.IsValid())
{
m_Lookups.acquire();
return;
}
host->Launch();
host.Launch();
// now refresh this host
refreshHost(node);
@@ -218,22 +208,25 @@ void RemoteManager::runRemoteServer(RDTreeWidgetItem *node)
void RemoteManager::refreshHost(RDTreeWidgetItem *node)
{
RemoteHost *host = getRemoteHost(node);
RemoteHost host = getRemoteHost(node);
if(!host)
if(!host.IsValid())
return;
m_Lookups.release();
// this function looks up the remote connections and for each one open
// queries it for the API, target (usually executable name) and if any user is already connected
LambdaThread *th = new LambdaThread([this, node, host]() {
LambdaThread *th = new LambdaThread([ this, node, h = host ]() {
QByteArray username = GetSystemUsername().toUtf8();
host->CheckStatus();
// make a mutable copy and check the status
RemoteHost host = h;
host.CheckStatus();
GUIInvoke::call(
this, [this, node, host]() { setRemoteServerLive(node, host->serverRunning, host->busy); });
GUIInvoke::call(this, [this, node, host]() {
setRemoteServerLive(node, host.IsServerRunning(), host.IsBusy());
});
uint32_t nextIdent = 0;
@@ -242,13 +235,13 @@ void RemoteManager::refreshHost(RDTreeWidgetItem *node)
// just a sanity check to make sure we don't hit some unexpected case and infinite loop
uint32_t prevIdent = nextIdent;
nextIdent = RENDERDOC_EnumerateRemoteTargets(host->hostname.c_str(), nextIdent);
nextIdent = RENDERDOC_EnumerateRemoteTargets(host.Hostname().c_str(), nextIdent);
if(nextIdent == 0 || prevIdent >= nextIdent)
break;
ITargetControl *conn =
RENDERDOC_CreateTargetControl(host->hostname.c_str(), nextIdent, username.data(), false);
RENDERDOC_CreateTargetControl(host.Hostname().c_str(), nextIdent, username.data(), false);
if(conn)
{
@@ -263,7 +256,7 @@ void RemoteManager::refreshHost(RDTreeWidgetItem *node)
else
running = tr("Running %1").arg(api);
RemoteConnect tag(host->hostname, host->Name(), nextIdent);
RemoteConnect tag(host.Hostname(), host.Name(), nextIdent);
GUIInvoke::call(this, [this, node, target, running, tag]() {
RDTreeWidgetItem *child = new RDTreeWidgetItem({target, running});
@@ -297,7 +290,7 @@ void RemoteManager::updateStatus()
ui->refreshAll->setEnabled(true);
for(RDTreeWidgetItem *item : m_QueuedDeletes)
deleteItemAndHost(item);
delete item;
m_QueuedDeletes.clear();
// if the external ref is gone now, we can delete ourselves
@@ -337,27 +330,27 @@ void RemoteManager::updateConnectButton()
ui->connect->setEnabled(true);
ui->connect->setText(tr("Connect to App"));
RemoteHost *host = getRemoteHost(item);
RemoteHost host = getRemoteHost(item);
if(host)
if(host.IsValid())
{
if(host->IsLocalhost())
if(host.IsLocalhost())
{
ui->connect->setText(tr("Run Server"));
ui->connect->setEnabled(false);
}
else if(host->serverRunning)
else if(host.IsServerRunning())
{
ui->connect->setText(tr("Shutdown"));
if(host->busy && !host->connected)
if(host.IsBusy() && !host.IsConnected())
ui->connect->setEnabled(false);
}
else
{
ui->connect->setText(tr("Run Server"));
if(host->runCommand.isEmpty())
if(host.RunCommand().isEmpty())
ui->connect->setEnabled(false);
}
}
@@ -375,23 +368,14 @@ void RemoteManager::addNewHost()
{
bool found = false;
for(int i = 0; i < m_Ctx.Config().RemoteHosts.count(); i++)
{
QString hostname = m_Ctx.Config().RemoteHosts[i]->hostname;
if(hostname.compare(host, Qt::CaseInsensitive) == 0)
{
found = true;
break;
}
}
RemoteHost h = m_Ctx.Config().GetRemoteHost(host);
if(!found)
if(!h.IsValid())
{
RemoteHost *h = new RemoteHost();
h->hostname = host;
h->runCommand = ui->runCommand->text().trimmed();
h = RemoteHost((rdcstr)host);
h.SetRunCommand(ui->runCommand->text().trimmed());
m_Ctx.Config().RemoteHosts.push_back(h);
m_Ctx.Config().AddRemoteHost(h);
m_Ctx.Config().Save();
addHost(h);
@@ -408,11 +392,11 @@ void RemoteManager::setRunCommand()
if(!item)
return;
RemoteHost *h = getRemoteHost(item);
RemoteHost h = getRemoteHost(item);
if(h)
if(h.IsValid())
{
h->runCommand = ui->runCommand->text().trimmed();
h.SetRunCommand(ui->runCommand->text().trimmed());
m_Ctx.Config().Save();
}
}
@@ -426,7 +410,7 @@ void RemoteManager::queueDelete(RDTreeWidgetItem *item)
}
else
{
deleteItemAndHost(item);
delete item;
}
}
@@ -448,21 +432,21 @@ void RemoteManager::on_hosts_itemSelectionChanged()
RDTreeWidgetItem *item = ui->hosts->selectedItem();
RemoteHost *host = item ? getRemoteHost(item) : NULL;
RemoteHost host = getRemoteHost(item);
ui->runCommand->setText(QString());
if(host)
if(host.IsValid())
{
if(ui->refreshAll->isEnabled())
ui->refreshOne->setEnabled(true);
ui->runCommand->setText(host->runCommand);
ui->hostname->setText(host->Name());
ui->runCommand->setText(host.RunCommand());
ui->hostname->setText(host.Name());
ui->addUpdateHost->setText(tr("Update"));
if(host->IsLocalhost() || host->IsADB())
if(host.IsLocalhost() || host.IsADB())
{
// localhost and android hosts cannot be updated or have their run command changed
ui->addUpdateHost->setEnabled(false);
@@ -532,7 +516,7 @@ void RemoteManager::on_runCommand_keyPress(QKeyEvent *event)
void RemoteManager::on_addUpdateHost_clicked()
{
RDTreeWidgetItem *item = ui->hosts->selectedItem();
if(item && getRemoteHost(item))
if(getRemoteHost(item).IsValid())
setRunCommand();
else
addNewHost();
@@ -589,26 +573,26 @@ void RemoteManager::on_connect_clicked()
return;
RemoteConnect connect = getRemoteConnect(node);
RemoteHost *host = getRemoteHost(node);
RemoteHost host = getRemoteHost(node);
if(connect.ident > 0)
{
connectToApp(node);
}
else if(host)
else if(host.IsValid())
{
if(host->serverRunning)
if(host.IsServerRunning())
{
QMessageBox::StandardButton res = RDDialog::question(
this, tr("Remote server shutdown"),
tr("Are you sure you wish to shut down running remote server on %1?").arg(host->Name()),
tr("Are you sure you wish to shut down running remote server on %1?").arg(host.Name()),
RDDialog::YesNoCancel);
if(res == QMessageBox::Cancel || res == QMessageBox::No)
return;
// shut down
if(host->connected)
if(host.IsConnected())
{
m_Ctx.Replay().ShutdownServer();
setRemoteServerLive(node, false, false);
@@ -617,7 +601,7 @@ void RemoteManager::on_connect_clicked()
{
IRemoteServer *server = NULL;
ReplayStatus status =
RENDERDOC_CreateRemoteServerConnection(host->hostname.c_str(), 0, &server);
RENDERDOC_CreateRemoteServerConnection(host.Hostname().c_str(), 0, &server);
if(server)
server->ShutdownServerAndConnection();
setRemoteServerLive(node, false, false);
@@ -627,6 +611,14 @@ void RemoteManager::on_connect_clicked()
tr("Error shutting down remote server: %1").arg(ToQStr(status)));
}
// kick off a thread to check the status
LambdaThread *th = new LambdaThread([ this, h = host ]() {
RemoteHost host = h;
host.CheckStatus();
});
th->selfDelete(true);
th->start();
updateConnectButton();
}
else
@@ -654,12 +646,12 @@ void RemoteManager::on_deleteHost_clicked()
if(!item)
return;
RemoteHost *host = getRemoteHost(item);
RemoteHost host = getRemoteHost(item);
int itemIdx = ui->hosts->indexOfTopLevelItem(item);
// don't delete running instances on a host
if(item->parent() != ui->hosts->invisibleRootItem() || itemIdx < 0 || !host)
if(item->parent() != ui->hosts->invisibleRootItem() || itemIdx < 0 || !host.IsValid())
return;
QString hostname = item->text(0);
@@ -676,12 +668,12 @@ void RemoteManager::on_deleteHost_clicked()
if(res == QMessageBox::Yes)
{
int32_t idx = m_Ctx.Config().RemoteHosts.indexOf(host);
if(idx < 0)
RemoteHost h = m_Ctx.Config().GetRemoteHost(host.Hostname());
if(!h.IsValid())
return;
// the host will be removed in queueDelete.
m_Ctx.Config().RemoteHosts.erase(idx);
m_Ctx.Config().RemoveRemoteHost(h);
m_Ctx.Config().Save();
item->clear();
+2 -2
View File
@@ -77,12 +77,12 @@ private:
QList<RDTreeWidgetItem *> m_QueuedDeletes;
RemoteHost getRemoteHost(RDTreeWidgetItem *item);
void queueDelete(RDTreeWidgetItem *item);
bool isRemoteServerLive(RDTreeWidgetItem *node);
void setRemoteServerLive(RDTreeWidgetItem *node, bool live, bool busy);
void addHost(RemoteHost *host);
void addHost(RemoteHost host);
void updateLookupsStatus();
void runRemoteServer(RDTreeWidgetItem *node);
+69 -86
View File
@@ -552,9 +552,10 @@ void MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir,
}
LiveCapture *live = new LiveCapture(
m_Ctx, m_Ctx.Replay().CurrentRemote() ? m_Ctx.Replay().CurrentRemote()->hostname : "",
m_Ctx.Replay().CurrentRemote() ? m_Ctx.Replay().CurrentRemote()->Name() : "", ret.ident,
this, this);
m_Ctx,
m_Ctx.Replay().CurrentRemote().IsValid() ? m_Ctx.Replay().CurrentRemote().Hostname() : "",
m_Ctx.Replay().CurrentRemote().IsValid() ? m_Ctx.Replay().CurrentRemote().Name() : "",
ret.ident, this, this);
ShowLiveCapture(live);
callback(live);
});
@@ -639,8 +640,7 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
QString machineIdent;
ReplaySupport support = ReplaySupport::Unsupported;
bool remoteReplay =
!local || (m_Ctx.Replay().CurrentRemote() && m_Ctx.Replay().CurrentRemote()->connected);
bool remoteReplay = !local || m_Ctx.Replay().CurrentRemote().IsConnected();
if(local)
{
@@ -701,8 +701,7 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
[this]() { return contextChooser->isEnabled(); });
}
remoteReplay =
(m_Ctx.Replay().CurrentRemote() && m_Ctx.Replay().CurrentRemote()->connected);
remoteReplay = m_Ctx.Replay().CurrentRemote().IsConnected();
if(!remoteReplay)
{
@@ -753,7 +752,7 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
QString remoteMessage =
tr("This capture was captured with %1 and cannot be replayed on %2.\n\n")
.arg(driver)
.arg(m_Ctx.Replay().CurrentRemote()->Name());
.arg(m_Ctx.Replay().CurrentRemote().Name());
remoteMessage += tr("Try selecting a different remote context in the status bar.");
@@ -1005,8 +1004,8 @@ void MainWindow::SetTitle(const QString &filename)
prefix += lit(" - ");
}
if(m_Ctx.Replay().CurrentRemote())
prefix += tr("Remote: %1 - ").arg(m_Ctx.Replay().CurrentRemote()->Name());
if(m_Ctx.Replay().CurrentRemote().IsValid())
prefix += tr("Remote: %1 - ").arg(m_Ctx.Replay().CurrentRemote().Name());
QString text = prefix + lit("RenderDoc ");
@@ -1592,8 +1591,8 @@ void MainWindow::remoteProbe()
{
QMutexLocker lock(&m_ProbeRemoteHostsLock);
m_ProbeRemoteHosts.clear();
for(RemoteHost *host : m_Ctx.Config().RemoteHosts)
m_ProbeRemoteHosts.push_back(*host);
for(RemoteHost host : m_Ctx.Config().GetRemoteHosts())
m_ProbeRemoteHosts.push_back(host);
}
});
@@ -1604,41 +1603,20 @@ void MainWindow::remoteProbe()
hosts = m_ProbeRemoteHosts;
}
QList<QPair<RemoteHost, RemoteHost>> updates;
for(RemoteHost &host : hosts)
{
// don't mess with a host we're connected to - this is handled anyway
if(host.connected)
if(host.IsConnected())
continue;
RemoteHost updated = host;
updated.CheckStatus();
// this will do the bulk of the status checking on this thread without holding any lock, then
// grab the remote host lock and update the config's host (if it's still there)
host.CheckStatus();
// bail as soon as we notice that we're done
if(!m_RemoteProbeSemaphore.available())
return;
if(updated != host)
updates.push_back(qMakePair(host, updated));
}
GUIInvoke::call(this, [this, updates] {
// this is a bit naive - it suffers from the A-B-A problem where the host could be updated
// then restored to its original state before we notice. In this case though we don't care
// about that, we just don't want to trash some important changes like the connected status
// changing or something.
for(const QPair<RemoteHost, RemoteHost> &u : updates)
{
for(RemoteHost *host : m_Ctx.Config().RemoteHosts)
{
if(*host == u.first)
*host = u.second;
}
}
});
}
}
@@ -1661,13 +1639,13 @@ void MainWindow::messageCheck()
bool disconnected = false;
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
{
bool wasRunning = m_Ctx.Replay().CurrentRemote()->serverRunning;
bool wasRunning = m_Ctx.Replay().CurrentRemote().IsServerRunning();
m_Ctx.Replay().PingRemote();
if(wasRunning != m_Ctx.Replay().CurrentRemote()->serverRunning)
if(wasRunning != m_Ctx.Replay().CurrentRemote().IsServerRunning())
{
qCritical() << "Remote server disconnected";
disconnected = true;
@@ -1692,7 +1670,8 @@ void MainWindow::messageCheck()
"RenderDoc to reconnect and load the capture again"));
}
if(m_Ctx.Replay().CurrentRemote() && !m_Ctx.Replay().CurrentRemote()->serverRunning)
if(m_Ctx.Replay().CurrentRemote().IsValid() &&
!m_Ctx.Replay().CurrentRemote().IsServerRunning())
contextChooser->setIcon(Icons::cross());
if(!msgs.empty())
@@ -1711,11 +1690,11 @@ void MainWindow::messageCheck()
}
else if(!m_Ctx.IsCaptureLoaded() && !m_Ctx.IsCaptureLoading())
{
if(m_Ctx.Replay().CurrentRemote())
if(m_Ctx.Replay().CurrentRemote().IsValid())
m_Ctx.Replay().PingRemote();
GUIInvoke::call(this, [this]() {
if(m_Ctx.Replay().CurrentRemote() && !m_Ctx.Replay().CurrentRemote()->serverRunning)
if(m_Ctx.Replay().CurrentRemote().IsValid() && !m_Ctx.Replay().CurrentRemote().IsServerRunning())
{
contextChooser->setIcon(Icons::cross());
contextChooser->setText(tr("Replay Context: %1").arg(tr("Local")));
@@ -1735,32 +1714,35 @@ void MainWindow::FillRemotesMenu(QMenu *menu, bool includeLocalhost)
{
menu->clear();
for(int i = 0; i < m_Ctx.Config().RemoteHosts.count(); i++)
{
RemoteHost *host = m_Ctx.Config().RemoteHosts[i];
rdcarray<RemoteHost> hosts = m_Ctx.Config().GetRemoteHosts();
// add localhost at the end
if(host->IsLocalhost())
for(int i = 0; i < hosts.count(); i++)
{
RemoteHost host = hosts[i];
// add localhost at the end, skip invalid hosts
if(host.IsLocalhost() || !host.IsValid())
continue;
QAction *action = new QAction(menu);
action->setIcon(host->serverRunning && !host->versionMismatch ? Icons::tick() : Icons::cross());
if(host->connected)
action->setText(tr("%1 (Connected)").arg(host->Name()));
else if(host->serverRunning && host->versionMismatch)
action->setText(tr("%1 (Bad Version)").arg(host->Name()));
else if(host->serverRunning && host->busy)
action->setText(tr("%1 (Busy)").arg(host->Name()));
else if(host->serverRunning)
action->setText(tr("%1 (Online)").arg(host->Name()));
action->setIcon(host.IsServerRunning() && !host.IsVersionMismatch() ? Icons::tick()
: Icons::cross());
if(host.IsConnected())
action->setText(tr("%1 (Connected)").arg(host.Name()));
else if(host.IsServerRunning() && host.IsVersionMismatch())
action->setText(tr("%1 (Bad Version)").arg(host.Name()));
else if(host.IsServerRunning() && host.IsBusy())
action->setText(tr("%1 (Busy)").arg(host.Name()));
else if(host.IsServerRunning())
action->setText(tr("%1 (Online)").arg(host.Name()));
else
action->setText(tr("%1 (Offline)").arg(host->Name()));
action->setText(tr("%1 (Offline)").arg(host.Name()));
QObject::connect(action, &QAction::triggered, this, &MainWindow::switchContext);
action->setData(i);
// don't allow switching to the connected host
if(host->connected)
if(host.IsConnected())
action->setEnabled(false);
menu->addAction(action);
@@ -1782,18 +1764,18 @@ void MainWindow::FillRemotesMenu(QMenu *menu, bool includeLocalhost)
void MainWindow::setRemoteHost(int hostIdx)
{
RemoteHost *host = NULL;
if(hostIdx >= 0 && hostIdx < m_Ctx.Config().RemoteHosts.count())
{
host = m_Ctx.Config().RemoteHosts[hostIdx];
}
rdcarray<RemoteHost> hosts = m_Ctx.Config().GetRemoteHosts();
RemoteHost host;
if(hostIdx >= 0 && hostIdx < hosts.count())
host = hosts[hostIdx];
for(LiveCapture *live : m_LiveCaptures)
{
// allow live captures to this host to stay open, that way
// we can connect to a live capture, then switch into that
// context
if(host && live->hostname() == host->hostname)
if(host.IsValid() && live->hostname() == host.Hostname())
continue;
if(!live->checkAllowClose())
@@ -1808,7 +1790,7 @@ void MainWindow::setRemoteHost(int hostIdx)
// allow live captures to this host to stay open, that way
// we can connect to a live capture, then switch into that
// context
if(host && live->hostname() == host->hostname)
if(host.IsValid() && live->hostname() == host.Hostname())
continue;
live->cleanItems();
@@ -1817,7 +1799,7 @@ void MainWindow::setRemoteHost(int hostIdx)
m_Ctx.Replay().DisconnectFromRemoteServer();
if(!host)
if(!host.IsValid())
{
contextChooser->setIcon(Icons::house());
contextChooser->setText(tr("Replay Context: %1").arg(tr("Local")));
@@ -1833,8 +1815,8 @@ void MainWindow::setRemoteHost(int hostIdx)
}
else
{
contextChooser->setText(tr("Replay Context: %1").arg(host->Name()));
contextChooser->setIcon(host->serverRunning ? Icons::connect() : Icons::disconnect());
contextChooser->setText(tr("Replay Context: %1").arg(host.Name()));
contextChooser->setIcon(host.IsServerRunning() ? Icons::connect() : Icons::disconnect());
// disable until checking is done
contextChooser->setEnabled(false);
@@ -1845,11 +1827,12 @@ void MainWindow::setRemoteHost(int hostIdx)
statusText->setText(tr("Checking remote server status..."));
LambdaThread *th = new LambdaThread([this, host]() {
// see if the server is up
host->CheckStatus();
LambdaThread *th = new LambdaThread([ this, h = host ]() {
// make a mutable copy and see if the server is up
RemoteHost host = h;
host.CheckStatus();
if(host->IsADB() && !RENDERDOC_IsAndroidSupported(host->hostname.c_str()))
if(host.IsADB() && !RENDERDOC_IsAndroidSupported(host.Hostname().c_str()))
{
// check to see if we should warn the user about this unsupported android version.
GUIInvoke::call(this, [this]() {
@@ -1869,7 +1852,7 @@ void MainWindow::setRemoteHost(int hostIdx)
});
}
if(!host->serverRunning && !host->runCommand.isEmpty())
if(!host.IsServerRunning() && !host.RunCommand().isEmpty())
{
GUIInvoke::call(this, [this]() {
statusText->setText(tr("Running remote server command..."));
@@ -1877,28 +1860,28 @@ void MainWindow::setRemoteHost(int hostIdx)
statusProgress->setMaximum(0);
});
ReplayStatus launchStatus = host->Launch();
ReplayStatus launchStatus = host.Launch();
if(launchStatus != ReplayStatus::Succeeded)
{
showLaunchError(launchStatus);
}
// check if it's running now
host->CheckStatus();
host.CheckStatus();
GUIInvoke::call(this, [this]() { statusProgress->setVisible(false); });
}
ReplayStatus status = ReplayStatus::Succeeded;
if(host->serverRunning && !host->busy)
if(host.IsServerRunning() && !host.IsBusy())
{
status = m_Ctx.Replay().ConnectToRemoteServer(host);
}
GUIInvoke::call(this, [this, host, status]() {
contextChooser->setIcon(host->serverRunning && !host->busy ? Icons::connect()
: Icons::disconnect());
contextChooser->setIcon(host.IsServerRunning() && !host.IsBusy() ? Icons::connect()
: Icons::disconnect());
if(status != ReplayStatus::Succeeded)
{
@@ -1906,22 +1889,22 @@ void MainWindow::setRemoteHost(int hostIdx)
contextChooser->setText(tr("Replay Context: %1").arg(tr("Local")));
statusText->setText(tr("Connection failed: %1").arg(ToQStr(status)));
}
else if(host->versionMismatch)
else if(host.IsVersionMismatch())
{
statusText->setText(
tr("Remote server is not running RenderDoc %1").arg(lit(FULL_VERSION_STRING)));
}
else if(host->busy)
else if(host.IsBusy())
{
statusText->setText(tr("Remote server in use elsewhere"));
}
else if(host->serverRunning)
else if(host.IsServerRunning())
{
statusText->setText(tr("Remote server ready"));
}
else
{
if(!host->runCommand.isEmpty())
if(!host.RunCommand().isEmpty())
statusText->setText(tr("Remote server not running or failed to start"));
else
statusText->setText(tr("Remote server not running - no start command configured"));
@@ -2030,7 +2013,7 @@ void MainWindow::OnCaptureClosed()
SetTitle();
// if the remote sever disconnected during capture replay, resort back to a 'disconnected' state
if(m_Ctx.Replay().CurrentRemote() && !m_Ctx.Replay().CurrentRemote()->serverRunning)
if(m_Ctx.Replay().CurrentRemote().IsValid() && !m_Ctx.Replay().CurrentRemote().IsServerRunning())
{
statusText->setText(
tr("Remote server disconnected. To attempt to reconnect please select it again."));
@@ -2914,10 +2897,10 @@ void MainWindow::showLaunchError(ReplayStatus status)
bool MainWindow::isCapturableAppRunningOnAndroid()
{
if(!m_Ctx.Replay().CurrentRemote() || !m_Ctx.Replay().CurrentRemote()->IsADB())
if(!m_Ctx.Replay().CurrentRemote().IsADB())
return false;
rdcstr host = m_Ctx.Replay().CurrentRemote()->hostname;
rdcstr host = m_Ctx.Replay().CurrentRemote().Hostname();
uint32_t ident = RENDERDOC_EnumerateRemoteTargets(host.c_str(), 0);
return ident != 0;
}