PintOS System Call Handling
I finished Project 2 of PintOS, and hoped to write a blog, but this has taken more time than imagined. Here are my thoughts and suggestions to help you in your project. So project 2 is supposed to be significantly longer and harder than project 1, but not to worry :D, it does involve more coding and better understanding of how system calls function but that will not be too hard for you guys if you have finished with project 1. I was able to complete all but 2 cases(, Sync-read and Sync-write, Still dont know how to complete these).
Project 2 is all about system call handling. I think you might have a decent idea about system calls as this must have been taught in class. I will shed some light about what you must do to implement system call handling in PintOS.
First with the statistics:
There are about 76 test cases which will test the functionality of the system, out of which a lot of them will also try to break your OS. You need to implement proper handling to ensure that faulty user programs are terminated by the kernel. Other than that there are also a few cases which will try to break the VM of the OS, as well as some which checks to see the extent to which file handling is implemented.
Let me break this down into a few main steps:
1) Argument passing
2) System calls
3) Executing and waiting for child processes(Included in system calls but is the hardest to implement and hence you should carefully decide the data structures and functionality related to this problem)
Do go through the code in userprog/ and filesys/ folder. For the latter, you only need to use functions defined here, without the need to modify anything here.
You will need to make minor change in the exception.c file to handler user errors.
go through the pagedir.c file as you will be needing functions like pagedir_get_page and the like. This will also help you gain a better understanding as to how memory is allocated.
Alright so lets begin!
The OS at this initial state is absolutely useless. It even does not print to output(From a user program perspective). The first thing that you need to implement is argument passing, so that functions can at least pass arguments to other functions(In the user to the kernel context).
The first step to solve this is to break your arguments using strtok_r. Store the original command line arguments in another variable. You will be needing this when you start pushing these arguments into the stack. This will have to be done once in process_execute and start_process.
Refer to the manual which states how the stack must look at the end.
For system calls, you need to first check whether the pointer passed to you by the user program is valid or not. Check whether it is null or not and also use thread_get_pagedir() to check if the pointer points to the memory of a user process. Once that is done, we can figure out which system call is being called. For filesystem calls, we have the filesystem interfaces in filesys. and file.h. Use that to open, close, read and write to files. Remember to acquire and release locks for implementing file system calls. For the specical case of write to STOUT_FILENO(1), just use the system call to write to console.
For implementing exec and wait system calls, a thread needs to maintain a list of child processes so that you can call wait on those processes. Also children need to have a pointer to a parent so that they can signal to the parent once they have exited. Remember childs may exit prematurely or, in some cases the parent must have already finished execution, so you need to handle that case properly.
That is about it.
You should have now have an OS that is able to run a lot of user programs, atleast the ones that need at least less than 4KB of memory.
In Project 3, we will be implementing features such as paging so that the OS can run user programs which need more than 4KB of memory.
I finished Project 2 of PintOS, and hoped to write a blog, but this has taken more time than imagined. Here are my thoughts and suggestions to help you in your project. So project 2 is supposed to be significantly longer and harder than project 1, but not to worry :D, it does involve more coding and better understanding of how system calls function but that will not be too hard for you guys if you have finished with project 1. I was able to complete all but 2 cases(, Sync-read and Sync-write, Still dont know how to complete these).
Project 2 is all about system call handling. I think you might have a decent idea about system calls as this must have been taught in class. I will shed some light about what you must do to implement system call handling in PintOS.
First with the statistics:
There are about 76 test cases which will test the functionality of the system, out of which a lot of them will also try to break your OS. You need to implement proper handling to ensure that faulty user programs are terminated by the kernel. Other than that there are also a few cases which will try to break the VM of the OS, as well as some which checks to see the extent to which file handling is implemented.
Let me break this down into a few main steps:
1) Argument passing
2) System calls
3) Executing and waiting for child processes(Included in system calls but is the hardest to implement and hence you should carefully decide the data structures and functionality related to this problem)
Do go through the code in userprog/ and filesys/ folder. For the latter, you only need to use functions defined here, without the need to modify anything here.
You will need to make minor change in the exception.c file to handler user errors.
go through the pagedir.c file as you will be needing functions like pagedir_get_page and the like. This will also help you gain a better understanding as to how memory is allocated.
Alright so lets begin!
The OS at this initial state is absolutely useless. It even does not print to output(From a user program perspective). The first thing that you need to implement is argument passing, so that functions can at least pass arguments to other functions(In the user to the kernel context).
The first step to solve this is to break your arguments using strtok_r. Store the original command line arguments in another variable. You will be needing this when you start pushing these arguments into the stack. This will have to be done once in process_execute and start_process.
Refer to the manual which states how the stack must look at the end.
For system calls, you need to first check whether the pointer passed to you by the user program is valid or not. Check whether it is null or not and also use thread_get_pagedir() to check if the pointer points to the memory of a user process. Once that is done, we can figure out which system call is being called. For filesystem calls, we have the filesystem interfaces in filesys. and file.h. Use that to open, close, read and write to files. Remember to acquire and release locks for implementing file system calls. For the specical case of write to STOUT_FILENO(1), just use the system call to write to console.
For implementing exec and wait system calls, a thread needs to maintain a list of child processes so that you can call wait on those processes. Also children need to have a pointer to a parent so that they can signal to the parent once they have exited. Remember childs may exit prematurely or, in some cases the parent must have already finished execution, so you need to handle that case properly.
That is about it.
You should have now have an OS that is able to run a lot of user programs, atleast the ones that need at least less than 4KB of memory.
In Project 3, we will be implementing features such as paging so that the OS can run user programs which need more than 4KB of memory.