It's more preferable to use Boost to do so since Boost is cross-platform. In fact, the code is simpler if you use Boost
// C code
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ext/stdio_filebuf.h>
int spawn(const char *cmd, int io_mask, ostream **stdin, istream **stdout, istream **stderr){
// io_mask: bit0:stdin, bit1:stdout, bit2:stderr
int pipes[3][2];
for(int x=0; x<3; ++x)
pipe(pipes[x]);
int pid;
if((pid=fork())!=0){ // parent
if(io_mask&1){ // create stdin
__gnu_cxx::stdio_filebuf<char> *filebuf = new __gnu_cxx::stdio_filebuf<char>(pipes[0][1], std::ios::out);
*stdin = new ostream(filebuf);
}
if(io_mask&2){ // create stdout
__gnu_cxx::stdio_filebuf<char> *filebuf = new __gnu_cxx::stdio_filebuf<char>(pipes[1][0], std::ios::in);
*stdout = new istream(filebuf);
}
if(io_mask&4){ // create stderr
__gnu_cxx::stdio_filebuf<char> *filebuf = new __gnu_cxx::stdio_filebuf<char>(pipes[2][0], std::ios::in);
*stderr = new istream(filebuf);
}
return pid;
} else { // child
if(io_mask&1)
dup2(pipes[0][0], STDIN_FILENO);
if(io_mask&2)
dup2(pipes[1][1], STDOUT_FILENO);
if(io_mask&4)
dup2(pipes[2][1], STDERR_FILENO);
int retval;
do{
cerr << "Creating process with command-line \"" << cmd << "\"" << endl;
retval = system(cmd);
cerr << "Decoder thread has exited with code " << retval << endl;
}while(io_mask&0x80000000);
_exit(retval);
}
}
// C++ code
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <boost/thread.hpp>
using namespace std;
class Thread{
public:
int m_pipes[3][2]; // for stdin, stdout and stderr respectively
int m_mask; // mask: bit0:stdin, bit1:stdout, bit2:stderr, bit31:persistent launch
string m_cmdline;
ostream *m_stdin;
istream *m_stdout;
istream *m_stderr;
boost::thread *m_thread;
__gnu_cxx::stdio_filebuf<char> *m_filebuf[3]; // for stdin, stdout and stderr respectively
static void _thread_func(Thread *p){ // OOP connector
p->thread_func();
}
template <class A>
ostream& operator << (A &a){
return (*m_stdin) << a;
}
template <class A>
istream& operator >> (A &a){
return (*m_stdout) >> a;
}
void flush(){
m_stdin->flush();
}
istream& getline(string &line){
return std::getline(*m_stdout, line);
}
ostream& putline(string &line){
ostream& ret = (*m_stdin << line << endl);
m_stdin->flush();
return ret;
}
void thread_func(){
// child thread
if(m_mask&1)
dup2(m_pipes[0][0], STDIN_FILENO);
if(m_mask&2)
dup2(m_pipes[1][1], STDOUT_FILENO);
if(m_mask&4)
dup2(m_pipes[2][1], STDERR_FILENO);
int retval;
do{
cerr << "Creating process with command-line \"" << m_cmdline << "\"" << endl;
retval = system(m_cmdline.c_str());
cerr << "Decoder thread has exited with code " << retval << endl;
}while(m_mask&0x80000000);
_exit(retval);
}
Thread(const string &cmdline, int mask=7):m_cmdline(cmdline),m_mask(mask){
for(int x=0; x<3; ++x)
pipe(m_pipes[x]);
m_thread = new boost::thread(&_thread_func, this);
// parent thread
if(m_mask&1){ // bind stdin
m_filebuf[0] = new __gnu_cxx::stdio_filebuf<char>(m_pipes[0][1], std::ios::out);
m_stdin = new ostream(m_filebuf[0]);
}
if(m_mask&2){ // bind stdout
m_filebuf[1] = new __gnu_cxx::stdio_filebuf<char>(m_pipes[1][0], std::ios::in);
m_stdout = new istream(m_filebuf[1]);
}
if(m_mask&4){ // bind stderr
m_filebuf[2] = new __gnu_cxx::stdio_filebuf<char>(m_pipes[2][0], std::ios::in);
m_stderr = new istream(m_filebuf[2]);
}
}
~Thread(){
for(int x=0; x<3; ++x)
close(m_pipes[x][0]), close(m_pipes[x][1]);
delete m_thread;
}
};
No comments:
Post a Comment