CS 332 w22 — Lab 3 FAQ
Table of Contents
- 1. Pipes and synchronization
- 2.
dupand pipes - 3. Can a process read while another writes?
- 4.
static - 5.
f_ops - 6.
pipe_close - 7. Where do we save the excess if the buffer we read contains more bytes than the user requested?
- 8. If the user makes a request after the read descriptor is closed, where do we retrieve the data from?
- 9. How do we handle a write waiting to insert in a full pipe,we need to make sure that the writes are done atomically and with the default setup it could be the case that a write waits once the buffer is full and then another write gets the lock?
- 10. What do we do with the offset variable?
pipe_readwill be similar tobbq_removepipe_writewill be similar tobbq_insert
1 Pipes and synchronization
- A reader-writer lock is probably a more complex solution than is necessary
- Having lots of readers would be very unusual (though technically possible)
- A pipe is essentially a bounded buffer/producer-consumer, so it will need
- a mutex (lock) to ensure only one thread is reading or writing at a time
- a condition variable for consumers/readers to wait on
- a condition variable for producers/writers to wait on
- Alternatively, you could create a bounded buffer as a separate type of data structure in the kernel (where a pipe would have a
struct BBQinside it)- In this case, the
struct BBQwould have a lock and two condition variables, though you likely would still need a separate lock for the pipe to protect the pipe struct's other fields
- In this case, the
2 dup and pipes
- There's nothing special about
duphere (the lab writeup is unnecessarily specific on this point, the sentence has been removed) - If a process opens a pipe and forks many times, many processes could be reading or writing to the pipe
- Thus,
pipe_readandpipe_writeneed to be thread-safe
3 Can a process read while another writes?
- One process can certainly call
pipe_readwhile another callspipe_write - You will need to use a lock and condition variables to ensure correct behavior under concurrency
4 static
- In C, a
staticfunction or variable is visible only in the file where it is declared - So it's appropriate for functions like
pipe_readand variables likepipe_opsthat should only be used as part of the pipe implementation and nowhere else in the kernel - A
pipe.hfile would only be needed to declare non-staticfunctions/variables that need to be used in multiple files- For example, you might implement a
pipe_initfunction inpipe.cthat is used insys_pipeinsyscall.c
- For example, you might implement a
5 f_ops
The pipe_read, pipe_write, and pipe_close functions you are implementing are the ones f_ops->read, f_ops->write, and f_ops->close will point to for pipe files. Inside pipe_read there's no other function to call to perform the read for you—you are implementing that function.
6 pipe_close
- Free the pipe struct/bounded buffer once both ends of the pipe are closed
- Remember from 208: every call to malloc should have a corresponding call to free
- So if you
kmallocorkmem_cache_allocmemory for the pipe struct, you will also need tokfreeorkmem_cache_freethat memory
- Take a look at the code for
fs_close_file:
void fs_close_file(struct file *file) { sleeplock_acquire(&file->f_lock); file->f_ref--; if (file->f_ref > 0 || file == &stdin || file == &stdout) { sleeplock_release(&file->f_lock); return; } sleeplock_release(&file->f_lock); // guaranteed that we are the last reference to this file if (file->f_inode) { fs_release_inode(file->f_inode); } if (file->f_ops->close) { file->f_ops->close(file); } fs_free_file(file); }
- If there are processes that still have the file open (i.e.,
file->f_ref > 0), then it just returns after decrementing this reference count - If no processes are still using the file, that's when it will call
file->f_ops->close(file)(i.e.,pipe_close), and afterwards free the file struct (fs_free_file) - This means your
pipe_closewill only be called if all processes that had a pointer to that end of the pipe have closed the file
7 Where do we save the excess if the buffer we read contains more bytes than the user requested?
You should only read as many bytes from the buffer as the user requested (read them one at a time in a loop, copying the byte from the pipe's data array to the array (buf) the user passed in
8 If the user makes a request after the read descriptor is closed, where do we retrieve the data from?
The only way for the user to make a request is with the descriptor for the read end of the pipe. If the user has previously closed that file, that entry in the open file table should be NULL, and sys_read will return an error.
9 How do we handle a write waiting to insert in a full pipe,we need to make sure that the writes are done atomically and with the default setup it could be the case that a write waits once the buffer is full and then another write gets the lock?
The pipe is not required to allow waiting writes to proceed in first-come-first-serve order, so it would be valid behavior for the second write to go first. The user would be responsible for accounting for this concurrent write behavior.
10 What do we do with the offset variable?
You do not need to do anything with it—it's used by the file system, but it's necessary for pipe. It has to be an argument to pipe_read and pipe_write in order to conform to the file API.