Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Win32, ReadFile from pipe block even after child terminated

I have a simple program (in C) that create two child process, wait on an inherited pipe each, and put the output in a file.

Everything works well, except that after some write/read cycle on the two pipe, when the child ends, the call to ReadFile block, waiting for data on the pipe. I use the following pattern:

...
//create pipe1
CreatePipe(&hReadDup,&hWrite,&saAttr,0);
DuplicateHandle(GetCurrentProcess(),hReadDup,GetCurrentProcess(),&hRead,0,FALSE,DUPLICATE_SAME_ACCESS);
CloseHandle(hReadDup);


si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hWrite;   

CreateProcess(  NULL,
        const_cast<LPWSTR>(cmd2.c_str()), //the command to execute
        NULL,
        NULL,
        TRUE,
        0,
        NULL,
        NULL,
        &si, //si.
        &pi
    );

...
CloseHandle(hWrite); // EDIT: this was the operation not properly done!

while(cont){
    ...
    cont = ReadFile(hRead,buf,50, &actual,NULL);
    ...
}
... 

The last call (after child process exit) block. Idea of why (and, if not, how to debug this)?

like image 464
ArtoAle Avatar asked May 31 '12 21:05

ArtoAle


2 Answers

I found out the solution myself (wich actually was a coding error). I wasn't closing the parent's write handle of the pipe properly (hWrite), so, the synchronous ReadFile wasn't able to report me back the child process termination.

If somebody has the same problem, make sure you close the inheritable handle of the pipe before starting the I/O operation on that pipe (as MSDN reports, cannot find again were).

like image 142
ArtoAle Avatar answered Oct 27 '22 00:10

ArtoAle


You are calling ReadFile() in synchronous mode. As long as the pipe is open, ReadFile() will block waiting for more data. If you leave open the process and thread handles that CreateProcess() returns to you, that will prevent the child process from fully exiting, so the pipe may not get closed on the child end. Before entering your reading loop, close the handles that CreateProcess() returns, allowing the pipe to close properly when the child process fully terminates, and then ReadFile() can report an error back to you when it can't read from the pipe anymore. Alterntively, switch to overlapped I/O on the pipe so you can monitor the child process with WaitForSingleObject() or GetExitCodeProcess() while the loop is running so you can detect when the child process terminates regardless of the pipe state.

like image 44
Remy Lebeau Avatar answered Oct 26 '22 23:10

Remy Lebeau