source: trunk/lang/matlab/rpExec.c @ 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: 7.5 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  INTERFACE: Matlab 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 "mex.h"
182
183void mexFunction( int nlhs, mxArray *plhs[],
184                  int nrhs, const mxArray *prhs[] )
185{
186   const mxArray      *cellArray;
187   const mwSize       *dims;
188   mwIndex             i1;
189   char               *tmp;
190   char              **commandArgs;
191   int                 exitStatus = 0;
192   int                *return1;
193   int                 streamOutput;
194   struct stdResults   commandOutput;
195
196   commandOutput.stdoutBuffer = NULL;
197   commandOutput.stderrBuffer = NULL;
198
199   /* check proper input and output */
200   if(nrhs != 2) {
201      mexErrMsgIdAndTxt("rpExec:invalidNumInputs","Two input arguments required.");
202      exitStatus = 1;
203   }
204   if(nlhs > 3) {
205      mexErrMsgIdAndTxt("rpExec:maxlhs","Too many output arguments.");
206      exitStatus = 1;
207   }
208
209   if(exitStatus == 0) {
210      if       (!mxIsCell(prhs[0])) {
211         mexErrMsgIdAndTxt("rpExec:inputNotCell","Command must be a cell array.");
212         exitStatus = 1;
213      } else if(mxGetNumberOfDimensions(prhs[0]) != 2) {
214         mexErrMsgIdAndTxt("rpExec:inputNot2DCell","Command must be a 2 dimensional cell array.");
215         exitStatus = 1;
216      } else if(mxGetM(prhs[0]) != 1) {
217         mexErrMsgIdAndTxt("rpExec:inputNotVector","Command must be a row vector.");
218         exitStatus = 1;
219      }
220   }
221
222   if(exitStatus == 0) {
223      if(mxGetNumberOfElements(prhs[1]) != 1) {
224         mexErrMsgIdAndTxt("rpExec:inputNotScalar","streamOutput must be a scaler.");
225         exitStatus = 1;
226      }
227   }
228
229   if(exitStatus == 0) {
230      dims = mxGetDimensions(prhs[0]);
231      commandArgs = mxCalloc(dims[1]+1,sizeof(char *));
232      for(i1=0; i1<dims[1]; i1++) {
233         cellArray = mxGetCell(prhs[0],i1);
234         commandArgs[i1] = mxArrayToString(cellArray);
235      }
236      commandArgs[dims[1]] = NULL;
237
238      commandOutput.streamOutput = mxGetScalar(prhs[1]);
239      exitStatus = systemCommand(commandArgs[0],commandArgs,&commandOutput);
240
241      for(i1=0; i1<dims[1]; i1++) {
242         mxFree(commandArgs[i1]);
243      }
244      mxFree(commandArgs);
245   }
246
247   if(nlhs > 1) {
248      plhs[0] = mxCreateNumericMatrix(1,1,mxINT32_CLASS,mxREAL);
249      return1 = (int *)mxGetData(plhs[0]);
250      return1[0] = exitStatus;
251   }
252
253   if(nlhs > 1) {
254      plhs[1] = mxCreateString(commandOutput.stdoutBuffer);
255   }
256
257   if(nlhs > 2) {
258      plhs[2] = mxCreateString(commandOutput.stderrBuffer);
259   }
260
261   mxFree(commandOutput.stdoutBuffer);
262   mxFree(commandOutput.stderrBuffer);
263}
264
265
Note: See TracBrowser for help on using the repository browser.