nanosm/src/Process.cpp

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