Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /***
- Copyright (©) 2021 Reece Wilson (a/k/a "Reece"). All rights reserved.
- Do not use, copy, distribute, publish, disseminate, modify, or sublicense without express permission from the rights holder[s].
- Please do no evil.
- File: KSpawn.cpp
- Date: 2021-1-15
- Author: Reece
- Purpose: TBD
- ***/
- #include "KInternal.hpp"
- #if defined (AURORA_PLATFORM_WIN32)
- #include <shellapi.h>
- #elif defined(AURORA_PLATFORM_LINUX)
- #include <unistd.h>
- #include <sys/syscall.h>
- #endif
- namespace Aurora::Spawn
- {
- #if defined (AURORA_PLATFORM_WIN32)
- static HANDLE gLeaderJob;
- #endif
- void Init()
- {
- #if defined (AURORA_PLATFORM_WIN32)
- gLeaderJob = CreateJobObject(NULL, NULL); // GLOBAL
- if (!gLeaderJob)
- {
- ErrorPushGen("CreateJobObject error");
- return;
- }
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
- jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
- if (!SetInformationJobObject(gLeaderJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
- {
- ErrorPushGen("SetInformationJobObject error");
- }
- #endif
- }
- class ProcessImpl : public IProcess
- {
- public:
- ProcessImpl(AuString cmd, AuList<AuString> args) : _cmd(cmd), _args(args)
- {
- // https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
- // ehhhh
- this->_args.insert(this->_args.begin(), cmd);
- for (const auto& arg : this->_args)
- {
- this->_cargs.push_back(arg.c_str());
- this->_tardows += arg + " ";
- }
- this->_cargs.push_back(nullptr);
- this->_tardows.resize(this->_tardows.size() - 1);
- }
- ~ProcessImpl()
- {
- if (this->_thread)
- {
- Threading::ExterminateThread(this->_thread);
- this->_thread = nullptr;
- }
- #if defined(AURORA_PLATFORM_WIN32)
- if ((this->_process) && (this->_type == SpawnType::kSpawnSubProcessWorker))
- {
- // TODO: enum window handles -> EndTask
- TerminateProcess(this->_process, 0);
- }
- CloseHandle(this->_process);
- CloseHandle(this->_hthread);
- #endif
- #if defined(AURORA_PLATFORM_LINUX)
- if (this->_linuxsucks)
- {
- if (this->_type == SpawnType::kSpawnSubProcessWorker)
- {
- sys_pidfd_send_signal(this->_linuxsucks, SIGCONT, NULL, 0);
- }
- close(this->_linuxsucks);
- }
- #endif
- }
- Aurora::Threading::IWaitable* AsWaitable() override
- {
- if (!this->_thread) return nullptr;
- return this->_thread->AsWaitable();
- }
- AuSInt GetExitCode() override
- {
- return this->_exitCode;
- }
- #if defined(AURORA_PLATFORM_LINUX)
- 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);
- }
- #endif
- bool Start(enum SpawnType type) override
- {
- this->_exitCode = 0x10110100;
- this->_type = type;
- if (type == SpawnType::kSpawnAtomicOvermap)
- {
- #if defined(AURORA_PLATFORM_WIN32)
- _spawnv(_P_OVERLAY, this->_cmd.c_str(), this->_cargs.data());
- ErrorPushGen("_spawnv didn't overwrite the process map, given {} ({})", this->_cmd, this->_tardows);
- #elif defined(AURORA_PLATFORM_LINUX)
- execv(this->_cmd.c_str(), this->_cargs.data());
- ErrorPushGen("execv didn't overwrite the process map, given {} ({})", this->_cmd, this->_tardows);
- #elif defined(AURORA_PLATFORM_ANDROID)
- // TODO:
- #endif
- return false;
- }
- Threading::IUserThreadHandler handler;
- #if defined(AURORA_PLATFORM_LINUX)
- pid_t pid;
- {
- Semaphore semaphore;
- pid = fork();
- if (pid == 0)
- {
- semaphore.Lock();
- if (type != SpawnType::kSpawnSubProcessWorker)
- {
- daemon();
- }
- execv(this->_cmd.c_str(), this->_cargs.data());
- ErrorPushGen("execv didn't overwrite the process map, given {} ({})", this->_cmd, this->_tardows);
- return false;
- }
- else if (pid < 0)
- {
- return false;
- }
- else
- {
- this->_linuxsucks = pidfd_open(pid, 0);
- semaphore.unlock();
- }
- }
- #elif defined(AURORA_PLATFORM_WIN32)
- PROCESS_INFORMATION processInfo = { 0 };
- {
- STARTUPINFOW startupInfo = { 0 };
- startupInfo.cb = sizeof(startupInfo);
- auto result = CreateProcessW(::Locale::ConvertFromUTF8(this->_cmd).c_str(),
- ::Locale::ConvertFromUTF8(this->_tardows).data(),
- NULL, NULL, FALSE,
- NULL,
- NULL, NULL, &startupInfo, &processInfo);
- if (!result)
- {
- ErrorPushGen("CreateProcess failed");
- return false;
- }
- this->_process = processInfo.hProcess;
- this->_hthread = processInfo.hThread;
- if (type == SpawnType::kSpawnSubProcessWorker)
- {
- if (gLeaderJob)
- {
- if (!AssignProcessToJobObject(gLeaderJob, processInfo.hProcess))
- {
- ErrorPushGen("Could not AssignProcessToObject");
- }
- }
- }
- }
- #endif
- handler.DoRun = [=](Threading::IAuroraThread*)
- {
- #if defined(AURORA_PLATFORM_WIN32)
- {
- WaitForSingleObject(processInfo.hProcess, INFINITE);
- DWORD exitCode;
- auto result = GetExitCodeProcess(processInfo.hProcess, &exitCode);
- this->_exitCode = exitCode;
- }
- #elif defined(AURORA_PLATFORM_LINUX)
- {
- // TODO: experimental (and requires kernel 5.3+)
- siginfo_t info = {
- .si_signo = 0,
- };
- // TODO: vaildate response
- aurora_sys_waitid(P_PIDFD, this->_linuxsucks, &info, WEXITED, NULL);
- // TODO: confirm this works?!?
- this->_exitCode = info.si_status;
- }
- #endif
- };
- this->_thread = Threading::NewThread(handler);
- if (!this->_thread) return false;
- this->_thread->Run();
- return true;
- }
- private:
- AuString _cmd;
- AuList<AuString> _args;
- AuList<const char*> _cargs;
- AuString _tardows;
- SpawnType _type;
- Threading::IAuroraThread* _thread;
- AuSInt _exitCode;
- #if defined(AURORA_PLATFORM_WIN32)
- HANDLE _process;
- HANDLE _hthread;
- #elif defined(AURORA_PLATFORM_LINUX)
- int _linuxsucks;
- #endif
- };
- AUKN_SYM IProcess* Spawn(const AuString& app, const AuList<AuString>& args)
- {
- return _new ProcessImpl(app, args);
- }
- AUKN_SYM void Release(IProcess* process)
- {
- SafeDelete<ProcessImpl*>(process);
- }
- #if defined (AURORA_PLATFORM_LINUX)
- static void LinuxOpenAsync(const AuString & open)
- {
- if (fork() == 0)
- {
- daemon();
- execl("xdg-open", open.c_str());
- }
- }
- #endif
- AUKN_SYM void OpenUri(const AuString& uri)
- {
- #if defined (AURORA_PLATFORM_WIN32)
- ShellExecuteW(NULL, NULL, ::Locale::ConvertFromUTF8(uri).c_str(), NULL, NULL, 0);
- #elif defined (AURORA_PLATFORM_LINUX)
- LinuxOpenAsync(uri);
- #endif
- }
- AUKN_SYM void OpenFile(const AuString& file)
- {
- #if defined (AURORA_PLATFORM_WIN32)
- ShellExecuteW(NULL, NULL, ::Locale::ConvertFromUTF8(file).c_str(), NULL, NULL, 0);
- #elif defined (AURORA_PLATFORM_LINUX)
- LinuxOpenAsync(file);
- #endif
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement