I have a program that launch another console program as its child process and communicate with it using anonymous pipe. I redirected both its stdin and stdout. The pseudocode is like:
// Create pipes for stdin and stdout
CreatePipe(&std_in_rd, &std_in_wr, NULL, 0);
CreatePipe(&std_out_rd, &std_out_wr, NULL, 0);
// redirection
startup_info.hStdOutput = std_out_wr;
startup_info.hStdInput = std_in_rd;
// create the process
CreateProcess(...);
// send command to the child process.
WriteFile(hWriteStdin, ...);
// receive feedback from the child process.
ReadFile(hReadStdout, ...);
But, the child process's processing the commands needs time, and I don't know how much time I should wait to get its output.
I used a loop that calls PeekNamedPipe to examine whether I can read from the pipe, but this method is not good for it consums a lot CPU.
The child process was not written by me and I can't modify its code.
How can I get informed when the child process has finished writing, like a hook?
Thanks.
You should try using ReadFileEx() to read from the pipe asynchronously.
Related
I'm writing a shell in cpp and I was hoping to get some advice. I have a command that will do an exec in the background, and I'm trying to keep track of which background processes are still running. I thought maybe I could keep track of the PID and do a string find on /proc/, but it seems to stay longer than it should. I'm testing it by using the sleep command, but it seems to always linger around wherever I look long after it should've finished. I'm probably just not doing the right thing to see if it is still running though.
Thanks in advance for any help.
Assuming you are spawning off the child process via fork() or forkpty(), one reasonably good way to track the child process's condition is to have the parent process create a connected-socket-pair (e.g. via socketpair()) before forking, and have the child process call dup2() to make one end of that socket-pair its stdin/stdout/stderr file descriptor, e.g.:
// Note: error-checking has been removed for clarity
int temp[2];
(void) socketpair(AF_UNIX, SOCK_STREAM, 0, temp);
pid_t pid = fork();
if (pid == 0)
{
// We are the child process!
(void) dup2(temp[1], STDIN_FILENO);
(void) dup2(temp[1], STDOUT_FILENO);
(void) dup2(temp[1], STDERR_FILENO);
// call exec() here...
}
The benefit of this is that now the parent process has a file descriptor (temp[0]) that is connected to the stdin, stdout, and stderr of the child process, and the parent process can select() on that descriptor to find out whenever the child process has written text to its stderr or stdout streams, and can then read() on that file descriptor to find out what the child process wrote (useful if you want to then display that text to the user, or if not you can just throw the read text away), and most importantly, it will know when the child process has closed its stderr and stdout streams, because then the parent process's next call to read() on that file descriptor will indicate 0 aka EOF.
Since the OS will automatically close the child process's streams whenever it exits for any reason (including crashing), this is a pretty reliable way to get notified that the child process has gone away.
The only potential gotcha is that the child process could (for whatever reason) manually call close(STDOUT_FILENO) and close(STDERR_FILENO), and yet still remain running; in that case the parent process would see the socket-pair connection closing as usual, and wrongly think the child process had gone away when in fact it hadn't. Fortunately it's pretty rare for a program to do that, so unless you need to be super-robust you can probably ignore that corner case.
On a POSIX-like system, after you create any child processes using fork, you should clean up those child processes by calling wait or waitpid from the parent process. The name "wait" is used because the functions are most commonly used when the parent has nothing to do until a child exits or is killed, but waitpid can also be used (by passing WNOHANG) to check on whether a child process is finished without making the parent process wait.
Note that at least on Linux, when a child process has exited or been killed but the parent process has not "waited" for the child, the kernel keeps some information about the child process in memory, as a "zombie process". This is done so that a later "wait" can correctly fetch the information about the child's exit code or fatal signal. These zombie processes do have entries in /proc, which may be why you see a child "stay longer than it should", if that's how you were checking.
I am trying to receive data from a child process over an anonymous pipe in Windows. I know how to do this using standard I/O streams but these are being used for other purposes. I also know how to do this in Linux or OSX using fork(), pipe() and execv().
In Windows, you can create a pipe with CreatePipe() and make one end not inheritable with SetHandleInformation(). Then for stdout and stderr you can pass STARTUPINFO, with hStdOutput or hStdError set, to CreateProcess() to pass the other end to the child. After the call to CreateProcess() the parent most close it's handle to the child's end of the pipe. This is all explained in detail in Creating a Child Process with Redirected Input and Output on MSDN. However, I have not found a way to pass a HANDLE, other than via stderr, stdout or stdin, to the child.
I've tried converting the HANDLE to a string with something like this:
std::ostringstream str;
str << hex << "0x" << handle;
std::string handleArg = str.str();
And then passing it as a command line argument and converting it back to a HANDLE, which is just a void * in the child process. Although the child process apparently inherits the pipe HANDLE the actual value of the HANDLE must be different than in the parent because passing it this way fails to work.
I know I can use a named pipe to do this but it seems it should be possible to do this with anonymous pipes.
So how can I pass a pipe HANDLE to a child process in Windows?
Update1: Sample code in this MSDN article seems to indicate that, at least with socket handles, you can pass them as a string to the child.
Update2: Turns out I made a mistake. See my answer below.
Turns out you can pass a HANDLE to a child process as a command line argument by converting it to string and then, in the child process, back to a HANDLE (which is just a void *). Sample code using a HANDLE to a socket can be found here.
To make this work you need to make sure you follow Creating a Child Process with Redirected Input and Output closely. It's important that you close the child process's end of the pipe after calling CreateProcess() and get all the inheritance settings right.
Note, I tried passing the HANDLE as a string on the command line before but I was doing it wrong. My mistake was in passing the HANDLE as an int to boost::iostreams::file_descriptor() which made it treat it as a file descriptor instead of a Windows HANDLE.
Why not use the method shown here?
Call the GetStdHandle function to get the current standard output
handle; save this handle so you can restore the original standard
output handle after the child process has been created.
Call the SetStdHandle function to set the standard output handle to
the write handle to the pipe. Now the parent process can create the
child process.
Call the CloseHandle function to close the write handle to the pipe.
After the child process inherits the write handle, the parent process
no longer needs its copy.
Call SetStdHandle to restore the original standard output handle.
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)?
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).
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.
In your case all good, you had access to both processes on the pipe. If however you did not, or just wanted to interrupt the ReadFile call, then CancelSynchronousIo is your friend: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363789(v=vs.85).aspx
I am developing a Windows application that has a separate thread for processing user (or 3rd party) application input via stdin.
This thread is designed such that it waits via WaitForMultipleObjects on two events:
A death signal. When this signal is raised, the interface-processing thread shuts down.
An interface signal. When this signal is raised, there is input ready to be read. The input is read and processed.
Under Windows this thread enters a main loop where it Waits for these 2 events (where bWaitAll is FALSE). Waiting on the stdin handle has the effect of signaling when there is input ready to be read, and the other event is set from elsewhere in the application.
This works exactly as I want. It waits for an event to be raised without entering in to a busy-wait, and it waits for both event simutaneously.
I wish to port this functionality to Linux, but I'm not sure how to achieve the desired result. Fundamentally, what I really want is this:
Under Linux, how do I design a thread so that it will respond
immediately to user-input on stdin, yet it can also respond
immediately to a kill-flag being raised from elsewhere in the
application?
In order to accomplish the latter, it seems to me that I cannot use cin, gets, getch or any other function that blocks until the user has entered text. Yet I do not know how to read user input in a console-based application without blocking.
I'm open to any change in architecture (if there's a more Linux-y way to do this) that include having user input processed in a separate thread that can be terminated from elsewhere in the application. I'm using GCC 4.4, and Boost 1.51.
The standard way of doing this in Linux is to use the select(2) system call. However, select is more limited than WaitForMultipleObjects, in that it can only wait on file descriptors, not other kinds of objects (such as events). So, the typical way of working around that is to create a pipe and write a dummy value to the pipe as your "signal".
Something like this:
// Error checking omitted for expository purposes
int pipefd[2];
pipe(pipefd); // Create the pipe
while(1)
{
// Create file descriptor set of stdin and the read end of the pipe
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
FD_SET(pipefd[0], &fds);
int maxfd = MAX(STDIN_FILENO, pipefd[0]);
// Wait until input becomes available on either stdin or the pipe
int num_available = select(&fds, NULL, NULL, NULL);
// Read & process stdin if possible (will not block)
if (FD_ISSET(STDIN_FILENO, &fds))
{
int n = read(STDIN_FILENO, buffer, size);
...
}
// Read & process pipe if possible (will not block)
if (FD_ISSET(pipefd[0], &fds))
{
char dummy;
read(pipefd[0], &dummy, 1);
// Handle signal (e.g. break out of loop)
}
}
Then to signal to the thread that it's done, just write a single byte to the write end of the pipe:
char dummy = 42;
write(pipefd[1], &dummy, 1);
libev (and several similar incarnations) offers a convenient abstraction around select including being able to pend on signals.
If you have the option to alter the origin of "An interface signal" then you could consider changing it to use raise instead.
I'm a noob to linux programming, so please bear with me. In my application, I fork(), then execl() another binary after having setup a single pipe for reading in. After the fork and exec are OK, i do a dup2() for reading in from the stdout of the executed binary. I need my parent application to wait for output from the process it has created and once there is output, read it. I figured I will use select(), and wait for a few milliseconds before trying to see if there is data to be read and if there is, use read(). However my code does not work because select() takes as argument an fd_set, while my pipe is of int converted by pipe() and dup2(). What can I do to overcome this and is there another alternative? Note, I'm not blocking the parent process until the process ends, but want to read info while the child process runs.
To use select() you must create a struct fd_set and populate it using the FD_ macros. In this way you will inform the function which descriptors you are interested in (note that it is common to be interested in several at once). For example:
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(your_input_fd, &rfds);
int retval = select(your_input_fd + 1, &rfds, NULL, NULL, NULL);
The first argument to select is to be the highest-numbered file descriptor you are interested in, plus one. That, along with example code, is explained here:
http://linux.die.net/man/3/fd_set