Note: This design was reformatted as the original student-submitted Markdown did not render well.
Design
Struct Designs
process struct
- struct filetable *filetable: pointer to file table
- parent process
- struct cv *wait_cv
- struct process_info *process_info
process_info struct
(Used to pass along info in processes instead of passing an entire process or pointer to -- since there can be copying issues or race conditions)
- current working directory
- pid
- exit code
- has_exited
filetable struct
- struct lock *lock: pointer to lock for file table operations
- struct openfile **openfiles: array of pointers to open files
- Note: we'll also define a constant for the max size of the array
openfile struct:
- vnode * : pointer to the vnode representing the file
- int flags: flags for what we are allowed to do with the file
- off_t offset: The file offset for the file the struct is referring to
- int ref_count: We want to count the number of file descriptors that point to the file so we can remove the object when ref count is 0.
- struct lock *: We want a lock to manage any race conditions or concurrency issues while accessing the files.
Function Designs
Functions implemented: open, read, write, lseek, close, dup2, chdir, __getcwd
open
int open(const char *filename, int flags, ...);
- Iterate through and find new spot to allocate file descriptor
- Create new openfile structure with given flags
- Use vfs_open to open the file
- Add the openfile to the process's file table
- Return the file descriptor
read
ssize_t read(int filehandle, void *buf, size_t size);
- Acquire lock
- Use VOP_READ to read the file (with given offset and other info provided in uio)
- Update the file offset
- Release lock
- Return the number of bytes read
write
ssize_t write(int filehandle, const void *buf, size_t size);
- Acquire lock
- Use VOP_WRITE write to the file at the current offset (provided in uio)
- Update the file offset
- Release lock
- Return the number of bytes written
lseek
off_t lseek(int filehandle, off_t pos, int code);
- Acquire lock
- Calculate the new offset based on the current offset
- Update the file offset
- Release lock
- Return the new offset
close
int close(int filehandle);
- Validate the file descriptor
- Remove the pointer to openfile from the process's file descriptor table by setting pointer to NULL
- Decrement the openfile's reference count
- If the reference count reaches zero, close the vnode and free the openfile struct
- Delete openfile from file table
dup2
int dup2(int filehandle, int newhandle);
- If file descriptors are the same, return immediately
- If the new file descriptor is already in use, close it
- Copy the openfile pointer from the old file descriptor to the new one
- Increment the openfile's reference count
chdir
int chdir(const char *path);
- Get directory vnode with vfs_getcurdir
- Update the process's current working directory
- Release the old directory vnode if it exists
__getcwd
ssize_t __getcwd(char *buf, size_t buflen);
- Use vfs_getcurdir to get the current working directory path
- Copy the path to the user-provided buffer
- Return the length of the path
fork
pid_t fork(void);
- Duplicate the calling process proc struct
- Copy over parent address space
- Copy parent's open file descriptors, update reference counts
- Copy parent cwd
- Return 1 to parent (later will return child PID to parent)
_exit
__DEAD void _exit(int code);
- Close open file descriptors
- Free process file descriptor table
- Free memory resources
- Mark hasExited on the process to true
- Set exit code
- Wake up waiting parents (phase 2)
getpid
pid_t getpid(void);
Returns pid from the current process
execv
int execv(const char *prog, char *const *args);
- Copy args from user space to kernel space
- Open program file
- Create new vaddr space, load program in
- Copy args over to new stack
- Return to usermode
waitpid
pid_t waitpid(pid_t pid, int *returncode, int flags);
- Acquire lock
- cv_wait until child has exited
- Clean up child
- Release lock
- Return pid
(When logged in, completion status appears here.)