I/O and Process Management!: Jennifer Rexford!
I/O and Process Management!: Jennifer Rexford!
Jennifer Rexford!
1
Goals of this Lecture: I/O!
The Unix stream concept!
Standard C I/O functions!
Unix system-level functions for I/O!
How C I/O functions use the Unix functions!
Additional abstractions provided by C I/O functions!
2
Stream Abstraction!
Any source of input or destination for output!
E.g., keyboard as input, and screen as output!
E.g., files on disk or CD, network ports, printer port, !
file file
6
Example: Formatted I/O!
int fprintf(fp1, "Number: %d\n", i)!
Convert and write output to stream in specified format!
int fscanf(fp1, "FooBar: %d", &i)
Read from stream in format and assign converted values!
Specialized versions!
printf() is just fprintf(stdout, )
scanf() is just fscanf(stdin, )
7
Layers of Abstraction!
File descriptor:!
Appl Pgm! An integer that!
User! uniquely identifies!
process! FILE * stream! an open file!
Stdio Library!
int fd!
File System! hierarchical file system!
Operating! Storage! variable-length segments!
System!
Driver! disk blocks!
Disk!
8
System-Level Functions for I/O!
int creat(char *pathname, mode_t mode);
Create a new file named pathname, and return a file descriptor!
int open(char *pathname, int flags, mode_t mode);
Open the file pathname and return a file descriptor!
int close(int fd);
Close fd
int read(int fd, void *buf, int count);
Read up to count bytes from fd into the buffer at buf !!
int write(int fd, void *buf, int count);
Writes up to count bytes into fd from the buffer at buf
int lseek(int fd, int offset, int whence);
Assigns the file pointer of fd to a new value by applying an offset!
9
Example: open()
Converts a path name into a file descriptor!
int open(const char *pathname, int flags,
mode_t mode);
Arguments!
Pathname: name of the file!
Flags: bit flags for O_RDONLY, O_WRONLY, O_RDWR
Mode: permissions to set if file must be created!
Returns!
File descriptor (or a -1 if an error)!
Performs a variety of checks!
E.g., whether the process is entitled to access the file!
Underlies fopen() 10
Example: read()
Reads bytes from a file descriptor!
int read(int fd, void *buf, int count);
Arguments!
File descriptor: integer descriptor returned by open()
Buffer: pointer to memory to store the bytes it reads!
Count: maximum number of bytes to read
Returns!
Number of bytes read!
Value of 0 if nothing more to read!
Value of -1 if an error!
Buffered I/O!
Read a large chunk from disk into a buffer!
Dole out bytes to the user process as needed!
Discard buffer contents when the stream is closed!
Similarly, for writing, write individual bytes to a buffer!
And write to disk when full, or when stream is closed!
Known as flushing the buffer!
13
Better getchar() with Buffered I/O!
int getchar(void) {
static char base[1024];
static char *ptr; persistent variables
static int cnt = 0;
17
Process Management!
18
Goals of this Lecture: Processes!
Help you learn about:!
Creating new processes!
Programmatically redirecting stdin, stdout, and stderr!
(Appendix) communication between processes via pipes!
Why?!
Creating new processes and programmatic redirection
are fundamental tasks of a Unix shell (Assignment 7)!
19
Why Create a New Process?!
Run a new program!
E.g., shell executing a program entered at command line!
Or, even running an entire pipeline of commands!
Such as wc l * | sort | uniq -c | sort nr!
Underlying mechanism!
A process executes fork() to create a child process!
(Optionally) child does exec() of a new program!
20
Creating a New Process!
Cloning an existing process!
Parent process creates a new child process!
The two processes then run concurrently ! parent
21
Fork System-Level Function!
fork() is called once!
But returns twice, once in each process!
pid = fork();
if (pid != 0) {
printf("parent: x = %d\n", --x);
exit(0);
} else {
printf("child: x = %d\n", ++x);
exit(0);
}
} 24
Executing a New Program!
fork() copies the state of the parent process!
Child continues running the parent program!
with a copy of the process memory and registers!
execvp("ls", argv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); 25
Waiting for the Child to Finish!
Parent should wait for children to finish!
Example: a shell waiting for operations to complete!
ls!
27
Simple Shell Code!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) {
/* in child */
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous 28
Simple Shell Trace (1)!
Parent Process!
Parse command line
Assign values to somepgm, someargv
pid = fork();
if (pid == 0) {
/* in child */
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous
29
Simple Shell Trace (2)!
Parent Process! Child Process!
Parse command line Parse command line
Assign values to somepgm, someargv Assign values to somefile, someargv
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {
concurrently!
/* in child */ /* in child */
executing!
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);
Repeat the previous Repeat the previous
30
Simple Shell Trace (3)!
Parent Process! childs pid! Child Process!
Parse command line Parse command line
Assign values to somepgm, someargv Assign values to somefile, someargv
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {
concurrently!
/* in child */ /* in child */
executing!
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);
Repeat the previous Repeat the previous
31
Simple Shell Trace (4)!
Parent Process! 0! Child Process!
Parse command line Parse command line
Assign values to somepgm, someargv Assign values to somefile, someargv
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {
concurrently!
/* in child */ /* in child */
executing!
execvp(somepgm, someargv); execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n"); fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* in parent */ /* in parent */
pid = wait(&status); pid = wait(&status);
Repeat the previous Repeat the previous
concurrently!
/* in child */
executing!
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous
concurrently!
/* in child */
executing!
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
Repeat the previous
Example!
int main(void) {
system("echo Hello world");
return 0;
}
36
Fork and Virtual Memory!
Incidentally!
Question:!
fork() duplicates an entire process (text, bss, data,
rodata, stack, heap sections)!
Isnt that very inefficient???!!!!
Answer:!
Using virtual memory, not really!!
Upon fork(), OS creates virtual pages for child
process!
Each child virtual page points to real page (in memory or
on disk) of parent!
OS duplicates real pages incrementally, and only if/when
write occurs!
37
Redirection!
Unix allows redirection of stdin, stdout, or stderr!
How?!
Use open(), creat(), and close() system calls!
Described in I/O Management lecture!
Use dup() system call!
38
Redirection Example!
How does shell implement somepgm > somefile?!
pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640);
close(1);
dup(fd);
close(fd);
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
39
Redirection Example Trace (1)!
Parent Process! /dev/tty!
0!
File! 1!
descriptor! 2!
table! 3!
pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640);
close(1);
dup(fd);
close(fd);
execvp(somepgm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640); somepgm
close(1);
dup(fd);
close(fd);
execvp(somepfm, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
pid = fork();
if (pid == 0) {
/* in child */
fd = creat("somefile", 0640);
close(1);
dup(fd);
close(fd);
execvp(somefile, someargv);
fprintf(stderr, "exec failed\n");
exit(EXIT_FAILURE);
}
/* in parent */
pid = wait(&status);
50
Summary!
System-level functions for creating processes!
fork(): process creates a new child process!
wait(): parent waits for child process to complete!
exec(): child starts running a new program!
system(): combines fork, wait, and exec all in one!
51
Appendix!
52
IPC!
different machines
same machine 53
IPC Mechanisms!
Pipes!
Processes on the same machine!
Allows parent process to communicate with child process!
Allows two sibling processes to communicate!
Used mostly for a pipeline of filters!
55
Example Use of Pipes!
Compute a histogram of content types in my e-mail!
Many e-mail messages, consisting of many lines!
Lines like Content-Type: image/jpeg indicate the type!
57
Pipe Example!
child
parent
58
Pipes and Stdio!
59
Pipes and Exec!
child process
60