* 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue