Archived

This forum has been archived. Please start a new discussion on GitHub.

Problem with fork() and execute() in an ICE server

Hi everybody!

First of all my aim: I want to implement an ICE server, which runs on a mobile robot and i want to start programs on this robot with an ICE client.

I found the "How can I fork and exec an Ice process? " in the FAQ, and implemmented exactly this. Here is my server code:
#include <Ice/Ice.h>
#include <MgsIceGui.h>

#include <fcntl.h>
#include <signal.h>

using namespace std;
using namespace programStarter;

class starterInterface : public Commander {
public:
/* Constructor */
starterInterface();
/* Destructor */
// virtual ~CommanderInterface();
/* Interface functions */
virtual void executeProcess(const string& commandLine, const Ice::Current&);
};

starterInterface::
starterInterface(void) {

}

void starterInterface::
executeProcess(const string& commandLine, const Ice::Current&) {

try {
//FROM ICE FAQ - How can I fork and exec an Ice process
//C++
//Set up a pipe so the child can report errors.
int fds[2];
if (pipe(fds) == -1) {
throw "cannot create pipe";
}

// Set clone-on-exec on write end of pipe.
int flags = fcntl(fds[1], F_GETFD);
if (flags == -1) {
throw "cannot get fcntl flags";
}
flags |= FD_CLOEXEC;
if (fcntl(fds[1], F_SETFD, flags) == -1) {
throw "cannot set clone-on-exec";
}

//If the parent uses signal handlers, block signal delivery here.

pid_t pid = fork();
switch(pid) {
case -1 : throw "cannot fork";
case 0 : {

cout << "child created" << endl;
//Child
//
//If the parent uses Ice::Application or IceUtil::CtrlCHandler,
//and the child requires the default behaviour for SIGHUP, SIGINT,
//and SIGTERM, reset these signals to the default behaviour here.

//Close all open file descriptors.

//int maxFd = static_cast<int>(sysconf(_SC_OPEN_MAX));
//for (int fd = 0; fd < maxFd; ++fd) {
// if(fd != fds[1]) {//Don't close write end of pipe
// close(fd);
// }
//}

execl("/usr/bin/ls","ls",(char *)0);

const char msg[] = "exec failed";
write(fds[1], msg, sizeof(msg)-1);
_exit(1);
}
default : {
//Parent
//
//Close the write end of the pipe
cout << "back in parent!" << endl;
close(fds[1]);

//Wait for child to write error message or exec succesfully
stringstream err;
char c;
while (read(fds[0], &c, 1) > 0) {
err << c;
}
close(fds[0]);
string msg = err.str();

//If the parent uses signal handlers,
//restore signal delivery here.
if (!msg.empty()) {
throw msg;
}
cout << "end of parent "<< endl;
}
}
}
catch(const char *msg) {
cerr << msg <<endl;
}

cout << "end of executeProcess" << endl;

}

int
main(void) {
Ice::CommunicatorPtr ic;
try {
ic = Ice::initialize();
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapterWithEndpoints("ProgramStarterAdapter","default -p 10003");
Ice::ObjectPtr object = new starterInterface();
adapter->add(object, ic->stringToIdentity("ProgramStarter"));
adapter->activate();
ic->waitForShutdown();
}
catch (const Ice::Exception& e) {
cerr << e << endl;
}
catch (const char *msg) {
cerr << msg <<endl;
}
if (ic) {
try {
ic->destroy();
}
catch (const Ice::Exception& e) {
cerr << e << endl;
}
}
return 0;
}

When i start my client and execute the excecuteProcess method i get:
back in parent!
child created
end of parent!
end of executeProcess
<and the output of "ls">

And then the IceServer is destroyed.
I tried to find out the problem with strace:
[pid 5229] write(1, <output of "ls">) = 204
[pid 5229] close(1) = 0
[pid 5229] munmap(0x7f80f5cd1000, 4096) = 0
[pid 5229] close(2) = 0
[pid 5229] exit_group(0) = ?
Process 5229 detached
[pid 5226] <... epoll_wait resumed> 6236d0, 4, 4294967295) = -1 EINTR (Interrupted system call)
[pid 5226] --- SIGCHLD (Child exited) @ 0 (0) ---
[pid 5226] clock_gettime(CLOCK_REALTIME, {1222756549, 393753500}) = 0
[pid 5226] close(9) = 0
[pid 5226] clock_gettime(CLOCK_REALTIME, {1222756549, 393930402}) = 0
[pid 5226] munmap(0x7f75bb096000, 524296192) = 0
[pid 5226] close(8) = 0
[pid 5226] exit_group(0) = ?
Process 5226 detached
[pid 5224] <... futex resumed> ) = ? ERESTARTSYS (To be restarted)
[pid 5225] <... futex resumed> ) = ? ERESTART_RESTARTBLOCK (To be restarted)

The ICE server has PID 5224 and PID of child seems to be 5229.

I hope that someone can help me.
Thank You!

Comments

  • benoit
    benoit Rennes, France
    Hi,

    Why did you comment out the code that closes the file descriptors in the child section? The child should close the file descriptors before the exec() call. You might also want to check how the IceGrid node implements this for more clues -- the code is in Ice-3.3.0/cpp/src/IceGrid/Activator.cpp.

    Cheers,
    Benoit.