ExecutableCommPort.cc
Go to the documentation of this file.00001 #include "ExecutableCommPort.h"
00002 #include <sys/types.h>
00003 #include <sys/socket.h>
00004 #include <sys/wait.h>
00005 #include <unistd.h>
00006
00007 using namespace std;
00008
00009 const std::string ExecutableCommPort::autoRegisterExecutableCommPort = CommPort::getRegistry().registerType<ExecutableCommPort>("ExecutableCommPort");
00010
00011 ExecutableCommPort::~ExecutableCommPort() {
00012 if(openedCnt>0) {
00013 cerr << "Connection still open in ExecutableCommPort destructor" << endl;
00014 command.removePrimitiveListener(this);
00015 shell.removePrimitiveListener(this);
00016 }
00017 if(!isChildRunning())
00018 return;
00019 cerr << "ExecutableCommPort destructing, but child is still running... waiting 3 seconds" << endl;
00020 if(waitChild(3000,500))
00021 return;
00022 cerr << "ExecutableCommPort child is STILL running... sending interrupt signal" << endl;
00023 if(kill(child,SIGINT)==-1) {
00024 perror("ExecutableCommPort unable to kill child");
00025 return;
00026 }
00027 if(waitChild(2000,500))
00028 return;
00029 cerr << "ExecutableCommPort child is STILL running... sending kill signal and moving on..." << endl;
00030 if(kill(child,SIGKILL)==-1) {
00031 perror("ExecutableCommPort unable to kill child");
00032 return;
00033 }
00034 }
00035
00036 bool ExecutableCommPort::open() {
00037 if(openedCnt++>0)
00038 return true;
00039 command.addPrimitiveListener(this);
00040 shell.addPrimitiveListener(this);
00041
00042 int s2c[2];
00043 int c2s[2];
00044 if(pipe(s2c)==-1) {
00045 perror("ERROR: ExecutableCommPort could not open simulator to child pipe");
00046 return false;
00047 }
00048 if(pipe(c2s)==-1) {
00049 perror("ERROR: ExecutableCommPort could not open child to simulator pipe");
00050 ::close(s2c[0]);
00051 ::close(s2c[1]);
00052 return false;
00053 }
00054
00055 child = fork();
00056 if(child==-1) {
00057 perror("ERROR: ExecutableCommPort could not fork to launch executable");
00058 ::close(s2c[0]);
00059 ::close(s2c[1]);
00060 ::close(c2s[0]);
00061 ::close(c2s[1]);
00062 return false;
00063 }
00064
00065 if(child==0) {
00066
00067 ::close(s2c[WRITEPIPE]);
00068 ::close(c2s[READPIPE]);
00069
00070 ::close(STDIN_FILENO);
00071 if(::dup2(s2c[READPIPE],STDIN_FILENO)==-1)
00072 perror("ERROR: ExecutableCommPort could not dup2 the child's input to stdin");
00073 ::close(s2c[READPIPE]);
00074
00075 ::close(STDOUT_FILENO);
00076 if(::dup2(c2s[WRITEPIPE],STDOUT_FILENO)==-1)
00077 perror("ERROR: ExecutableCommPort could not dup2 the child's output to stdout");
00078 ::close(c2s[WRITEPIPE]);
00079
00080
00081 execlp(shell.c_str(), shell.c_str(), "-c", command.c_str(), NULL);
00082
00083
00084 perror("ERROR: ExecutableCommPort could not launch the executable!");
00085 ::close(STDIN_FILENO);
00086 ::close(STDOUT_FILENO);
00087 _exit(EXIT_FAILURE);
00088
00089 } else {
00090
00091 ::close(s2c[READPIPE]);
00092 ::close(c2s[WRITEPIPE]);
00093 rbuf.adoptFD(c2s[READPIPE]);
00094 wbuf.adoptFD(s2c[WRITEPIPE]);
00095 }
00096 opened();
00097 return true;
00098 }
00099
00100 bool ExecutableCommPort::close() {
00101 if(openedCnt==0)
00102 std::cerr << "Warning: ExecutableCommPort close() without open()" << std::endl;
00103 if(--openedCnt>0)
00104 return false;
00105 closing();
00106 command.removePrimitiveListener(this);
00107 shell.removePrimitiveListener(this);
00108 rbuf.close();
00109 wbuf.close();
00110 return true;
00111 }
00112
00113 void ExecutableCommPort::plistValueChanged(const plist::PrimitiveBase& pl) {
00114 if(&pl==&command || &pl==&shell) {
00115 if(openedCnt>0) {
00116 unsigned int tmp=openedCnt;
00117 openedCnt=1;
00118 close();
00119 open();
00120 openedCnt=tmp;
00121 }
00122 } else {
00123 std::cerr << "Unhandled value change in " << getClassName() << ": " << pl.get() << std::endl;
00124 }
00125 }
00126
00127 bool ExecutableCommPort::waitChild(unsigned int t, unsigned int p) {
00128 if(!isChildRunning())
00129 return true;
00130 for(unsigned int x=0; x<t; x+=p) {
00131 usleep(p*1000);
00132 if(!isChildRunning())
00133 return true;
00134 }
00135 return false;
00136 }
00137
00138 bool ExecutableCommPort::isChildRunning() const {
00139 if(child==0)
00140 return false;
00141 int status=0;
00142 int ret=waitpid(child,&status,WNOHANG);
00143 if(ret==-1) {
00144 perror("ExecutableCommPort unable to check child status, waitpid");
00145 return false;
00146 }
00147 if(ret==0)
00148 return false;
00149 if(WIFEXITED(status) || WIFSIGNALED(status))
00150 return false;
00151 return true;
00152 }
00153
00154
00155
00156
00157