Preparing for initial WSA network POC rewrite, not porting gen1 code. Linux support is way behind. Will work on it soon.
[*] Minor refactors [*] Begin refactoring the Processes subsystem [*] Added empty files ready to move the gross c++ functional callback in the parse subsystem to a dedicated interface w/ utils [*] Broke out Win32 Process into an NT base variant (Process.NT.cpp) with Win32 overloaded process exit pokes (Process.Win32.cpp)
This commit is contained in:
parent
a6f96315f3
commit
19ebdf3761
@ -22,14 +22,14 @@ namespace Aurora::Crypto::AES
|
||||
// Initialization vectors could be derived from SHA1, Tiger, or SHA2 digests
|
||||
AUKN_SYM bool Encrypt(const Memory::MemoryViewRead &plainText,
|
||||
const Memory::MemoryViewRead &inIv,
|
||||
const Memory::MemoryViewWrite &outIv,
|
||||
const Memory::MemoryViewWrite &outIv, // optional
|
||||
const Memory::MemoryViewRead &inKey,
|
||||
Memory::ByteBuffer &out,
|
||||
bool auCoolCodePadding);
|
||||
|
||||
AUKN_SYM bool Decrypt(const Memory::MemoryViewRead &cipherText,
|
||||
const Memory::MemoryViewRead &inIv,
|
||||
const Memory::MemoryViewWrite &outIv,
|
||||
const Memory::MemoryViewWrite &outIv, // optional
|
||||
const Memory::MemoryViewRead &inKey,
|
||||
Memory::ByteBuffer &plainText,
|
||||
bool auCoolCodePadding);
|
||||
|
@ -18,25 +18,20 @@ namespace Aurora::Debug
|
||||
|
||||
/**
|
||||
Retrieves a print-friendly callstack of the last trap (either innocent exception or fatal mem access) <br>
|
||||
On Win32, this information is always available <br>
|
||||
On other platforms, this function will likely yield no valuable information
|
||||
On Win32, this information is always available
|
||||
*/
|
||||
AUKN_SYM AuString GetLastErrorStack();
|
||||
|
||||
AUKN_SYM StackTrace GetLastStackTrace();
|
||||
|
||||
AUKN_SYM StackTrace GetStackTrace();
|
||||
|
||||
|
||||
/**
|
||||
Retrieve information about the last exception. <br>
|
||||
On Win32, this information is always available <br>
|
||||
On other platforms, this information is only available within C++14 catch blocks
|
||||
Retrieve information about the last exception.
|
||||
On Win32, this information is always available
|
||||
*/
|
||||
AUKN_SYM AuString GetLastException();
|
||||
|
||||
/**
|
||||
Retrieve the last system error (IE: Win32, GetLastError())
|
||||
Retrieve the last system error (Example -> Win32, GetLastError())
|
||||
*/
|
||||
AUKN_SYM OSError_t GetLastSystemMessage();
|
||||
|
||||
@ -53,6 +48,9 @@ namespace Aurora::Debug
|
||||
|
||||
AUKN_SYM void CheckErrors();
|
||||
|
||||
|
||||
AUKN_SYM StackTrace GetStackTrace();
|
||||
|
||||
/**
|
||||
Immediately terminates the process.
|
||||
May attempt some hardened telemetry debug ops
|
||||
|
@ -12,7 +12,7 @@ namespace Aurora::Hashing
|
||||
class IHashStream
|
||||
{
|
||||
public:
|
||||
/*
|
||||
/**
|
||||
* Digest length of pBuf bytes
|
||||
*/
|
||||
virtual void Ingest(const void *pBuf, AuUInt32 length) = 0;
|
||||
|
12
Include/Aurora/IO/Character/Character.hpp
Normal file
12
Include/Aurora/IO/Character/Character.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Character.hpp
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
#include "ICharacterProvider.hpp"
|
||||
#include "IBufferedCharacterConsumer.hpp"
|
||||
#include "ILineBufferer.hpp"
|
13
Include/Aurora/IO/Character/IBufferedCharacterConsumer.hpp
Normal file
13
Include/Aurora/IO/Character/IBufferedCharacterConsumer.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: IBufferedCharacterConsumer.hpp
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::IO::Character
|
||||
{
|
||||
|
||||
}
|
15
Include/Aurora/IO/Character/ICharacterProvider.hpp
Normal file
15
Include/Aurora/IO/Character/ICharacterProvider.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: ICharacterProvider.hpp
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::IO::Character
|
||||
{
|
||||
AUKN_INTERFACE(ICharacterProvider,
|
||||
AUI_METHOD(AuUInt8, GetByte, ())
|
||||
);
|
||||
}
|
13
Include/Aurora/IO/Character/ILineBufferer.hpp
Normal file
13
Include/Aurora/IO/Character/ILineBufferer.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: ILineBufferer.hpp
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::IO::Character
|
||||
{
|
||||
|
||||
}
|
@ -33,7 +33,7 @@ namespace Aurora::IO::Net
|
||||
eIPProtocolV6
|
||||
));
|
||||
|
||||
struct IPAddress
|
||||
struct AUKN_SYM IPAddress
|
||||
{
|
||||
EIPProtocol ip;
|
||||
union
|
||||
@ -42,10 +42,17 @@ namespace Aurora::IO::Net
|
||||
AuUInt16 v6[8];
|
||||
};
|
||||
|
||||
AUKN_SYM IPAddress(const AuString &parse);
|
||||
IPAddress();
|
||||
IPAddress(const AuString &parse);
|
||||
|
||||
AUKN_SYM AuString ToString();
|
||||
AUKN_SYM bool IsValid();
|
||||
AuString ToString() const;
|
||||
bool IsValid() const;
|
||||
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
inline bool operator ==(const IPAddress &cmp) const
|
||||
{
|
||||
@ -268,7 +275,7 @@ namespace Aurora::IO::Net
|
||||
// Attempts to seek backwards or forwards in the UDP or TCP packet
|
||||
// If you are under the callstack of a HasXXXHasData callback, you are guaranteed (bufferedReadSize - streamPosition - streamRemaining) bytes backwards
|
||||
//
|
||||
virtual bool SeekAsync(int signedDistanceFromCur = 0);
|
||||
virtual bool SeekAsync(int signedDistanceFromCur = 0) = 0;
|
||||
|
||||
// When BufferInputStreamAdhoc is called with false / in the default condition, read sync will be constrained by the async buffer
|
||||
// When BufferInputStreamAdhoc is called with true, you will block until you can get the requested data (all of it if, all = true; any of it, all = false)
|
||||
@ -415,18 +422,42 @@ namespace Aurora::IO::Net
|
||||
virtual AuSPtr<ISocketFactory> GetSocketFactory() = 0;
|
||||
};
|
||||
|
||||
struct AUKN_SYM WorkRange
|
||||
{
|
||||
WorkRange();
|
||||
|
||||
AuUInt8 workerOffsetOrAny;
|
||||
AuUInt8 workerCountOrAny;
|
||||
};
|
||||
|
||||
struct AUKN_SYM WorkPoolGroup
|
||||
{
|
||||
WorkPoolGroup();
|
||||
|
||||
AuSPtr<Async::IThreadPool> pool; // optional -> defaults to async apps core loop
|
||||
AuUInt8 asyncWorkGroup;
|
||||
AuUInt8 asyncWorkPoolOffsetOrAny;
|
||||
WorkRange range;
|
||||
};
|
||||
|
||||
struct INetworkingPool
|
||||
{
|
||||
// A:
|
||||
virtual AuUInt32 Pump(int idx) = 0;
|
||||
virtual AuUInt32 Pump(AuUInt8 workerId) = 0;
|
||||
|
||||
// B:
|
||||
virtual AuUInt32 PumpRead(int idx) = 0;
|
||||
virtual AuUInt32 PumpWrite(int idx) = 0;
|
||||
virtual AuUInt32 PumpRead(AuUInt8 workerId) = 0;
|
||||
virtual AuUInt32 PumpWrite(AuUInt8 workerId) = 0;
|
||||
|
||||
// C:
|
||||
virtual AuUInt32 PollWorker(int idx) = 0;
|
||||
virtual AuUInt32 RunWorker(int idx, AuUInt32 timeout) = 0;
|
||||
virtual AuUInt32 PollWorker(AuUInt8 workerId) = 0;
|
||||
virtual AuUInt32 RunWorker(AuUInt8 workerId, AuUInt32 timeout) = 0;
|
||||
|
||||
|
||||
// D: class APIs
|
||||
virtual bool BeginReadPollingOnWorkQueues(const WorkPoolGroup &workGroup) = 0;
|
||||
virtual bool BeginSubmissionsOnOnWorkQueues(const WorkPoolGroup &workGroup) = 0;
|
||||
virtual void StopPollingOnWorkQueues() = 0;
|
||||
|
||||
virtual AuUInt8 GetWorkers() = 0;
|
||||
|
||||
@ -435,34 +466,10 @@ namespace Aurora::IO::Net
|
||||
virtual void Shutdown() = 0;
|
||||
};
|
||||
|
||||
AUE_DEFINE(ENetworkPoolModel, (
|
||||
|
||||
// Do not attach to a thread subsystem
|
||||
eNoHooks,
|
||||
|
||||
/// given a group id, uses prespawned async application event queues
|
||||
eAsyncApp,
|
||||
|
||||
/// it just werks
|
||||
eInternalThreadPool,
|
||||
|
||||
/// Developer intends to call the INetworkingPoll poll functions with the respective thread id
|
||||
eUserCreateThreadRunnable
|
||||
))
|
||||
|
||||
struct NetworkPool
|
||||
{
|
||||
AuUInt8 workers {1};
|
||||
|
||||
ENetworkPoolModel mode;
|
||||
|
||||
AuUInt8 asyncWorkGroup {};
|
||||
AuUInt8 asyncWorkerIdOffset {};
|
||||
|
||||
AuSPtr<Async::IThreadPool> threadPool;
|
||||
|
||||
/// Ignore me. Used on platforms that suck (win32) when the model is defined as eAsyncApp or eAsyncThreadPool
|
||||
AuUInt32 frequencyNotAsync {50};
|
||||
};
|
||||
|
||||
AUKN_SHARED_API(CreateNetworkPool, INetworkingPool, const NetworkPool & meta);
|
||||
|
@ -21,6 +21,6 @@ namespace Aurora::Parse
|
||||
AUKN_SYM void ByteToHex(AuUInt8 val, char(&hex)[2]);
|
||||
AUKN_SYM bool HexToInt (const char *hex, AuUInt32 length, AuUInt64 &val);
|
||||
|
||||
AUKN_SYM void EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &out);
|
||||
AUKN_SYM bool EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &out);
|
||||
AUKN_SYM bool DecodeHex(const AuString &in, Memory::ByteBuffer &out);
|
||||
}
|
@ -9,10 +9,13 @@
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
enum class ESpawnType
|
||||
{
|
||||
eSpawnAtomicOvermap, // posix: exec, win32: i dunno
|
||||
eSpawnChildProcessWorker, // posix: thread, win32: job process
|
||||
eSpawnThreadLeader // posix: thread leader / new sid / pid != 0 daemon, win32: process
|
||||
};
|
||||
AUE_DEFINE(ESpawnType,
|
||||
(
|
||||
// posix: exec, win32: i dunno
|
||||
eSpawnAtomicOvermap,
|
||||
// posix: thread, win32: job process
|
||||
eSpawnChildProcessWorker,
|
||||
// posix: thread leader / new sid / pid != 0 daemon, win32: process
|
||||
eSpawnThreadLeader
|
||||
));
|
||||
}
|
11
Include/Aurora/Processes/EStandardHandle.hpp
Normal file
11
Include/Aurora/Processes/EStandardHandle.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
AUE_DEFINE(EStandardHandle,
|
||||
(
|
||||
eStdIn,
|
||||
eStdOut,
|
||||
eStdError
|
||||
));
|
||||
}
|
@ -28,9 +28,7 @@ namespace Aurora::Processes
|
||||
|
||||
virtual AuUInt GetProcessId() = 0;
|
||||
|
||||
///
|
||||
// TODO(Reece): what in the hell this is ugly
|
||||
virtual bool Start(enum ESpawnType, bool fwdOut, bool fwdErr, bool fwdIn) = 0;
|
||||
virtual bool Start() = 0;
|
||||
|
||||
virtual bool Terminate() = 0;
|
||||
virtual bool TryKill() = 0;
|
||||
|
@ -8,7 +8,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ESpawnType.hpp"
|
||||
#include "EStandardHandle.hpp"
|
||||
#include "IProcess.hpp"
|
||||
#include "StartupParmaters.hpp"
|
||||
#include "Spawn.hpp"
|
||||
#include "UtilRun.hpp"
|
||||
|
||||
|
@ -9,5 +9,5 @@
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
AUKN_SHARED_API(Spawn, IProcess, const AuString &app, const AuList<AuString> &args);
|
||||
AUKN_SHARED_API(Spawn, IProcess, const StartupParmaters &startup);
|
||||
}
|
15
Include/Aurora/Processes/StartupParmaters.hpp
Normal file
15
Include/Aurora/Processes/StartupParmaters.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
struct StartupParmaters
|
||||
{
|
||||
AuString process;
|
||||
AuList<AuString> args;
|
||||
enum ESpawnType type;
|
||||
bool fwdOut {};
|
||||
bool fwdErr {};
|
||||
bool fwdIn {};
|
||||
bool noShowConsole {}; // Hides conhost or otherwise blanks stdin/out handles
|
||||
};
|
||||
}
|
@ -10,8 +10,9 @@
|
||||
#include <Source/Telemetry/Telemetry.hpp>
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#include "ExceptionWatcher.NT.hpp"
|
||||
#include "ExceptionWatcher.Win32.hpp"
|
||||
#include "ExceptionWatcher.NT.hpp"
|
||||
#include "ExceptionWatcher.Win32.hpp"
|
||||
#include "Stack.Win32.hpp"
|
||||
#endif
|
||||
|
||||
namespace Aurora::Debug
|
||||
@ -200,7 +201,11 @@ namespace Aurora::Debug
|
||||
|
||||
AUKN_SYM StackTrace GetStackTrace()
|
||||
{
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
return PlatformWalkCallStack();
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
AUKN_SYM AuString GetLastException()
|
||||
|
@ -138,7 +138,6 @@ namespace Aurora::Debug
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
static void HandleFatal(bool fatal, _EXCEPTION_POINTERS *pExceptionInfo)
|
||||
{
|
||||
static bool handlingFatal = false;
|
||||
|
@ -128,4 +128,3 @@ namespace Aurora::Debug
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
0
Source/IO/Character/BufferedCharacterConsumer.cpp
Normal file
0
Source/IO/Character/BufferedCharacterConsumer.cpp
Normal file
0
Source/IO/Character/BufferedCharacterConsumer.hpp
Normal file
0
Source/IO/Character/BufferedCharacterConsumer.hpp
Normal file
0
Source/IO/Character/LineBuffer.cpp
Normal file
0
Source/IO/Character/LineBuffer.cpp
Normal file
0
Source/IO/Character/LineBuffer.hpp
Normal file
0
Source/IO/Character/LineBuffer.hpp
Normal file
@ -193,7 +193,7 @@ namespace Aurora::Parse
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM void EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &in)
|
||||
AUKN_SYM bool EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &in)
|
||||
{
|
||||
bool hexedit = formatting == EHexDump::eHexEditor;
|
||||
|
||||
@ -206,100 +206,111 @@ namespace Aurora::Parse
|
||||
|
||||
bool space = formatting != EHexDump::eString;
|
||||
|
||||
in.reserve(length * 4);
|
||||
|
||||
auto &newLine = AuLocale::NewLine();
|
||||
|
||||
if (hexedit)
|
||||
try
|
||||
{
|
||||
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15");
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.size(), " ");
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
else if (squareBracket)
|
||||
{
|
||||
in.insert(in.end(), '[');
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
else if (curlyBracket)
|
||||
{
|
||||
in.insert(in.end(), '{');
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; )
|
||||
{
|
||||
AuUInt32 x, rowMax;
|
||||
in.reserve(length * 4);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
if (hexedit || squareBracket || curlyBracket)
|
||||
{
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (squareBracket || curlyBracket)
|
||||
{
|
||||
in.insert(in.size(), " ");
|
||||
}
|
||||
|
||||
rowMax = AuMin(AuUInt32(i + 16), AuUInt32(length));
|
||||
|
||||
for (x = i;
|
||||
x < rowMax;
|
||||
x ++)
|
||||
{
|
||||
if (space)
|
||||
{
|
||||
if (x != i)
|
||||
{
|
||||
in.insert(in.end(), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
if (zeroX)
|
||||
{
|
||||
in.insert(in.size(), "0x");
|
||||
}
|
||||
|
||||
{
|
||||
char hex[2];
|
||||
ByteToHex(reinterpret_cast<const AuUInt8*>(pBuf)[x], hex);
|
||||
in.insert(in.size(), hex, 2);
|
||||
}
|
||||
|
||||
if (x != (length - 1))
|
||||
{
|
||||
if (squareBracket || curlyBracket)
|
||||
{
|
||||
in.insert(in.end(), ',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = x;
|
||||
auto &newLine = AuLocale::NewLine();
|
||||
|
||||
if (hexedit)
|
||||
{
|
||||
// TODO: print space + i * 16 padded + space hex(i * 16 padded)
|
||||
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15");
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.size(), " ");
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
else if (squareBracket)
|
||||
{
|
||||
in.insert(in.end(), '[');
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
else if (curlyBracket)
|
||||
{
|
||||
in.insert(in.end(), '{');
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (squareBracket)
|
||||
{
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.end(), ']');
|
||||
}
|
||||
else if (curlyBracket)
|
||||
{
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.end(), '}');
|
||||
}
|
||||
for (int i = 0; i < length; )
|
||||
{
|
||||
AuUInt32 x, rowMax;
|
||||
|
||||
in.shrink_to_fit();
|
||||
if (i != 0)
|
||||
{
|
||||
if (hexedit || squareBracket || curlyBracket)
|
||||
{
|
||||
in.insert(in.size(), newLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (squareBracket || curlyBracket)
|
||||
{
|
||||
in.insert(in.size(), " ");
|
||||
}
|
||||
|
||||
rowMax = AuMin(AuUInt32(i + 16), AuUInt32(length));
|
||||
|
||||
for (x = i;
|
||||
x < rowMax;
|
||||
x++)
|
||||
{
|
||||
if (space)
|
||||
{
|
||||
if (x != i)
|
||||
{
|
||||
in.insert(in.end(), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
if (zeroX)
|
||||
{
|
||||
in.insert(in.size(), "0x");
|
||||
}
|
||||
|
||||
{
|
||||
char hex[2];
|
||||
ByteToHex(reinterpret_cast<const AuUInt8 *>(pBuf)[x], hex);
|
||||
in.insert(in.size(), hex, 2);
|
||||
}
|
||||
|
||||
if (x != (length - 1))
|
||||
{
|
||||
if (squareBracket || curlyBracket)
|
||||
{
|
||||
in.insert(in.end(), ',');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = x;
|
||||
|
||||
if (hexedit)
|
||||
{
|
||||
// TODO: print space + i * 16 padded + space hex(i * 16 padded)
|
||||
}
|
||||
}
|
||||
|
||||
if (squareBracket)
|
||||
{
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.end(), ']');
|
||||
}
|
||||
else if (curlyBracket)
|
||||
{
|
||||
in.insert(in.size(), newLine);
|
||||
in.insert(in.end(), '}');
|
||||
}
|
||||
|
||||
in.shrink_to_fit();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
SysPushErrorGen("EncodeHex failed");
|
||||
in.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
404
Source/Processes/Process.NT.cpp
Normal file
404
Source/Processes/Process.NT.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Process.NT.cpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Processes.hpp"
|
||||
#include "Process.Win32.hpp"
|
||||
#include <process.h>
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#include "Process.Win32.hpp"
|
||||
#endif
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
class ProcessImpl : public IProcess
|
||||
{
|
||||
public:
|
||||
ProcessImpl(const StartupParmaters ¶ms);
|
||||
~ProcessImpl();
|
||||
|
||||
bool TermWinEnumProcesses();
|
||||
|
||||
bool TryKill() override;
|
||||
bool HasExited();
|
||||
|
||||
AuUInt GetProcessId() override;
|
||||
|
||||
bool Terminate() override;
|
||||
AuSPtr<Threading::IWaitable> AsWaitable() override;
|
||||
AuSInt GetExitCode() override;
|
||||
|
||||
void ShutdownPipes();
|
||||
|
||||
bool Read(bool error, void *buffer, AuUInt32 &len) override;
|
||||
bool Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock) override;
|
||||
|
||||
bool Write(const void *buffer, AuUInt32 len) override;
|
||||
|
||||
bool Start() override;
|
||||
|
||||
bool Init();
|
||||
|
||||
private:
|
||||
|
||||
HANDLE pipeStdOutRead_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdOutWrite_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdErrRead_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdErrWrite_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdInRead_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdInWrite_ {INVALID_HANDLE_VALUE};
|
||||
|
||||
StartupParmaters startup_;
|
||||
ESpawnType type_;
|
||||
|
||||
AuList<const char *> cargs_;
|
||||
AuString windowsCli_;
|
||||
|
||||
AuThreads::ThreadUnique_t thread_;
|
||||
HANDLE process_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE hthread_ {INVALID_HANDLE_VALUE};
|
||||
AuSInt exitCode_;
|
||||
};
|
||||
|
||||
|
||||
ProcessImpl::ProcessImpl(const StartupParmaters ¶ms) : startup_(params)
|
||||
{
|
||||
startup_.args.insert(startup_.args.begin(), startup_.process);
|
||||
|
||||
// ehhhh https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
|
||||
for (const auto &arg : this->startup_.args)
|
||||
{
|
||||
this->cargs_.push_back(arg.c_str());
|
||||
this->windowsCli_ += arg + " ";
|
||||
}
|
||||
|
||||
this->cargs_.push_back(nullptr);
|
||||
this->windowsCli_.resize(this->windowsCli_.size() - 1);
|
||||
this->type_ = params.type;
|
||||
}
|
||||
|
||||
ProcessImpl::~ProcessImpl()
|
||||
{
|
||||
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
||||
{
|
||||
TryKill();
|
||||
Terminate();
|
||||
}
|
||||
|
||||
if (this->thread_)
|
||||
{
|
||||
this->thread_.reset();
|
||||
}
|
||||
|
||||
AuWin32CloseHandle(this->process_);
|
||||
AuWin32CloseHandle(this->hthread_);
|
||||
|
||||
ShutdownPipes();
|
||||
}
|
||||
|
||||
AuUInt ProcessImpl::GetProcessId()
|
||||
{
|
||||
if (this->process_ == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return ::GetProcessId(this->process_);
|
||||
}
|
||||
|
||||
bool ProcessImpl::TermWinEnumProcesses()
|
||||
{
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
return SendExitSignal(this->process_);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ProcessImpl::TryKill()
|
||||
{
|
||||
return TermWinEnumProcesses();
|
||||
}
|
||||
|
||||
bool ProcessImpl::HasExited()
|
||||
{
|
||||
DWORD a;
|
||||
if (!GetExitCodeProcess(this->process_, &a)) return true;
|
||||
return a != STILL_ACTIVE;
|
||||
}
|
||||
|
||||
bool ProcessImpl::Terminate()
|
||||
{
|
||||
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TerminateProcess(this->process_, 0) || HasExited();
|
||||
}
|
||||
|
||||
AuSPtr<Threading::IWaitable> ProcessImpl::AsWaitable()
|
||||
{
|
||||
if (!this->thread_) return nullptr;
|
||||
return this->thread_->AsWaitable();
|
||||
}
|
||||
|
||||
AuSInt ProcessImpl::GetExitCode()
|
||||
{
|
||||
return this->exitCode_;
|
||||
}
|
||||
|
||||
void ProcessImpl::ShutdownPipes()
|
||||
{
|
||||
AuWin32CloseHandle(this->pipeStdOutRead_);
|
||||
AuWin32CloseHandle(this->pipeStdOutWrite_);
|
||||
AuWin32CloseHandle(this->pipeStdErrRead_);
|
||||
AuWin32CloseHandle(this->pipeStdErrWrite_);
|
||||
AuWin32CloseHandle(this->pipeStdInRead_);
|
||||
AuWin32CloseHandle(this->pipeStdInWrite_);
|
||||
}
|
||||
|
||||
bool ProcessImpl::Read(bool error, void *buffer, AuUInt32 &len)
|
||||
{
|
||||
return Read(buffer, len, error, false);
|
||||
}
|
||||
|
||||
bool ProcessImpl::Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock)
|
||||
{
|
||||
DWORD size = AuExchange(len, 0);
|
||||
|
||||
auto handle = errorStream ? pipeStdErrRead_ : pipeStdOutRead_;
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nonblock)
|
||||
{
|
||||
DWORD avail {};
|
||||
if (!PeekNamedPipe(handle, NULL, NULL, NULL, &avail, NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!avail)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size = AuMin(size, avail);
|
||||
}
|
||||
|
||||
auto ret = ReadFile(handle, buffer, size, &size, NULL);
|
||||
len = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ProcessImpl::Write(const void *buffer, AuUInt32 len)
|
||||
{
|
||||
DWORD size = len;
|
||||
if (pipeStdInWrite_ == INVALID_HANDLE_VALUE) return false;
|
||||
return WriteFile(pipeStdInWrite_, buffer, size, &size, NULL) && size == len;
|
||||
}
|
||||
|
||||
|
||||
bool ProcessImpl::Init()
|
||||
{
|
||||
SECURITY_ATTRIBUTES saAttr {};
|
||||
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
|
||||
if (this->type_ == ESpawnType::eSpawnAtomicOvermap)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->exitCode_ = 0x10110100;
|
||||
if (this->startup_.fwdOut)
|
||||
{
|
||||
if (!CreatePipe(&pipeStdOutRead_, &pipeStdOutWrite_, &saAttr, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation(pipeStdOutRead_, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->startup_.fwdErr)
|
||||
{
|
||||
if (!CreatePipe(&pipeStdErrRead_, &pipeStdErrWrite_, &saAttr, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation(pipeStdErrRead_, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->startup_.fwdIn)
|
||||
{
|
||||
if (!CreatePipe(&pipeStdInRead_, &pipeStdInWrite_, &saAttr, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation(pipeStdInWrite_, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->startup_.noShowConsole)
|
||||
{
|
||||
HANDLE nulFile = INVALID_HANDLE_VALUE;
|
||||
|
||||
// I dont want to move the other SetHandleInformations down below the if block above is, just to find out double SetHandleInfo with the same input params results in a return false condition
|
||||
// This will do for.now
|
||||
#define CHK_NUL \
|
||||
if (nulFile == INVALID_HANDLE_VALUE) \
|
||||
{ \
|
||||
nulFile = CreateFileA("nul:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); \
|
||||
SetHandleInformation(nulFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); \
|
||||
}
|
||||
|
||||
if (this->pipeStdInRead_ == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CHK_NUL;
|
||||
this->pipeStdInRead_ = nulFile;
|
||||
}
|
||||
|
||||
if (this->pipeStdErrWrite_ == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CHK_NUL;
|
||||
this->pipeStdErrWrite_ = nulFile;
|
||||
}
|
||||
|
||||
if (this->pipeStdOutWrite_ == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CHK_NUL;
|
||||
this->pipeStdOutWrite_ = nulFile;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessImpl::Start()
|
||||
{
|
||||
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->type_ == ESpawnType::eSpawnAtomicOvermap)
|
||||
{
|
||||
_spawnv(_P_OVERLAY, this->startup_.process.c_str(), this->cargs_.data());
|
||||
SysPushErrorGen("_spawnv didn't overwrite the process map, given {} ({})", this->startup_.process, this->windowsCli_);
|
||||
return false;
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION processInfo = { 0 };
|
||||
{
|
||||
STARTUPINFOW startupInfo = { 0 };
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
bool inheritHandles = this->startup_.fwdIn || this->startup_.fwdErr || this->startup_.fwdOut || this->startup_.noShowConsole;
|
||||
|
||||
startupInfo.hStdInput = pipeStdInRead_;
|
||||
startupInfo.hStdError = pipeStdErrWrite_;
|
||||
startupInfo.hStdOutput = pipeStdOutWrite_;
|
||||
startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0);
|
||||
|
||||
auto result = CreateProcessW(Locale::ConvertFromUTF8(this->startup_.process).c_str(),
|
||||
Locale::ConvertFromUTF8(this->windowsCli_).data(),
|
||||
NULL, NULL, inheritHandles,
|
||||
this->startup_.noShowConsole ? CREATE_NO_WINDOW : NULL, // yea we can keep CREATE_NO_WINDOW on for non-console apps. its legal -> https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
|
||||
NULL, NULL, &startupInfo, &processInfo);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
SysPushErrorGen("CreateProcess failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->process_ = processInfo.hProcess;
|
||||
this->hthread_ = processInfo.hThread;
|
||||
|
||||
AuWin32CloseHandle(this->pipeStdOutRead_);
|
||||
AuWin32CloseHandle(this->pipeStdErrRead_);
|
||||
AuWin32CloseHandle(this->pipeStdInWrite_);
|
||||
|
||||
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
||||
{
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
AssignJobWorker(processInfo.hProcess);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: delegate to a singular worker thread
|
||||
auto a = [=]()
|
||||
{
|
||||
WaitForSingleObject(processInfo.hProcess, INFINITE);
|
||||
|
||||
DWORD exitCode;
|
||||
auto result = GetExitCodeProcess(processInfo.hProcess, &exitCode);
|
||||
this->exitCode_ = exitCode;
|
||||
};
|
||||
|
||||
this->thread_ = AuThreads::ThreadUnique(AuThreads::ThreadInfo(
|
||||
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(a)),
|
||||
AuThreads::IThreadVectorsFunctional::OnExit_t{})
|
||||
));
|
||||
|
||||
if (!this->thread_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->thread_->Run();
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM IProcess *SpawnNew(const StartupParmaters ¶ms)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto hi = _new ProcessImpl(params);
|
||||
if (!hi) return {};
|
||||
|
||||
if (!hi->Init())
|
||||
{
|
||||
delete hi;
|
||||
return {};
|
||||
}
|
||||
|
||||
return hi;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
AUKN_SYM void SpawnRelease(IProcess *process)
|
||||
{
|
||||
SafeDelete<ProcessImpl *>(process);
|
||||
}
|
||||
}
|
13
Source/Processes/Process.NT.hpp
Normal file
13
Source/Processes/Process.NT.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
/***
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Process.NT.hpp
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
Copyright (C) 2021-2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Process.Win32.cpp
|
||||
Date: 2021-6-12
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "Processes.hpp"
|
||||
#include "Process.Win32.hpp"
|
||||
#include <shellapi.h>
|
||||
#include <tlhelp32.h>
|
||||
@ -38,98 +37,26 @@ namespace Aurora::Processes
|
||||
AuWin32CloseHandle(gLeaderJob);
|
||||
}
|
||||
|
||||
class ProcessImpl : public IProcess
|
||||
void AssignJobWorker(HANDLE handle)
|
||||
{
|
||||
public:
|
||||
ProcessImpl(AuString execModule, AuList<AuString> args);
|
||||
~ProcessImpl();
|
||||
|
||||
bool TermWinEnumProcesses();
|
||||
|
||||
bool TryKill() override;
|
||||
bool HasExited();
|
||||
|
||||
AuUInt GetProcessId() override;
|
||||
|
||||
bool Terminate() override;
|
||||
AuSPtr<Threading::IWaitable> AsWaitable() override;
|
||||
AuSInt GetExitCode() override;
|
||||
|
||||
void ShutdownPipes();
|
||||
|
||||
bool Read(bool error, void *buffer, AuUInt32 &len) override;
|
||||
bool Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock) override;
|
||||
|
||||
bool Write(const void *buffer, AuUInt32 len) override;
|
||||
|
||||
// TODO: what in the hell this is ugly
|
||||
bool Start(enum ESpawnType type, bool fwdOut, bool fwdErr, bool fwdIn) override;
|
||||
|
||||
private:
|
||||
|
||||
HANDLE pipeStdOutRead_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdOutWrite_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdErrRead_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdErrWrite_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdInRead_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE pipeStdInWrite_ {INVALID_HANDLE_VALUE};
|
||||
|
||||
AuString execModule_;
|
||||
ESpawnType type_;
|
||||
|
||||
AuList<AuString> args_;
|
||||
AuList<const char *> cargs_;
|
||||
AuString windowsCli_;
|
||||
|
||||
AuThreads::ThreadUnique_t thread_;
|
||||
HANDLE process_ {INVALID_HANDLE_VALUE};
|
||||
HANDLE hthread_ {INVALID_HANDLE_VALUE};
|
||||
AuSInt exitCode_;
|
||||
};
|
||||
|
||||
|
||||
ProcessImpl::ProcessImpl(AuString execModule, AuList<AuString> args) : execModule_(execModule), args_(args)
|
||||
{
|
||||
this->args_.insert(this->args_.begin(), execModule);
|
||||
|
||||
// ehhhh https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
|
||||
for (const auto &arg : this->args_)
|
||||
if (gLeaderJob)
|
||||
{
|
||||
this->cargs_.push_back(arg.c_str());
|
||||
this->windowsCli_ += arg + " ";
|
||||
if (!AssignProcessToJobObject(gLeaderJob, handle))
|
||||
{
|
||||
SysPushErrorGen("Could not AssignProcessToObject");
|
||||
}
|
||||
}
|
||||
|
||||
this->cargs_.push_back(nullptr);
|
||||
this->windowsCli_.resize(this->windowsCli_.size() - 1);
|
||||
}
|
||||
|
||||
ProcessImpl::~ProcessImpl()
|
||||
static bool HasWin32ProcessExited(HANDLE handle)
|
||||
{
|
||||
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
||||
DWORD exitCode;
|
||||
if (!GetExitCodeProcess(handle, &exitCode))
|
||||
{
|
||||
TryKill();
|
||||
Terminate();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->thread_)
|
||||
{
|
||||
this->thread_.reset();
|
||||
}
|
||||
|
||||
AuWin32CloseHandle(this->process_);
|
||||
AuWin32CloseHandle(this->hthread_);
|
||||
|
||||
ShutdownPipes();
|
||||
}
|
||||
|
||||
AuUInt ProcessImpl::GetProcessId()
|
||||
{
|
||||
if (this->process_ == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return ::GetProcessId(this->process_);
|
||||
return exitCode != STILL_ACTIVE;
|
||||
}
|
||||
|
||||
static BOOL TermWinHandleWin32Thread(HWND handle, LPARAM a)
|
||||
@ -139,17 +66,12 @@ namespace Aurora::Processes
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessImpl::TermWinEnumProcesses()
|
||||
static bool SendExtermianteWinloopCloseMessages(HANDLE handle)
|
||||
{
|
||||
THREADENTRY32 te{};
|
||||
HANDLE h{};
|
||||
|
||||
if (this->process_ == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetProcessId());
|
||||
h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetProcessId(handle));
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
@ -177,229 +99,57 @@ namespace Aurora::Processes
|
||||
return false;
|
||||
}
|
||||
|
||||
return Threading::YieldPoll(true, 2500, [=]()
|
||||
{
|
||||
return !HasExited();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessImpl::TryKill()
|
||||
static bool SendControlCEquiv(HANDLE handle)
|
||||
{
|
||||
return TermWinEnumProcesses();
|
||||
}
|
||||
|
||||
bool ProcessImpl::HasExited()
|
||||
{
|
||||
DWORD a;
|
||||
if (!GetExitCodeProcess(this->process_, &a)) return true;
|
||||
return a != STILL_ACTIVE;
|
||||
}
|
||||
|
||||
bool ProcessImpl::Terminate()
|
||||
{
|
||||
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||
if (!(AttachConsole(GetProcessId(handle))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TerminateProcess(this->process_, 0) || HasExited();
|
||||
if (SetConsoleCtrlHandler({}, true))
|
||||
{
|
||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||
SysAssert(FreeConsole(), "Couldn't pop off zombie process console");
|
||||
Sleep(750);
|
||||
}
|
||||
else
|
||||
{
|
||||
SysAssert(FreeConsole(), "Couldn't pop off zombie process console");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetConsoleCtrlHandler({}, true))
|
||||
{
|
||||
SysPushErrorHAL("Couldn't swap control+c handler -> wont accept control termination on exit");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AuSPtr<Threading::IWaitable> ProcessImpl::AsWaitable()
|
||||
static bool Wait2500OrUntilClose(HANDLE handle)
|
||||
{
|
||||
if (!this->thread_) return nullptr;
|
||||
return this->thread_->AsWaitable();
|
||||
return Threading::YieldPoll(true, 2500, [=]()
|
||||
{
|
||||
return !HasWin32ProcessExited(handle);
|
||||
});
|
||||
}
|
||||
|
||||
AuSInt ProcessImpl::GetExitCode()
|
||||
bool SendExitSignal(HANDLE handle)
|
||||
{
|
||||
return this->exitCode_;
|
||||
}
|
||||
|
||||
void ProcessImpl::ShutdownPipes()
|
||||
{
|
||||
AuWin32CloseHandle(this->pipeStdOutRead_);
|
||||
AuWin32CloseHandle(this->pipeStdOutWrite_);
|
||||
AuWin32CloseHandle(this->pipeStdErrRead_);
|
||||
AuWin32CloseHandle(this->pipeStdErrWrite_);
|
||||
AuWin32CloseHandle(this->pipeStdInRead_);
|
||||
AuWin32CloseHandle(this->pipeStdInWrite_);
|
||||
}
|
||||
|
||||
bool ProcessImpl::Read(bool error, void *buffer, AuUInt32 &len)
|
||||
{
|
||||
return Read(buffer, len, error, false);
|
||||
}
|
||||
|
||||
bool ProcessImpl::Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock)
|
||||
{
|
||||
DWORD size = AuExchange(len, 0);
|
||||
|
||||
auto handle = errorStream ? pipeStdErrRead_ : pipeStdOutRead_;
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nonblock)
|
||||
{
|
||||
DWORD avail {};
|
||||
if (!PeekNamedPipe(handle, NULL, NULL, NULL, &avail, NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!avail)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size = AuMin(size, avail);
|
||||
}
|
||||
|
||||
auto ret = ReadFile(handle, buffer, size, &size, NULL);
|
||||
len = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ProcessImpl::Write(const void *buffer, AuUInt32 len)
|
||||
{
|
||||
DWORD size = len;
|
||||
if (pipeStdInWrite_ == INVALID_HANDLE_VALUE) return false;
|
||||
return WriteFile(pipeStdInWrite_, buffer, size, &size, NULL) && size == len;
|
||||
}
|
||||
|
||||
bool ProcessImpl::Start(enum ESpawnType type, bool fwdOut, bool fwdErr, bool fwdIn)
|
||||
{
|
||||
this->exitCode_ = 0x10110100;
|
||||
this->type_ = type;
|
||||
|
||||
if (type == ESpawnType::eSpawnAtomicOvermap)
|
||||
{
|
||||
_spawnv(_P_OVERLAY, this->execModule_.c_str(), this->cargs_.data());
|
||||
SysPushErrorGen("_spawnv didn't overwrite the process map, given {} ({})", this->execModule_, this->windowsCli_);
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
SECURITY_ATTRIBUTES saAttr{};
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
|
||||
if (fwdOut)
|
||||
{
|
||||
if (!CreatePipe(&pipeStdOutRead_, &pipeStdOutWrite_, &saAttr, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation(pipeStdOutRead_, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fwdErr)
|
||||
{
|
||||
if (!CreatePipe(&pipeStdErrRead_, &pipeStdErrWrite_, &saAttr, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation(pipeStdErrRead_, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fwdIn)
|
||||
{
|
||||
if (!CreatePipe(&pipeStdInRead_, &pipeStdInWrite_, &saAttr, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation(pipeStdInWrite_, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION processInfo = { 0 };
|
||||
{
|
||||
STARTUPINFOW startupInfo = { 0 };
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
bool inheritHandles = fwdIn || fwdErr || fwdOut;
|
||||
|
||||
startupInfo.hStdInput = pipeStdInRead_;
|
||||
startupInfo.hStdError = pipeStdErrWrite_;
|
||||
startupInfo.hStdOutput = pipeStdOutWrite_;
|
||||
startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0);
|
||||
|
||||
auto result = CreateProcessW(Locale::ConvertFromUTF8(this->execModule_).c_str(),
|
||||
Locale::ConvertFromUTF8(this->windowsCli_).data(),
|
||||
NULL, NULL, inheritHandles,
|
||||
NULL,
|
||||
NULL, NULL, &startupInfo, &processInfo);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
SysPushErrorGen("CreateProcess failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->process_ = processInfo.hProcess;
|
||||
this->hthread_ = processInfo.hThread;
|
||||
|
||||
AuWin32CloseHandle(this->pipeStdOutRead_);
|
||||
AuWin32CloseHandle(this->pipeStdErrRead_);
|
||||
AuWin32CloseHandle(this->pipeStdInWrite_);
|
||||
|
||||
if (type == ESpawnType::eSpawnChildProcessWorker)
|
||||
{
|
||||
if (gLeaderJob)
|
||||
{
|
||||
if (!AssignProcessToJobObject(gLeaderJob, processInfo.hProcess))
|
||||
{
|
||||
SysPushErrorGen("Could not AssignProcessToObject");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: delegate to a singular worker thread
|
||||
auto a = [=]()
|
||||
{
|
||||
WaitForSingleObject(processInfo.hProcess, INFINITE);
|
||||
|
||||
DWORD exitCode;
|
||||
auto result = GetExitCodeProcess(processInfo.hProcess, &exitCode);
|
||||
this->exitCode_ = exitCode;
|
||||
};
|
||||
|
||||
this->thread_ = AuThreads::ThreadUnique(AuThreads::ThreadInfo(
|
||||
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(a)),
|
||||
AuThreads::IThreadVectorsFunctional::OnExit_t{})
|
||||
));
|
||||
|
||||
if (!this->thread_)
|
||||
if (!(SendControlCEquiv(handle) // send GenerateConsoleCtrlEvent
|
||||
|| SendExtermianteWinloopCloseMessages(handle))) // send WM_CLOSE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->thread_->Run();
|
||||
return true;
|
||||
}
|
||||
|
||||
AUKN_SYM IProcess *SpawnNew(const AuString &app, const AuList<AuString> &args)
|
||||
{
|
||||
return _new ProcessImpl(app, args);
|
||||
}
|
||||
|
||||
AUKN_SYM void SpawnRelease(IProcess *process)
|
||||
{
|
||||
SafeDelete<ProcessImpl *>(process);
|
||||
return Wait2500OrUntilClose(handle);
|
||||
}
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Process.Win32.hpp
|
||||
Date: 2021-6-12
|
||||
Date: 2022-1-29
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
void InitWin32();
|
||||
void DeinitWin32();
|
||||
void InitWin32();
|
||||
void AssignJobWorker(HANDLE handle);
|
||||
bool SendExitSignal(HANDLE handle);
|
||||
}
|
@ -12,7 +12,7 @@ using high_res_clock = std::chrono::high_resolution_clock;
|
||||
using sys_clock = std::chrono::system_clock;
|
||||
|
||||
#if defined(AURORA_PLATFORM_WIN32)
|
||||
#define timegm _mkgmtime
|
||||
#define timegm _mkgmtime
|
||||
#endif
|
||||
|
||||
static sys_clock::duration gEpoch;
|
||||
@ -20,13 +20,7 @@ static sys_clock::duration gUnixDelta;
|
||||
|
||||
static auto InitEpoch()
|
||||
{
|
||||
std::tm start{};
|
||||
start.tm_mday = 29; // day number
|
||||
start.tm_mon = 7; // month idx, aug
|
||||
start.tm_year = 101; // 1900 + 101
|
||||
start.tm_hour = 9; // 11 - index - DST
|
||||
start.tm_min = 15; // minute offset
|
||||
|
||||
std::tm start{0, 15, 10, 29, 7, 101, 0, 0, 0};
|
||||
auto epoch = sys_clock::from_time_t(timegm(&start)).time_since_epoch();
|
||||
|
||||
std::tm unixStart{};
|
||||
|
@ -16,7 +16,7 @@ namespace Aurora::Time
|
||||
ULARGE_INTEGER ull;
|
||||
ull.LowPart = ft.dwLowDateTime;
|
||||
ull.HighPart = ft.dwHighDateTime;
|
||||
return ull.QuadPart / 10000ULL - 12'643'550'100'000ULL;
|
||||
return ull.QuadPart / 10000ULL - 12'643'553'700'000ULL;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user