[+] AuProcess::EnvironmentGetAll
[+] AuProcess::EnvironmentGetOne [+] AuProcess::EnvironmentSetOne [+] AuProcess::EnvironmentRemoveOne [+] AuProcess::EnvironmentRemoveMany [+] AuProcess::EnvironmentSetMany [+] AuProcess::GetProcessStartupTimeNS [+] AuProcess::GetProcessStartupTimeMS [*] Note WakeOnAddress on all platforms [*] Updated READMEs
This commit is contained in:
parent
a977f0d1b5
commit
bdec6ff8ba
@ -11,6 +11,8 @@
|
|||||||
#include "ProcessMap.hpp"
|
#include "ProcessMap.hpp"
|
||||||
#include "IProcessSectionMapView.hpp"
|
#include "IProcessSectionMapView.hpp"
|
||||||
#include "IProcessSectionView.hpp"
|
#include "IProcessSectionView.hpp"
|
||||||
|
#include "ProcessEnvironment.hpp"
|
||||||
|
#include "ProcessStartTime.hpp"
|
||||||
|
|
||||||
namespace Aurora::Process
|
namespace Aurora::Process
|
||||||
{
|
{
|
||||||
|
38
Include/Aurora/Process/ProcessEnvironment.hpp
Normal file
38
Include/Aurora/Process/ProcessEnvironment.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: ProcessEnvironment.hpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
|
||||||
|
Note: I can't stand environment variables.
|
||||||
|
They're leftover POSIX shitstains used for configuration during process initialization of yesteryear (muh 'stdio/out ipc all the tiny things to build big things' model of computer operating systems).
|
||||||
|
The underlying environ block as described by the POSIX specifications is inherently thread unsafe, and hasn't carried itself into the modern era of computing past its' usage for shell $%PATH$% expansion...
|
||||||
|
Well, maybe there's software in the UNIX ecosystem glued together with XDG_HOPES_AND_DREAMS. I try not to think about those.
|
||||||
|
Well, maybe I'm forgetting the primary user of env-vars... JAVA_HOME!!! I suppose we can't forget about those few Java programs that don't ship the JRE & have startup.[sh/bat] scripts.
|
||||||
|
|
||||||
|
Alternatives:
|
||||||
|
* Win32 users are better served by the Windows registry
|
||||||
|
* Linux drivers have module_param to avoid early file io
|
||||||
|
* NT drivers can query the registry via RtlXXXXX APIs
|
||||||
|
* Userland IPC identification between child processes can be served by AuCmdLine
|
||||||
|
* Unix services are a mess of non-standard configuration files
|
||||||
|
Depending on the use case and OS, early application configuration on modern Unix (^) will differ
|
||||||
|
^: IE: A MacOS application package, a Linux server program with nonstandard configs+yamls, or BSD systems with xml interfaces will all want different IO
|
||||||
|
* Sqlite for large application configuration stores
|
||||||
|
|
||||||
|
Warning:
|
||||||
|
Aurora Runtime, in a bid to support environment variables properly in userland (ie: not emulating the api with no real effects in real-time), does not buffer the block
|
||||||
|
Other code in a UNIX process can bypass the mutex required for that respective platform
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
AUKN_SYM AuList<AuPair<AuString, AuString>> EnvironmentGetAll();
|
||||||
|
AUKN_SYM AuOptional<AuString> EnvironmentGetOne(const AuString &key);
|
||||||
|
AUKN_SYM bool EnvironmentSetOne(const AuString &key, const AuString &value);
|
||||||
|
AUKN_SYM bool EnvironmentRemoveOne(const AuString &key);
|
||||||
|
AUKN_SYM bool EnvironmentRemoveMany(const AuList<AuString> &list);
|
||||||
|
AUKN_SYM bool EnvironmentSetMany(const AuList<AuPair<AuString, AuString>> &list);
|
||||||
|
}
|
21
Include/Aurora/Process/ProcessStartTime.hpp
Normal file
21
Include/Aurora/Process/ProcessStartTime.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: ProcessStartTime.hpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Defer to the AuTime namespace to convert the return unsigned integer to something useful
|
||||||
|
*/
|
||||||
|
AUKN_SYM AuUInt64 GetProcessStartupTimeNS();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defer to the AuTime namespace to convert the return unsigned integer to something useful
|
||||||
|
*/
|
||||||
|
AUKN_SYM AuUInt64 GetProcessStartupTimeMS();
|
||||||
|
}
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
# Features
|
# Features
|
||||||
* Thread synchronization primitives: condition ex, condition mutex, condition variable, critical section, event, mutex, rwlock, semaphore, and spinlock
|
* Thread synchronization primitives: condition ex, condition mutex, condition variable, critical section, event, mutex, rwlock, semaphore, and spinlock
|
||||||
* All primitives include a trylock and a timed lock member
|
* All primitives include a trylock and a nanosecond-resolution timed lock methods
|
||||||
* SleepNs function supporting higher resolution sleep available than in most APIs (^1)
|
* SleepNs function supporting higher resolution sleep available than in most APIs (^1)
|
||||||
|
* Enchanced Win32 support with increased yield resolution and optimization around internal XP, internal Win8, and UWP APIs
|
||||||
|
* WakeOnAddress support on every operating system regardless of kernel support
|
||||||
* Thread Object per native OS thread
|
* Thread Object per native OS thread
|
||||||
* Thread spawning with TLS handles and shutdown routines dispatched under pseudo fibers
|
* Thread spawning with TLS handles and shutdown routines dispatched under pseudo fibers
|
||||||
* Update thread affinity, throttle, name, and related attributes
|
* Update thread affinity, throttle, name, and related attributes
|
||||||
|
@ -18,12 +18,13 @@ pipeline to get started.
|
|||||||
- Crypto ECC/[25519, P-384, P-256], [AES, RSA, X509], CBC[AES, Stinky3DES], HMAC, HashCash, BCrypt, [common digests]
|
- Crypto ECC/[25519, P-384, P-256], [AES, RSA, X509], CBC[AES, Stinky3DES], HMAC, HashCash, BCrypt, [common digests]
|
||||||
- Basic cmdline parsing from any module
|
- Basic cmdline parsing from any module
|
||||||
- Exit and fatal save condition callbacks
|
- Exit and fatal save condition callbacks
|
||||||
- Random; secure, user-seeded, and fast
|
- Random; secure and fast user-seeded backends
|
||||||
- Hardware Info; memory and cpu info (including cpu feature bits, core topology, e-core awareness, and basic cache size)
|
- Hardware Info; memory and cpu info (including cpu feature bits, core topology, e-core awareness, and basic cache size)
|
||||||
- Software stack information for retrieving kernel, version, brand, family, build string, etc
|
- Software stack information for retrieving kernel, version, brand, family, build string, etc
|
||||||
- Compression (deflate, gzip, zstd, LZ4, bzip2, TODO: lzma, brotli)
|
- Compression (deflate, gzip, zstd, LZ4, bzip2, lzma, brotli)
|
||||||
- Locale and encoding
|
- Locale and encoding
|
||||||
- High performance threading and synchronization primitives (os userland sched optimized)
|
- High performance threading and synchronization primitives (os userland sched optimized)
|
||||||
|
- Alternative WakeOnAddress implementation for non-aurt/user synchronization primitives when kernel support is missing (polyfill when faced with old and/or locked down private APIs)
|
||||||
- Async subsystem backed by high performance sync primitives (cv loop) and hybrid switching into IO polling (think userland cv-backed promises + waitmultipleobjects)
|
- Async subsystem backed by high performance sync primitives (cv loop) and hybrid switching into IO polling (think userland cv-backed promises + waitmultipleobjects)
|
||||||
- IO subsystem for standard cross-platform IO loop queues, IPC (mutex with auto-unlock, semaphores, full-duplex single-connection pipes, and shared memory), file (direct uncached access), and network
|
- IO subsystem for standard cross-platform IO loop queues, IPC (mutex with auto-unlock, semaphores, full-duplex single-connection pipes, and shared memory), file (direct uncached access), and network
|
||||||
- Abstract kernel IO transactions, IPC objects, timers, semaphores, and others in the form of ILoopSources
|
- Abstract kernel IO transactions, IPC objects, timers, semaphores, and others in the form of ILoopSources
|
||||||
|
132
Source/Process/AuProcessEnvironment.NT.cpp
Normal file
132
Source/Process/AuProcessEnvironment.NT.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessEnvironment.NT.cpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <Source/RuntimeInternal.hpp>
|
||||||
|
#include "AuProcessEnvironment.hpp"
|
||||||
|
#include "AuProcessEnvironment.NT.hpp"
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
AUKN_SYM AuList<AuPair<AuString, AuString>> EnvironmentGetAll()
|
||||||
|
{
|
||||||
|
AuList<AuPair<AuString, AuString>> ret;
|
||||||
|
|
||||||
|
auto pWideStrings = ::GetEnvironmentStringsW();
|
||||||
|
auto pFreeBase = pWideStrings;
|
||||||
|
|
||||||
|
while (auto uLength = ::wcslen(pWideStrings))
|
||||||
|
{
|
||||||
|
auto utfString = AuLocale::ConvertFromWChar(pWideStrings, uLength);
|
||||||
|
|
||||||
|
if (utfString.empty())
|
||||||
|
{
|
||||||
|
::FreeEnvironmentStringsW(pFreeBase);
|
||||||
|
SysPushErrorNested();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto optSplit = EnvironmentSplitString(utfString);
|
||||||
|
if (optSplit)
|
||||||
|
{
|
||||||
|
ret.push_back(optSplit.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
::FreeEnvironmentStringsW(pFreeBase);
|
||||||
|
SysPushErrorCatch();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pWideStrings += uLength;
|
||||||
|
pWideStrings += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::FreeEnvironmentStringsW(pFreeBase);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM AuOptional<AuString> EnvironmentGetOne(const AuString &key)
|
||||||
|
{
|
||||||
|
auto keyString = AuLocale::ConvertFromUTF8(key);
|
||||||
|
|
||||||
|
if (keyString.empty())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto uLength = ::GetEnvironmentVariableW(keyString.c_str(),
|
||||||
|
nullptr,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (uLength == 0)
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
|
||||||
|
{
|
||||||
|
SysPushErrorResourceMissing();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring temp;
|
||||||
|
|
||||||
|
if (!AuTryResize(temp, uLength))
|
||||||
|
{
|
||||||
|
SysPushErrorMemory();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
uLength = ::GetEnvironmentVariableW(keyString.c_str(),
|
||||||
|
temp.data(),
|
||||||
|
temp.size());
|
||||||
|
|
||||||
|
if (!uLength)
|
||||||
|
{
|
||||||
|
SysPushErrorGeneric();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
temp.resize(uLength);
|
||||||
|
return AuLocale::ConvertFromWChar(temp.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM bool EnvironmentSetOne(const AuString &key, const AuString &value)
|
||||||
|
{
|
||||||
|
auto keyString = AuLocale::ConvertFromUTF8(key);
|
||||||
|
auto valString = AuLocale::ConvertFromUTF8(value);
|
||||||
|
|
||||||
|
if (keyString.empty() || valString.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::SetEnvironmentVariableW(keyString.c_str(),
|
||||||
|
valString.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM bool EnvironmentRemoveOne(const AuString &key)
|
||||||
|
{
|
||||||
|
std::wstring keyString;
|
||||||
|
|
||||||
|
if ((keyString = AuLocale::ConvertFromUTF8(key)).size())
|
||||||
|
{
|
||||||
|
return ::SetEnvironmentVariableW(keyString.c_str(), nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Source/Process/AuProcessEnvironment.NT.hpp
Normal file
13
Source/Process/AuProcessEnvironment.NT.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessEnvironment.NT.hpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
71
Source/Process/AuProcessEnvironment.Unix.cpp
Normal file
71
Source/Process/AuProcessEnvironment.Unix.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessEnvironment.Unix.cpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <Source/RuntimeInternal.hpp>
|
||||||
|
#include "AuProcessEnvironment.hpp"
|
||||||
|
#include "AuProcessEnvironment.Unix.hpp"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
static AuThreadPrimitives::Mutex gEnvMutex;
|
||||||
|
|
||||||
|
AUKN_SYM AuList<AuPair<AuString, AuString>> EnvironmentGetAll()
|
||||||
|
{
|
||||||
|
AU_LOCK_GUARD(gEnvMutex);
|
||||||
|
AuList<AuPair<AuString, AuString>> ret;
|
||||||
|
|
||||||
|
auto pIterator = environ;
|
||||||
|
while (auto pCurrent = *(pIterator++))
|
||||||
|
{
|
||||||
|
auto optSplit = EnvironmentSplitString(pCurrent);
|
||||||
|
if (optSplit)
|
||||||
|
{
|
||||||
|
ret.push_back(optSplit.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM AuOptional<AuString> EnvironmentGetOne(const AuString &key)
|
||||||
|
{
|
||||||
|
AU_LOCK_GUARD(gEnvMutex);
|
||||||
|
|
||||||
|
if (key.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pValue = ::getenv(key.c_str());
|
||||||
|
return pValue ? AuString(pValue) : AuOptional<AuString> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM bool EnvironmentSetOne(const AuString &key, const AuString &value)
|
||||||
|
{
|
||||||
|
AU_LOCK_GUARD(gEnvMutex);
|
||||||
|
|
||||||
|
if (key.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::setenv(key.c_str(), value.c_str(), 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM bool EnvironmentRemoveOne(const AuString &key)
|
||||||
|
{
|
||||||
|
AU_LOCK_GUARD(gEnvMutex);
|
||||||
|
|
||||||
|
if (key.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::unsetenv(key.c_str()) == 0;
|
||||||
|
}
|
||||||
|
}
|
13
Source/Process/AuProcessEnvironment.Unix.hpp
Normal file
13
Source/Process/AuProcessEnvironment.Unix.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessEnvironment.Unix.hpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
63
Source/Process/AuProcessEnvironment.cpp
Normal file
63
Source/Process/AuProcessEnvironment.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessEnvironment.cpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <Source/RuntimeInternal.hpp>
|
||||||
|
#include "AuProcessEnvironment.hpp"
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
AUKN_SYM bool EnvironmentRemoveMany(const AuList<AuString> &list)
|
||||||
|
{
|
||||||
|
bool bFailed {};
|
||||||
|
|
||||||
|
for (const auto &key : list)
|
||||||
|
{
|
||||||
|
if (!EnvironmentRemoveOne(key))
|
||||||
|
{
|
||||||
|
bFailed |= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !bFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AUKN_SYM bool EnvironmentSetMany(const AuList<AuPair<AuString, AuString>> &list)
|
||||||
|
{
|
||||||
|
for (const auto &[key, value] : list)
|
||||||
|
{
|
||||||
|
if (!EnvironmentSetOne(key, value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuOptional<AuPair<AuString, AuString>> EnvironmentSplitString(const AuString &str)
|
||||||
|
{
|
||||||
|
auto uIdx = str.find('=');
|
||||||
|
|
||||||
|
if (uIdx == str.npos)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uIdx == 0)
|
||||||
|
{
|
||||||
|
// Ignore Microsoft DOS shell environment hints
|
||||||
|
// Expect to see:
|
||||||
|
// <empty>=::=::\
|
||||||
|
// (opt) <empty>=<drive letter>:=<user home>
|
||||||
|
// (opt) <empty>=ExitCode={:08x}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuMakePair(str.substr(0, uIdx), str.substr(uIdx + 1));
|
||||||
|
}
|
||||||
|
}
|
13
Source/Process/AuProcessEnvironment.hpp
Normal file
13
Source/Process/AuProcessEnvironment.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessEnvironment.hpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
AuOptional<AuPair<AuString, AuString>> EnvironmentSplitString(const AuString &str);
|
||||||
|
}
|
40
Source/Process/AuProcessStartTime.cpp
Normal file
40
Source/Process/AuProcessStartTime.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessStartTime.cpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <Source/RuntimeInternal.hpp>
|
||||||
|
#include "AuProcessStartTime.hpp"
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
AUKN_SYM AuUInt64 GetProcessStartupTimeNS()
|
||||||
|
{
|
||||||
|
static AuOptional<AuUInt64> optKnownWallTime;
|
||||||
|
|
||||||
|
if (optKnownWallTime.has_value())
|
||||||
|
{
|
||||||
|
return optKnownWallTime.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto uUptime = AuTime::ProcessClockNS();
|
||||||
|
|
||||||
|
if (!uUptime)
|
||||||
|
{
|
||||||
|
optKnownWallTime = AuTime::CurrentClockNS();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
optKnownWallTime = AuTime::CurrentClockNS() - uUptime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return optKnownWallTime.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM AuUInt64 GetProcessStartupTimeMS()
|
||||||
|
{
|
||||||
|
return AuNSToMS<AuUInt64>(GetProcessStartupTimeNS());
|
||||||
|
}
|
||||||
|
}
|
13
Source/Process/AuProcessStartTime.hpp
Normal file
13
Source/Process/AuProcessStartTime.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: AuProcessStartTime.hpp
|
||||||
|
Date: 2023-7-10
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Process
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user