Re: [ace-users] Why Does the Child Process Not Receive EOF?

6 views
Skip to first unread message

John Davison

unread,
Nov 6, 2005, 1:33:55 PM11/6/05
to
Douglas C. Schmidt writes:

> . 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;
}

//--------------------------------------------------------------------------
---

Reply all
Reply to author
Forward
0 new messages