I've made a program that create 5 pipes and fork 5 processes in a loop. I've managed to send data from the parent to each child processe, when each child processe is overlapped by another program. Each loop is done in the following manner
(parent.c):
// Child process - reads from pipe
if (childpid == 0) {
dup2(fd[0], 0); // replace stdin with pipe input
execv("program", arguments);
} else { // Parent process - writes to pipe
write(fd[1], buffer, strlen(buffer)+1);
}
So now i'm able to get the data that is sent from the parent to the pipe, by reading from STDIN_FILENO in the program the childs executes with execv(...).
Like this (program.c):
char *buffer = (char *)malloc(50);
read(STDIN_FILENO, buffer, 50);
My problem however is, how can I send data back to the parent? I was thinking of something like replacing stdout with the pipe output by using dup2 again, but I can't get it to work. I realise this have to be done before using execv(...) at least.
I'm not sure if that explanation was sufficient so I can make a little image with text : )
This is how it is right now:
Parent -> Pipe
Pipe -> Child process 1
Pipe -> Child process 2
Pipe -> ...
Pipe -> Child process 5
I want it to be like this.
Parent -> Pipe
Pipe -> Child process 1
Pipe -> Child process 2
Pipe -> ...
Pipe -> Child process 5
Child process 1 -> Parent
Child process 2 -> Parent
...
Child process 5 -> Parent
Thankful for help!
Pipes are unidirectional, not bidirectional, so a generic solution is to create five more pipes (gak!) for the return data. The parent then needs to use select() system call to know which of the return pipes have data ready for reading.
Oh, and I would have written
dup2(fd[0], 0); // replace stdin with pipe input
should be
dup2(fd[0], 0); // replace stdin with output from pipe
and vice versa.
Like the other replies say, there are other communication methods that may be more appropriate, depending on what you are trying to achieve.
See this unix programming faq here, look at question 1.5, maybe using a memory map to allow the parent/child processes to read/write from on both ends...There is an excellent guide to understanding IPC here.
I looked around on the internet for a bit. It seems that you can use pipes only to communicate one way. Which makes sense - input from stdin and output to stdout. If you want to have two way communication between your parent and child processes, use sockets. There are other methods to achieve two way IPC. I suggest that you learn more about inter process communication.
All the best.
If you want to keep using pipes, then make one group of FDs for child->parent communication and one for parent->child communication. So instead of having int fd[2], you have int toParent[2], toChild[2]. Instead of dup2(fd[0], 0), you have dup2(toChild[0], 0); dup2(toParent[1], 1).
And don't just dup, but close the FDs you aren't using.
Related
This question already has answers here:
C stdio redirection to and from child process
(2 answers)
Closed 7 months ago.
I can't figure out how to exec a process and read its stdout. It seems like this should be a combination of fork() and execve(), but I can't figure out how to get the pipes connected.
I know how to create a pipe and fork, and read the pipe written by the child process in the parent process;
I know how to execve to replace a process with another process.
What I don't understand is how to pass an open pipe from the forked child to the exec'ed process (I would like the pipe to be the exec'ed processes' stdout) for reading by the original parent.
e.g. parent => child => new-prog
(creates pipe) fork execve (I want the pipe to be stdout of new-prog)
(reads pipe) (writes pipe/stdout)
Any pointers / examples would be much appreciated.
The missing step is using dup2 in the child (pre-exec) to copy the pipe fd onto stdout. Don't forget to close the pipe fd after doing this.
Create a pipe. Let's call its ends r and w.
Fork.
Child:
Close r.
Use dup2 clone w onto stdout.
Close w.
Exec.
Parent:
Close w.
...
Error checking left out for clarity.
Considering the following code, when the parent is terminated, the stdin control is taken back by the shell and there is no way to see that the child process is running except through the "ps -e" command.
Is there is any way to give the stdin control to the child process before the parent dies?
I read some similar topics here, but non of them gives a solution to this issue. One has suggested to use "#cat | ./a.out" as a work around but I want a code level solution if there is any.
pid = fork();
if( pid == 0)
{
while(1);
}
else
{
//wait(&childstatus);
printf("Hello From Parent\n");
}
Yes, this is the way shell works. If you don't want the shell take active process group, keep the parent alive.
Shortened Question:
I have a parent process that creates a child process as seen below:
int me2them[2], them2me[2];
pipe(me2them);pipe(them2me);
if (!fork()){
close(0); dup2(me2them[0],0); close(me2them[0]);
close(1); dup2(them2me[1],1); close(them2me[1]);
char * cmds[] = {"wish", "myProg.tcl",NULL};
execvp(cmds[0], cmds);
fprintf(stderr, "Unable to exec 1\n");
exit(-1);
}
close(0); dup2(them2me[0],0); close(them2me[0]);
close(1); dup2(me2them[1],1); close(me2them[1]);
But, I need the child process to be able to recieve input from the user. With this method, the stdin for the child is changed from the keyboard to the stdout of the parent. How can I maintain communication with both the keyboard and the parent?
Also, the parent is the client of a server, and thus multiple parents can be running on the same or different machines, making a shared file between parent and child difficult because the child of any parent would be able to access any other parent's file.
NOTE: I'd prefer to keep the parent's stdout being mapped to the child's input because I did not write the c code and I want to re-route its printf statements to the child.
Original Version:
I am using tcl to make a GUI for a c code. The tcl is a child process of the c code and I use I/O redirection to make the stdout of the c to be the stdin of the tcl and the stdout of the tcl to be the stdin of the c. However, there is a part where the c requests the user's name and it sends the request via stdout to the stdin of the tcl code, no problems, then the tcl requests the name. The tcl name request presents two problems:
1) tcl is in effect sending the request to the c code, causing the c code to mistake the request as being the actual name (solved by sending the request to stderr instead of stdout)
2) When tcl attempts to get the user input for the name, it will be checking stdin, which is mapped to receive from the c code not the keyboard, and will not be able to read the response from the user.
Is there a way to specify to get the response from the keyboard? Or should I map the stdout of the c code to a different fd for the tcl? And if so, how do I specify to get from the keyboard/new fd.
Here is how I make the tcl a child process of the c code:
int me2them[2], them2me[2];
pipe(me2them);pipe(them2me);
if (!fork()){
close(0); dup2(me2them[0],0); close(me2them[0]);
close(1); dup2(them2me[1],1); close(them2me[1]);
char * cmds[] = {"wish", "myProg.tcl",NULL};
execvp(cmds[0], cmds);
fprintf(stderr, "Unable to exec 1\n");
exit(-1);
}
close(0); dup2(them2me[0],0); close(them2me[0]);
close(1); dup2(me2them[1],1); close(me2them[1]);
It sounds as if the child would have a conventional command-line interface, e.g.,line-buffered. I suggest these design changes:
modify the two-way pipe to the child to something other than its standard input and output (you can read/write on other streams)
it might be simplest to make that change within the child
you can use dup2, etc., within the child to modify the pipe. That leaves the question of how to get a usable keyboard interface for the child.
you can solve that problem by opening /dev/tty directly, and (again with dup2 and friends) making the file opened on /dev/tty into the child's standard input and output.
As an example, the dialog program has a feature for reading data via a pipe (at the shell level, that is its standard input), and in initialization, changing that into a different stream and opening /dev/tty for a "real" standard input. Your problem is a little more complicated (with both input and output pipes), but reading the dialog source may be helpful. For reference, that is the init_dialog function in util.c (source here).
Hi I have a simple function where i create a child process and parent process.
The child process suppose to run dd if=/some/file of=/somedisk.
The parent process suppose to run in a loop (until the child exists) and send signal SIGUSR1 which is forcing the dd in child process to report progress data.
Of course i have pipes where i redirect stdio and stderr from the child to the parent. (this i use in other functions and it works fine)
The problem i have is that:
1. I don't get anything on my stderr;
2. As soon as i send SIGUSR1 the process exits somehow.
if(my_pid>0) //The parent part
{
close(FD_pipe_stdout[1]);// Parent process closes output side of the pipe
close(FD_pipe_stderr[1]);// Parent process closes output side of the pipe
while(0==waitpid(my_pid, &my_pid_status, WNOHANG))
{
kill(my_pid, SIGUSR1);
sleep(1);
//read(FD_pipe_stderr[0], pipe_error,PIPE_MAX_SIZE); // Read in a string from the stderror
//puts(pipe_error);
}
puts("going out");
read(FD_pipe_stdout[0], pipe_output,PIPE_MAX_SIZE); // Read in a string from the pipe's input side
close(FD_pipe_stdout[0]);//on the end close the other side of pipe
close(FD_pipe_stderr[0]);//on the end close the other side of pipe
}
else
{ // The child part
close(FD_pipe_stdout[0]);/* Child process closes input side of the pipe */
close(FD_pipe_stderr[0]);/* Child process closes input side of the pipe */
dup2(FD_pipe_stdout[1],1); //redirect the stdout(1) to the fd_pipe and then close the sdtout
dup2(FD_pipe_stderr[1],2);//redirect also stderr to the pipe
system(dd if=/image.img of=/dev/sda);
close(FD_pipe_stdout[1]); //on the end close the other side of pipe
close(FD_pipe_stderr[1]); //on the end close the other side of pipe
exit(0);
}
I see on the screen that the parent is going out from the while loop and i don't understand why.
Thanks in advance
system() creates a child process to run the specified command, so you really have three processes here:
The parent process (the one with the loop)
The child process (the one that calls system()
The dd process
You're signaling the child process instead of the dd process. SIGUSR1 by default causes a process to exit, so you're killing the child process.
To fix this, you could run dd using one of the exec functions, instead of calling system():
{ // The child part
close(FD_pipe_stdout[0]);
close(FD_pipe_stderr[0]);
dup2(FD_pipe_stdout[1],1);
dup2(FD_pipe_stderr[1],2);
execlp("dd", "dd", "if=/image.img", "of=/dev/sda", NULL);
perror("exec failed");
exit(1);
}
Now you only have two processes, because the child process becomes the dd process. When the parent signals the child, the signal will go to dd.
Note that there is a race condition here. The parent process may send a SIGUSR1 signal before dd starts and sets up its signal handler. To be robust, you should handle this somehow.
I want to make a proxy process which opens the real one.
Like if I rename linux's espeak to espeak_real and my app to espeak.
espeak opens espeak_real and I get the output.
I want to make possible to:
Prints it's STDIN to the console
Prints it's STDIN to another process's STDIN
Prints the second process's STDOUT
I'm trying to do it in C (I guesss it's possible with raw bash too).
I don't exactly understand what you do, but it seems like a combination of fork, exec, pipe and dup2 should do it.
app can use pipe to get a pair of file descriptors, connected with a pipe (what's written into one is read from the other).
Then it can fork, and the child can exec app_real.
But between fork and exec, dup2 can be used to change any file descriptor you want to 0,1 and 2 (but close the real 0,1,2) first.
Short code example:
int pipe_fds[2];
pipe(pipe_fds);
if (fork()==0) {
// Child
close(fds[1]); // This side is for the parent only
close(0); // Close original stdin before dup2
dup2(fds[0],0); // Now one side of the pipe is the child's stdin
close(fds[0]); // No need to have it open twice
exec(...);
} else {
// Parent
close(fds[0]); // This side is for the child only
write(fds[1],data,len); // This data goes to the child
}