Monday, June 6, 2011

Pipes

Pipes

- One way communication

- Create pipe with pipe() system call as
int p[2]
pipe(p)
p[1] is the write end and p[0] is the read end.

- Pipe has some buffer associated with it, that can be checked with “ulimit” command

- Pipe u can understand like FIFO, stream buffer, there is no message boundary, its like bucket with one tap at the end, you can pour from top and get from the bottom. How much you get from bottom is not controlled at all, the longer tap is opened the more you get.

- In pipe terminology you can write() anything and get by read(), whatever buffers you pass in write and read function calls is independent. Remember

- Pipes can be used only if process are related ie. Child and parent. You create the pipe then fork the child. Though the fork would create copy of file descriptor returned but all four of them would point to the same thing.

- If you read a pipe before anything is written, read call will wait something for to be written.

- You have written 10 bytes, you try to read 50 what will happen, it will only give 10 J.

- Pipes are meant for one way communication, what will happen if you try to write from both process, if will still work, But its logically incorrect and there are more than one reasons to close the unused end.

- Reasons to close the unused end
1) file descriptors are limited, don’t let them opened.

2) suppose you create something like below
if(fork()==0)//child, assume it runs first

{

//do nothing closing

}

Else//parent process

{

Read(p[0],buff,5)

}

This program will hang forever, the reason is simple, child as it runs exits immediately and hence its file descriptors also closes. Now comes the parent, here read call is made, at this juncture process will wait for something to be written to the pipe as write end of the parent pipe is not closed. And hence process will keep on waiting. Logical correction of the program is to close the write end. If you close the write end in the parent system will know that there is no one who can write to the pipe hence closes the program immediately.

- Suppose child dies immediately and in parent you close read end first, there after you have write statement, Now unix knows there is no one to read hence thinks fool does not have mind hence sends SIGPIPE signal, whose default action is to the pipe.

- If any of the write end is not closed and pipe is empty, read call will make the prog wait. But if you don’t want to wait on read. You can always configure the pipe read end as O_NDELAY
fcntl(p[0], F_SETFL,O_NDELAY). Now when instead of waiting at read call next statement will be executed.


Pipes drawbacks

- Can only be used on related process

- Not permanent, termination of the process leads to their termination

- Its more like files, have i-node number etc. But they are not files, they you can think as kernel buffer, having some kernel max buffer size limit. E.g. its about 4k in my system-


Few words about pipe implementation

- Each pipe implemented as file mounted on virtual file system “pipefs”.

- The normal process would inovle with pipe call would be like: Creates an inode

- Creates a file

- Associates the directory entry and the inode with it

- Creates 2 file * by opening it with O_RDONLY and O_WRONLY flags

- Installs the file *s in the file descriptor table of the process and generates 2 file descriptors (of type int)

- Returns the file descriptors in the fd[2] array.

- Naturally read, write call on file would use some sort of locking mechanism. To read write data

How FIFO is implemented

- Its fully same as pipe only difference being the it creates and installs the inode in global file system instead of pipefs which is kind of virtual and non persistent

- Mknod call is used to create the fifo, btw mknod is used to create many type files

About Buffer removal

- For each pipe/FIFO reader writer count is maintained, when ever you close the fd, the reader write count is decremented, when count reaches zero it get rid of pipe buffer and pipe object is destroyed.

- In case of FIFO don’t get rid of the node entry but get rid of the kernel buffer

No comments: