Integrating latest from github/staging

Integrating up through commit 5e1bdae
This commit is contained in:
alexpete
2021-03-26 14:31:50 -07:00
parent 9c54341af8
commit 36c4e827bd
764 changed files with 11453 additions and 20251 deletions
@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
namespace AzFramework
{
// Type of communication between parent and child processes
enum ProcessCommunicationType
{
COMMUNICATOR_TYPE_STDINOUT,
COMMUNICATOR_TYPE_NONE,
//COMMUNICATOR_TYPE_IPC
};
enum ProcessPriority
{
// we don't support raising priority
PROCESSPRIORITY_NORMAL,
PROCESSPRIORITY_BELOWNORMAL, // below other normal priorities
PROCESSPRIORITY_IDLE, // lowest possible priority
};
struct ProcessData;
class ProcessOutput;
class ProcessCommunicator;
class ProcessCommunicatorForChildProcess;
class StdProcessCommunicator;
class StdProcessCommunicatorForChildProcess;
class CommunicatorHandleImpl;
} // namespace AzFramework
@@ -0,0 +1,195 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Process/ProcessCommunicator.h>
namespace AzFramework
{
void ProcessOutput::Clear()
{
outputResult.clear();
errorResult.clear();
}
bool ProcessOutput::HasOutput() const
{
return !outputResult.empty();
}
bool ProcessOutput::HasError() const
{
return !errorResult.empty();
}
AZ::u32 ProcessCommunicator::BlockUntilErrorAvailable(AZStd::string& readBuffer)
{
// block until errors can actually be read
ReadError(readBuffer.data(), 0);
// at this point errors can be read, return the peek amount
return PeekError();
}
AZ::u32 ProcessCommunicator::BlockUntilOutputAvailable(AZStd::string& readBuffer)
{
// block until output can actually be read
ReadOutput(readBuffer.data(), 0);
// at this point output can be read, return the peek amount
return PeekOutput();
}
void ProcessCommunicator::ReadIntoProcessOutput(ProcessOutput& processOutput)
{
OutputStatus status;
char readBuffer[s_readBufferSize];
// read from the process until the handle is no longer valid
while (true)
{
WaitForReadyOutputs(status);
ReadFromOutputs(processOutput, status, readBuffer, s_readBufferSize);
if (!status.outputDeviceReady && !status.errorsDeviceReady)
{
break;
}
}
}
void ProcessCommunicator::ReadFromOutputs(ProcessOutput& processOutput, OutputStatus& status, char* buffer, AZ::u32 bufferSize)
{
AZ::u32 bytesRead = 0;
if (status.shouldReadOutput)
{
// Send in the size - 1 to leave room for us to write out the 0 in
// bytesRead position on the next line
bytesRead = ReadOutput(buffer, bufferSize - 1);
buffer[bytesRead] = 0;
processOutput.outputResult.append(buffer, bytesRead);
}
if (status.shouldReadErrors)
{
// Send in the size - 1 to leave room for us to write out the 0 in
// bytesRead position on the next line
bytesRead = ReadError(buffer, bufferSize - 1);
buffer[bytesRead] = 0;
processOutput.errorResult.append(buffer, bytesRead);
}
}
AZ::u32 ProcessCommunicatorForChildProcess::BlockUntilInputAvailable(AZStd::string& readBuffer)
{
ReadInput(readBuffer.data(), 0);
return PeekInput();
}
StdInOutProcessCommunicator::StdInOutProcessCommunicator()
: m_stdInWrite(new CommunicatorHandleImpl())
, m_stdOutRead(new CommunicatorHandleImpl())
, m_stdErrRead(new CommunicatorHandleImpl())
{
}
StdInOutProcessCommunicator::~StdInOutProcessCommunicator()
{
CloseAllHandles();
}
bool StdInOutProcessCommunicator::IsValid() const
{
return m_initialized && (m_stdInWrite->IsValid() || m_stdOutRead->IsValid() || m_stdErrRead->IsValid());
}
AZ::u32 StdInOutProcessCommunicator::ReadError(void* readBuffer, AZ::u32 bufferSize)
{
AZ_Assert(m_stdErrRead->IsValid(), "Error read handle is invalid, unable to read error stream");
return ReadDataFromHandle(m_stdErrRead, readBuffer, bufferSize);
}
AZ::u32 StdInOutProcessCommunicator::PeekError()
{
AZ_Assert(m_stdErrRead->IsValid(), "Error read handle is invalid, unable to read error stream");
return PeekHandle(m_stdErrRead);
}
AZ::u32 StdInOutProcessCommunicator::ReadOutput(void* readBuffer, AZ::u32 bufferSize)
{
AZ_Assert(m_stdOutRead->IsValid(), "Output read handle is invalid, unable to read output stream");
return ReadDataFromHandle(m_stdOutRead, readBuffer, bufferSize);
}
AZ::u32 StdInOutProcessCommunicator::PeekOutput()
{
AZ_Assert(m_stdOutRead->IsValid(), "Output read handle is invalid, unable to read output stream");
return PeekHandle(m_stdOutRead);
}
AZ::u32 StdInOutProcessCommunicator::WriteInput(const void* writeBuffer, AZ::u32 bytesToWrite)
{
AZ_Assert(m_stdInWrite->IsValid(), "Input write handle is invalid, unable to write input stream");
return WriteDataToHandle(m_stdInWrite, writeBuffer, bytesToWrite);
}
void StdInOutProcessCommunicator::CloseAllHandles()
{
m_stdInWrite->Close();
m_stdOutRead->Close();
m_stdErrRead->Close();
m_initialized = false;
}
StdInOutProcessCommunicatorForChildProcess::StdInOutProcessCommunicatorForChildProcess()
: m_stdInRead(new CommunicatorHandleImpl())
, m_stdOutWrite(new CommunicatorHandleImpl())
, m_stdErrWrite(new CommunicatorHandleImpl())
{
}
StdInOutProcessCommunicatorForChildProcess::~StdInOutProcessCommunicatorForChildProcess()
{
CloseAllHandles();
}
bool StdInOutProcessCommunicatorForChildProcess::IsValid() const
{
return m_initialized && (m_stdInRead->IsValid() || m_stdOutWrite->IsValid() || m_stdErrWrite->IsValid());
}
AZ::u32 StdInOutProcessCommunicatorForChildProcess::WriteError(const void* writeBuffer, AZ::u32 bytesToWrite)
{
return WriteDataToHandle(m_stdErrWrite, writeBuffer, bytesToWrite);
}
AZ::u32 StdInOutProcessCommunicatorForChildProcess::WriteOutput(const void* writeBuffer, AZ::u32 bytesToWrite)
{
return WriteDataToHandle(m_stdOutWrite, writeBuffer, bytesToWrite);
}
AZ::u32 StdInOutProcessCommunicatorForChildProcess::PeekInput()
{
return PeekHandle(m_stdInRead);
}
AZ::u32 StdInOutProcessCommunicatorForChildProcess::ReadInput(void* buffer, AZ::u32 bufferSize)
{
return ReadDataFromHandle(m_stdInRead, buffer, bufferSize);
}
void StdInOutProcessCommunicatorForChildProcess::CloseAllHandles()
{
m_stdInRead->Close();
m_stdOutWrite->Close();
m_stdErrWrite->Close();
m_initialized = false;
}
} // namespace AzFramework
@@ -0,0 +1,238 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Process/ProcessCommon_fwd.h>
#include <AzFramework/AzFramework_Traits_Platform.h>
#if AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT
#include <Default/AzFramework/Process/ProcessCommon_Default.h>
#else
#include <AzFramework/Process/ProcessCommon.h>
#endif
namespace AzFramework
{
class ProcessOutput
{
public:
AZStd::string outputResult;
AZStd::string errorResult;
void Clear();
bool HasOutput() const;
bool HasError() const;
};
class ProcessCommunicator
{
public:
struct OutputStatus
{
bool outputDeviceReady = false;
bool errorsDeviceReady = false;
bool shouldReadOutput = false;
bool shouldReadErrors = false;
};
ProcessCommunicator() = default;
virtual ~ProcessCommunicator() = default;
// Check if communicator is in a valid state
virtual bool IsValid() const = 0;
// Read error data into a given buffer size (returns amount of data read)
// Blocking call (until child process writes data)
virtual AZ::u32 ReadError(void* readBuffer, AZ::u32 bufferSize) = 0;
// Peek if error data is ready to be read (returns amount of data available to read)
// Non-blocking call
virtual AZ::u32 PeekError() = 0;
// Read output data into a given buffer size (returns amount of data read)
// Blocking call (until child process writes data)
virtual AZ::u32 ReadOutput(void* readBuffer, AZ::u32 bufferSize) = 0;
// Peek if output data is ready to be read (returns amount of data available to read)
// Non-blocking call
virtual AZ::u32 PeekOutput() = 0;
// Write input data to child process (returns amount of data sent)
// Blocking call (until child process reads data)
virtual AZ::u32 WriteInput(const void* writeBuffer, AZ::u32 bytesToWrite) = 0;
// Waits for errors to be ready to read
// Blocking call (until child process writes errors)
AZ::u32 BlockUntilErrorAvailable(AZStd::string& readBuffer);
// Waits for output to be ready to read
// Blocking call (until child process writes output)
AZ::u32 BlockUntilOutputAvailable(AZStd::string& readBuffer);
// Reads into process output until the communicator's output handles are no longer valid
void ReadIntoProcessOutput(ProcessOutput& processOutput);
protected:
AZ_DISABLE_COPY(ProcessCommunicator);
// Waits for output or error to be ready for reading
virtual void WaitForReadyOutputs(OutputStatus& outputStatus) const = 0;
void ReadFromOutputs(ProcessOutput& processOutput,
OutputStatus& status, char* buffer, AZ::u32 bufferSize);
private:
static const size_t s_readBufferSize = 16 * 1024;
};
class ProcessCommunicatorForChildProcess
{
public:
ProcessCommunicatorForChildProcess() = default;
virtual ~ProcessCommunicatorForChildProcess() = default;
// Check if communicator is in a valid state
virtual bool IsValid() const = 0;
// Write error data to parent process (returns amount of data sent)
// Blocking call (until parent process reads data)
virtual AZ::u32 WriteError(const void* writeBuffer, AZ::u32 bytesToWrite) = 0;
// Write output data to parent process (returns amount of data sent)
// Blocking call (until parent process reads data)
virtual AZ::u32 WriteOutput(const void* writeBuffer, AZ::u32 bytesToWrite) = 0;
// Peek if input data is ready to be read (returns amount of data available to read)
// Non-blocking call
virtual AZ::u32 PeekInput() = 0;
// Read input data into a given buffer size (returns amount of data read)
// Blocking call (until parent process writes data)
virtual AZ::u32 ReadInput(void* readBuffer, AZ::u32 bufferSize) = 0;
// Waits for input to be ready to read
// Blocking call (until parent process writes errors)
AZ::u32 BlockUntilInputAvailable(AZStd::string& readBuffer);
protected:
AZ_DISABLE_COPY(ProcessCommunicatorForChildProcess);
};
using StdProcessCommunicatorHandle = AZStd::unique_ptr<CommunicatorHandleImpl>;
class StdInOutCommunication
{
public:
virtual ~StdInOutCommunication() = default;
protected:
AZ::u32 PeekHandle(StdProcessCommunicatorHandle& handle);
AZ::u32 ReadDataFromHandle(StdProcessCommunicatorHandle& handle, void* readBuffer, AZ::u32 bufferSize);
AZ::u32 WriteDataToHandle(StdProcessCommunicatorHandle& handle, const void* writeBuffer, AZ::u32 bytesToWrite);
};
class StdProcessCommunicator
: public ProcessCommunicator
{
public:
virtual bool CreatePipesForProcess(AzFramework::ProcessData* processData) = 0;
};
/**
* Communicator to talk to processes via std::in and std::out
*
* to do this, it must provide handles for the child process to
* inherit before process creation
*/
class StdInOutProcessCommunicator
: public StdProcessCommunicator
, public StdInOutCommunication
{
public:
StdInOutProcessCommunicator();
~StdInOutProcessCommunicator();
//////////////////////////////////////////////////////////////////////////
// AzFramework::ProcessCommunicator overrides
bool IsValid() const override;
AZ::u32 ReadError(void* readBuffer, AZ::u32 bufferSize) override;
AZ::u32 PeekError() override;
AZ::u32 ReadOutput(void* readBuffer, AZ::u32 bufferSize) override;
AZ::u32 PeekOutput() override;
AZ::u32 WriteInput(const void* writeBuffer, AZ::u32 bytesToWrite) override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AzFramework::StdProcessCommunicator overrides
bool CreatePipesForProcess(ProcessData* processData) override;
//////////////////////////////////////////////////////////////////////////
protected:
void CreateHandles();
void CloseAllHandles();
//////////////////////////////////////////////////////////////////////////
// AzFramework::ProcessCommunicator overrides
void WaitForReadyOutputs(OutputStatus& outputStatus) const override;
//////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<CommunicatorHandleImpl> m_stdInWrite;
AZStd::unique_ptr<CommunicatorHandleImpl> m_stdOutRead;
AZStd::unique_ptr<CommunicatorHandleImpl> m_stdErrRead;
bool m_initialized = false;
};
class StdProcessCommunicatorForChildProcess
: public ProcessCommunicatorForChildProcess
{
public:
virtual bool AttachToExistingPipes() = 0;
};
class StdInOutProcessCommunicatorForChildProcess
: public StdProcessCommunicatorForChildProcess
, public StdInOutCommunication
{
public:
StdInOutProcessCommunicatorForChildProcess();
~StdInOutProcessCommunicatorForChildProcess();
//////////////////////////////////////////////////////////////////////////
// AzFramework::ProcessCommunicatorForChildProcess overrides
bool IsValid() const override;
AZ::u32 WriteError(const void* writeBuffer, AZ::u32 bytesToWrite) override;
AZ::u32 WriteOutput(const void* writeBuffer, AZ::u32 bytesToWrite) override;
AZ::u32 PeekInput() override;
AZ::u32 ReadInput(void* buffer, AZ::u32 bufferSize) override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AzFramework::StdProcessCommunicatorForChildProcess overrides
bool AttachToExistingPipes() override;
//////////////////////////////////////////////////////////////////////////
protected:
void CreateHandles();
void CloseAllHandles();
StdProcessCommunicatorHandle m_stdInRead;
StdProcessCommunicatorHandle m_stdOutWrite;
StdProcessCommunicatorHandle m_stdErrWrite;
bool m_initialized = false;
};
} // namespace AzFramework
@@ -0,0 +1,109 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/smart_ptr/scoped_ptr.h>
#include <AzCore/std/parallel/thread.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/Process/ProcessWatcher.h>
#include <AzFramework/Process/ProcessCommunicator.h>
namespace AzFramework
{
bool ProcessWatcher::LaunchProcessAndRetrieveOutput(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType, AzFramework::ProcessOutput& outProcessOutput)
{
// launch the process
AZStd::scoped_ptr<ProcessWatcher> pWatcher(LaunchProcess(processLaunchInfo, communicationType));
if (!pWatcher)
{
AZ_TracePrintf("Process Watcher", "ProcessWatcher::LaunchProcessAndRetrieveOutput: Unable to launch process '%s %s'", processLaunchInfo.m_processExecutableString.c_str(), processLaunchInfo.m_commandlineParameters.c_str());
return false;
}
else
{
// get the communicator and ensure it is valid
ProcessCommunicator* pCommunicator = pWatcher->GetCommunicator();
if (!pCommunicator || !pCommunicator->IsValid())
{
AZ_TracePrintf("Process Watcher", "ProcessWatcher::LaunchProcessAndRetrieveOutput: No communicator for watcher's process (%s %s)!", processLaunchInfo.m_processExecutableString.c_str(), processLaunchInfo.m_commandlineParameters.c_str());
return false;
}
else
{
pCommunicator->ReadIntoProcessOutput(outProcessOutput);
}
}
return true;
}
bool ProcessWatcher::SpawnProcess(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType)
{
InitProcessData(communicationType == COMMUNICATOR_TYPE_STDINOUT);
if (communicationType == COMMUNICATOR_TYPE_STDINOUT)
{
StdProcessCommunicator* pStdCommunicator = CreateStdCommunicator();
if (pStdCommunicator->CreatePipesForProcess(m_pWatcherData.get()))
{
m_pCommunicator = pStdCommunicator;
}
else
{
// Communicator failure, just clean it up
delete pStdCommunicator;
}
}
else if (communicationType == COMMUNICATOR_TYPE_NONE)
{
//Implemented, but don't do anything.
}
else
{
AZ_Assert(false, "communicationType %d not implemented", communicationType);
}
return ProcessLauncher::LaunchProcess(processLaunchInfo, *m_pWatcherData);
}
class ProcessCommunicator* ProcessWatcher::GetCommunicator()
{
return m_pCommunicator;
}
AZStd::shared_ptr<ProcessCommunicatorForChildProcess> ProcessWatcher::GetCommunicatorForChildProcess(ProcessCommunicationType communicationType)
{
if (communicationType == COMMUNICATOR_TYPE_STDINOUT)
{
StdProcessCommunicatorForChildProcess* communicator = CreateStdCommunicatorForChildProcess();
if (!communicator->AttachToExistingPipes())
{
// Delete the communicator if attaching fails, it is useless
delete communicator;
communicator = nullptr;
}
return AZStd::shared_ptr<ProcessCommunicatorForChildProcess>{
communicator
};
}
else if (communicationType == COMMUNICATOR_TYPE_NONE)
{
AZ_Assert(false, "No communicator for communicationType %d", communicationType);
}
else
{
AZ_Assert(false, "communicationType %d not implemented", communicationType);
}
return AZStd::shared_ptr<ProcessCommunicatorForChildProcess>{};
}
} // AzFramework
@@ -0,0 +1,109 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzFramework/Process/ProcessCommon_fwd.h>
namespace AzFramework
{
namespace ProcessLauncher
{
enum ProcessLaunchResult : AZ::u32
{
PLR_Success, // Process Launched Normally
PLR_MissingFile, // Missing file or command
};
struct ProcessLaunchInfo
{
//! This is the process to execute. Do not escape spaces here.
AZStd::string m_processExecutableString;
/**
* Command line parameters, concatenated.
* In order to prevent a proliferation of ifdefs all over client code to convert into various standards,
* instead we assume windows style use of "double quotes" to escape spaces
* for example: params="hello world" "/Users/JOE SMITH/Desktop"
* On windows, the command line will be passed as-is to the shell (with quotes)
* on UNIX/OSX, the command line will be converted as appropriate (quotes removed, but used to chop up parameters)
*/
AZStd::string m_commandlineParameters;
/**
* (optional) If you specify a working directory, the command will be executed with that directory as the current directory.
* Do not use quotes around the working directory string.
*/
AZStd::string m_workingDirectory;
ProcessPriority m_processPriority = PROCESSPRIORITY_NORMAL;
AZStd::vector<AZStd::string>* m_environmentVariables = nullptr;
mutable ProcessLaunchResult m_launchResult = PLR_Success;
//Not Supported On Mac
bool m_showWindow = true;
};
static const AZ::u32 INFINITE_TIMEOUT = (AZ::u32) -1;
bool LaunchProcess(const ProcessLaunchInfo& processLaunchInfo, ProcessData& processData);
bool LaunchUnwatchedProcess(const ProcessLaunchInfo& processLaunchInfo);
} // namespace ProccessLauncher
class ProcessWatcher
{
public:
// Use LaunchProcess to launch a child process at a given path with a commandline and communication type, optional environment variables (null means inherit from parent environment)
static ProcessWatcher* LaunchProcess(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType);
// Use LaunchProcessAndRetrieveOutput to launch a process via LaunchProcess and return its output, as of now used for fire-and-forget executables (exe's that do something and close immediately)
static bool LaunchProcessAndRetrieveOutput(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType, AzFramework::ProcessOutput& outProcessOutput);
// GetCommunicatorForChildProcess is used when you are implementing the given child process and want a better interface than std::in/std::out (not required)
static AZStd::shared_ptr<class ProcessCommunicatorForChildProcess> GetCommunicatorForChildProcess(ProcessCommunicationType communicationType);
// GetCommunicator returns a ProcessCommunicator to communicate with the child process
ProcessCommunicator* GetCommunicator();
// Check if child process is running, outExitCode returns exit code if process terminated
bool IsProcessRunning(AZ::u32* outExitCode = nullptr);
// Wait for process to exit, waitTime is in seconds, returns true if process exited, false if still running
bool WaitForProcessToExit(AZ::u32 waitTimeInSeconds, AZ::u32* outExitCode = nullptr);
// Terminate child process with a given exit code (if still running)
void TerminateProcess(AZ::u32 exitCode);
// Delete ProcessWatcher when done with child process
virtual ~ProcessWatcher();
protected:
bool SpawnProcess(const ProcessLauncher::ProcessLaunchInfo& processLaunchInfo, ProcessCommunicationType communicationType);
private:
StdProcessCommunicator* CreateStdCommunicator();
static StdProcessCommunicatorForChildProcess* CreateStdCommunicatorForChildProcess();
void InitProcessData(bool stdCommunication);
ProcessWatcher();
ProcessWatcher(const ProcessWatcher&) = delete;
ProcessWatcher& operator= (const ProcessWatcher&) = delete;
AZStd::unique_ptr<ProcessData> m_pWatcherData;
ProcessCommunicator* m_pCommunicator;
ProcessCommunicator* m_pChildCommunicator;
};
} // namespace AzFramework