ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/debug/Process.cpp
Revision: 1490
Committed: Fri Aug 13 15:02:28 2010 UTC (14 years, 8 months ago) by chuckv
File size: 6127 byte(s)
Log Message:
Adding some error reporting and debuging code to OpenMD. This code is borrowed from ProtoMol.

File Contents

# Content
1 /*******************************************************************\
2
3 Copyright (C) 2004 Joseph Coffland
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 02111-1307, USA.
19
20 For information regarding this software email
21 jcofflan@users.sourceforge.net
22
23 \*******************************************************************/
24 #include <protomol/debug/Process.h>
25
26 #include <protomol/base/Exception.h>
27 #include <protomol/debug/Debugger.h>
28 #include <protomol/debug/Pipe.h>
29 #include <protomol/type/String.h>
30 #include <protomol/base/Zap.h>
31
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <signal.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <string>
40
41 using namespace std;
42 using namespace ProtoMol;
43
44 void PipeProcessFunctor::child() {
45 if (direction == Process::TO_CHILD) {
46 pipe.closeIn();
47 if (fd >= 0) pipe.moveOutFD(fd);
48 } else {
49 pipe.closeOut();
50 if (fd >= 0) pipe.moveInFD(fd);
51 }
52 }
53
54 void PipeProcessFunctor::parent() {
55 if (direction == Process::TO_CHILD) pipe.closeOut();
56 else pipe.closeIn();
57 }
58
59 void FDReplaceProcessFunctor::child() {
60 if (dup2(replacement, fd) != fd)
61 THROW("Error replacing file descriptor in child process!");
62 }
63
64 Process::Process() :
65 pid(0), running(false), returnCode(0) {}
66
67 Process::~Process() {
68 if (isRunning()) {
69 kill(SIGHUP);
70 wait();
71 }
72
73 for (unsigned int i = 0; i < functors.size(); i++)
74 delete functors[i];
75 }
76
77 void Process::exec(list<string> &args) {
78 SmartPointer<char *>::Array argv = new char *[args.size() + 1];
79 list<string>::iterator it;
80 unsigned int i = 0;
81
82 for (i = 0, it = args.begin(); it != args.end(); i++, it++)
83 argv[i] = (char *)it->c_str();
84
85 argv[i] = 0;
86
87 exec(argv.get());
88 }
89
90 void Process::exec(const char *args) {
91 SmartPointer<char, SP_MALLOC> tmp = strdup(args);
92 exec(tmp.get());
93 }
94
95 void Process::exec(char *args) {
96 char *argv[256];
97 int argc = 0;
98
99 parseArgs(args, argc, argv, 256);
100 exec(argv);
101 }
102
103 void Process::exec(char *argv[]) {
104 ASSERT_OR_THROW("Process all ready running!", !isRunning());
105
106 pid = fork();
107
108 if (pid == 0) {
109 try {
110 for (unsigned int i = 0; i < functors.size(); i++)
111 functors[i]->child();
112 } catch (const Exception &e) {
113 perror(e.getMessage().c_str());
114 }
115
116 execvp(argv[0], argv);
117
118 // Execution failed!
119 string errorStr = "Process() executing '";
120 for (unsigned i = 0; argv[i]; i++) {
121 if (i) errorStr += " ";
122 errorStr += argv[i];
123 }
124
125 errorStr += "'";
126
127 perror(errorStr.c_str());
128 exit(1);
129 } else if (pid == -1)
130 THROW("Failed to spawn child!");
131
132 running = true;
133
134 for (unsigned int i = 0; i < functors.size(); i++)
135 functors[i]->parent();
136 }
137
138 void Process::parseArgs(char *args, int &argc, char *argv[], int n) {
139 if (args) {
140 bool inArg = false;
141 bool inSQuote = false;
142 bool inDQuote = false;
143 bool addChar;
144 int i = 0;
145
146 for (char *ptr = args; *ptr; ptr++) {
147 addChar = false;
148
149 switch (*ptr) {
150 case '\\':
151 if (ptr[1] != '\0') {
152 ptr++;
153 switch (*ptr) {
154 case 'n': *ptr = '\n';
155 break;
156 case 't': *ptr = '\t';
157 break;
158 case 'r': *ptr = '\r';
159 break;
160 default: break;
161 }
162
163 addChar = true;
164 }
165 break;
166
167 case '\'':
168 if (inDQuote) addChar = true;
169 else
170 if (inSQuote) inSQuote = false;
171 else inSQuote = true;
172 break;
173
174 case '"':
175 if (inSQuote) addChar = true;
176 else
177 if (inDQuote) inDQuote = false;
178 else inDQuote = true;
179 break;
180
181 case '\t':
182 case ' ':
183 case '\n':
184 case '\r':
185 if (inArg) {
186 if (inSQuote || inDQuote) addChar = true;
187 else {
188 args[i++] = 0;
189 inArg = false;
190 }
191 }
192 break;
193
194 default: addChar = true;
195 break;
196 }
197
198 if (addChar) {
199 if (!inArg) {
200 ASSERT_OR_THROW("Too many arguments!", argc < n - 1);
201 argv[argc++] = &args[i];
202 inArg = true;
203 }
204 args[i++] = *ptr;
205 }
206 }
207
208 if (inArg) args[i] = 0;
209 }
210
211 argv[argc] = 0;
212 }
213
214 Pipe *Process::getChildPipe(dir_t dir, int childFD) {
215 ASSERT_OR_THROW("Process all ready running!", !running);
216
217 PipeProcessFunctor *functor = new PipeProcessFunctor(dir, childFD);
218 functors.push_back(functor);
219
220 return functor->getPipe();
221 }
222
223 void Process::replaceChildFD(int fd, int replacement) {
224 functors.push_back(new FDReplaceProcessFunctor(fd, replacement));
225 }
226
227 void Process::kill(int sig) {
228 ASSERT_OR_THROW("Process not running!", running);
229
230 if (::kill(pid, sig) != 0)
231 THROW(string("Failed to kill process ") + String(pid) + ":" +
232 strerror(errno));
233 }
234
235 int Process::wait(int options) {
236 ASSERT_OR_THROW("Process not running!", running);
237
238 int status = 0;
239 int retVal = waitpid(pid, &status, options);
240
241 if (retVal == -1) {
242 running = false;
243 THROW(string("Failed to wait on process ") + String(pid) + ":" +
244 strerror(errno));
245 }
246
247 if (retVal) {
248 if (WIFEXITED(status)) {
249 returnCode = WEXITSTATUS(status);
250 running = false;
251 } else if (WIFSIGNALED(status))
252 // TODO report on signal
253 running = false;
254 }
255
256 return status;
257 }
258
259 bool Process::isRunning() {
260 if (running) wait(WNOHANG);
261 return running;
262 }
263