source: branches/1.5/lang/matlab/rpExec.c @ 5927

Last change on this file since 5927 was 5927, checked in by clarksm, 7 years ago

Fix memory allocation issue revealed when using newer Matlab versions.

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