[*] 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:
parent
d32b84edf4
commit
e25d8a65c8
@ -871,7 +871,7 @@ namespace Aurora::Async
|
||||
|
||||
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)),
|
||||
AuThreads::IThreadVectorsFunctional::OnExit_t{}),
|
||||
gRuntimeConfig.async.threadPoolDefaultStackSize
|
||||
|
@ -25,17 +25,12 @@ namespace Aurora::Logging
|
||||
{
|
||||
AUKN_SYM IBasicSink *NewStdSinkNew()
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return Sinks::NewStdSinkNew();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
AUKN_SYM void NewStdSinkRelease(IBasicSink *sink)
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
Sinks::NewStdSinkRelease(sink);
|
||||
#endif
|
||||
}
|
||||
|
||||
AUKN_SYM IBasicSink *NewOSEventDirectorySinkNew()
|
||||
@ -49,12 +44,17 @@ namespace Aurora::Logging
|
||||
|
||||
AUKN_SYM IBasicSink *NewDebugLoggerNew()
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return Sinks::NewDebugLoggerNew();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
AUKN_SYM void NewDebugLoggerRelease(IBasicSink *sink)
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return Sinks::NewDebugLoggerRelease(sink);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,4 +91,20 @@ namespace Aurora::Loop
|
||||
{
|
||||
return ELoopSource::eSourceEvent;
|
||||
}
|
||||
|
||||
AUKN_SYM AuSPtr<ILSEvent> NewLSEvent()
|
||||
{
|
||||
auto event = AuMakeShared<LSEvent>();
|
||||
if (!event)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!event->HasValidHandle())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
@ -10,11 +10,11 @@
|
||||
namespace Aurora::Loop
|
||||
{
|
||||
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 {};
|
||||
source->OnPresleep();
|
||||
val = ((that).*(IsSignaledNonblocking))();
|
||||
val = ((that)->*(IsSignaledNonblocking))();
|
||||
source->OnFinishSleep();
|
||||
return val;
|
||||
}
|
||||
|
@ -7,8 +7,67 @@
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "LSSemaphore.hpp"
|
||||
#include "LSFromFdNonblocking.hpp"
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
Author: Reece
|
||||
***/
|
||||
#pragma once
|
||||
#include "LSHandle.hpp"
|
||||
|
||||
namespace Aurora::Loop
|
||||
{
|
||||
|
@ -24,6 +24,10 @@ namespace Aurora::Loop
|
||||
// network and file transactions independent from the loop queues
|
||||
// As such, loop queues continue to be defined as a mechanism to merely
|
||||
// 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()
|
||||
{
|
||||
@ -82,7 +86,7 @@ namespace Aurora::Loop
|
||||
|
||||
bool LoopQueue::Commit()
|
||||
{
|
||||
return {};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoopQueue::IsSignaled()
|
||||
|
@ -9,6 +9,6 @@
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
#include "LoopQueue.NT.hpp"
|
||||
#elif defined(AURORA_PLATFORM_LINX)
|
||||
#elif defined(AURORA_PLATFORM_LINUX)
|
||||
#include "LoopQueue.Linux.hpp"
|
||||
#endif
|
@ -73,7 +73,7 @@ namespace Aurora::Loop
|
||||
FD_SET(read, &readSet);
|
||||
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)
|
||||
{
|
||||
// todo push error
|
||||
|
@ -11,7 +11,7 @@ namespace Aurora::Loop
|
||||
{
|
||||
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 void OnPresleep() override;
|
||||
virtual void OnFinishSleep() override;
|
||||
|
@ -14,6 +14,7 @@ namespace Aurora::Loop
|
||||
{
|
||||
bool val {};
|
||||
AuUInt one {};
|
||||
AuUInt two {};
|
||||
this->OnPresleep();
|
||||
|
||||
if (this->Singular())
|
||||
@ -33,8 +34,16 @@ namespace Aurora::Loop
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
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)
|
||||
{
|
||||
val = this->OnTrigger(one);
|
||||
|
@ -13,9 +13,11 @@ namespace Aurora::Loop
|
||||
{
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
#define _OPT_WRITE , AuUInt &write
|
||||
#define _OPT_WRITE , AuUInt write
|
||||
#define _OPT_WRITE_REF , AuUInt &write
|
||||
#else
|
||||
#define _OPT_WRITE
|
||||
#define _OPT_WRITE_REF
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
@ -29,7 +31,7 @@ namespace Aurora::Loop
|
||||
{
|
||||
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;
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -22,6 +22,8 @@ namespace Aurora::Processes
|
||||
{
|
||||
ProcessImpl::ProcessImpl(const StartupParmaters ¶ms) : startup_(params)
|
||||
{
|
||||
AuIOFS::NormalizePath(this->startup_.process, this->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
|
||||
@ -34,7 +36,10 @@ namespace Aurora::Processes
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -300,7 +305,7 @@ namespace Aurora::Processes
|
||||
startupInfo.hStdOutput = pipeStdOutWrite_;
|
||||
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(),
|
||||
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
|
||||
|
384
Source/Processes/Process.Unix.cpp
Normal file
384
Source/Processes/Process.Unix.cpp
Normal 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 ¶ms);
|
||||
~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 ¶ms) : 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 ¶ms)
|
||||
{
|
||||
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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,7 +1,14 @@
|
||||
/***
|
||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||
|
||||
File: Process.Unix.hpp
|
||||
File: Process.Linux.hpp
|
||||
Date: 2021-6-12
|
||||
Author: Reece
|
||||
***/
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
void DeinitUnix();
|
||||
void InitUnix();
|
||||
}
|
@ -13,6 +13,10 @@
|
||||
#include "Open.Win32.hpp"
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
#include "Process.Unix.hpp"
|
||||
#endif
|
||||
|
||||
namespace Aurora::Processes
|
||||
{
|
||||
void Init()
|
||||
@ -21,6 +25,10 @@ namespace Aurora::Processes
|
||||
InitWin32();
|
||||
InitWin32Opener();
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
InitUnix();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Deinit()
|
||||
@ -29,5 +37,9 @@ namespace Aurora::Processes
|
||||
DeinitWin32();
|
||||
DeinitWin32Opener();
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
DeinitUnix();
|
||||
#endif
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ namespace Aurora::Threading::Threads
|
||||
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 callMe = *handle;
|
||||
@ -40,13 +40,6 @@ namespace Aurora::Threading::Threads
|
||||
callMe();
|
||||
};
|
||||
|
||||
void *(*OSEP_f)(void *) = [](void *that) -> void *
|
||||
{
|
||||
auto thiz = reinterpret_cast<OSThread *>(that);
|
||||
thiz->_ThreadEP();
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto ret = pthread_attr_init(&tattr);
|
||||
if (ret != 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user