Hello All

I'm having a little trouble using XtAppAddInput in its ViewKit
incarnation. I was wondering if anybody here who might be able to help
me out?

0. I have written a ViewKit component that encapsulates dup2/fork and
exec. The forking/dupping/exec-ing part of the class seems to work OK.

1. As per the advice of the Motif reference part 6a, I'm aware of the
need to use XtAppAddInput as the preferred way of making sure that
events on the filedescriptors of my spawned process get noticed. But as
my IRIX box offers the VkInput component as a wrapper around
XtAppAddInput it seemed like a good idea to use it.

2. The problem is that VkInput (and thus XtAppAddInput) keeps on sending
out events even after the spawned process has long gone and done it's
stuff.

I surmise that the XtAppAddInput() is still monitoring the fd's of the
non existant process, and is getting confused. My question is thus: how
to my make sure that XtAppAddInput/VkInput is informed about the demise
of the process so that it can stop monitoring those fd's? I sort of have
the feeeling that I need to unregister the listeners via picking up the
SIGTERM of the spawned binary or something. But any further info on
VkInput is 'elusive' to say the least...

Any help on the matter however tangential is most appreciated and the
full code of my VkProcess class is added below.

grts,

Avi


-----

#ifndef VkProcess_h
#define VkProcess_h

#include
#include
#include

using namespace std;

#include
#include
#include
#include
#include
#include

#define READ 0
#define WRITE 1

#include
#include

class VkProcess : public VkCallbackObject {

public:

VkProcess(void);
VkProcess(string command);
~VkProcess(void);

// class methods
void setCommand(string cmd_line);

pid_t runPipe();
void runPopen();

int getOutputSize();
string getOutput(int line_nr);
string getOutput(int start, int end);

// callbacks
void dumpOutput( VkCallbackObject* obj, void *clientData, void
*callData );


private:

char *_process_args[20]; // FIXME: arbitrary constant

string _command;
vector _commandOutput;

pid_t _pid;

FILE *_in_to_process_fd, *_out_from_process_fd, *_err_from_process_fd;

void _parametrizeCommand(string command);

};

#endif


-----------

#include "VkProcess.h"


VkProcess::VkProcess(){

_command = "";

}



VkProcess::VkProcess(string command){

setCommand(command);

}



void VkProcess::setCommand(string command) {

_command = command;
_parametrizeCommand(command);

}


void VkProcess::_parametrizeCommand( string command) {

int i = 0;
char *param;

// hack because strtok only accepts char * not const char *
char cmd[BUFSIZ];
strcpy( cmd, command.c_str());

param = strtok( cmd, " ");

while ( param != NULL ) {

_process_args[i] = param; i++;
param = strtok(NULL, " "); // NULL is here to make strtok
continue // with previous string.
}

/*
for( int c = 0; c < i; c++) {

cout << "_process_args[" << c << "]: " << _process_args[c] << endl;
}
*/
}


VkProcess::~VkProcess() {

// empty

}


void VkProcess::runPopen() {

char line[BUFSIZ];
FILE *cmdOutputFd;

if ((cmdOutputFd = popen(_command.c_str(), "r")) != NULL) {

_commandOutput.resize(0);

while( fgets(line, BUFSIZ, cmdOutputFd) != NULL) {

// collect output
_commandOutput.push_back(line);
}
}

pclose(cmdOutputFd);
}


pid_t VkProcess::runPipe() {

int pipe_in[2], pipe_out[2], pipe_err[2];

pipe(pipe_in);
pipe(pipe_out);
pipe(pipe_err);

if ( (_pid = fork()) < 0 ) { // fork() failed

cout << "Fork failed" << endl;

} else if ( _pid == 0 ) { // in child

close(pipe_in[WRITE]);
close(pipe_out[READ]);
close(pipe_err[READ]);

dup2( pipe_in[READ], fileno(stdin) );
dup2( pipe_out[WRITE], fileno(stdout) );
dup2( pipe_err[WRITE], fileno(stderr) );

// call exec.
execv( _process_args[0], _process_args);

} else { // in parent

close(pipe_in[READ]);
close(pipe_out[WRITE]);
close(pipe_err[WRITE]);

// register filestreams
_in_to_process_fd = fdopen( pipe_in[WRITE], "w");
_out_from_process_fd = fdopen( pipe_out[READ], "r");
_err_from_process_fd = fdopen( pipe_err[READ], "r");


// setup monitoring
VkInput *_process_out = new VkInput();
_process_out->attach(fileno(_out_from_process_fd), XtInputReadMask);
_process_out->addCallback(VkInput::inputCallback, this,
(VkCallbackMethod) &VkProcess::dumpOutput );

VkInput *_process_err = new VkInput();
_process_err->attach(fileno(_err_from_process_fd), XtInputReadMask);
_process_err->addCallback(VkInput::inputCallback, this,
(VkCallbackMethod) &VkProcess::dumpOutput );

}

return (_pid); // make compiler happy.
}


string VkProcess::getOutput(int line_nr) {

if ( (line_nr - 1) < _commandOutput.size()) {
return _commandOutput.at(line_nr - 1);
} else {
return(""); // here to make compiler happy
}
}


string VkProcess::getOutput(int start, int end) {

string output;

for ( int i = start; i < _commandOutput.size() ; i++ ) {
output.append( _commandOutput.at(i) );
}

return(output);
}


int VkProcess::getOutputSize() {

return _commandOutput.size();

}


void VkProcess::dumpOutput( VkCallbackObject* obj, void *clientData,
void *callData ) {

VkInput *input = (VkInput *) callData;

cout << fileno(_out_from_process_fd) << "/" << input->fd() << endl;

if ( input->fd() == fileno(_out_from_process_fd) ) {

cout << "something happened on the output stream" << endl;

} else {

cout << "something happened on the error stream" << endl;
}
}