Advertisement
ItsTotallyRSX

REEE Process arsery

Jan 15th, 2021 (edited)
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.12 KB | None | 0 0
  1. /***
  2.     Copyright (©) 2021 Reece Wilson (a/k/a "Reece"). All rights reserved.
  3.     Do not use, copy, distribute, publish, disseminate, modify, or sublicense without express permission from the rights holder[s].
  4.     Please do no evil.
  5.  
  6.     File: KSpawn.cpp
  7.     Date: 2021-1-15
  8.     Author: Reece
  9.     Purpose: TBD
  10. ***/
  11. #include "KInternal.hpp"
  12.  
  13. #if defined (AURORA_PLATFORM_WIN32)
  14.     #include <shellapi.h>
  15. #elif defined(AURORA_PLATFORM_LINUX)
  16.     #include <unistd.h>
  17.     #include <sys/syscall.h>
  18. #endif
  19.  
  20. namespace Aurora::Spawn
  21. {
  22.     #if defined (AURORA_PLATFORM_WIN32)
  23.     static HANDLE gLeaderJob;
  24.     #endif
  25.  
  26.     void Init()
  27.     {
  28.     #if defined (AURORA_PLATFORM_WIN32)
  29.         gLeaderJob = CreateJobObject(NULL, NULL); // GLOBAL
  30.         if (!gLeaderJob)
  31.         {
  32.             ErrorPushGen("CreateJobObject error");
  33.             return;
  34.         }
  35.  
  36.         JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
  37.  
  38.         jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
  39.         if (!SetInformationJobObject(gLeaderJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
  40.         {
  41.             ErrorPushGen("SetInformationJobObject error");
  42.         }
  43.     #endif
  44.     }
  45.  
  46.     class ProcessImpl : public IProcess
  47.     {
  48.     public:
  49.         ProcessImpl(AuString cmd, AuList<AuString> args) : _cmd(cmd), _args(args)
  50.         {
  51.             // https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
  52.             // ehhhh
  53.  
  54.             this->_args.insert(this->_args.begin(), cmd);
  55.  
  56.             for (const auto& arg : this->_args)
  57.             {
  58.                 this->_cargs.push_back(arg.c_str());
  59.                 this->_tardows += arg + " ";
  60.             }
  61.            
  62.             this->_cargs.push_back(nullptr);
  63.             this->_tardows.resize(this->_tardows.size() - 1);
  64.         }
  65.  
  66.         ~ProcessImpl()
  67.         {
  68.             if (this->_thread)
  69.             {
  70.                 Threading::ExterminateThread(this->_thread);
  71.                 this->_thread = nullptr;
  72.             }
  73.  
  74.             #if defined(AURORA_PLATFORM_WIN32)
  75.             if ((this->_process) && (this->_type == SpawnType::kSpawnSubProcessWorker))
  76.             {
  77.                 // TODO: enum window handles -> EndTask
  78.                 TerminateProcess(this->_process, 0);
  79.             }
  80.             CloseHandle(this->_process);
  81.             CloseHandle(this->_hthread);
  82.             #endif
  83.  
  84.             #if defined(AURORA_PLATFORM_LINUX)
  85.             if (this->_linuxsucks)
  86.             {
  87.                 if (this->_type == SpawnType::kSpawnSubProcessWorker)
  88.                 {
  89.                     sys_pidfd_send_signal(this->_linuxsucks, SIGCONT, NULL, 0);
  90.                 }
  91.                 close(this->_linuxsucks);
  92.             }
  93.             #endif
  94.         }
  95.  
  96.         Aurora::Threading::IWaitable* AsWaitable() override
  97.         {
  98.             if (!this->_thread) return nullptr;
  99.             return this->_thread->AsWaitable();
  100.         }
  101.  
  102.         AuSInt GetExitCode() override
  103.         {
  104.             return this->_exitCode;
  105.         }
  106.        
  107.         #if defined(AURORA_PLATFORM_LINUX)
  108.         static int aurora_sys_waitid(int which, pid_t pid, siginfo_t* info, int options,
  109.             struct rusage* ru)
  110.         {
  111.             return syscall(__NR_waitid, which, pid, info, options, ru);
  112.         }
  113.         #endif
  114.  
  115.         bool Start(enum SpawnType type) override
  116.         {
  117.             this->_exitCode = 0x10110100;
  118.             this->_type = type;
  119.        
  120.             if (type == SpawnType::kSpawnAtomicOvermap)
  121.             {
  122.             #if defined(AURORA_PLATFORM_WIN32)
  123.                 _spawnv(_P_OVERLAY, this->_cmd.c_str(), this->_cargs.data());
  124.                 ErrorPushGen("_spawnv didn't overwrite the process map, given {} ({})", this->_cmd, this->_tardows);
  125.             #elif defined(AURORA_PLATFORM_LINUX)
  126.                 execv(this->_cmd.c_str(), this->_cargs.data());
  127.                 ErrorPushGen("execv didn't overwrite the process map, given {} ({})", this->_cmd, this->_tardows);
  128.             #elif defined(AURORA_PLATFORM_ANDROID)
  129.                 // TODO:
  130.             #endif
  131.                 return false;
  132.             }
  133.  
  134.             Threading::IUserThreadHandler handler;
  135.  
  136.             #if defined(AURORA_PLATFORM_LINUX)
  137.             pid_t pid;
  138.             {
  139.                 Semaphore semaphore;
  140.                 pid = fork();
  141.                 if (pid == 0)
  142.                 {
  143.                     semaphore.Lock();
  144.  
  145.                     if (type != SpawnType::kSpawnSubProcessWorker)
  146.                     {
  147.                         daemon();
  148.                     }
  149.  
  150.                     execv(this->_cmd.c_str(), this->_cargs.data());
  151.                     ErrorPushGen("execv didn't overwrite the process map, given {} ({})", this->_cmd, this->_tardows);
  152.                     return false;
  153.                 }
  154.                 else if (pid < 0)
  155.                 {
  156.                     return false;
  157.                 }
  158.                 else
  159.                 {
  160.                     this->_linuxsucks = pidfd_open(pid, 0);
  161.                     semaphore.unlock();
  162.                 }
  163.             }
  164.             #elif defined(AURORA_PLATFORM_WIN32)
  165.             PROCESS_INFORMATION processInfo = { 0 };
  166.             {
  167.                 STARTUPINFOW startupInfo = { 0 };
  168.                 startupInfo.cb = sizeof(startupInfo);
  169.  
  170.  
  171.                 auto result = CreateProcessW(::Locale::ConvertFromUTF8(this->_cmd).c_str(),
  172.                                              ::Locale::ConvertFromUTF8(this->_tardows).data(),
  173.                                              NULL, NULL, FALSE,
  174.                                              NULL,
  175.                                              NULL, NULL, &startupInfo, &processInfo);
  176.  
  177.                 if (!result)
  178.                 {
  179.                     ErrorPushGen("CreateProcess failed");
  180.                     return false;
  181.                 }
  182.  
  183.                 this->_process = processInfo.hProcess;
  184.                 this->_hthread = processInfo.hThread;
  185.  
  186.                 if (type == SpawnType::kSpawnSubProcessWorker)
  187.                 {
  188.                     if (gLeaderJob)
  189.                     {
  190.                         if (!AssignProcessToJobObject(gLeaderJob, processInfo.hProcess))
  191.                         {
  192.                             ErrorPushGen("Could not AssignProcessToObject");
  193.                         }
  194.                     }
  195.                 }
  196.             }
  197.             #endif
  198.  
  199.             handler.DoRun = [=](Threading::IAuroraThread*)
  200.             {
  201.                 #if defined(AURORA_PLATFORM_WIN32)
  202.                 {
  203.                     WaitForSingleObject(processInfo.hProcess, INFINITE);
  204.  
  205.                     DWORD exitCode;
  206.                     auto result = GetExitCodeProcess(processInfo.hProcess, &exitCode);
  207.                     this->_exitCode = exitCode;
  208.                 }
  209.                 #elif defined(AURORA_PLATFORM_LINUX)
  210.                 {
  211.                     // TODO: experimental (and requires kernel 5.3+)
  212.                     siginfo_t info = {
  213.                         .si_signo = 0,
  214.                     };
  215.  
  216.                     // TODO: vaildate response
  217.                     aurora_sys_waitid(P_PIDFD, this->_linuxsucks, &info, WEXITED, NULL);
  218.  
  219.                     // TODO: confirm this works?!?
  220.                     this->_exitCode = info.si_status;
  221.                 }
  222.                 #endif
  223.             };
  224.            
  225.             this->_thread = Threading::NewThread(handler);
  226.             if (!this->_thread) return false;
  227.            
  228.             this->_thread->Run();
  229.             return true;
  230.         }
  231.  
  232.     private:
  233.  
  234.         AuString _cmd;
  235.         AuList<AuString> _args;
  236.  
  237.         AuList<const char*> _cargs;
  238.         AuString _tardows;
  239.         SpawnType _type;
  240.         Threading::IAuroraThread* _thread;
  241.         AuSInt _exitCode;
  242.  
  243.     #if defined(AURORA_PLATFORM_WIN32)
  244.         HANDLE _process;
  245.         HANDLE _hthread;
  246.     #elif defined(AURORA_PLATFORM_LINUX)
  247.         int _linuxsucks;
  248.     #endif
  249.     };
  250.  
  251.     AUKN_SYM IProcess* Spawn(const AuString& app, const AuList<AuString>& args)
  252.     {
  253.         return _new ProcessImpl(app, args);
  254.     }
  255.  
  256.     AUKN_SYM void Release(IProcess* process)
  257.     {
  258.         SafeDelete<ProcessImpl*>(process);
  259.     }
  260.  
  261.     #if defined (AURORA_PLATFORM_LINUX)
  262.     static void LinuxOpenAsync(const AuString & open)
  263.     {
  264.         if (fork() == 0)
  265.         {
  266.             daemon();
  267.             execl("xdg-open", open.c_str());
  268.         }
  269.     }
  270.     #endif
  271.  
  272.     AUKN_SYM void OpenUri(const AuString& uri)
  273.     {
  274.     #if defined (AURORA_PLATFORM_WIN32)
  275.         ShellExecuteW(NULL, NULL, ::Locale::ConvertFromUTF8(uri).c_str(), NULL, NULL, 0);
  276.     #elif defined (AURORA_PLATFORM_LINUX)
  277.         LinuxOpenAsync(uri);
  278.     #endif
  279.     }
  280.  
  281.     AUKN_SYM void OpenFile(const AuString& file)
  282.     {
  283.     #if defined (AURORA_PLATFORM_WIN32)
  284.         ShellExecuteW(NULL, NULL, ::Locale::ConvertFromUTF8(file).c_str(), NULL, NULL, 0);
  285.     #elif defined (AURORA_PLATFORM_LINUX)
  286.         LinuxOpenAsync(file);
  287.     #endif
  288.     }
  289. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement