University of Minnesota
Computer Science & Engineering Department
Fall 2011, CSci 4061 Exam #1
NAME __________________________________ Student ID # _____________________________
Do all your work on these exam sheets.
(There is a total of 7 pages including this cover page, function signature page/work area)
This is a open-book, open-notes exam. No electronics.
You have one hour and fifteen minutes to answer the questions.
Please write down your name and student id on the top of this page first before you start answering any question. Answer all questions directly on the exam papers. If you need additional sheets, please let us know.
Partial credit is possible for an answer. Please show your work steps and make your exam as readable as possible. We must be able to read your handwriting in order to be able to grade your exam. Spend your time in accordance with the point allocations.
1
Problem
Points
Score
1
35
2
15
3
25
4
25
Total
100
Problem 1: Concepts (35 Points, Please be concise)
a. [8 points] The standard I/O library offers two primary advantages over the low-level Unix interface. Name them and briefly explain why they are an advantage.
b. [6 points] When does random I/O provide an advantage over sequential I/O?
c. [8 points] In Unix, the write system call can fail (return -1) in a variety of ways. Describe two of them.
2
d. [8 points] Consider the code fragment below. The CPU executes the code in the order specified by the number. What is the value of X at points 3, 5, and 7?
1. int X = 3;
2. if (fork() != 0) {
4. X=4; 7. print X;
} else {
3. print X;
5. print X;
6. X = 7;
}
e. [5 points] A file contains 1K bytes and has the following names: /usr/f1, /usr/f2, /usr/f3. The directory entries for /usr are the following:
Name i-node
==========
f1 23
f2 23
f3 23
How much disk storage does this file occupy (for the file contents only)?
3
Problem 2: Analyze this! (15 Pts)
Consider the following code fragment. For each write statement, indicate where the I/O will be sent (e.g. file name, stdout, or an error). Also, show the state of the file descriptor (fd) tables for parent and child at points A and B.
int main () {
int fd1, fd2, fd3, fd4;
fd1 = open (“foo”, O_RDWR);
fd2 = open (“bar”, O_RDWR);
fd3 = open (“baz”, O_RDWR);
fd4 = open (“baw”, O_RDWR);
link (“foo”, “txt”);
dup2 (1, fd3);
dup2 (fd2, 1);
if (fork() == 0) {
dup2 (fd1, fd4);
close (fd1);
write (fd3, “aaa”, 3);
write (1, “bbb”, 3);
write (fd2, “ccc”, 3);
write (fd1, “ddd”, 3);
// point A }
else {
write (fd1, “fff”, 3);
dup2 (fd1, fd3);
write (fd3, “eee”, 3);
write (fd4, “ggg”, 3);
// point B }
}
4
Problem 3: Processes and IPC (25 Pts)
A parent process creates and communicates with a set of K child processes. The parent communicates a series of messages of type m_t specific to that child. The child does not know how many messages will be sent. You will use a pipe between each parent-child process pair – the parent will send the message and the child will receive the message. Close any file descriptors you do not need. Make sure all processes terminate correctly. The parent calls a function int get_next_msg_to_send (m_t *msg, int *id) that returns the next message to send to a child (msg) and the child id (id) is a value between [0, K-1]. When there are no more messages this function returns a 0. For each message received, the child calls do_something_with_msg (msg). Hint: an array of pipes will be handy. You do not need to put in any error checking. You do not need to program get_next_msg_to_send/ do_something_with_msg, just use them.
#define K 10
void main () {
m_t msg;
// fork processes and create pipes
// child code
// parent code
}
5
Problem 4: Programming I/O (25 Pts)
Write the function fputs_simple that writes a string to an open FILE (it is a simpler version of the stdio function). You may find the function int fileno (FILE *stream) useful: it returns the low-level file descriptor (fd) associated with a FILE stream. Recall that stdio functions such as fputs operate on internal buffers as will fputs_simple. Assume the buffer is a char array of size BufSize. You may use only low-level I/O routines to implement fputs_simple. You may also use strlen which returns the length of a string. You do not need to put in any error checking. Hint: think about when the internal buffer gets sent to the OS.
// Here are the declarations for internal buffering – add more declarations if needed
char internal_buf [BufSize];
// fputs returns the number of bytes written from the string str int fputs (char *str, FILE *f) {
6
System call signatures (not all may be needed):
pid_t fork();
int execl (const char *path, const char *arg0, … const char *argn);
int pipe (int ends[2]);
int dup2 (int fd1, int fd2);
off_t lseek (int fd, off_t offset, SEEK_SET);
pid_t wait (int *stat_loc);
pid_t waitpid (pid_t pid, int *stat_loc, int options); int strlen (char *str);
int fstat (int fd, struct stat *sb);
void exit (int status);
Sketch Area (Note: Answers on this sheet will not be graded!!!!) —————————————————–
7