]> git.tdb.fi Git - libs/core.git/blob - source/core/unix/process.cpp
Add new exception classes for some common errors
[libs/core.git] / source / core / unix / process.cpp
1 #include <unistd.h>
2 #include <sys/wait.h>
3 #include <signal.h>
4 #include <msp/core/systemerror.h>
5 #include <msp/fs/dir.h>
6 #include <msp/io/console.h>
7 #include "except.h"
8 #include "process.h"
9 #include "process_private.h"
10
11 using namespace std;
12
13 namespace Msp {
14
15 Process::~Process()
16 { }
17
18 void Process::platform_get_self_info(Private &priv)
19 {
20         priv.info.pid = getpid();
21 }
22
23 void Process::execute(const string &command, bool path_search, const Arguments &args)
24 {
25         pid_t pid = 0;
26         if(this!=_self)
27                 pid = fork();
28
29         if(pid==-1)
30                 throw system_error("fork");
31         else if(pid==0)
32         {
33                 try
34                 {
35                         vector<const char *> argv(args.size()+2);
36                         argv[0] = command.c_str();
37                         for(unsigned i=0; i<args.size(); ++i)
38                                 argv[i+1] = args[i].c_str();
39                         argv[args.size()+1] = nullptr;
40
41                         if(redirect)
42                         {
43                                 // dup2 clears O_CLOEXEC
44                                 if(cin)
45                                         IO::cin.redirect(*cin);
46                                 if(cout)
47                                         IO::cout.redirect(*cout);
48                                 if(cerr)
49                                         IO::cerr.redirect(*cerr);
50                         }
51
52                         if(!work_dir.empty())
53                                 FS::chdir(work_dir);
54
55                         if(path_search)
56                                 execvp(command.c_str(), const_cast<char *const *>(&argv[0]));
57                         else
58                                 execv(command.c_str(), const_cast<char *const *>(&argv[0]));
59                 }
60                 catch(...)
61                 { }
62                 _exit(255);
63         }
64         else
65         {
66                 priv->info.pid = pid;
67                 running = true;
68         }
69 }
70
71 bool Process::wait(bool block)
72 {
73         if(!running)
74                 throw invalid_state("not running");
75
76         int status;
77         int pid = waitpid(priv->info.pid, &status, (block ? 0 : WNOHANG));
78         if(pid==-1)
79                 throw system_error("waitpid");
80
81         if(pid)
82         {
83                 finished = true;
84                 running = false;
85                 if(WIFEXITED(status))
86                         exit_code = WEXITSTATUS(status);
87                 else if(WIFSIGNALED(status))
88                         exit_code = 0x100|WTERMSIG(status);
89         }
90
91         return finished;
92 }
93
94 void Process::terminate()
95 {
96         ::kill(priv->info.pid, SIGTERM);
97 }
98
99 void Process::kill()
100 {
101         ::kill(priv->info.pid, SIGKILL);
102 }
103
104 void Process::interrupt()
105 {
106         ::kill(priv->info.pid, SIGINT);
107 }
108
109
110 Process::Private::Private()
111 {
112         info.pid = 0;
113 }
114
115 } // namespace Msp