ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/debug/Process.cpp
Revision: 1491
Committed: Mon Aug 16 18:05:58 2010 UTC (14 years, 8 months ago) by chuckv
File size: 6111 byte(s)
Log Message:
Adding debugging and tracing tools from protomol to openmd.

File Contents

# User Rev Content
1 chuckv 1490 /*******************************************************************\
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 chuckv 1491 #include "debug/Process.hpp"
25 chuckv 1490
26 chuckv 1491 #include "utils/Exception.hpp"
27     #include "debug/Debugger.hpp"
28     #include "debug/Pipe.hpp"
29     #include "utils/StringUtils.hpp"
30     #include "utils/Zap.hpp"
31 chuckv 1490
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 chuckv 1491 using namespace OpenMD;
43 chuckv 1490
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 chuckv 1491 THROW(string("Failed to kill process ") + string(toString(pid)) + ":" +
232 chuckv 1490 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 chuckv 1491 THROW(string("Failed to wait on process ") + string(toString(pid)) + ":" +
244 chuckv 1490 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