InterProcess Communication Unix Pipes Overview q Communication between
Inter-Process Communication Unix Pipes
Overview q Communication between processes - Pipe between two processes - Redirecting stdin and stdout
Inter-Process Communication q Mechanism by which two processes exchange information and coordinate activities different machines same machine
Inter-Process Communication q Anonymous pipes - q Related processes on the same machine Used mostly for a pipeline of filters Sockets - Unrelated processes on any machines Used for client/server communication (e. g. , Web)
Preliminaries: File Descriptors and System I/O
File Descriptors q A file descriptor is a number that uniquely identifies an open file or other input/output resource (such as a pipe) q When a file is opened, the OS creates an entry into a File Descriptor Table to store information about that opened file - this entry number is the file descriptor Process File Descriptor Table File descriptor (integer) 0 1 2 3 … File data …
Standard File Descriptors q When you start a new process, three file descriptors (0, 1 and 2) are created by default: - File descriptor 0 maps to standard input (keyboard) File descriptor 1 maps to standard output (screen) File descriptor 2 maps to standard error (screen) Process File Descriptor Table File descriptor (integer) 0 1 2 3 stdin data stdout data stderr data readme data
Standard File Descriptors q Automatically opened for each process - File descriptor 0 (stdin) process - File descriptor 1 (stdout) - File descriptor 2 (stderr) User process Operating System scanf(. . . ); printf(. . . ); read(0, . . . ); write(1, . . . );
File Descriptors Process User process Operating System FILE * fp = fopen("readme", "r"); fread(fp, . . . ); user mode stdio Library int fd = open("readme", O_RDONLY); read(fd, . . . ); supervisor mode Process File Descriptor Table File descriptor (integer) stdin data stdout data read stderr data readme data
Main UNIX System Calls for Files int open(char * fname, int flags); Open the file fname and return a file descriptor int close(int fd); Close a file descriptor fd int read(int fd, void * buf, int count); Read up to count bytes from fd into the buffer buf int write(int fd, void * buf, int count); Writes up to count bytes to fd from the buffer buf
UNIX open() and close() System Calls q Example use int fd 1, fd 2; /* Open file for reading */ fd 1 = open(“in. txt”, O_RDONLY); /* Open file for writing */ fd 2 = open(“out. txt”, O_RDWR | O_CREAT); . . . close(fd 1); close(fd 2);
UNIX read() System Call q Example use #define MAX 100 /* Assume fd is integer returned by open*/ char buf[MAX]; int n; n = read(fd, buf, MAX); q read returns the number of bytes read (-1 if error) q To read from standard input (keyboard): read(0, buf, MAX);
UNIX write() System Call q Example use #define MAX 100 /* Assume fd 1, fd 2 are integers returned by open calls*/ char buf[MAX]; int n 1, n 2; n 1 = read(fd 1, buf, MAX); n 2 = write(fd 2, buf, n 1); q write returns the number of bytes written (-1 if error) q To write to standard output (screen): write(1, “hello”, strlen(hello));
UNIX read() System Call • Read data from an open file int read(int fd, void *buf, int count); • Parameters o File descriptor fd = integer descriptor returned by open() o Buffer buf = buffer to store the input data o count = maximum number of bytes to read • Returns o Number of bytes read o 0 if nothing more to read, -1 if an error • Example use char buf[MAX]; n = read(0, buf, MAX);
Test Program q Write a simple test program that uses read/write to read a string from the standard input and write it back to the standard output.
Anonymous Unix Pipes
Pipes q A pipe is an operating system buffer used to pass data from one process to another pipe (system buffer) q Pipes enable ONE WAY communication
Example Use of Pipes q List information about the bash process only: ps -f | grep bash ps grep Output of ps becomes input for grep
Multiple Pipes? q Count the number of root processes in the system: ps -ef | grep root | wc -l q The Unix shell creates 3 processes with two pipes between them ps process grep process wc process
Other Examples q Display who is logged in, in alphabetical order: who | sort who q sort Count the number of files in the current directory: ls | wc -l ls wc
Creating a Pipe q Pipe is an abstract communication channel - q Process A can write into the pipe (using the write system call) Process B can read from the pipe (using the read system call) Creating a pipe int pipe(int fd[2]); - return 0 upon success, -1 upon failure - fd[0] is open for reading - fd[1] is open for writing q Two related processes can exchange data using a pipe
Pipe (Parent Child) Example int ret, p[2]; . . . ret = pipe(p); if(ret == -1) exit(1); ret = fork(); if(ret == 0) { /* child */ close(p[1]); . . . read using p[0] as file descriptor. . . close(p[0]); } else { /* parent */ close(p[0]); . . . write using p[1] as file descriptor till EOF. . . close(p[1]); /* sends EOF to the reader */ } Child Parent p[0] p[1] pipe OS
Pipe Example int ret, p[2]; . . . if(pipe(p) == -1) exit(1); ret = fork(); . . . q q q Child Parent p[0] p[1] pipe p Parent creates a pipe, then forks a child Child inherits the file descriptor table (and so the pipe) Pipe is used between parent and child in one direction Exercise: Starting with this example, write a simple test program for pipes. OS
Dup a. out < foo
Dup 2
dup 2 System Call q dup 2 duplicates a file descriptor value dup 2(fd, fd 2); q As a result, fd 2 will refer to the same device as fd - closes fd 2 if it was in use FDT before dup 2 FDT after dup 2 0 1 2 fd 2 . . . fd . . . File data fd File data
Dup 2 q Commonly used to redirect stdin/stdout q Example: redirect stdout to “foo” int fd; fd = open(”foo", O_RDWR | O_CREAT); FDT 0 1 2 3 … stdin data stdout data stderr data foo data dup 2(fd, 1); /* 1 points to foo now */ close(fd); /* close unused file descriptor */. . . printf(. . . ); /* output goes to foo */ write(1, . . . ); /* output goes to foo */ q Important note: only when the last open descriptor for a file is closed, the file itself is closed
Pipes and stdin/stdout int ret, p[2]; if(pipe(p) == -1) exit(1); ret = fork(); if(ret == 0) { /* child */ close(p[1]); dup 2(p[0], 0); /* read end of pipe takes role of stdin */ close(p[0]); . . . read from stdin or invoke new program with execv. . . } else { /* parent */ close(p[0]); dup 2(p[1], 1); /* read end of pipe takes role of stdin */ close(p[1]); . . . write to stdout. . . wait(NULL); }
Activity q Write a program factorial that reads an integer from the command line and calculates its factorial bash$ factorial 50 3041409320171337… q Easy to code 1 * 2 * 3 * 4 * … *49 * 50 - But the product is much too large to fit into an integer or a long Try the program bc (handles any size integers) bash$ bc 1*2*3*…*50 3041409320171337… q Solution: use bc inside the factorial program
Structure of the factorial program q Create a pipe q Fork a child (who will inherit the pipe) q Parent q - write “ 1*2*3* … *50n” into the pipe - write “quitn” into the pipe (to terminate the child) - wait for the child to finish executing Child - redirect stdin to the read end of the pipe - invoke the program bc using execv (bc will read from the pipe, compute the result, print it out) (Optional): Instead of the fixed value 50, have the parent read an integer N from the user, then write 1*2*3 … *Nn into the pipe -Use sprintf(buf, “%d”, x) to turn integer x into a string, then write it immediately into the pipe
Recap q System calls for inter-process communication - pipe: creates a one-way communication channel; has a write end a read end - open/close: opens a file and returns a file descriptor; close uses this file descriptor to close the file - read/write: read from / write to a device identified by a file descriptor (an integer) - dup 2: duplicate a file descriptor
- Slides: 31