> . Strip down imore.cpp so it just does the unnamed pipe stuff.
>
> . Make sure it still works.
>
> . Go through it and modify it one piece at a time and make sure it
> continues to work.
>
> . When you're done and it works, please send it to us and we'll add it
> to the ACE examples.
>
> My guess is that you're not closing one of the handles in the parent
> process, which means that the child doesn't know that the parent is
> done and hence never exits!
Russell Mora writes:
>The child cat process is getting a copy of the write handle on the fork
>- try setting CLOEXEC on the write handle to prevent this.
The following seems to work, although I don't know if it will work with any
operating systems that aren't based on POSIX (such as Microsoft Windows).
I'm a little nervous about the idea of subclassing off of ACE_IPC_SAP simply
to manipulate an ACE_HANDLE -- why doesn't ACE_Pipe make use of ACE_IPC_SAP?
-- but perhaps this is the desired way to do it. Is this what you were
getting at?
I've tested this only in the aforementioned g++/GNU/Linux environment:
#include <cerrno>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <ace/IPC_SAP.h>
#include <ace/Log_Msg.h>
#include <ace/Pipe.h>
#include <ace/Process.h>
//--------------------------------------------------------------------------
---
// This class exists solely because I want to use ACE_IPC_SAP to change
certain
// characteristics of an ACE_HANDLE (specifically, the CLOEXEC bit), and
// I can't use the ACE_IPC_SAP object directly because its constructor
// is protected. -- jmd, Mon Oct 31 12:57:05 EST 2005
class HandleWrapper: public ACE_IPC_SAP
{
};
//--------------------------------------------------------------------------
---
int ACE_TMAIN(int, ACE_TCHAR *[])
{
//----------------------------
// Program to run
const char childProgram[] = "cat";
ACE_Process new_process;
ACE_exitcode status;
// "Notice that we must enclose ACE_Process_Options in the block
// so the file handlers it keeps can be close elegantly."
// -- from ACE sample code
{
ACE_Process_Options options;
ACE_Pipe pipe;
if (pipe.open () == -1)
ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "pipe.open"), -1);
options.set_handles(pipe.read_handle());
HandleWrapper hr;
hr.set_handle(pipe.write_handle());
hr.enable(ACE_CLOEXEC);
options.command_line(childProgram);
if (new_process.spawn(options) == -1)
{
const int error = ACE_OS::last_error();
ACE_ERROR_RETURN((LM_ERROR, "%p errno = %d.\n",
"test_more", error), -1);
}
const char sendThisToChild[] =
"This is a message that I am sending to the stdin of "
"the child process.\n";
::ssize_t result = ACE::write_n(
pipe.write_handle(), sendThisToChild, sizeof(sendThisToChild));
if (result != sizeof(sendThisToChild))
{
std::cerr
<< "ACE::write_n return value was "
<< result
<< " for a message of length "
<< sizeof(sendThisToChild)
<< "."
<< std::endl;
}
options.release_handles();
pipe.close();
}
// Wait till child is done.
new_process.wait (&status); // <-- used to hang before I set ACE_CLOEXEC
std::cout << "Child process is done." << std::endl;
ACE_DEBUG ((LM_DEBUG, "Process exited with status %d\n", status));
if (status)
{
std::cerr
<< "child process exited with error status: "
<< status
<< "."
<< std::endl;
}
return EXIT_SUCCESS;
}
//--------------------------------------------------------------------------
---