95 lines
1.9 KiB
C++
95 lines
1.9 KiB
C++
#include "Process.hpp"
|
|
|
|
#include <linux/sched.h>
|
|
#include <sched.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "WordExp.hpp"
|
|
|
|
namespace nanosm {
|
|
|
|
inline static pid_t Clone3(const clone_args& args) {
|
|
return syscall(SYS_clone3, &args, sizeof(clone_args));
|
|
}
|
|
|
|
Process::~Process() {
|
|
Kill();
|
|
Reset();
|
|
}
|
|
|
|
int Process::GetFD() const {
|
|
return pidFd;
|
|
}
|
|
|
|
int Process::InterestedEvents() const {
|
|
/// Pidfd only returns EPOLLIN.
|
|
return EPOLLIN;
|
|
}
|
|
|
|
void Process::Spawn(const std::string& commandLine) {
|
|
commLine = commandLine;
|
|
Respawn();
|
|
}
|
|
|
|
void Process::Respawn() {
|
|
pid = Clone3({
|
|
.flags = CLONE_PIDFD,
|
|
.pidfd = std::bit_cast<u64>(&pidFd),
|
|
.exit_signal = SIGCHLD,
|
|
});
|
|
|
|
if(pid < 0)
|
|
perror("Clone3()");
|
|
|
|
if(pid == 0) {
|
|
// Forked from the parent successfully, execute the given thing
|
|
auto exp = nanosm::WordExp::Expand(commLine);
|
|
std::vector<char*> argv(exp.words.size());
|
|
for(usize i = 0; i < exp.words.size(); ++i)
|
|
argv[i] = exp.words[i].data();
|
|
|
|
execvp(exp.words[0].data(), argv.data());
|
|
} else {
|
|
// Parent: monitor FD
|
|
eventLoop.AddObject(IoObject::Ptr(shared_from_this()));
|
|
}
|
|
}
|
|
|
|
void Process::OnReady(int eventMask) {
|
|
// In our case, any readiness signaled by the pidfd means the process exited
|
|
// so this will never block (or really, wait).
|
|
waitid(P_PIDFD, pidFd, &siginfo, WNOHANG);
|
|
|
|
// Post a callback to call the user's exit callback (if one exists)
|
|
eventLoop.Post([self = shared_from_this()]() {
|
|
// Prepare for re-attaching, or etc.
|
|
self->eventLoop.RemoveObject(self);
|
|
self->Reset();
|
|
|
|
if(self->onProcessExit)
|
|
self->onProcessExit(self->siginfo.si_status);
|
|
});
|
|
}
|
|
|
|
void Process::Kill() {
|
|
if(pid != -1)
|
|
kill(pid, SIGTERM);
|
|
}
|
|
|
|
void Process::SetExitCallback(std::function<void(int)> f) {
|
|
onProcessExit = f;
|
|
}
|
|
|
|
void Process::Reset() {
|
|
if(pidFd != -1) {
|
|
close(pidFd);
|
|
pidFd = -1;
|
|
}
|
|
|
|
pid = -1;
|
|
siginfo = {};
|
|
}
|
|
|
|
} // namespace nanosm
|