ppt

Shell (Part 2)
Example
 What if we want to support something like
this:

ps –le | sort
 One process should execute ps –le and
another should execute sort
 By default a command like ps requires that
its output goes to standard output i.e., the
terminal (stdout)
 The sort command requires that a file be
provided as a command line argument from
standard input (stdin)
First Attempt
pid = fork();
if (pid<0) {
perror("Problem forking");
exit(1);
} else if (pid>0) {
/* parent process */
execlp("ps","ps","-le",
NULL);
perror("exec problem");
exit(1);
} else {
/* child process */
}
execlp("sort","sort",NULL);
perror("exec problem");
exit(1);
}
}
return(0);
Example
 Why doesn’t this work?

The output of the ps -le goes to the terminal
 We want it to be the input to the sort
 The diagram on the next page shows the
status of the file descriptor tables after
the fork
Fork and Files
0
1
2
3
4
stdin
stdout
stderr
Parent File
Descriptor table
0
1
2
3
4
stdin
stdout
stderr
Child File
Descriptor table
Terminal
info
Terminal
info
Terminal
info
System file table
What is Needed?
 Assume process P1 is to execute ps –le and that P2
is to execute sort
 There is a need for shared memory that allows P1
to write the results of ps –le to the shared
memory
 P2 should be able to read the results from the
shared memory and provide the results to the sort
command
Pipes
 The pipe function can be used to provide the
shared memory
 We will first provide a general discussion of the
pipe function which is to be followed by a
discussion of how it applies to executing ps –le |
sort
Pipes
 Pipes can be used between processes that
have a common ancestor
 Typical use:
Pipe created by a process
 Process calls fork()
 Pipe used between parent and child
 Allows for communication between processes

Creating a Pipe
#include <unistd.h>
int pipe(int filedes[2]);
 Returns 0 if ok, -1 on error
 Returns two file descriptors
 filedes[0] is open for reading
 filedes[1] is open for writing
Example
#include <unistd.h>
#include <stdio.h>
int main(void){
int n;
int fd[2];
pid_t pid;
char line[80];
// track of num bytes read
// hold fds of both ends of pipe
// pid of child process
// hold text read/written
Continued …
if (pipe(fd) < 0)
perror("pipe error");
// create the pipe
if ((pid = fork()) < 0) {
// fork off a child
perror("fork error");
} else if (pid > 0) {
// parent process
close(fd[0]);
// close read end
write(fd[1], "hello world\n", 12); // write to it
wait(NULL);
}…
Continued…
else {
close(fd[1]);
n = read(fd[0], line, 80);
write(1, line, n);
}
exit(0);
}
// child process
// close write end
// read from pipe
// echo to screen
Fork and Pipes
 A fork copies the file descriptor table to
the child
 The parent should close one of the file
descriptors while the child should close the
other
 Example code on the two previous slides:
Parent closes fd[0] since it does not read
from it
 Child closes fd[1] since it does not write

Fork and Pipes
0
1
2
3
4
stdin
stdout
stderr
fd[0]
fd[1]
Parent File Descriptor table
0
1
2
3
4
stdin
stdout
stderr
fd[0]
pipe info e.g.,
read offset
pipe info e.g.,
write offset
System file table
fd[1]
Child File Descriptor table
After Fork
Fork and Pipes
0
1
2
3
4
stdin
stdout
stderr
fd[0] = NULL
fd[1]
Parent File Descriptor table
0
1
2
3
4
stdin
stdout
stderr
fd[0]
fd[1] = NULL
Child File Descriptor table
pipe info e.g.,
read offset
pipe info e.g.,
write offset
System file table
After Closing Ends
Pipes
 By default, if a writing process attempts to
write to a full pipe, the system will
automatically block the process until the
pipe is able to receive the data
 Likewise, if a read is attempted on an
empty pipe, the process will block until
data is available
 In addition, the process will block if a
specified pipe has been opened for reading,
but another process has not opened the
pipe for writing
Pipe Capacity
 The OS has a limit on the buffer space
used by the pipe

If you hit the limit, write will block
Example
 We will now show how pipes can be used for
supporting the execution of ps –le | sort
Example
 First let us
 Create shared memory that is to be used by the
parent and child processes
 This is done using the pipe function
 The pipe function is executed before the
fork function
 The results of ps –le should be put into
the shared memory to be used by the child
process for sort
 See next slide for code
 The slide after code slide depicts the file
