COP4610: Operating Systems & Concurrent Programming | up ↑ |
What are the differences between the following, and how do they relate to one another?
This diagram shows the relationships of file descriptors, streams, buffers, open file descriptions, and files.
Pay special attention to the many-one relationships.
Streams provide buffered I/O support. They are built on top of the lower-level abstractions of open file descriptor and open file description.
The fdopen operation takes a file descriptor and access mode information, creates a stream, and returns a pointer to the stream object. The fclose operation deallocates the stream object.
abstracted from simple_fork.c
FILE *outstream; ... if (!(outstream = fdopen (outfildes, "w"))) { perror ("could not open stream for writing"); exit (-1); } ... fprintf (outstream, "some text\n");
Read the entire example program.
abstracted from hw1.c
int fd; fd = open ("my_file", O_RDONLY, 0); if (fd == -1) { perror ("open failed\n"); exit (-1); } close (0); if (dup2 (fd, 0) < 0) { perror ("dup2 failed"); exit(-1); } close (fd);
The dup2() call acts like an assignment statement for file descriptors. It make file descriptor 0 (stdin) refer to the same open file description as fd. We can then close fd, so that only 0 refers to the open file.
Read the entire example program.
The above are just summaries. See the Unix man-pages for complete descriptions of the effects of open, close, fdopen, and fclose.
The reference from the open file description to the actual file data is also indirect, through operating system data structures we will study later.
The diagram shows the relationships of directories, filenames, pathnames, and files.
Again pay attention to which relationships are one-one and which are many-one.
Unix files do not have names. Only links (in directories) have names.
Shell command ln makes direct and indirect links. The form "ln -s" is used to create symbolic links.
Shell command rm removes links.
The corresponcding system calls (C API) are link() and unlink().
See the Unix man pages for more detail on each of these system calls.
int pipe(int filedes[2]);
Read the entire example program.
abstracted from hmwk1.c
int pipefd[2]; ... if (pipe (pipefd) == -1) {perror ("could not create pipe"); exit (-1);} child = fork(); if (child != 0) { close (pipefd[0]); /* the reading end of the pipe */ if (write (pipefd[1], &outbuf, sizeof(outbuf)) == -1) perror ("write to pipe failed"); exit -1; } ... close (pipefd[1]); } else { close (pipefd[1]); if ((nread = read (pipefd[0], &buffer, count)) == -1) { perror ("read failed"); exit (-1); } ... close (pipefd[0]); }
The parent process creates the pipe, and then forks. The parent closes one end of the pipe. The child closes the other. The parent writes to the pipe, and the child reads from it.
This example uses of the unbuffered I/O operations, read() and write(), just for variety. A stream could be associated with either or both of the file descriptors, allowing use of the stream input and output functions. In program hmk1.c, the child process used dup2() to map the input side of the pipe to stdin, before executing a new program.
Read the entire example program.
T. P. Baker. ($Id) |