Lecture 16
Lecture 16
0201-003
Memory
I/O Devices
• Very diverse devices
— behavior (i.e., input vs. output vs. storage)
— partner (who is at the other end?)
— data rate
• I/O Design affected by many factors (expandability,
resilience)
• Performance:
— access latency
— throughput
— connection between devices
and the system
— the memory hierarchy
— the operating system
• A variety of different users
Application programs
If this is enough
• Why fd?
– Kernel maintains an array of info on currently opened
files for a process
– fd indexes into this in-kernel array
• Each process starts out with three open files
• 0: standard input
• 1: standard output
• 2: standard error
Closing Files
• Closing a file informs kernel that you
are finished accessing that file
int fd; /* file descriptor */
if (close(fd) < 0) {
perror("close");
exit(1);
}
Simple read/write example
• Copying standard in to standard out, one
byte at a time
#include <stdio.h>
int main(void)
{
char c; Returns # of bytes read, -1 for error
...
fd 4 ...
File B (disk)
File access
File size
File pos
refcnt=1 File type
...
...
Kernel tracks user processes’
opened files
• Calling open twice with the same
filename
Descriptor table Open file table v-node table
[one table per process] [shared by all processes] [shared by all processes]
File A (disk)
stdin fd 0 File access
stdout fd 1
File pos File size
stderr fd 2
fd 3 refcnt=1 File type
...
...
fd 4
File B (disk)
File pos
refcnt=1
...
Child process inherits its parent’s
open files
• Before fork() call:
...
...
fd 4
File B (disk)
File access
File size
File pos
refcnt=1 File type
...
...
Child process inherits its parent’s
open files
• After fork():
Child’s descriptor table same as parent’s, and +1 to
each refcnt
...
...
fd 4
...
...
fd 4
Fun with File Descriptors (fork)
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1;
Solution:
char c1, c2;
char *fname = argv[1];
fd1 = open(fname, O_RDONLY, 0); Parent: c1 = a, c2 = b
read(fd1, &c1, 1); Child: c1 = a, c2 = c
if (fork()) { /* Parent */
read(fd1, &c2, 1);
printf("Parent: c1 = %c, c2 = %c\n", c1, c2);
} else { /* Child */
sleep(5);
read(fd1, &c2, 1);
printf("Child: c1 = %c, c2 = %c\n", c1, c2);
}
return 0;
}
fd 0 fd 0
fd 1 a fd 1 b
fd 2 fd 2
fd 3 fd 3
fd 4 b fd 4 b
I/O Redirection Example
• Step #1: open output file to which stdout
should be redirected
...
...
fd 4
File B
File access
Opened file has fd=4 File size
File pos
refcnt=1 File type
...
...
I/O Redirection Example (cont.)
• Step #2: call dup2(4,1)
cause fd=1 (stdout) to refer to disk file pointed at by fd=4
...
...
fd 4
File B
File access
File size
File pos
refcnt=2 File type
...
...
Standard I/O Functions
• The C library (libc.so) contains a
collection of higher-level standard
I/O functions fopen fdopen
fread fwrite
fscanf fprintf
sscanf sprintf
fgets fputs
fflush fseek
fclose
open read
write lseek
stat close
Standard I/O Streams
• Standard I/O implements buffered streams
– Abstraction for a file descriptor and a buffer in
memory.
• C programs begin life with three open streams
– stdin (standard input)
– stdout (standard output)
– stderr (standard error)
#include <stdio.h>
extern FILE *stdin; /* standard input (descriptor 0) */
extern FILE *stdout; /* standard output (descriptor 1) */
extern FILE *stderr; /* standard error (descriptor 2) */
int main() {
fprintf(stdout, "Hello, world\n");
}
Unix I/O vs. standard I/O
• Unix I/O:
– Pros
• most general, lowest overhead.
• All other I/O packages are implemented using
Unix I/O functions.
• Provides functions for accessing file metadata.
• async-signal-safe and can be used safely in signal
handlers.
– Cons
• Efficient reading/writing may require some form
of buffering
Unix I/O vs. Standard I/O:
• Standard I/O:
– Pros:
• Buffering increases efficiency by reducing # of
read and write system calls
– Cons:
• Provides no function for accessing file metadata
• Not async-signal-safe, and not appropriate for
signal handlers.
• Not appropriate for input and output on network
sockets
Choosing I/O Functions
• General rule: use the highest-level I/O
functions you can
– Many C programmers are able to do all of their
work using the standard I/O functions
write(1, "hello\n", 6) = 6
...
exit_group(0) = ?
Conclusions
• UNIX/LINUX use files to abstract
many I/O devices
• Accessing files can be done either by
standard I/O or UNIX I/O