descriptor table and System File table
Example
int main(int argc, char **argv) {
int fds[2];
pid_t pid;
/* attempt to create a pipe */
if (pipe(fds)<0) {
perror("Fatal Error");
exit(1);
}
Example
Terminal info
Parent
File
Desc.
table
0
1
2
3
4
stdin
stdout
stderr
fds[0]
fds[1]
Terminal info
Terminal info
Shared mem. info:
read
Shared mem. Info:
write
System file table
Terminal info
Example
Terminal info
Terminal info
Shared mem. Info:
read
Shared mem. Info:
write
System file table
Shared Memory
Example
 Each entry in the system file table has
information about the “file” which could be
the terminal, disk file or pipe (shared
memory)
 For shared memory created by the pipe
function:
The read descriptor includes information about
the last location read from
 The write descriptor includes information about
the last location written to.

Example
 Let us now add the code for the fork
 See next slide for the code
Example
/* create another process */
pid = fork();
if (pid<0) {
perror("Problem forking");
exit(1);
}
……………..
What is the status of the file descriptor table
Example
Parent
File
Desc.
table
Child
File
Desc.
table
0
1
2
3
4
0
1
2
3
4
stdin
stdout
stderr
fds[0]
fds[1]
stdin
stdout
stderr
fds[0]
fds[1]
Terminal info
Terminal info
Terminal info
Shared mem. Info:
read
Shared mem. Info:
write
System file table
Fork and Pipes
 A fork copies the file descriptor table to
the child
 The parent should close one of the file
descriptors while the child should close the
other
Fork and Pipes
0
1
2
3
4
stdin
stdout
stderr
fd[0]
fd[1]
Parent File Descriptor table
0
1
2
3
4
stdin
stdout
stderr
fd[0]
pipe info e.g.,
read offset
pipe info e.g.,
write offset
System file table
fd[1]
Child File Descriptor table
After Fork
Fork and Pipes
0
1
2
3
4
stdin
stdout
stderr
fd[0] = NULL
fd[1]
Parent File Descriptor table
0
1
2
3
4
stdin
stdout
stderr
fd[0]
fd[1] = NULL
Child File Descriptor table
pipe info e.g.,
read offset
pipe info e.g.,
write offset
System file table
After Closing Ends
Example
 We want the output of the ps –le command
to be put into the shared memory
 The sort command should read from the
shared memory
 Two issues:
The sort command assumes that it receives its
input from stdin
 The ps command assumes that it outputs to
stdout

 We need to “reroute”
 This can be done using the dup() function
dup() and dup2
#include <unistd.h>
int dup(int filedes1);
int dup2(int filedes1, int filedes2);
 Both will duplicate an existing file descriptor
 dup() returns lowest available file descriptor, now
referring to whatever filedes1 refers to
 dup2() - filedes2 (if open) will be closed and then
set to refer to whatever filedes1 refers to
Example
 Now we want what would normally go to the
standard output to go to the shared
memory
 This is done with the following code:
if ( dup2(fds[1],STDOUT_FILENO)<0) {
perror("can't dup");
exit(1);
}
 The new parent file descriptor table is on
the next page
Example
Terminal info
Parent
File
Desc.
table
Child
File
Desc.
table
stdin
0
stdout
1
stderr
2
3 fds[0]=NULL
fds[1]
4
stdin
stdout
stderr
fds[0]
0
1
2
3
4 fds[1]=NULL
Terminal info
Terminal info
Shared mem. info:
read
Shared mem. info:
write
System file table
Example
 Now want to set it up so that the child
reads from the shared memory
 This is done with the following code:
if ( dup2(fds[0],STDIN_FILENO)<0) {
perror("can't dup");
exit(1);
}
 The new child file descriptor is on the next
page
Example
Terminal info
Parent
File
Desc.
table
Child
File
Desc.
table
stdin
0
stdout
1
stderr
2
3 fds[0]=NULL
fds[1]
4
stdin
stdout
stderr
fds[0]
0
1
2
3
4 fds[1]=NULL
Terminal info
Terminal info
Shared mem. info:
read
Shared mem. info:
write
System file table
Example
 Let us now put it together
Example
/* create another process */
pid = fork();
if (pid<0) {
perror("Problem forking");
exit(1);
} else if (pid>0) {
/* parent process */
close(fds[0]);
/* close stdout, reconnect to the writing end of the pipe */
if ( dup2(fds[1],STDOUT_FILENO)<0) {
perror("can't dup");
exit(1);
}
execlp("ps","ps","-le", NULL);
perror("exec problem");
exit(1);
Example
} else {
/* child process */
}
}
close(fds[1]);
if (dup2(fds[0],STDIN_FILENO) < 0) {
perror("can't dup");
exit(1);
}
execlp("sort","sort",NULL);
perror("exec problem");
exit(1);
return(0);