Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does shell pipe the child process? [duplicate]

Recently I'm studying linux inter process communication. But I have some problems in understanding the pipe mechanism.

I know that pipe is a pair of files created by parent process, then the parent process passes the file descriptors to its child process then child process can operate on it.

But since child process has a totally new virtual memory when exec() is called after fork(), so why can the parent process pass its information to the child process? Is there anything that I have missed?

like image 926
Fat Cat Avatar asked Jul 08 '26 07:07

Fat Cat


2 Answers

A file descriptor is a handle to a resource managed by the operating system(kernel). When you create a pipe, the kernel creates facilities so data can be sent from one end of the pipe to the other.

This data is sent via the kernel.

When you fork(), the child inherits all file descriptors, which means they inherit the data structure that is managed by the kernel that the file descriptors refer to. So now the file descriptor refers to the very same kernel resource in the child and the parent. Since the kernel resource lives in the kernel, that part is shared between the 2 processes, it is not duplicated like the user space memory.

Basically, you write() data to one end of the pipe, that data is copied into a buffer in the kernel. You can then read() that data, and it gets copied from the kernel buffer into memory space of the reading process. After a fork(), both child and parent refer to that same buffer in the kernel which was created with pipe().

like image 198
nos Avatar answered Jul 10 '26 21:07

nos


When a process exec()s to another, that child generally inherits the parent's standard file paths: stdin(0), stdout(1), stderr(2). When a shell creates a pipeline, it uses the dup2() call to duplicate a path to a desired path number in order to force the right paths to the child's standard paths.

// pseudo-code:
// create the pipe
int pipe_end[2];
pipe(pipe_end);

// "back up" stdin
int save_in = dup(0);

// position the pipe to stdin for the benefit of the child
dup2(pipe_end[0], 0);

// start the child
fork() && exec();

// restore stdin
close(0);
dup2(save_in, 0);

// write to the child
write(pipe_end[1], ...);
like image 34
mah Avatar answered Jul 10 '26 20:07

mah