source: branches/1.4/lang/octave/src/rpExec.cc @ 5918

Last change on this file since 5918 was 5918, checked in by dkearney, 9 years ago

merging r5799 and r5800 (rpExec functions for matlab and octave) from trunk to 1.4 branch

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   int             error;
79
80   error = pipe(stdoutPipe);
81   error = pipe(stderrPipe);
82
83   if((pid = fork()) < 0) {
84      perror("fork");
85      return(1);
86   }
87
88   matlabSighup = signal(SIGHUP,sighup);
89   matlabSigint = signal(SIGINT,sigint);
90   matlabSigterm = signal(SIGTERM,sigterm);
91
92   if(pid == 0) { /* child */
93      dup2(stdoutPipe[1],STDOUT_FILENO);
94      dup2(stderrPipe[1],STDERR_FILENO);
95      close(stdoutPipe[0]);
96      close(stderrPipe[0]);
97
98      signal(SIGHUP,SIG_DFL);
99      signal(SIGINT,SIG_DFL);
100      signal(SIGTERM,SIG_DFL);
101
102      execvp(commandExe,commandArgs);
103   } else {       /* parent */
104      close(stdoutPipe[1]);
105      close(stderrPipe[1]);
106
107      stdoutBuffer = (char *)calloc(stdoutBufferSize,sizeof(char));
108      stderrBuffer = (char *)calloc(stderrBufferSize,sizeof(char));
109
110      stdoutEOF = 0;
111      stderrEOF = 0;
112      while(!stdoutEOF || !stderrEOF) {
113         FD_ZERO(&fdSet);
114         if(!stdoutEOF)
115            FD_SET(stdoutPipe[0],&fdSet);
116         if(!stderrEOF)
117            FD_SET(stderrPipe[0],&fdSet);
118         timeout.tv_sec = 0;
119         timeout.tv_usec = 500000;
120
121         selectReturn = select(FD_SETSIZE,&fdSet,NULL,NULL,&timeout);
122         if(selectReturn > 0) {
123            if(FD_ISSET(stdoutPipe[0],&fdSet)) {
124               nRead = read(stdoutPipe[0],buffer,MAXBUFFER);
125               if(nRead > 0) {
126                  buffer[nRead] = '\0';
127                  if(strlen(stdoutBuffer)+nRead > stdoutBufferSize) {
128                     stdoutBufferSize = 2*stdoutBufferSize;
129                     stdoutBuffer = (char *)realloc(stdoutBuffer,stdoutBufferSize);
130                  }
131                  strcat(stdoutBuffer,buffer);
132                  if(commandOutput->streamOutput)
133                     fprintf(stdout,"%s",buffer);
134               } else {
135                  stdoutEOF = 1;
136               }
137            }
138            if(FD_ISSET(stderrPipe[0],&fdSet)) {
139               nRead = read(stderrPipe[0],buffer,MAXBUFFER);
140               if(nRead > 0) {
141                  buffer[nRead] = '\0';
142                  if(strlen(stderrBuffer)+nRead > stderrBufferSize) {
143                     stderrBufferSize = 2*stderrBufferSize;
144                     stderrBuffer = (char *)realloc(stderrBuffer,stderrBufferSize);
145                  }
146                  strcat(stderrBuffer,buffer);
147                  if(commandOutput->streamOutput)
148                     fprintf(stderr,"%s",buffer);
149               } else {
150                  stderrEOF = 1;
151               }
152            }
153         }
154      }
155
156      commandOutput->stdoutBuffer = stdoutBuffer;
157      commandOutput->stderrBuffer = stderrBuffer;
158
159      exitPid = waitpid(pid,&status,0);
160      if       (WIFSIGNALED(status)) {
161         termSignal = WTERMSIG(status);
162         exitStatus = signalStatus + termSignal;
163      } else if(WIFSTOPPED(status)) {
164         termSignal = WSTOPSIG(status);
165         exitStatus = signalStatus + termSignal;
166      } else if(WIFEXITED(status)) {
167         if(parentSignal > 0) {
168            termSignal = parentSignal;
169            exitStatus = signalStatus + termSignal;
170         } else {
171            exitStatus = WEXITSTATUS(status);
172         }
173      }
174   }
175   signal(SIGHUP,matlabSighup);
176   signal(SIGINT,matlabSigint);
177   signal(SIGTERM,matlabSigterm);
178
179   return(exitStatus);
180}
181
182#include "octave/oct.h"
183#include "octave/Cell.h"
184
185#include "RpOctaveInterface.h"
186
187DEFUN_DLD(rpExec,args,nlhs,
188"-*- texinfo -*-\n\
189@deftypefn {Function} {[@var{exitStatus}]} = rpExec(@var{command},@var{streamOutput})\n\
190@deftypefnx {Function} {[@var{exitStatus}, @var{stdOutput}]} = rpExec(@var{command},@var{streamOutput})\n\
191@deftypefnx {Function} {[@var{exitStatus}, @var{stdOutput}, @var{stdError}]} = rpExec(@var{command},@var{streamOutput})\n\
192\n\
193Execute @var{command} with the ability to terminate the\n\
194process upon reception of a interrupt, hangup, or terminate\n\
195signal. Doing so allows the process to terminated when the\n\
196Rappture \"Abort\" button is pressed.  @var{command} should\n\
197contain a set of strings that comprise the command to be\n\
198executed.  If @var{streamOutput} equals 1 the stdout and\n\
199stderr from @var{command} are piped back to the current process\n\
200stdout and stderr descriptors as @var{command} executes.\n\n\
201On output @var{exitStatus} indicates whether or not an error\n\
202occurred.  @var{exitStatus} equals 0 indicates that no error\n\
203occurred. If @var{stdOutput} is supplied it will contain a\n\
204copy of stdout from @var{command}.  In the same manner if\n\
205@var{stdError} is supplied it will contain a copy of stderr\n\
206from @var{command}.\n\n\
207Example:\n\n\
208[exitStatus,stdOutput,stdError] = rpExec(@{\"submit\",\"--wallTime\",\"30\",\"lammps-12Feb14-serial\",\"-in\",\"lmp.in\"@},1);\n\
209@end deftypefn")
210{
211   static std::string   who = "rpExec";
212   int                  exitStatus = 0;
213   octave_value_list    retval;
214   int                  nrhs = args.length();
215   Cell                 commandCell;
216   char               **commandArgs;
217   const char          *commandArg;
218   struct stdResults    commandOutput;
219   octave_idx_type      i1;
220
221   commandOutput.stdoutBuffer = NULL;
222   commandOutput.stderrBuffer = NULL;
223
224   /* check proper input and output */
225   if(nrhs != 2) {
226      _PRINT_USAGE (who.c_str());
227      exitStatus = 1;
228   }
229   if(nlhs > 3) {
230      _PRINT_USAGE (who.c_str());
231      exitStatus = 1;
232   }
233
234   if(exitStatus == 0) {
235      if(!args(0).is_cell()) {
236         _PRINT_USAGE (who.c_str());
237         exitStatus = 1;
238      }
239   }
240
241   if(exitStatus == 0) {
242      if(!args(1).is_real_scalar()) {
243         _PRINT_USAGE (who.c_str());
244         exitStatus = 1;
245      }
246   }
247
248   if(exitStatus == 0) {
249      commandCell = args(0).cell_value();
250      if(!error_state) {
251         commandArgs = (char **)calloc(commandCell.numel()+1,sizeof(char *));
252         for(i1=0; i1<commandCell.numel(); i1++) {
253            commandArg = commandCell(i1).string_value().c_str();
254            commandArgs[i1] = (char *)calloc(strlen(commandArg)+1,sizeof(char));
255            strcpy(commandArgs[i1],commandArg);
256         }
257         commandArgs[commandCell.numel()] = NULL;
258
259         commandOutput.streamOutput = args(1).int_value();
260         exitStatus = systemCommand(commandArgs[0],commandArgs,&commandOutput);
261
262         for(i1=0; i1<commandCell.numel(); i1++) {
263            free(commandArgs[i1]);
264         }
265         free(commandArgs);
266      }
267   }
268
269   if(nlhs > 0) {
270      retval(0) = octave_value(exitStatus);
271   }
272
273   if(nlhs > 1) {
274      if(commandOutput.stdoutBuffer == NULL) {
275         retval(1) = octave_value("",'"');
276      } else {
277         retval(1) = octave_value(commandOutput.stdoutBuffer,'"');
278      }
279   }
280
281   if(nlhs > 2) {
282      if(commandOutput.stderrBuffer == NULL) {
283         retval(2) = octave_value("",'"');
284      } else {
285         retval(2) = octave_value(commandOutput.stderrBuffer,'"');
286      }
287   }
288
289   free(commandOutput.stdoutBuffer);
290   free(commandOutput.stderrBuffer);
291
292   return retval;
293}
294
295
Note: See TracBrowser for help on using the repository browser.