[+] 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:
Reece Wilson 2023-07-10 16:29:38 +01:00
parent a977f0d1b5
commit bdec6ff8ba
13 changed files with 425 additions and 3 deletions

View File

@ -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
{ {

View 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);
}

View 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();
}

View File

@ -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

View File

@ -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

View 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;
}
}
}

View 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
{
}

View 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;
}
}

View 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
{
}

View 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));
}
}

View 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);
}

View 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());
}
}

View 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
{
}