using namespace std;
using namespace Msp;
-ExternalTask::ExternalTask(const vector<string> &a, const FS::Path &wd):
+ExternalTask::ExternalTask(const Arguments &a, const FS::Path &wd):
argv(a),
work_dir(wd),
- pid(-1),
+ process(0),
exit_code(-1),
stdout_dest(PASSTHROUGH),
stderr_dest(PASSTHROUGH),
capture_pipe(0)
-{ }
+{
+ if(argv.empty())
+ throw invalid_argument("ExternalTask::ExternalTask");
+}
ExternalTask::~ExternalTask()
{
void ExternalTask::start()
{
- if(stdout_dest==CAPTURE || stderr_dest==CAPTURE)
- capture_pipe = new IO::Pipe;
+ IO::File *devnull = 0;
prepare();
- if((pid = fork()))
+ process = new Process;
+
+ if(stdout_dest==IGNORE || stderr_dest==IGNORE)
{
- if(pid==-1)
- exit_code = 1026;
- else
- exit_code = 0;
+ devnull = new IO::File("/dev/null", IO::M_WRITE);
+ if(stdout_dest==IGNORE)
+ process->redirect_cout(*devnull);
+ if(stderr_dest==IGNORE)
+ process->redirect_cerr(*devnull);
}
- else
+
+ if(stdout_dest==CAPTURE || stderr_dest==CAPTURE)
{
- vector<const char *> cargv(argv.size()+1);
- for(unsigned i=0; i<argv.size(); ++i)
- cargv[i] = argv[i].c_str();
- cargv.back() = 0;
+ capture_pipe = new IO::Pipe;
+ if(stdout_dest==CAPTURE)
+ process->redirect_cout(*capture_pipe);
+ if(stderr_dest==CAPTURE)
+ process->redirect_cerr(*capture_pipe);
+ }
- if(stdout_dest==IGNORE || stderr_dest==IGNORE)
- {
- IO::File devnull("/dev/null", IO::M_WRITE);
- if(stdout_dest==IGNORE)
- IO::cout.redirect(devnull);
- if(stderr_dest==IGNORE)
- IO::cerr.redirect(devnull);
- }
+ if(!work_dir.empty())
+ process->set_working_directory(work_dir);
- if(capture_pipe)
- {
- if(stdout_dest==CAPTURE)
- IO::cout.redirect(*capture_pipe);
- if(stderr_dest==CAPTURE)
- IO::cerr.redirect(*capture_pipe);
- delete capture_pipe;
- }
+ Process::Arguments args(argv.begin()+1, argv.end());
+ process->execute(argv.front(), args);
+ if(capture_pipe)
+ capture_pipe->set_mode(IO::M_READ);
- if(!work_dir.empty())
- FS::chdir(work_dir);
- execvp(cargv.front(), const_cast<char *const *>(&cargv.front()));
- IO::print("Couldn't execute %s\n", argv.front());
- exit(1);
- }
+ delete devnull;
}
Task::Status ExternalTask::check()
Task::Status ExternalTask::do_wait(bool block)
{
- if(pid>0)
+ if(process)
{
- int status;
- if(waitpid(pid, &status, (block ? 0 : WNOHANG))==pid)
+ if(process->wait(block))
{
- if(WIFEXITED(status))
- exit_code = WEXITSTATUS(status);
- else if(WIFSIGNALED(status))
- exit_code = 256+WTERMSIG(status);
- else
- exit_code = 1025;
- pid = 0;
+ exit_code = process->get_exit_code();
+ delete process;
+ process = 0;
}
// Do this after waiting to avoid a race condition
- if(capture_pipe)
+ while(capture_pipe && IO::poll(*capture_pipe, IO::P_INPUT, Time::zero))
{
- while(IO::poll(*capture_pipe, IO::P_INPUT, Time::zero))
- {
- char buf[1024];
- unsigned len = capture_pipe->read(buf, sizeof(buf));
+ char buf[1024];
+ unsigned len = capture_pipe->read(buf, sizeof(buf));
+ if(len)
output.append(buf, len);
- if(len<sizeof(buf))
- break;
- }
+ else
+ break;
}
- if(pid>0)
+ if(process)
return RUNNING;
else
signal_finished.emit(!exit_code);