[*] Linux Progress... It compiles (APIs are out of date, subsystems are missing, and it doesn't link. Worse than being 5m behind)

This commit is contained in:
Reece Wilson 2022-04-05 11:11:19 +01:00
parent d32b84edf4
commit e25d8a65c8
18 changed files with 518 additions and 353 deletions

View File

@ -871,7 +871,7 @@ namespace Aurora::Async
if (!create) if (!create)
{ {
threadState->threadObject = AuThreads::ThreadUnique(AuThreads::ThreadInfo( threadState->threadObject = AuThreads::ThreadShared(AuThreads::ThreadInfo(
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(&ThreadPool::Entrypoint, this, threadState->id)), AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(&ThreadPool::Entrypoint, this, threadState->id)),
AuThreads::IThreadVectorsFunctional::OnExit_t{}), AuThreads::IThreadVectorsFunctional::OnExit_t{}),
gRuntimeConfig.async.threadPoolDefaultStackSize gRuntimeConfig.async.threadPoolDefaultStackSize

View File

@ -25,17 +25,12 @@ namespace Aurora::Logging
{ {
AUKN_SYM IBasicSink *NewStdSinkNew() AUKN_SYM IBasicSink *NewStdSinkNew()
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED)
return Sinks::NewStdSinkNew(); return Sinks::NewStdSinkNew();
#endif
return {};
} }
AUKN_SYM void NewStdSinkRelease(IBasicSink *sink) AUKN_SYM void NewStdSinkRelease(IBasicSink *sink)
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED)
Sinks::NewStdSinkRelease(sink); Sinks::NewStdSinkRelease(sink);
#endif
} }
AUKN_SYM IBasicSink *NewOSEventDirectorySinkNew() AUKN_SYM IBasicSink *NewOSEventDirectorySinkNew()
@ -49,12 +44,17 @@ namespace Aurora::Logging
AUKN_SYM IBasicSink *NewDebugLoggerNew() AUKN_SYM IBasicSink *NewDebugLoggerNew()
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED)
return Sinks::NewDebugLoggerNew(); return Sinks::NewDebugLoggerNew();
#endif
return {};
} }
AUKN_SYM void NewDebugLoggerRelease(IBasicSink *sink) AUKN_SYM void NewDebugLoggerRelease(IBasicSink *sink)
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED)
return Sinks::NewDebugLoggerRelease(sink); return Sinks::NewDebugLoggerRelease(sink);
#endif
} }

View File

@ -91,4 +91,20 @@ namespace Aurora::Loop
{ {
return ELoopSource::eSourceEvent; return ELoopSource::eSourceEvent;
} }
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent()
{
auto event = AuMakeShared<LSEvent>();
if (!event)
{
return {};
}
if (!event->HasValidHandle())
{
return {};
}
return event;
}
} }

View File

@ -10,11 +10,11 @@
namespace Aurora::Loop namespace Aurora::Loop
{ {
template<typename T> template<typename T>
inline void IsSignaledFromNonblockingImpl(ILoopSourceEx *source, T * that, bool(T *::IsSignaledNonblocking)()) inline bool IsSignaledFromNonblockingImpl(ILoopSourceEx *source, T * that, bool(T::*IsSignaledNonblocking)())
{ {
bool val {}; bool val {};
source->OnPresleep(); source->OnPresleep();
val = ((that).*(IsSignaledNonblocking))(); val = ((that)->*(IsSignaledNonblocking))();
source->OnFinishSleep(); source->OnFinishSleep();
return val; return val;
} }

View File

@ -7,8 +7,67 @@
***/ ***/
#include <Source/RuntimeInternal.hpp> #include <Source/RuntimeInternal.hpp>
#include "LSSemaphore.hpp" #include "LSSemaphore.hpp"
#include "LSFromFdNonblocking.hpp"
namespace Aurora::Loop namespace Aurora::Loop
{ {
LSSemaphore::LSSemaphore(AuUInt32 initialCount)
{
Init(initialCount);
}
void LSSemaphore::Init(AuUInt32 initialCount)
{
handle = eventfd(initialCount, EFD_SEMAPHORE | EFD_NONBLOCK);
}
bool LSSemaphore::IsSignaledNonblocking()
{
AuUInt64 oldSemaphoreValue {};
return read(this->handle, &oldSemaphoreValue, sizeof(oldSemaphoreValue)) == 8;
}
bool LSSemaphore::AddOne()
{
AuUInt64 plsNoOverflow {1};
if (write(this->handle, &plsNoOverflow, sizeof(plsNoOverflow)) != 8)
{
// todo push error
return false;
}
return true;
}
bool LSSemaphore::OnTrigger(AuUInt handle)
{
return IsSignaledNonblocking();
}
bool LSSemaphore::IsSignaled()
{
return IsSignaledFromNonblockingImpl(this, this, &LSSemaphore::IsSignaledNonblocking);
}
ELoopSource LSSemaphore::GetType()
{
return ELoopSource::eSourceSemaphore;
}
AUKN_SYM AuSPtr<ILSSemaphore> NewLSSemaphore(AuUInt32 initialCount)
{
auto semaphore = AuMakeShared<LSSemaphore>(initialCount);
if (!semaphore)
{
return {};
}
if (!semaphore->HasValidHandle())
{
return {};
}
return semaphore;
}
} }

View File

@ -6,6 +6,7 @@
Author: Reece Author: Reece
***/ ***/
#pragma once #pragma once
#include "LSHandle.hpp"
namespace Aurora::Loop namespace Aurora::Loop
{ {

View File

@ -24,6 +24,10 @@ namespace Aurora::Loop
// network and file transactions independent from the loop queues // network and file transactions independent from the loop queues
// As such, loop queues continue to be defined as a mechanism to merely // As such, loop queues continue to be defined as a mechanism to merely
// wait, not dispatch/manage work // wait, not dispatch/manage work
// Delegating mutex reads to a single io_submit would be a linux-specific
// kevent-non-reusable ThreadWorkerQueueShim hack
// ...it wouldn't make sense create another loop queue per thread concept
// outside of the async subsystem (not counting TLS overlapped io)
LoopQueue::LoopQueue() LoopQueue::LoopQueue()
{ {
@ -82,7 +86,7 @@ namespace Aurora::Loop
bool LoopQueue::Commit() bool LoopQueue::Commit()
{ {
return {}; return true;
} }
bool LoopQueue::IsSignaled() bool LoopQueue::IsSignaled()

View File

@ -9,6 +9,6 @@
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
#include "LoopQueue.NT.hpp" #include "LoopQueue.NT.hpp"
#elif defined(AURORA_PLATFORM_LINX) #elif defined(AURORA_PLATFORM_LINUX)
#include "LoopQueue.Linux.hpp" #include "LoopQueue.Linux.hpp"
#endif #endif

View File

@ -73,7 +73,7 @@ namespace Aurora::Loop
FD_SET(read, &readSet); FD_SET(read, &readSet);
FD_SET(write, &writeSet); FD_SET(write, &writeSet);
auto active = select(handle + 1, read != -1 ? &readSet : NULL, write != -1 ? &writeSet : NULL, NULL, &tv); auto active = select(AuMax(read, write) + 1, read != -1 ? &readSet : NULL, write != -1 ? &writeSet : NULL, NULL, &tv);
if (active == -1) if (active == -1)
{ {
// todo push error // todo push error

View File

@ -11,7 +11,7 @@ namespace Aurora::Loop
{ {
struct WaitSingleGeneric : WaitSingleBase struct WaitSingleGeneric : WaitSingleBase
{ {
virtual bool WaitForAtleastOne(const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &read _OPT_WRITE) override; virtual bool WaitForAtleastOne(const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &read _OPT_WRITE_REF) override;
virtual bool WaitForOne(AuUInt handle _OPT_WRITE) override; virtual bool WaitForOne(AuUInt handle _OPT_WRITE) override;
virtual void OnPresleep() override; virtual void OnPresleep() override;
virtual void OnFinishSleep() override; virtual void OnFinishSleep() override;

View File

@ -14,6 +14,7 @@ namespace Aurora::Loop
{ {
bool val {}; bool val {};
AuUInt one {}; AuUInt one {};
AuUInt two {};
this->OnPresleep(); this->OnPresleep();
if (this->Singular()) if (this->Singular())
@ -33,8 +34,16 @@ namespace Aurora::Loop
} }
else else
{ {
#if defined(AURORA_IS_POSIX_DERIVED)
auto handles = this->GetHandles(); auto handles = this->GetHandles();
val = WaitForAtleastOne(handles, one); auto handlesRw = this->GetWriteHandles();
val = this->WaitForAtleastOne(handles, handlesRw, one, two);
if (one == -1) one = two;
#else
auto handles = this->GetHandles();
val = this->WaitForAtleastOne(handles, one);
#endif
if (val) if (val)
{ {
val = this->OnTrigger(one); val = this->OnTrigger(one);

View File

@ -13,9 +13,11 @@ namespace Aurora::Loop
{ {
#if defined(AURORA_IS_POSIX_DERIVED) #if defined(AURORA_IS_POSIX_DERIVED)
#define _OPT_WRITE , AuUInt &write #define _OPT_WRITE , AuUInt write
#define _OPT_WRITE_REF , AuUInt &write
#else #else
#define _OPT_WRITE #define _OPT_WRITE
#define _OPT_WRITE_REF
#endif #endif
#if defined(AURORA_IS_POSIX_DERIVED) #if defined(AURORA_IS_POSIX_DERIVED)
@ -29,7 +31,7 @@ namespace Aurora::Loop
{ {
bool IsSignaled() override; bool IsSignaled() override;
virtual bool WaitForAtleastOne(const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &one _OPT_WRITE) = 0; virtual bool WaitForAtleastOne(const AuList<AuUInt> &handles _OPT_WRITE_ARRAY, AuUInt &one _OPT_WRITE_REF) = 0;
virtual bool WaitForOne(AuUInt handle _OPT_WRITE) = 0; virtual bool WaitForOne(AuUInt handle _OPT_WRITE) = 0;
}; };
} }

View File

@ -1,327 +0,0 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Process.Linux.cpp
Date: 2021-6-12
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "Processes.hpp"
#include "Process.Linux.hpp"
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <Source/Threading/Primitives/Semaphore.Unix.hpp>
static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
unsigned int flags)
{
return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
}
static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(__NR_pidfd_open, pid, flags);
}
#ifndef P_PIDFD
#define P_PIDFD 3
#endif
namespace Aurora::Processes
{
class ProcessImpl : public IProcess
{
public:
ProcessImpl(AuString cmd, AuList<AuString> args);
~ProcessImpl();
void ShutdownPipes();
bool TryKill() override;
bool Terminate() override;
AuSPtr<Aurora::Threading::IWaitable> AsWaitable() override;
AuSInt GetExitCode() override;
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(enum ESpawnType type, bool fwdOut, bool fwdErr, bool fwdIn) override;
private:
int pipeStdOut_[2]{};
int pipeStdErr_[2]{};
int pipeStdIn_ [2]{};
AuString module_;
ESpawnType type_;
AuList<AuString> args_;
AuList<const char *> cargs_;
AuString windows_;
Threading::Threads::ThreadUnique_t thread_;
std::atomic<int> handle_;
AuSInt exitCode_;
};
ProcessImpl::ProcessImpl(AuString cmd, AuList<AuString> args) : module_(cmd), args_(args)
{
this->args_.insert(this->args_.begin(), cmd);
for (auto &arg : this->args_)
{
this->cargs_.push_back(arg.c_str());
this->windows_ += arg + " ";
}
this->cargs_.push_back(nullptr);
this->windows_.resize(this->windows_.size() - 1);
}
ProcessImpl::~ProcessImpl()
{
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
{
TryKill();
Terminate();
}
if (this->handle_)
{
if (this->type_ == ESpawnType::eSpawnThreadLeader)
{
sys_pidfd_send_signal(this->handle_, SIGCONT, NULL, 0);
}
}
if (this->thread_)
{
this->thread_.reset();
}
if (auto handle = this->handle_.exchange(0))
{
close(handle);
}
ShutdownPipes();
}
void ProcessImpl::ShutdownPipes()
{
if (auto fd = std::exchange(pipeStdErr_[0], {})) close(fd);
if (auto fd = std::exchange(pipeStdErr_[1], {})) close(fd);
if (auto fd = std::exchange(pipeStdOut_[0], {})) close(fd);
if (auto fd = std::exchange(pipeStdOut_[1], {})) close(fd);
if (auto fd = std::exchange(pipeStdIn_[0], {})) close(fd);
if (auto fd = std::exchange(pipeStdIn_[1], {})) close(fd);
}
bool ProcessImpl::TryKill()
{
if (this->handle_)
{
return sys_pidfd_send_signal(this->handle_, SIGTERM, NULL, 0) == 0;
}
return true;
}
bool ProcessImpl::Terminate()
{
if (this->handle_)
{
sys_pidfd_send_signal(this->handle_, SIGKILL, NULL, 0);
}
return true;
}
AuSPtr<Aurora::Threading::IWaitable> ProcessImpl::AsWaitable()
{
if (!this->thread_) return nullptr;
return this->thread_->AsWaitable();
}
AuSInt ProcessImpl::GetExitCode()
{
return this->exitCode_;
}
static int aurora_sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
struct rusage *ru)
{
return syscall(__NR_waitid, which, pid, info, options, ru);
}
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)
{
len = 0;
auto handle = errorStream ? pipeStdErr_[0] : pipeStdOut_[0];
if (handle < 0)
{
return false;
}
auto control = fcntl(fd, F_GETFL);
auto ref = control;
if (nonblock)
{
control |= O_NONBLOCK;
}
else
{
control &= ~O_NONBLOCK;
}
if (ref != control)
{
fcntl(fd, F_SETFL, control);
}
auto tmp = read(handle, buffer, len);
if (tmp < 0)
{
return false;
}
len = tmp;
return true;
}
bool ProcessImpl::Write(const void *buffer, AuUInt32 len)
{
auto handle = pipeStdIn_[1];
if (!handle) return false;
return write(handle, buffer, len) == len;
}
bool ProcessImpl::Start(enum ESpawnType type, bool fwdOut, bool fwdErr, bool fwdIn)
{
this->exitCode_ = 0x10110100;
this->type_ = type;
if (type == ESpawnType::eSpawnAtomicOvermap)
{
execv(this->module_.c_str(), (char *const *)this->cargs_.data()); // https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
SysPushErrorGen("execv didn't overwrite the process map, given {} ({})", this->module_, this->windows_);
return false;
}
if (fwdOut)
{
if (!pipe(pipeStdOut_))
{
return false;
}
}
if (fwdErr)
{
if (!pipe(pipeStdErr_))
{
return false;
}
}
if (fwdIn)
{
if (!pipe(pipeStdIn_))
{
return false;
}
}
Threading::Threads::AbstractThreadVectors handler;
pid_t pid;
{
Threading::Primitives::Semaphore semaphore;
pid = fork();
if (pid == 0)
{
semaphore.Lock();
if (fwdIn)
{
dup2(pipeStdIn_[0], STDIN_FILENO);
close(std::exchange(pipeStdIn_[0], 0));
}
if (fwdErr)
{
dup2(pipeStdErr_[1], STDERR_FILENO);
close(std::exchange(pipeStdErr_[1], 0));
}
if (fwdOut)
{
dup2(pipeStdOut_[1], STDOUT_FILENO);
close(std::exchange(pipeStdOut_[1], 0));
}
if (type != ESpawnType::eSpawnChildProcessWorker)
{
setsid();
}
execv(this->module_.c_str(), (char * const *)this->cargs_.data()); // https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
SysPushErrorGen("execv didn't overwrite the process map, given {} ({})", this->module_, this->windows_);
return false;
}
else if (pid < 0)
{
return false;
}
else
{
this->handle_ = sys_pidfd_open(pid, 0);
semaphore.Unlock();
}
}
handler.DoRun = [=](Threading::Threads::IAuroraThread *)
{
{
// TODO: experimental (and requires kernel 5.3+)
siginfo_t info = {
.si_signo = 0,
};
// TODO: vaildate response
aurora_sys_waitid(P_PIDFD, this->handle_, &info, WEXITED, NULL);
// TODO: confirm this works?!?
this->exitCode_ = info.si_status;
}
};
this->thread_ = Threading::Threads::ThreadUnique(handler);
if (!this->thread_) 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);
}
}

View File

@ -22,6 +22,8 @@ namespace Aurora::Processes
{ {
ProcessImpl::ProcessImpl(const StartupParmaters &params) : startup_(params) ProcessImpl::ProcessImpl(const StartupParmaters &params) : startup_(params)
{ {
AuIOFS::NormalizePath(this->startup_.process, this->startup_.process);
this->startup_.args.insert(startup_.args.begin(), startup_.process); this->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 // ehhhh https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
@ -34,7 +36,10 @@ namespace Aurora::Processes
} }
this->cargs_.push_back(nullptr); this->cargs_.push_back(nullptr);
this->windowsCli_.resize(this->windowsCli_.size() - 1); if (windowsCli_.size())
{
this->windowsCli_.resize(this->windowsCli_.size() - 1);
}
this->type_ = params.type; this->type_ = params.type;
} }
@ -300,7 +305,7 @@ namespace Aurora::Processes
startupInfo.hStdOutput = pipeStdOutWrite_; startupInfo.hStdOutput = pipeStdOutWrite_;
startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0); startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0);
auto result = CreateProcessW(Locale::ConvertFromUTF8(AuIOFS::NormalizePathRet(this->startup_.process)).c_str(), auto result = CreateProcessW(Locale::ConvertFromUTF8(this->startup_.process).c_str(),
Locale::ConvertFromUTF8(this->windowsCli_).data(), Locale::ConvertFromUTF8(this->windowsCli_).data(),
NULL, NULL, inheritHandles, 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 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

View File

@ -0,0 +1,384 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Process.Unix.cpp
File: Process.Linux.cpp
Date: 2021-6-12
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "Processes.hpp"
#include "Process.Unix.hpp"
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <Source/Threading/Primitives/Semaphore.Unix.hpp>
namespace Aurora::Processes
{
struct ProcessImpl;
struct ProcessImpl;
static AuThreadPrimitives::SpinLock gSpinLock;
static AuHashMap<pid_t, ProcessImpl *> gPidLookupMap;
class ProcessImpl : public IProcess
{
public:
ProcessImpl(const StartupParmaters &params);
~ProcessImpl();
void ShutdownPipes();
bool TryKill() override;
bool Terminate() override;
AuSPtr<Aurora::Threading::IWaitable> AsWaitable() override;
AuSInt GetExitCode() override;
AuUInt GetProcessId() override;
bool Read(EStandardHandle stream, const AuMemoryViewStreamWrite &destination, bool nonblock) override;
bool Write(const AuMemoryViewStreamRead &source) override;
bool Start() override;
bool Init();
void ByeLol(AuSInt code);
private:
int pipeStdOut_[2]{};
int pipeStdErr_[2]{};
int pipeStdIn_ [2]{};
AuThreadPrimitives::EventShared_t finished_;
StartupParmaters startup_;
ESpawnType type_;
AuList<const char *> cargs_;
AuString debug_;
pid_t pidt_;
bool alive_ {};
AuSInt exitCode_;
};
ProcessImpl::ProcessImpl(const StartupParmaters &params) : startup_(params)
{
AuIOFS::NormalizePath(this->startup_.process, this->startup_.process);
this->startup_.args.insert(startup_.args.begin(), startup_.process);
for (const auto &arg : this->startup_.args)
{
this->cargs_.push_back(arg.c_str());
this->debug_ += arg + " ";
}
this->cargs_.push_back(nullptr);
if (this->debug_.size())
{
this->debug_.resize(this->debug_.size() - 1);
}
}
ProcessImpl::~ProcessImpl()
{
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
{
TryKill();
Terminate();
}
{
AU_LOCK_GUARD(gSpinLock);
AuTryRemove(gPidLookupMap, this->pidt_);
}
if (this->alive_)
{
if (this->type_ == ESpawnType::eSpawnThreadLeader)
{
::kill(this->pidt_, SIGCONT);
}
}
ShutdownPipes();
}
AuUInt ProcessImpl::GetProcessId()
{
return this->pidt_;
}
void ProcessImpl::ByeLol(AuSInt code)
{
this->exitCode_ = code;
if (this->finished_)
{
this->finished_->Set();
}
}
void ProcessImpl::ShutdownPipes()
{
if (auto fd = AuExchange(pipeStdErr_[0], {})) close(fd);
if (auto fd = AuExchange(pipeStdErr_[1], {})) close(fd);
if (auto fd = AuExchange(pipeStdOut_[0], {})) close(fd);
if (auto fd = AuExchange(pipeStdOut_[1], {})) close(fd);
if (auto fd = AuExchange(pipeStdIn_[0], {})) close(fd);
if (auto fd = AuExchange(pipeStdIn_[1], {})) close(fd);
}
bool ProcessImpl::TryKill()
{
AU_LOCK_GUARD(gSpinLock);
if (this->alive_)
{
return ::kill(this->pidt_, SIGTERM) == 0;
}
return true;
}
bool ProcessImpl::Terminate()
{
AU_LOCK_GUARD(gSpinLock);
if (this->alive_)
{
return ::kill(this->pidt_, SIGKILL) == 0;
}
return true;
}
AuSPtr<Aurora::Threading::IWaitable> ProcessImpl::AsWaitable()
{
return this->finished_;
}
AuSInt ProcessImpl::GetExitCode()
{
return this->exitCode_;
}
bool ProcessImpl::Read(EStandardHandle stream, const AuMemoryViewStreamWrite &destination, bool nonblock)
{
auto handle = stream == EStandardHandle::eStdError ? this->pipeStdErr_[0] : this->pipeStdOut_[0];
if (handle < 0)
{
return false;
}
auto control = fcntl(handle, F_GETFL);
auto ref = control;
if (nonblock)
{
control |= O_NONBLOCK;
}
else
{
control &= ~O_NONBLOCK;
}
if (ref != control)
{
fcntl(handle, F_SETFL, control);
}
auto tmp = read(handle, destination.ptr, destination.length);
if (tmp < 0)
{
return false;
}
destination.outVariable = tmp;
return true;
}
bool ProcessImpl::Write(const AuMemoryViewStreamRead &source)
{
auto handle = pipeStdIn_[1];
if (!handle)
{
return false;
}
return write(handle, source.ptr, source.length) == source.length;
}
bool ProcessImpl::Init()
{
if (this->startup_.fwdOut)
{
if (!pipe(this->pipeStdOut_))
{
return false;
}
}
if (this->startup_.fwdErr)
{
if (!pipe(this->pipeStdErr_))
{
return false;
}
}
if (this->startup_.fwdIn)
{
if (!pipe(this->pipeStdIn_))
{
return false;
}
}
this->finished_ = AuThreadPrimitives::EventShared(false, false, true);
return bool(this->finished_);
}
bool ProcessImpl::Start()
{
this->exitCode_ = 0x10110100;
if (this->type_ == ESpawnType::eSpawnOvermap)
{
execv(this->startup_.process.c_str(), (char *const *)this->cargs_.data()); // https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
SysPushErrorGen("execv didn't overwrite the process map, given {} ({})", this->startup_.process, this->debug_);
return false;
}
pid_t pid;
{
//Threading::Primitives::Semaphore semaphore;
pid = fork();
if (pid == 0)
{
if (this->startup_.fwdIn)
{
dup2(pipeStdIn_[0], STDIN_FILENO);
close(AuExchange(pipeStdIn_[0], 0));
}
if (this->startup_.fwdErr)
{
dup2(pipeStdErr_[1], STDERR_FILENO);
close(AuExchange(pipeStdErr_[1], 0));
}
if (this->startup_.fwdOut)
{
dup2(pipeStdOut_[1], STDOUT_FILENO);
close(AuExchange(pipeStdOut_[1], 0));
}
if (this->type_ != ESpawnType::eSpawnChildProcessWorker)
{
setsid();
}
{
AU_LOCK_GUARD(gSpinLock);
AuTryInsert(gPidLookupMap, getpid(), this);
}
this->alive_ = true;
//semaphore.Unlock();
execv(this->startup_.process.c_str(), (char * const *)this->cargs_.data()); // https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
SysPushErrorGen("execv didn't overwrite the process map, given {} ({})", this->startup_.process, this->debug_);
return false;
}
else if (pid < 0)
{
return false;
}
else
{
this->pidt_ = pid;
//semaphore.Lock();
}
}
return true;
}
AUKN_SYM IProcess *SpawnNew(const StartupParmaters &params)
{
auto ret = _new ProcessImpl(params);
if (!ret)
{
return {};
}
if (!ret->Init())
{
delete ret;
return {};
}
return ret;
}
AUKN_SYM void SpawnRelease(IProcess *process)
{
AuSafeDelete<ProcessImpl *>(process);
}
static void HandleChildTermiantion(pid_t pid, int code)
{
AU_LOCK_GUARD(gSpinLock);
auto handler = gPidLookupMap.find(pid);
if (handler == gPidLookupMap.end()) return;
{
auto process = *handler;
process.second->ByeLol(code);
}
gPidLookupMap.erase(handler);
}
static void SigChldHandler(int)
{
int code;
pid_t pid;
while (true)
{
pid = wait3(&code, WNOHANG, nullptr);
if ((pid == 0) ||
(pid == -1))
{
break;
}
HandleChildTermiantion(pid, code);
}
}
void InitUnix()
{
signal(SIGCHLD, SigChldHandler);
}
void DeinitUnix()
{
}
}

View File

@ -1,7 +1,14 @@
/*** /***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Process.Unix.hpp
File: Process.Linux.hpp File: Process.Linux.hpp
Date: 2021-6-12 Date: 2021-6-12
Author: Reece Author: Reece
***/ ***/
namespace Aurora::Processes
{
void DeinitUnix();
void InitUnix();
}

View File

@ -13,6 +13,10 @@
#include "Open.Win32.hpp" #include "Open.Win32.hpp"
#endif #endif
#if defined(AURORA_IS_POSIX_DERIVED)
#include "Process.Unix.hpp"
#endif
namespace Aurora::Processes namespace Aurora::Processes
{ {
void Init() void Init()
@ -21,6 +25,10 @@ namespace Aurora::Processes
InitWin32(); InitWin32();
InitWin32Opener(); InitWin32Opener();
#endif #endif
#if defined(AURORA_IS_POSIX_DERIVED)
InitUnix();
#endif
} }
void Deinit() void Deinit()
@ -29,5 +37,9 @@ namespace Aurora::Processes
DeinitWin32(); DeinitWin32();
DeinitWin32Opener(); DeinitWin32Opener();
#endif #endif
#if defined(AURORA_IS_POSIX_DERIVED)
DeinitUnix();
#endif
} }
} }

View File

@ -32,7 +32,7 @@ namespace Aurora::Threading::Threads
return {false, 0}; return {false, 0};
} }
static auto callVoidPtr_f = [](void *that) -> void static auto OSEP_f = [](void *that) -> void *
{ {
auto handle = reinterpret_cast<AuFunction<void()> *>(that); auto handle = reinterpret_cast<AuFunction<void()> *>(that);
auto callMe = *handle; auto callMe = *handle;
@ -40,13 +40,6 @@ namespace Aurora::Threading::Threads
callMe(); callMe();
}; };
void *(*OSEP_f)(void *) = [](void *that) -> void *
{
auto thiz = reinterpret_cast<OSThread *>(that);
thiz->_ThreadEP();
return nullptr;
};
auto ret = pthread_attr_init(&tattr); auto ret = pthread_attr_init(&tattr);
if (ret != 0) if (ret != 0)
{ {