source: trunk/lang/octave/src/rpExec.cc @ 5799

Last change on this file since 5799 was 5799, checked in by clarksm, 8 years ago

Added rpExec functions to run external processes with Matlab and Octave.

File size: 8.7 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  INTERFACE: Octave Rappture Library Interface Helper Functions
4 *
5 * ======================================================================
6 *  AUTHOR:  Steven Clark, Purdue University
7 *  Copyright (c) 2015-2015  HUBzero Foundation, LLC
8 *
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 */
13#include <stdio.h>
14#include <stdlib.h>
15#include <signal.h>
16#include <sys/wait.h>
17#include <unistd.h>
18#include <stdarg.h>
19#include <string.h>
20
21int pid;
22int parentSignal = 0;
23
24void sighup(int sigNum) {
25   if(pid != 0) {
26      parentSignal = SIGHUP;
27      kill(pid,SIGHUP);
28   }
29}
30
31void sigint(int sigNum) {
32   if(pid != 0) {
33      parentSignal = SIGINT;
34      kill(pid,SIGINT);
35   }
36}
37
38void sigterm(int sigNum) {
39   if(pid != 0) {
40      parentSignal = SIGTERM;
41      kill(pid,SIGTERM);
42   }
43}
44
45#define MAXBUFFER 1024
46
47struct stdResults {
48   int streamOutput;
49   char *stdoutBuffer;
50   char *stderrBuffer;
51};
52
53int systemCommand(char *commandExe,
54                  char **commandArgs,
55                  struct stdResults *commandOutput)
56{
57   int             exitPid;
58   int             status;
59   int             exitStatus = 0;
60   int             termSignal = 0;
61   int             signalStatus = 1<<7;
62   sighandler_t    matlabSighup;
63   sighandler_t    matlabSigint;
64   sighandler_t    matlabSigterm;
65   int             stdoutPipe[2];
66   int             stderrPipe[2];
67   fd_set          fdSet;
68   struct timeval  timeout;
69   int             selectReturn;
70   char            buffer[MAXBUFFER+1];
71   int             stdoutEOF;
72   int             stderrEOF;
73   int             nRead;
74   int             stdoutBufferSize = 32*MAXBUFFER;
75   int             stderrBufferSize = 32*MAXBUFFER;
76   char           *stdoutBuffer;
77   char           *stderrBuffer;
78
79   pipe(stdoutPipe);
80   pipe(stderrPipe);
81
82   if((pid = fork()) < 0) {
83      perror("fork");
84      return(1);
85   }
86
87   matlabSighup = signal(SIGHUP,sighup);
88   matlabSigint = signal(SIGINT,sigint);
89   matlabSigterm = signal(SIGTERM,sigterm);
90
91   if(pid == 0) { /* child */
92      dup2(stdoutPipe[1],STDOUT_FILENO);
93      dup2(stderrPipe[1],STDERR_FILENO);
94      close(stdoutPipe[0]);
95      close(stderrPipe[0]);
96
97      signal(SIGHUP,SIG_DFL);
98      signal(SIGINT,SIG_DFL);
99      signal(SIGTERM,SIG_DFL);
100
101      execvp(commandExe,commandArgs);
102   } else {       /* parent */
103      close(stdoutPipe[1]);
104      close(stderrPipe[1]);
105
106      stdoutBuffer = (char *)calloc(stdoutBufferSize,sizeof(char));
107      stderrBuffer = (char *)calloc(stderrBufferSize,sizeof(char));
108
109      stdoutEOF = 0;
110      stderrEOF = 0;
111      while(!stdoutEOF || !stderrEOF) {
112         FD_ZERO(&fdSet);
113         if(!stdoutEOF)
114            FD_SET(stdoutPipe[0],&fdSet);
115         if(!stderrEOF)
116            FD_SET(stderrPipe[0],&fdSet);
117         timeout.tv_sec = 0;
118         timeout.tv_usec = 500000;
119
120         selectReturn = select(FD_SETSIZE,&fdSet,NULL,NULL,&timeout);
121         if(selectReturn > 0) {
122            if(FD_ISSET(stdoutPipe[0],&fdSet)) {
123               nRead = read(stdoutPipe[0],buffer,MAXBUFFER);
124               if(nRead > 0) {
125                  buffer[nRead] = '\0';
126                  if(strlen(stdoutBuffer)+nRead > stdoutBufferSize) {
127                     stdoutBufferSize = 2*stdoutBufferSize;
128                     stdoutBuffer = (char *)realloc(stdoutBuffer,stdoutBufferSize);
129                  }
130                  strcat(stdoutBuffer,buffer);
131                  if(commandOutput->streamOutput)
132                     fprintf(stdout,"%s",buffer);
133               } else {
134                  stdoutEOF = 1;
135               }
136            }
137            if(FD_ISSET(stderrPipe[0],&fdSet)) {
138               nRead = read(stderrPipe[0],buffer,MAXBUFFER);
139               if(nRead > 0) {
140                  buffer[nRead] = '\0';
141                  if(strlen(stderrBuffer)+nRead > stderrBufferSize) {
142                     stderrBufferSize = 2*stderrBufferSize;
143                     stderrBuffer = (char *)realloc(stderrBuffer,stderrBufferSize);
144                  }
145                  strcat(stderrBuffer,buffer);
146                  if(commandOutput->streamOutput)
147                     fprintf(stderr,"%s",buffer);
148               } else {
149                  stderrEOF = 1;
150               }
151            }
152         }
153      }
154
155      commandOutput->stdoutBuffer = stdoutBuffer;
156      commandOutput->stderrBuffer = stderrBuffer;
157
158      exitPid = waitpid(pid,&status,0);
159      if       (WIFSIGNALED(status)) {
160         termSignal = WTERMSIG(status);
161         exitStatus = signalStatus + termSignal;
162      } else if(WIFSTOPPED(status)) {
163         termSignal = WSTOPSIG(status);
164         exitStatus = signalStatus + termSignal;
165      } else if(WIFEXITED(status)) {
166         if(parentSignal > 0) {
167            termSignal = parentSignal;
168            exitStatus = signalStatus + termSignal;
169         } else {
170            exitStatus = WEXITSTATUS(status);
171         }
172      }
173   }
174   signal(SIGHUP,matlabSighup);
175   signal(SIGINT,matlabSigint);
176   signal(SIGTERM,matlabSigterm);
177
178   return(exitStatus);
179}
180
181#include "octave/oct.h"
182#include "octave/Cell.h"
183
184#include "RpOctaveInterface.h"
185
186DEFUN_DLD(rpExec,args,nlhs,
187"-*- texinfo -*-\n\
188@deftypefn {Function} {[@var{exitStatus}]} = rpExec(@var{command},@var{streamOutput})\n\
189@deftypefnx {Function} {[@var{exitStatus}, @var{stdOutput}]} = rpExec(@var{command},@var{streamOutput})\n\
190@deftypefnx {Function} {[@var{exitStatus}, @var{stdOutput}, @var{stdError}]} = rpExec(@var{command},@var{streamOutput})\n\
191\n\
192Execute @var{command} with the ability to terminate the\n\
193process upon reception of a interrupt, hangup, or terminate\n\
194signal. Doing so allows the process to terminated when the\n\
195Rappture \"Abort\" button is pressed.  @var{command} should\n\
196contain a set of strings that comprise the command to be\n\
197executed.  If @var{streamOutput} equals 1 the stdout and\n\
198stderr from @var{command} are piped back to the current process\n\
199stdout and stderr descriptors as @var{command} executes.\n\n\
200On output @var{exitStatus} indicates whether or not an error\n\
201occurred.  @var{exitStatus} equals 0 indicates that no error\n\
202occurred. If @var{stdOutput} is supplied it will contain a\n\
203copy of stdout from @var{command}.  In the same manner if\n\
204@var{stdError} is supplied it will contain a copy of stderr\n\
205from @var{command}.\n\n\
206Example:\n\n\
207[exitStatus,stdOutput,stdError] = rpExec(@{\"submit\",\"--wallTime\",\"30\",\"lammps-12Feb14-serial\",\"-in\",\"lmp.in\"@},1);\n\
208@end deftypefn")
209{
210   static std::string   who = "rpExec";
211   int                  exitStatus = 0;
212   octave_value_list    retval;
213   int                  nrhs = args.length();
214   Cell                 commandCell;
215   char               **commandArgs;
216   const char          *commandArg;
217   struct stdResults    commandOutput;
218   octave_idx_type      i1;
219
220   commandOutput.stdoutBuffer = NULL;
221   commandOutput.stderrBuffer = NULL;
222
223   /* check proper input and output */
224   if(nrhs != 2) {
225      _PRINT_USAGE (who.c_str());
226      exitStatus = 1;
227   }
228   if(nlhs > 3) {
229      _PRINT_USAGE (who.c_str());
230      exitStatus = 1;
231   }
232
233   if(exitStatus == 0) {
234      if(!args(0).is_cell()) {
235         _PRINT_USAGE (who.c_str());
236         exitStatus = 1;
237      }
238   }
239
240   if(exitStatus == 0) {
241      if(!args(1).is_real_scalar()) {
242         _PRINT_USAGE (who.c_str());
243         exitStatus = 1;
244      }
245   }
246
247   if(exitStatus == 0) {
248      commandCell = args(0).cell_value();
249      if(!error_state) {
250         commandArgs = (char **)calloc(commandCell.numel()+1,sizeof(char *));
251         for(i1=0; i1<commandCell.numel(); i1++) {
252            commandArg = c(i1).string_value().c_str();
253            commandArgs[i1] = (char *)calloc(strlen(commandArg)+1,sizeof(char));
254            strcpy(commandArgs[i1],commandArg);
255         }
256         commandArgs[commandCell.numel()] = NULL;
257
258         commandOutput.streamOutput = args(1).int_value();
259         exitStatus = systemCommand(commandArgs[0],commandArgs,&commandOutput);
260
261         for(i1=0; i1<commandCell.numel(); i1++) {
262            free(commandArgs[i1]);
263         }
264         free(commandArgs);
265      }
266   }
267
268   if(nlhs > 0) {
269      retval(0) = octave_value(exitStatus);
270   }
271
272   if(nlhs > 1) {
273      if(commandOutput.stdoutBuffer == NULL) {
274         retval(1) = octave_value("",'"');
275      } else {
276         retval(1) = octave_value(commandOutput.stdoutBuffer,'"');
277      }
278   }
279
280   if(nlhs > 2) {
281      if(commandOutput.stderrBuffer == NULL) {
282         retval(2) = octave_value("",'"');
283      } else {
284         retval(2) = octave_value(commandOutput.stderrBuffer,'"');
285      }
286   }
287
288   free(commandOutput.stdoutBuffer);
289   free(commandOutput.stderrBuffer);
290
291   return retval;
292}
293
294
Note: See TracBrowser for help on using the repository browser.