shell (part 2). example r what if we want to support something like this: m ps –le | sort r one...

Post on 20-Jan-2016

217 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

Parent File Descriptor table

01234

stdinstdoutstderr

System file table

Terminal info

01234

stdinstdoutstderr

Child File Descriptor table

Terminal info

Terminal info

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; // track of num bytes read int fd[2]; // hold fds of both ends of pipe pid_t pid; // pid of child process char line[80]; // hold text read/written

Continued …

if (pipe(fd) < 0) // create the pipe perror("pipe error");

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 { // child process close(fd[1]); // close write end n = read(fd[0], line, 80); // read from

pipe write(1, line, n); // echo to

screen } exit(0);}

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

Parent File Descriptor table

01234

stdinstdoutstderr fd[0]

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1]

pipe info e.g., write offset

After Fork

Fork and Pipes

Parent File Descriptor table

01234

stdinstdoutstderr

fd[0] = NULL

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1] = NULL

pipe info e.g., write offset

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

Parent File Desc. table

01234

fds[0] fds[1]

stdinstdoutstderr

System file table

Terminal info

Terminal info

Terminal info

Shared mem. info: read Shared mem. Info:write

Example

System file table

Terminal info

Terminal info

Terminal info

Shared mem. Info: read

Shared mem. Info:write

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

01234

fds[0] fds[1]

stdinstdoutstderr

System file table

01234

fds[0] fds[1]

stdinstdoutstderr

Child File Desc.table

Terminal info

Terminal info

Terminal info

Shared mem. Info: read

Shared mem. Info:write

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

Parent File Descriptor table

01234

stdinstdoutstderr fd[0]

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1]

pipe info e.g., write offset

After Fork

Fork and Pipes

Parent File Descriptor table

01234

stdinstdoutstderr

fd[0] = NULL

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1] = NULL

pipe info e.g., write offset

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

Parent File Desc. table

01234

fds[0]=NULL

fds[1]

stdinstdoutstderr

System file table

01234

fds[0] fds[1]=NULL

stdinstdoutstderr

Child File Desc.table

Terminal info

Terminal info

Terminal info

Shared mem. info: read

Shared mem. info:write

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

Parent File Desc. table

01234

fds[0]=NULL

fds[1]

stdinstdoutstderr

System file table

01234

fds[0] fds[1]=NULL

stdinstdoutstderr

Child File Desc.table

Terminal info

Terminal info

Terminal info

Shared mem. info: read

Shared mem. info:write

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);}

top related