The aim of this project is build a custom shell with the use of System Call APIs with C programming
If you wish to compile the script from source, you will need the following:
- A Linux Based System (OS)
- This script was built on Ubuntu 22.04.1 LTS in WSL2, there is no guaranteed support on other systems
- gcc (Compiler)
- If you wish to compile the source codes, you will need gcc to do so
- Alternatively, a precompiled binary
shellis also provided if you do not wish to compile from source
Before you compile and run the shell, you may want to change some of the following configurations:
/******************************************************************************
* Configs
******************************************************************************/
enum {
MAX_PROCESSES = 64, // change this to change the maximum allowed processes at one time
MAX_RUNTIME = 5, // change this to change the maximum runtime
};If you wish to compile the codes, you may use the run_shell.sh script provided.
Take note that you may also need to make the file executable with the chmod command.
# make run_shell.sh executable
chmod +x run_shell.sh
# execute run_shell.sh
./run_shell.shAlternatively, if you do not wish to compile the source code, a precompiled binary, shell has been provided at the root of the project for use:
# make shell binary executable
chmod +x shell
# execute the shell binary
./shellThere are 3 main components to the shell.
- Main Process
- Handles the user's inputs from the shell prompt
- Background Handler Process
- Handles the scheduling of jobs in a round robin manner
- Timer Process
- A process that sleeps for
MAX_RUNTIMEseconds and returns
- A process that sleeps for
Upon running the shell, the Main Process forks a Background Handler Process and starts listening for user inputs from the shell prompt.
An empty Process List and a Process Queue is first created.
The Process List is used to track the different processes created and their states.
The Process Queue is used to keep track of which process is to be executed at the moment.
When a user inputs a run command, the Main Process parses this command and forks a child to execute the command with execvp.
However, before running execvp, the forked child will run raise(SIGSTOP) to stop itself from executing any futher.
The purpose of this is to make it so the Background Handler is the only process capable starting any new processes to ensure they only run for MAX_RUNTIME seconds.
The Background Handler Process will then try to dequeue the next process in to be executed and resume it with the SIGCONT signal. Besides resuming the Next Processes, it also forks a Timer Process that runs for exactly MAX_RUNTIME seconds which is by default 5 seconds. While these two processes are running, the Background Handler Process waits for any of the following conditons:
- The
Next Processreturns before theTimer Process- We know the process has completed in less than
5seconds, which means it has finished running. - In this case we will continue to the next process in the
Process Queue
- We know the process has completed in less than
- The
Timer Processreturns before thenext process- We know the process has yet to complete and has used up all its
5seconds of allocated time. - In this case, we will queue this process to the end of the
Process Queueagain as it has not finished.
- We know the process has yet to complete and has used up all its
- The
Next Processstatus is no longerRUNNING- This means the user has use a command like
killorstopand has interrupted the process's running - In this case we will continue to the next process in the
Process Queue
- This means the user has use a command like
