* Wrapper class around pids.
This commit is contained in:
parent
155d7c8dfa
commit
c9fbd2dfd5
4 changed files with 162 additions and 87 deletions
|
@ -3,11 +3,8 @@
|
||||||
#include <boost/enable_shared_from_this.hpp>
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "normalise.hh"
|
#include "normalise.hh"
|
||||||
|
@ -60,7 +57,7 @@ protected:
|
||||||
|
|
||||||
virtual ~Goal()
|
virtual ~Goal()
|
||||||
{
|
{
|
||||||
debug("goal destroyed");
|
printMsg(lvlVomit, "goal destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -157,26 +154,6 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
void killChild(pid_t pid)
|
|
||||||
{
|
|
||||||
/* Send a KILL signal to every process in the child process group
|
|
||||||
(which hopefully includes *all* its children). */
|
|
||||||
if (kill(-pid, SIGKILL) != 0)
|
|
||||||
printMsg(lvlError, format("killing process %1%") % pid);
|
|
||||||
else {
|
|
||||||
/* Wait until the child dies, disregarding the exit status. */
|
|
||||||
int status;
|
|
||||||
while (waitpid(pid, &status, 0) == -1)
|
|
||||||
if (errno != EINTR) printMsg(lvlError,
|
|
||||||
format("waiting for process %1%") % pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,7 +210,7 @@ private:
|
||||||
map<Path, Path> inputSucs;
|
map<Path, Path> inputSucs;
|
||||||
|
|
||||||
/* The process ID of the builder. */
|
/* The process ID of the builder. */
|
||||||
pid_t pid;
|
Pid pid;
|
||||||
|
|
||||||
/* The temporary directory. */
|
/* The temporary directory. */
|
||||||
Path tmpDir;
|
Path tmpDir;
|
||||||
|
@ -309,7 +286,6 @@ NormalisationGoal::NormalisationGoal(const Path & _nePath, Worker & _worker)
|
||||||
: Goal(_worker)
|
: Goal(_worker)
|
||||||
{
|
{
|
||||||
nePath = _nePath;
|
nePath = _nePath;
|
||||||
pid = -1;
|
|
||||||
state = &NormalisationGoal::init;
|
state = &NormalisationGoal::init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,13 +294,6 @@ NormalisationGoal::~NormalisationGoal()
|
||||||
{
|
{
|
||||||
/* Careful: we should never ever throw an exception from a
|
/* Careful: we should never ever throw an exception from a
|
||||||
destructor. */
|
destructor. */
|
||||||
|
|
||||||
if (pid != -1) {
|
|
||||||
printMsg(lvlError, format("killing child process %1% (%2%)")
|
|
||||||
% pid % nePath);
|
|
||||||
killChild(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deleteTmpDir(false);
|
deleteTmpDir(false);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
@ -471,20 +440,16 @@ void NormalisationGoal::buildDone()
|
||||||
{
|
{
|
||||||
debug(format("build done for `%1%'") % nePath);
|
debug(format("build done for `%1%'") % nePath);
|
||||||
|
|
||||||
int status;
|
|
||||||
|
|
||||||
/* Since we got an EOF on the logger pipe, the builder is presumed
|
/* Since we got an EOF on the logger pipe, the builder is presumed
|
||||||
to have terminated. In fact, the builder could also have
|
to have terminated. In fact, the builder could also have
|
||||||
simply have closed its end of the pipe --- just don't do that
|
simply have closed its end of the pipe --- just don't do that
|
||||||
:-) */
|
:-) */
|
||||||
/* !!! this could block! */
|
/* !!! this could block! */
|
||||||
if (waitpid(pid, &status, 0) != pid)
|
pid_t savedPid = pid;
|
||||||
throw SysError(format("builder for `%1%' should have terminated")
|
int status = pid.wait(true);
|
||||||
% nePath);
|
|
||||||
|
|
||||||
/* So the child is gone now. */
|
/* So the child is gone now. */
|
||||||
worker.childTerminated(pid);
|
worker.childTerminated(savedPid);
|
||||||
pid = -1;
|
|
||||||
|
|
||||||
/* Close the read side of the logger pipe. */
|
/* Close the read side of the logger pipe. */
|
||||||
logPipe.readSide.close();
|
logPipe.readSide.close();
|
||||||
|
@ -570,7 +535,8 @@ NormalisationGoal::HookReply NormalisationGoal::tryBuildHook()
|
||||||
fromHook.create();
|
fromHook.create();
|
||||||
|
|
||||||
/* Fork the hook. */
|
/* Fork the hook. */
|
||||||
switch (pid = fork()) {
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
throw SysError("unable to fork");
|
throw SysError("unable to fork");
|
||||||
|
@ -678,11 +644,9 @@ void NormalisationGoal::terminateBuildHook()
|
||||||
{
|
{
|
||||||
/* !!! drain stdout of hook */
|
/* !!! drain stdout of hook */
|
||||||
debug("terminating build hook");
|
debug("terminating build hook");
|
||||||
int status;
|
pid_t savedPid = pid;
|
||||||
if (waitpid(pid, &status, 0) != pid)
|
pid.wait(true);
|
||||||
printMsg(lvlError, format("process `%1%' missing") % pid);
|
worker.childTerminated(savedPid);
|
||||||
worker.childTerminated(pid);
|
|
||||||
pid = -1;
|
|
||||||
fromHook.readSide.close();
|
fromHook.readSide.close();
|
||||||
toHook.writeSide.close();
|
toHook.writeSide.close();
|
||||||
fdLogFile.close();
|
fdLogFile.close();
|
||||||
|
@ -836,7 +800,8 @@ void NormalisationGoal::startBuilder()
|
||||||
currently use forks to run and wait for the children, it
|
currently use forks to run and wait for the children, it
|
||||||
shouldn't be hard to use threads for this on systems where
|
shouldn't be hard to use threads for this on systems where
|
||||||
fork() is unavailable or inefficient. */
|
fork() is unavailable or inefficient. */
|
||||||
switch (pid = fork()) {
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
throw SysError("unable to fork");
|
throw SysError("unable to fork");
|
||||||
|
@ -885,6 +850,7 @@ void NormalisationGoal::startBuilder()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent */
|
/* parent */
|
||||||
|
pid.setSeparatePG(true);
|
||||||
logPipe.writeSide.close();
|
logPipe.writeSide.close();
|
||||||
worker.childStarted(shared_from_this(),
|
worker.childStarted(shared_from_this(),
|
||||||
pid, logPipe.readSide, true);
|
pid, logPipe.readSide, true);
|
||||||
|
@ -1199,7 +1165,7 @@ private:
|
||||||
Pipe logPipe;
|
Pipe logPipe;
|
||||||
|
|
||||||
/* The process ID of the builder. */
|
/* The process ID of the builder. */
|
||||||
pid_t pid;
|
Pid pid;
|
||||||
|
|
||||||
/* Lock on the store path. */
|
/* Lock on the store path. */
|
||||||
PathLocks outputLock;
|
PathLocks outputLock;
|
||||||
|
@ -1209,7 +1175,6 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SubstitutionGoal(const Path & _nePath, Worker & _worker);
|
SubstitutionGoal(const Path & _nePath, Worker & _worker);
|
||||||
~SubstitutionGoal();
|
|
||||||
|
|
||||||
void work();
|
void work();
|
||||||
|
|
||||||
|
@ -1227,22 +1192,10 @@ SubstitutionGoal::SubstitutionGoal(const Path & _storePath, Worker & _worker)
|
||||||
: Goal(_worker)
|
: Goal(_worker)
|
||||||
{
|
{
|
||||||
storePath = _storePath;
|
storePath = _storePath;
|
||||||
pid = -1;
|
|
||||||
state = &SubstitutionGoal::init;
|
state = &SubstitutionGoal::init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SubstitutionGoal::~SubstitutionGoal()
|
|
||||||
{
|
|
||||||
/* !!! turn this into a destructor for pids */
|
|
||||||
if (pid != -1) {
|
|
||||||
printMsg(lvlError, format("killing child process %1% (%2%)")
|
|
||||||
% pid % storePath);
|
|
||||||
killChild(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SubstitutionGoal::work()
|
void SubstitutionGoal::work()
|
||||||
{
|
{
|
||||||
(this->*state)();
|
(this->*state)();
|
||||||
|
@ -1345,7 +1298,8 @@ void SubstitutionGoal::tryToRun()
|
||||||
deletePath(storePath);
|
deletePath(storePath);
|
||||||
|
|
||||||
/* Fork the substitute program. */
|
/* Fork the substitute program. */
|
||||||
switch (pid = fork()) {
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
throw SysError("unable to fork");
|
throw SysError("unable to fork");
|
||||||
|
@ -1402,6 +1356,7 @@ void SubstitutionGoal::tryToRun()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent */
|
/* parent */
|
||||||
|
pid.setSeparatePG(true);
|
||||||
logPipe.writeSide.close();
|
logPipe.writeSide.close();
|
||||||
worker.childStarted(shared_from_this(),
|
worker.childStarted(shared_from_this(),
|
||||||
pid, logPipe.readSide, true);
|
pid, logPipe.readSide, true);
|
||||||
|
@ -1414,18 +1369,14 @@ void SubstitutionGoal::finished()
|
||||||
{
|
{
|
||||||
debug(format("substitute finished of `%1%'") % storePath);
|
debug(format("substitute finished of `%1%'") % storePath);
|
||||||
|
|
||||||
int status;
|
|
||||||
|
|
||||||
/* Since we got an EOF on the logger pipe, the substitute is
|
/* Since we got an EOF on the logger pipe, the substitute is
|
||||||
presumed to have terminated. */
|
presumed to have terminated. */
|
||||||
/* !!! this could block! */
|
/* !!! this could block! */
|
||||||
if (waitpid(pid, &status, 0) != pid)
|
pid_t savedPid = pid;
|
||||||
throw SysError(format("substitute for `%1%' should have terminated")
|
int status = pid.wait(true);
|
||||||
% storePath);
|
|
||||||
|
|
||||||
/* So the child is gone now. */
|
/* So the child is gone now. */
|
||||||
worker.childTerminated(pid);
|
worker.childTerminated(savedPid);
|
||||||
pid = -1;
|
|
||||||
|
|
||||||
/* Close the read side of the logger pipe. */
|
/* Close the read side of the logger pipe. */
|
||||||
logPipe.readSide.close();
|
logPipe.readSide.close();
|
||||||
|
@ -1534,7 +1485,7 @@ void Worker::removeGoal(GoalPtr goal)
|
||||||
|
|
||||||
void Worker::wakeUp(GoalPtr goal)
|
void Worker::wakeUp(GoalPtr goal)
|
||||||
{
|
{
|
||||||
debug("wake up");
|
printMsg(lvlVomit, "wake up");
|
||||||
awake.insert(goal);
|
awake.insert(goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1593,8 +1544,6 @@ void Worker::run()
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
debug(format("main loop (%1% goals left)") % goals.size());
|
|
||||||
|
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
/* Call every wake goal. */
|
/* Call every wake goal. */
|
||||||
|
@ -1602,7 +1551,8 @@ void Worker::run()
|
||||||
Goals awake2(awake); /* !!! why is this necessary? */
|
Goals awake2(awake); /* !!! why is this necessary? */
|
||||||
awake.clear();
|
awake.clear();
|
||||||
for (Goals::iterator i = awake2.begin(); i != awake2.end(); ++i) {
|
for (Goals::iterator i = awake2.begin(); i != awake2.end(); ++i) {
|
||||||
debug("goal");
|
printMsg(lvlVomit,
|
||||||
|
format("running goal (%1% left)") % goals.size());
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
GoalPtr goal = *i;
|
GoalPtr goal = *i;
|
||||||
goal->work();
|
goal->work();
|
||||||
|
@ -1714,5 +1664,7 @@ void ensurePath(const Path & path)
|
||||||
/* If the path is already valid, we're done. */
|
/* If the path is already valid, we're done. */
|
||||||
if (isValidPath(path)) return;
|
if (isValidPath(path)) return;
|
||||||
|
|
||||||
/* !!! add realisation goal */
|
Worker worker;
|
||||||
|
worker.addSubstitutionGoal(path, GoalPtr());
|
||||||
|
worker.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,21 +127,22 @@ void copyPath(const Path & src, const Path & dst)
|
||||||
use a thread). */
|
use a thread). */
|
||||||
|
|
||||||
/* Create a pipe. */
|
/* Create a pipe. */
|
||||||
int fds[2];
|
Pipe pipe;
|
||||||
if (pipe(fds) == -1) throw SysError("creating pipe");
|
pipe.create();
|
||||||
|
|
||||||
/* Fork. */
|
/* Fork. */
|
||||||
pid_t pid;
|
Pid pid;
|
||||||
switch (pid = fork()) {
|
pid = fork();
|
||||||
|
switch (pid) {
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
throw SysError("unable to fork");
|
throw SysError("unable to fork");
|
||||||
|
|
||||||
case 0: /* child */
|
case 0: /* child */
|
||||||
try {
|
try {
|
||||||
close(fds[1]);
|
pipe.writeSide.close();
|
||||||
CopySource source;
|
CopySource source;
|
||||||
source.fd = fds[0];
|
source.fd = pipe.readSide;
|
||||||
restorePath(dst, source);
|
restorePath(dst, source);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
} catch (exception & e) {
|
} catch (exception & e) {
|
||||||
|
@ -150,19 +151,16 @@ void copyPath(const Path & src, const Path & dst)
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fds[0]);
|
|
||||||
|
|
||||||
/* Parent. */
|
/* Parent. */
|
||||||
|
|
||||||
|
pipe.readSide.close();
|
||||||
|
|
||||||
CopySink sink;
|
CopySink sink;
|
||||||
sink.fd = fds[1];
|
sink.fd = pipe.writeSide;
|
||||||
dumpPath(src, sink);
|
dumpPath(src, sink);
|
||||||
|
|
||||||
/* Wait for the child to finish. */
|
/* Wait for the child to finish. */
|
||||||
int status;
|
int status = pid.wait(true);
|
||||||
if (waitpid(pid, &status, 0) != pid)
|
|
||||||
throw SysError("waiting for child");
|
|
||||||
|
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||||
throw Error(format("cannot copy `%1% to `%2%': child %3%")
|
throw Error(format("cannot copy `%1% to `%2%': child %3%")
|
||||||
% src % dst % statusToString(status));
|
% src % dst % statusToString(status));
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
|
@ -337,6 +339,10 @@ void writeFull(int fd, const unsigned char * buf, size_t count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
AutoDelete::AutoDelete(const string & p) : path(p)
|
AutoDelete::AutoDelete(const string & p) : path(p)
|
||||||
{
|
{
|
||||||
del = true;
|
del = true;
|
||||||
|
@ -353,16 +359,22 @@ void AutoDelete::cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::AutoCloseFD()
|
AutoCloseFD::AutoCloseFD()
|
||||||
{
|
{
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::AutoCloseFD(int fd)
|
AutoCloseFD::AutoCloseFD(int fd)
|
||||||
{
|
{
|
||||||
this->fd = fd;
|
this->fd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::~AutoCloseFD()
|
AutoCloseFD::~AutoCloseFD()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -372,17 +384,20 @@ AutoCloseFD::~AutoCloseFD()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AutoCloseFD::operator =(int fd)
|
void AutoCloseFD::operator =(int fd)
|
||||||
{
|
{
|
||||||
if (this->fd != fd) close();
|
if (this->fd != fd) close();
|
||||||
this->fd = fd;
|
this->fd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseFD::operator int()
|
AutoCloseFD::operator int()
|
||||||
{
|
{
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AutoCloseFD::close()
|
void AutoCloseFD::close()
|
||||||
{
|
{
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
|
@ -393,6 +408,7 @@ void AutoCloseFD::close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AutoCloseFD::isOpen()
|
bool AutoCloseFD::isOpen()
|
||||||
{
|
{
|
||||||
return fd != -1;
|
return fd != -1;
|
||||||
|
@ -408,32 +424,119 @@ void Pipe::create()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
AutoCloseDir::AutoCloseDir()
|
AutoCloseDir::AutoCloseDir()
|
||||||
{
|
{
|
||||||
dir = 0;
|
dir = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseDir::AutoCloseDir(DIR * dir)
|
AutoCloseDir::AutoCloseDir(DIR * dir)
|
||||||
{
|
{
|
||||||
this->dir = dir;
|
this->dir = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseDir::~AutoCloseDir()
|
AutoCloseDir::~AutoCloseDir()
|
||||||
{
|
{
|
||||||
if (dir) closedir(dir);
|
if (dir) closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AutoCloseDir::operator =(DIR * dir)
|
void AutoCloseDir::operator =(DIR * dir)
|
||||||
{
|
{
|
||||||
this->dir = dir;
|
this->dir = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoCloseDir::operator DIR *()
|
AutoCloseDir::operator DIR *()
|
||||||
{
|
{
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
Pid::Pid()
|
||||||
|
{
|
||||||
|
pid = -1;
|
||||||
|
separatePG = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Pid::~Pid()
|
||||||
|
{
|
||||||
|
kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pid::operator =(pid_t pid)
|
||||||
|
{
|
||||||
|
if (this->pid != pid) kill();
|
||||||
|
this->pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Pid::operator pid_t()
|
||||||
|
{
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pid::kill()
|
||||||
|
{
|
||||||
|
if (pid == -1) return;
|
||||||
|
|
||||||
|
printMsg(lvlError, format("killing child process %1%") % pid);
|
||||||
|
|
||||||
|
/* Send a KILL signal to the child. If it has its own process
|
||||||
|
group, send the signal to every process in the child process
|
||||||
|
group (which hopefully includes *all* its children). */
|
||||||
|
if (::kill(separatePG ? -pid : pid, SIGKILL) != 0)
|
||||||
|
printMsg(lvlError, format("killing process %1%") % pid);
|
||||||
|
else {
|
||||||
|
/* Wait until the child dies, disregarding the exit status. */
|
||||||
|
int status;
|
||||||
|
while (waitpid(pid, &status, 0) == -1)
|
||||||
|
if (errno != EINTR) printMsg(lvlError,
|
||||||
|
format("waiting for process %1%") % pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Pid::wait(bool block)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
int status;
|
||||||
|
int res = waitpid(pid, &status, block ? 0 : WNOHANG);
|
||||||
|
if (res == pid) {
|
||||||
|
pid = -1;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if (res == 0 && !block) return -1;
|
||||||
|
if (errno != EINTR)
|
||||||
|
throw SysError("cannot get child exit status");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pid::setSeparatePG(bool separatePG)
|
||||||
|
{
|
||||||
|
this->separatePG = separatePG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
volatile sig_atomic_t _isInterrupted = 0;
|
volatile sig_atomic_t _isInterrupted = 0;
|
||||||
|
|
||||||
void _interrupted()
|
void _interrupted()
|
||||||
|
@ -448,6 +551,10 @@ void _interrupted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
string packStrings(const Strings & strings)
|
string packStrings(const Strings & strings)
|
||||||
{
|
{
|
||||||
string d;
|
string d;
|
||||||
|
|
|
@ -172,6 +172,7 @@ public:
|
||||||
void cancel();
|
void cancel();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AutoCloseFD
|
class AutoCloseFD
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -185,6 +186,7 @@ public:
|
||||||
bool isOpen();
|
bool isOpen();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Pipe
|
class Pipe
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -192,6 +194,7 @@ public:
|
||||||
void create();
|
void create();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AutoCloseDir
|
class AutoCloseDir
|
||||||
{
|
{
|
||||||
DIR * dir;
|
DIR * dir;
|
||||||
|
@ -204,6 +207,21 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Pid
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
bool separatePG;
|
||||||
|
public:
|
||||||
|
Pid();
|
||||||
|
~Pid();
|
||||||
|
void operator =(pid_t pid);
|
||||||
|
operator pid_t();
|
||||||
|
void kill();
|
||||||
|
int wait(bool block);
|
||||||
|
void setSeparatePG(bool separatePG);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* User interruption. */
|
/* User interruption. */
|
||||||
|
|
||||||
extern volatile sig_atomic_t _isInterrupted;
|
extern volatile sig_atomic_t _isInterrupted;
|
||||||
|
|
Loading…
Reference in a new issue