From 7bb91e666dfeaa087d0d3645bd611bd5e0fd1537 Mon Sep 17 00:00:00 2001 From: p-w-rs Date: Wed, 7 Sep 2022 11:18:56 -0500 Subject: [PATCH] stuff --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 1 + 00-WSLSetup/LinuxVMSetup.md | 320 +++++++++++++++++ 00-WSLSetup/hello.c | 35 ++ 01-StackMachine/.DS_Store | Bin 0 -> 6148 bytes 01-StackMachine/Makefile | 13 + 01-StackMachine/StackMachine.md | 253 +++++++++++++ 01-StackMachine/smTester.c | 37 ++ 01-StackMachine/stackm.h | 195 ++++++++++ 01-StackMachine/testcases/tc1.c | 8 + 01-StackMachine/testcases/tc10.c | 30 ++ 01-StackMachine/testcases/tc11.c | 27 ++ 01-StackMachine/testcases/tc12.c | 39 ++ 01-StackMachine/testcases/tc13.c | 27 ++ 01-StackMachine/testcases/tc14.c | 39 ++ 01-StackMachine/testcases/tc15.c | 27 ++ 01-StackMachine/testcases/tc16.c | 39 ++ 01-StackMachine/testcases/tc17.c | 21 ++ 01-StackMachine/testcases/tc18.c | 21 ++ 01-StackMachine/testcases/tc19.c | 26 ++ 01-StackMachine/testcases/tc2.c | 20 ++ 01-StackMachine/testcases/tc20.c | 30 ++ 01-StackMachine/testcases/tc21.c | 34 ++ 01-StackMachine/testcases/tc22.c | 31 ++ 01-StackMachine/testcases/tc23.c | 31 ++ 01-StackMachine/testcases/tc24.c | 42 +++ 01-StackMachine/testcases/tc25.c | 16 + 01-StackMachine/testcases/tc3.c | 24 ++ 01-StackMachine/testcases/tc4.c | 14 + 01-StackMachine/testcases/tc5.c | 9 + 01-StackMachine/testcases/tc6.c | 25 ++ 01-StackMachine/testcases/tc7.c | 36 ++ 01-StackMachine/testcases/tc8.c | 9 + 01-StackMachine/testcases/tc9.c | 19 + 02-TeenyTinyShell/.DS_Store | Bin 0 -> 6148 bytes 02-TeenyTinyShell/Makefile | 17 + 02-TeenyTinyShell/TeenyTinyShell.md | 203 +++++++++++ 02-TeenyTinyShell/testcases/tc1 | 2 + 02-TeenyTinyShell/testcases/tc10 | 3 + 02-TeenyTinyShell/testcases/tc2 | 3 + 02-TeenyTinyShell/testcases/tc3 | 3 + 02-TeenyTinyShell/testcases/tc4 | 5 + 02-TeenyTinyShell/testcases/tc5 | 4 + 02-TeenyTinyShell/testcases/tc6 | 3 + 02-TeenyTinyShell/testcases/tc7 | 3 + 02-TeenyTinyShell/testcases/tc8 | 3 + 02-TeenyTinyShell/testcases/tc9 | 3 + 02-TeenyTinyShell/ttsh.c | 102 ++++++ 03-MatrixAddition/.DS_Store | Bin 0 -> 6148 bytes 03-MatrixAddition/MatrixAddition.md | 284 +++++++++++++++ 03-MatrixAddition/matrices/matA | 3 + 03-MatrixAddition/matrices/matB | 3 + 03-MatrixAddition/matrices/matC | 11 + 03-MatrixAddition/matrices/matD | 11 + 03-MatrixAddition/matrices/matE | 101 ++++++ 03-MatrixAddition/matrices/matF | 101 ++++++ 03-MatrixAddition/matrices/vector1 | 3 + 03-MatrixAddition/matrices/vector2 | 3 + 05-RootVegFarm/.DS_Store | Bin 0 -> 6148 bytes 05-RootVegFarm/RootVegFarm.md | 179 ++++++++++ 05-RootVegFarm/testcases/given | 6 + 05-RootVegFarm/testcases/tc1 | 4 + 05-RootVegFarm/testcases/tc2 | 9 + 05-RootVegFarm/testcases/tc3 | 28 ++ 05-RootVegFarm/testcases/tc4 | 6 + 05-RootVegFarm/testcases/tc5 | 7 + 05-RootVegFarm/testcases/tc6 | 4 + 06-MemoryManager/.DS_Store | Bin 0 -> 6148 bytes 06-MemoryManager/Makefile | 16 + 06-MemoryManager/MemoryManager.drawio | 1 + 06-MemoryManager/MemoryManager.md | 287 +++++++++++++++ 06-MemoryManager/MemoryManager.png | Bin 0 -> 41494 bytes 06-MemoryManager/memory_manager.c | 140 ++++++++ 06-MemoryManager/memory_manager.h | 119 +++++++ 06-MemoryManager/pthread_testmemmgr.c | 53 +++ .../testcases/pthread_testmemmgr.c | 53 +++ 06-MemoryManager/testcases/tc0.c | 23 ++ 06-MemoryManager/testcases/tc1.c | 35 ++ 06-MemoryManager/testcases/tc10.c | 47 +++ 06-MemoryManager/testcases/tc11.c | 72 ++++ 06-MemoryManager/testcases/tc12.c | 72 ++++ 06-MemoryManager/testcases/tc2.c | 35 ++ 06-MemoryManager/testcases/tc3.c | 35 ++ 06-MemoryManager/testcases/tc4.c | 32 ++ 06-MemoryManager/testcases/tc5.c | 41 +++ 06-MemoryManager/testcases/tc6.c | 45 +++ 06-MemoryManager/testcases/tc7.c | 62 ++++ 06-MemoryManager/testcases/tc8.c | 62 ++++ 06-MemoryManager/testcases/tc9.c | 62 ++++ 06-MemoryManager/testcases/testmemmgr.c | 62 ++++ 06-MemoryManager/testmemmgr.c | 62 ++++ 07-FunWithFileSystems/FunWithFileSystems.md | 337 ++++++++++++++++++ 07-FunWithFileSystems/dir.drawio | 1 + 07-FunWithFileSystems/dir.png | Bin 0 -> 4521 bytes 07-FunWithFileSystems/dirblock.drawio | 1 + 07-FunWithFileSystems/dirblock.png | Bin 0 -> 7496 bytes 07-FunWithFileSystems/inode.drawio | 1 + 07-FunWithFileSystems/inode.png | Bin 0 -> 23964 bytes 07-FunWithFileSystems/ttfs.drawio | 1 + 07-FunWithFileSystems/ttfs.h | 37 ++ 07-FunWithFileSystems/ttfs.img | Bin 0 -> 52528 bytes 07-FunWithFileSystems/ttfs.png | Bin 0 -> 17711 bytes README.md | 3 + TTOS/.DS_Store | Bin 0 -> 6148 bytes TTOS/include/elf.h | 232 ++++++++++++ TTOS/include/errorCode.h | 15 + TTOS/include/fs/fs.h | 22 ++ TTOS/include/memory.h | 15 + TTOS/include/process.h | 19 + TTOS/include/syscall.h | 6 + TTOS/ld.script | 5 + TTOS/makefile | 16 + TTOS/src/elf.c | 307 ++++++++++++++++ TTOS/src/fs/fs.c | 57 +++ TTOS/src/main.c | 16 + TTOS/src/memory.c | 52 +++ TTOS/src/process.c | 80 +++++ TTOS/src/syscall.c | 21 ++ TTOS/test.c | 27 ++ TTOS/test2.c | 3 + build.bat | 1 + 121 files changed, 5306 insertions(+) create mode 100644 .DS_Store create mode 100644 .gitignore create mode 100644 00-WSLSetup/LinuxVMSetup.md create mode 100644 00-WSLSetup/hello.c create mode 100644 01-StackMachine/.DS_Store create mode 100644 01-StackMachine/Makefile create mode 100644 01-StackMachine/StackMachine.md create mode 100644 01-StackMachine/smTester.c create mode 100644 01-StackMachine/stackm.h create mode 100644 01-StackMachine/testcases/tc1.c create mode 100644 01-StackMachine/testcases/tc10.c create mode 100644 01-StackMachine/testcases/tc11.c create mode 100644 01-StackMachine/testcases/tc12.c create mode 100644 01-StackMachine/testcases/tc13.c create mode 100644 01-StackMachine/testcases/tc14.c create mode 100644 01-StackMachine/testcases/tc15.c create mode 100644 01-StackMachine/testcases/tc16.c create mode 100644 01-StackMachine/testcases/tc17.c create mode 100644 01-StackMachine/testcases/tc18.c create mode 100644 01-StackMachine/testcases/tc19.c create mode 100644 01-StackMachine/testcases/tc2.c create mode 100644 01-StackMachine/testcases/tc20.c create mode 100644 01-StackMachine/testcases/tc21.c create mode 100644 01-StackMachine/testcases/tc22.c create mode 100644 01-StackMachine/testcases/tc23.c create mode 100644 01-StackMachine/testcases/tc24.c create mode 100644 01-StackMachine/testcases/tc25.c create mode 100644 01-StackMachine/testcases/tc3.c create mode 100644 01-StackMachine/testcases/tc4.c create mode 100644 01-StackMachine/testcases/tc5.c create mode 100644 01-StackMachine/testcases/tc6.c create mode 100644 01-StackMachine/testcases/tc7.c create mode 100644 01-StackMachine/testcases/tc8.c create mode 100644 01-StackMachine/testcases/tc9.c create mode 100644 02-TeenyTinyShell/.DS_Store create mode 100644 02-TeenyTinyShell/Makefile create mode 100644 02-TeenyTinyShell/TeenyTinyShell.md create mode 100644 02-TeenyTinyShell/testcases/tc1 create mode 100644 02-TeenyTinyShell/testcases/tc10 create mode 100644 02-TeenyTinyShell/testcases/tc2 create mode 100644 02-TeenyTinyShell/testcases/tc3 create mode 100644 02-TeenyTinyShell/testcases/tc4 create mode 100644 02-TeenyTinyShell/testcases/tc5 create mode 100644 02-TeenyTinyShell/testcases/tc6 create mode 100644 02-TeenyTinyShell/testcases/tc7 create mode 100644 02-TeenyTinyShell/testcases/tc8 create mode 100644 02-TeenyTinyShell/testcases/tc9 create mode 100644 02-TeenyTinyShell/ttsh.c create mode 100644 03-MatrixAddition/.DS_Store create mode 100644 03-MatrixAddition/MatrixAddition.md create mode 100644 03-MatrixAddition/matrices/matA create mode 100644 03-MatrixAddition/matrices/matB create mode 100644 03-MatrixAddition/matrices/matC create mode 100644 03-MatrixAddition/matrices/matD create mode 100644 03-MatrixAddition/matrices/matE create mode 100644 03-MatrixAddition/matrices/matF create mode 100644 03-MatrixAddition/matrices/vector1 create mode 100644 03-MatrixAddition/matrices/vector2 create mode 100644 05-RootVegFarm/.DS_Store create mode 100644 05-RootVegFarm/RootVegFarm.md create mode 100644 05-RootVegFarm/testcases/given create mode 100644 05-RootVegFarm/testcases/tc1 create mode 100644 05-RootVegFarm/testcases/tc2 create mode 100644 05-RootVegFarm/testcases/tc3 create mode 100644 05-RootVegFarm/testcases/tc4 create mode 100644 05-RootVegFarm/testcases/tc5 create mode 100644 05-RootVegFarm/testcases/tc6 create mode 100644 06-MemoryManager/.DS_Store create mode 100644 06-MemoryManager/Makefile create mode 100644 06-MemoryManager/MemoryManager.drawio create mode 100644 06-MemoryManager/MemoryManager.md create mode 100644 06-MemoryManager/MemoryManager.png create mode 100644 06-MemoryManager/memory_manager.c create mode 100644 06-MemoryManager/memory_manager.h create mode 100644 06-MemoryManager/pthread_testmemmgr.c create mode 100644 06-MemoryManager/testcases/pthread_testmemmgr.c create mode 100644 06-MemoryManager/testcases/tc0.c create mode 100644 06-MemoryManager/testcases/tc1.c create mode 100644 06-MemoryManager/testcases/tc10.c create mode 100644 06-MemoryManager/testcases/tc11.c create mode 100644 06-MemoryManager/testcases/tc12.c create mode 100644 06-MemoryManager/testcases/tc2.c create mode 100644 06-MemoryManager/testcases/tc3.c create mode 100644 06-MemoryManager/testcases/tc4.c create mode 100644 06-MemoryManager/testcases/tc5.c create mode 100644 06-MemoryManager/testcases/tc6.c create mode 100644 06-MemoryManager/testcases/tc7.c create mode 100644 06-MemoryManager/testcases/tc8.c create mode 100644 06-MemoryManager/testcases/tc9.c create mode 100644 06-MemoryManager/testcases/testmemmgr.c create mode 100644 06-MemoryManager/testmemmgr.c create mode 100644 07-FunWithFileSystems/FunWithFileSystems.md create mode 100644 07-FunWithFileSystems/dir.drawio create mode 100644 07-FunWithFileSystems/dir.png create mode 100644 07-FunWithFileSystems/dirblock.drawio create mode 100644 07-FunWithFileSystems/dirblock.png create mode 100644 07-FunWithFileSystems/inode.drawio create mode 100644 07-FunWithFileSystems/inode.png create mode 100644 07-FunWithFileSystems/ttfs.drawio create mode 100644 07-FunWithFileSystems/ttfs.h create mode 100644 07-FunWithFileSystems/ttfs.img create mode 100644 07-FunWithFileSystems/ttfs.png create mode 100644 README.md create mode 100644 TTOS/.DS_Store create mode 100644 TTOS/include/elf.h create mode 100644 TTOS/include/errorCode.h create mode 100644 TTOS/include/fs/fs.h create mode 100644 TTOS/include/memory.h create mode 100644 TTOS/include/process.h create mode 100644 TTOS/include/syscall.h create mode 100644 TTOS/ld.script create mode 100644 TTOS/makefile create mode 100644 TTOS/src/elf.c create mode 100644 TTOS/src/fs/fs.c create mode 100644 TTOS/src/main.c create mode 100644 TTOS/src/memory.c create mode 100644 TTOS/src/process.c create mode 100644 TTOS/src/syscall.c create mode 100644 TTOS/test.c create mode 100644 TTOS/test2.c create mode 100644 build.bat diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..16b490a4f898fed250ac4536c0ddafa74e871a97 GIT binary patch literal 6148 zcmeHKu};H441E_e6fsaX#{2+M^9P{{BVq^>5)w2)6w#6nu;0qB@CAGTAI9_f6eVga z5JRORyYjt@eZKR(NO29oP2ZXv7y}ql1(QP#8$|q~Ym!8ZI9=G|75Av|j7y@)J}@Bf z?idr~I75a0`>Qd>6JGGJc+9K1U9R*xpYK0MEZef2E!r7Za({nw(tMr&CaU>E)N0<# zE(uAdxaRK))iCqh59ZMMw&d9JZ_K9i56*QHZf#-=7z4(@-Y~$LEiyV%w9yza28@A@ z0r@^;RKX&mR}7yH4xt4grZflPTzUzK$s!gJy&^pnr=dg*b+N^88cur_*A)@HqK3o8 z=EKF4UF=X?IGy`vVL4o(XrnP;3=A1K(8saV|BLPY|1ij&i~(cdUoqg)vMQ&%Qmn0O wmy=qXQSYcCvd$}ZA)JI#%(YUAPpLs@&tyU@B6>wyDE3Dn&|rfxuu}%U0mlDJ)c^nh literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b342695 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +soln/ \ No newline at end of file diff --git a/00-WSLSetup/LinuxVMSetup.md b/00-WSLSetup/LinuxVMSetup.md new file mode 100644 index 0000000..822e29c --- /dev/null +++ b/00-WSLSetup/LinuxVMSetup.md @@ -0,0 +1,320 @@ +## Introduction + +The purpose of this assignment is to set up the Windows Subsystem for Linux (WSL). WSL acts as a virtual machine that will allow you to develop code on a Linux based operating system while working in your Windows environment. By completing this exercise, you will have the ability to install Linux within WSL, create a program, and start learning about operating systems based on Linux. + +For more information on WSL see the documentation on Microsoft's web page: [https://docs.microsoft.com/en-us/windows/wsl/](https://docs.microsoft.com/en-us/windows/wsl/) + +## Objectives + +By the end of this assignment you will be able to: + +- Create a fresh installation of Linux +- Understand the concepts of the Windows Subsystem for Linux (WSL) +- Demonstrate an ability to use a Linux shell. +- Use the 'man' command to obtain documentation about Linux commands +- Explain how to list the contents of a directory in multiple forms. +- Navigate the Linux file system by changing directories. +- Manage the creation and deletion of new files and directories from within the command shell. +- Capture the output of a Linux program executing to a file. + +## Install Windows Subsystem for Linux (WSL) + +The following procedure is documented in Microsoft's WSL install weg page: [https://docs.microsoft.com/en-us/windows/wsl/install](https://docs.microsoft.com/en-us/windows/wsl/install) + +While often you hear of Linux described as an operating system, Linux itself is not an operating system, but a kernel. Many operating systems have been built using the linux kernel. These operating systems are often called 'distributions'. To install a Linux distribution in WSL, you need to perform 2 things: + +1. Install the WSL version of the Linux kernel +2. Install the distribution for the Linux operating system + +Microsoft makes this easy by doing both in a single step. By default, the WSL installer installs the Ubuntu Linux distribution, which is sufficient for the work we'll be doing. If you want to look into installing other distributions, you can find information on the Microsoft WSL install web site: [https://docs.microsoft.com/en-us/windows/wsl/install#ways-to-run-multiple-linux-distributions-with-wsl](https://docs.microsoft.com/en-us/windows/wsl/install#ways-to-run-multiple-linux-distributions-with-wsl) + +To install WSL and Ubuntu: + +1. Open a command window as Administrator + 1. Open the start menu and type ```cmd.exe``` + 2. In the menu on the right, click: Run as Administrator +2. When the command prompt opens run ```wsl --install``` + +This might take a while as WSL installs the kernel and the Linux distribution. You'll see status messages printed to the command prompt as it goes. + +Once it has completed installation, you will be asked to create a username and password for your Linux distribution. This does not need to be the same as your Windows login, but it might be easier to remember if you do set it to the same. The choice is yours. + +## File System Setup + +Once the installation completes, and you create a username and password you will see a slightly different command prompt. You are now running in the Ubuntu Linux environment. Any command you type will default to a Linux command. + +### Accessing Windows Files from Linux + +On Windows, the file system is typically NTFS and is organized by drive (e.g. C:\ or D:\ etc.). The file system works slightly different on Linux. Directories (i.e Folders) are 'mounted' inside each other. You can think of it like a book on a bookshelf. Each disk drive on your system is like a book and the file system as a whole is like the shelf. In Windows, each book is given a drive letter, while in Linux each book is given a directory name. + +For example, to access your Windows file system from Linux you have to go where it is mounted (e.g. what shelf it is on). In WSL, the mount point for each drive is in ```/mnt```. + +NOTE: that Linux uses forward slash '/' to delimit a directory while Windows uses the backslash '\'. + +The ```cd``` command allows you to change directories while the ```ls``` command allows you to list the contents of a directory from the command line. + +```text +user@machine:~$ ls /mnt +c wsl +user@machine:~$ +``` + +This lists the contents of the ```/mnt``` directory. In this example, there are two things ```c``` which represents the C: 'drive' on Windows and another directory ```wsl``` which WSL uses for device mapping. + +You can access any file in your Windows C: drive from Linux though ```/mnt/c/```. + +For example, to list the contents of your Windows desktop you'd type: + +``` +user@machine:~$ ls /mnt/c/Users/WINDOWSUSERID/Desktop/ +``` + +Replacing ```WINDOWSUSERID``` with your actual Windows username. + +### Accessing Linux Files from Windows + +On Windows, files are typically accessed through the File Explorer. WSL makes it easy to get to the Linux file system through the File Explorer. You can actually open the Windows File Explorer directly from your Linux command line. + +```text +user@machine:~$ explorer.exe . +``` + +NOTE: it is important to use the add the dot (.) after the command. The dot tells the Windows File Explorer to open the current directory (e.g. your Linux directory) instead of the default directory on Windows. + +When the File Explorer opens you'll notice that your Linux file system is actually mapped to a network device in Windows, most likely: ```\\wsl$\Ubuntu```. If you installed a different Linux distribution, the name might be different. + +On Windows, the folder for all of your user files (desktop, document, etc.) is located in ```C:\Users\WINDOWSUSERID```. On most Linux distributions, your Linux user files are located in ```/home/LINUXUSERID```. Using the File Explorer that is equivalent to ```\\wsl$\Ubuntu\home\LINUXUSERID```. + +Find this folder on your Windows File Explorer and add it to your quick access bar. It will be very helpful to do this for accessioning your Linux file later. + +## Installing Software + +We'll need to use several Linux applications in this class. Installing software in Linux is pretty easy. Ubuntu provides a command called ```apt``` which stands for Application Package Tool. It utilizes a central repository for commands that can be installed directly from the command line. + +To install the software we'll need for this course run the following. You'll have to enter your password to grant ```apt``` administrator authority on your Linux installation. + +```text +sudo apt-get update +sudo apt-get install gcc make +``` + +You'll be asked to confirm before ```apt``` starts downloading and installing the software. + +- ```gcc```: is the [GNU](https://www.gnu.org/) C compiler - we'll be using that to build programs +- ```make``` is a build tool that can be used to automate builds for projects. + +## Editing a Text File + +Using the Windows File Explorer, create a text file in your Linux home directory. Add some text to the file, use your favorite text editor. + +From the Linux command window, change to your home directory by typing ```cd``` without any arguments. You'll know you're in your home directory when you see a tilde (~) symbol at your command prompt. + +Now, display the contents of the file with the ```cat``` command on Linux. For example, from the command prompt try this: + +```text +user@machine:~$ ls +text.txt +user@machine:~$ cat text.txt +this is some text +``` + +The ```cat``` command is short for "concatenate". It will print out the contents of a file to the command prompt. + +## Exploring Linux + +Now that you have WSL and Ubuntu Linux set up and installed, you will explore your Linux environment. This exploration will involve experimenting with some other command. There are some interesting and powerful things you can accomplish with relative ease. + +From your Linux command window and experiment with the commands below. You can get help on commands with the ```man``` command (which is short for "manual"). For example, try running ```man ls```. + +You can search for appropriate commands with the ```apropos``` command. For example, try running ```apropos zip```. + +Some commands you should experiment with (these are all typed via the command line, or terminal): + +1. view a man page: man < command > e.g. man ls +2. list a directory: ls +3. list a directory, long: ls -l +4. list a directory, long, all: ls -al +5. search for a file in the file system: find -name .profile +6. Search through a file or a through a program output: grep +7. change directory: cd < dir > +8. change directory up one level: cd .. +9. change to last directory: cd – +10. make directory: mkdir < dir > +11. remove file: rm < file > +12. remove directory: rmdir < dir > +13. copy files: cp < source > < dest > +14. display contents of a file: cat output.txt +15. zip some files into a .zip file: zip lab1 hello.cpp output.txt +16. Create a tarball: tar -cf new tar file.tar * +17. Extract a tarball: tar -xvf new tar file.tar +18. Create an empty file touch empty.txt + +Some of these commands may not be installed yet, if you need to install them use ```apt``` as we did before. For example, to install ```zip``` you'd use: ```sudo apt-get install zip```. + +As you are experimenting write a description (in your own words) of what each command (ls, find, cd, mkdir, rmdir, cp, cat, zip, tar, touch) is used for. Include the command description in your report (see "Deliverables" below). + +## Creating a Development Environment + +### Create a Development Directory + +Next you will want to create a development directory to hold the projects you will complete. To do this, create a directory (folder) in your Linux home directory for this class. Feel free to do this from the Linux command line or the Window File Explorer. + +### Setting up your Development Editor + +**WINDOWS**: + +For this class, it will be easiest to edit files from Windows and then build and execute them from your Linux command line. With that, feel free to use any Windows editor that you like. Here are a couple recommendations + +- Notepad++ [https://notepad-plus-plus.org/](https://notepad-plus-plus.org/) is a simple text editor with text highlighting and has project file management as well +- Eclipse is a Java based editor that has a C/C++ plugin. It can be installed by going to [https://www.eclipse.org/cdt/](https://www.eclipse.org/cdt/). +- CLion - This is a C/C++ editor created by JetBrains and is similar in look and feel to IntelliJ. + - You can download CLion from JetBrains web site: [https://www.jetbrains.com/clion/](https://www.jetbrains.com/clion/) + - There is no community version, but you can get a free license if you register with JetBrains as a student: [https://www.jetbrains.com/community/education/#students](https://www.jetbrains.com/community/education/#students) +- VSCode [https://code.visualstudio.com/](https://code.visualstudio.com/) is an IDE created by Microsoft with lots of configuration and plugin options. + +Choose the editor that you like best. Feel free to experiment with multiple if you'd like. + +**LINUX**: + +While for this class, it will be easiest to edit files from Windows and then build and execute them from your Linux command line, if you want to experiment with editors on Linux there are many out there: + +- Notepad++ doesn't exist for Linux there is a similar one called notepadqq which has similar features. It can be installed by running: ```sudo apt install notepadqq``` +- gedit is simple text editor with tabbed editing and code highlighting but isn't an integrated development environment. It can be installed by running: ```sudo apt install gedit``` +- Codelite has a similar interface to notepadqq and does have compiler integration. It can be installed by running: ```sudo apt install codelite``` +- vim is a non-graphical text editor that you might have used if you use Git Bash on Windows. It is installed by default on your WSL Ubuntu installation. More information on vim can be found here: [https://www.vim.org/](https://www.vim.org/) +- Emacs is another non-graphical text editor. It can be installed by running: ```sudo apt install emacs```. More information on emacs can be found here: [https://www.gnu.org/software/emacs/](https://www.gnu.org/software/emacs/) + +NOTE: If you wish to enter the long-running debate of 'emacs' vs 'vim' ([https://en.wikipedia.org/wiki/Editor_war](https://en.wikipedia.org/wiki/Editor_war) feel free to try out one (or both) of those editors. + +## Building and Running a Program + +Try compiling the following program (copy/paste to a file named hello.c or [download it](hello.c)): + +```c +/********************************** + * hello.c + * Written by: H. Welch - 11/26/2006 + * Modified W. Schilling - 8/15/2009 + * + * Demonstrate basic C-program along with + * system call requiring struct and pointer + * manipulation. + ***********************************/ + #include + #include + #include + int main (int argc, char* argv[]) { + /* Get system information using the uts system interface.*/ + /* Declare a buffer to store information about the system. */ + struct utsname buf; + /* Declare a pointer to the user information. */ + char *usr; + /* Populate the buffer with data from the system. */ + uname(&buf); + /* Get information about the user from the system. */ + usr=getenv("USER"); + /* Print out system information to the console. */ + printf("Hello %s:%s:%s:%s:z%s\n", buf.sysname, buf.nodename, + buf.release,buf.version,buf.machine); + printf("The size of the UTS structure is %lu.\n", sizeof(buf)); + /* Print out the user information if the pointer is not NULL. */ + if (usr != NULL) { + printf("%s\n",usr); + } else { + printf("User information not returned by the operating system."); + } + /* Return to O/S */ + return 0; +} +``` + +Now try compiling the program. Answer the questions as you go. + +At the command shell, issue the command: + +```text +gcc -E hello.c | less +``` + +This command will preprocess the source code and pipe the results to the console. + +Questions: + +1. What is the length of the ```sysname``` element of the ```utsname``` structure? +2. How did you determine the sizes? + +Now issue the commands: + +```text +gcc -S hello.cpp +``` + +This will compile the given code, resulting in the creation of a ".s" file containing the assembly code for the program. You can view the contents of the file through ```less``` which is a command to display a text file in the terminal (command window) allowing you to move up and down using the arrow keys + +```text +less hello.s +``` + +Create a "screenshot" image of the output from less (you don't have to include all the output, just one "page" is enough) and include this in your report. + +Questions: + +3. Notice the align command in the assembly output. This aligns the start of the definition on an 8-byte boundary. Why does the compiler add this? +4. Do a Google search to find out more information on compiler memory alignment. Document your resources in your answer. +5. Of the assembly code, which seems to be the most common instructions? Why do you think this is the case? +6. Do a Google search for the most common instructions that you see in the .s file. What do they do? Make sure you document your resources in your answer. + +Now issue the commands: +```text +gcc -c hello.c +ls -al +``` +The first command creates an object file for the hello.c source code. This is code which contains assembled instructions that can later be linked by the linker. + +Questions: + +7. What extension is given to this file? +8. Research object files and give a short description in your own words. Make sure you document your resources in your answer. + +Lastly, issue the command: +```text +gcc -o hello hello.c +ls -al +``` +This will perform all stages of compilation, writing the given file to the program hello. . + +Questions: + +9. Viewing the output from ls what is the difference in size between the object file (.o) and the complete executable? +10. Do some research on Linux executables to see if you can figure out why there is a difference in size. Write a short description in your report. Make sure you document your resources in your answer. + +Now issue the command: +```text +./hello +``` +This will run the program. Follow the instructions in the program and create a screenshot of your output to include in your report. + +## Deliverables + +Once you've completed all the activities and have answers to all the questions, create a report (text, doc, or pdf file) including the following: + +- Your name, date, and title +- Introduction – a description the assignment in your own words +- Resources – a description of any external resources you used to complete the assignment +- Analysis – a description of your experience working with Linux + - A reflection on your experience working with command line tools in Linux and the descriptions of the commands you used in your own words. + - Include all required screenshots. + - Answers to the questions from the "Building and Running a Program" section. +- Conclusion + - Summary of what you learned + - What specifically was challenging? + - What did you like about it? + - What could we do to improve it for others? + +Submit your report to per your instructor's instructions. + +## Grading Criteria (100 Points) + +- (20 Points) Report introduction- Thorough description of the assignment in your own words. +- (60 Points) Analysis - Answers to the analysis questions +- (20 Points) Report Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for improvements. \ No newline at end of file diff --git a/00-WSLSetup/hello.c b/00-WSLSetup/hello.c new file mode 100644 index 0000000..9d558c6 --- /dev/null +++ b/00-WSLSetup/hello.c @@ -0,0 +1,35 @@ +/********************************** + * hello.c + * Written by: H. Welch - 11/26/2006 + * Modified W. Schilling - 8/15/2009 + * + * Demonstrate basic C-program along with + * system call requiring struct and pointer + * manipulation. + ***********************************/ + #include + #include + #include + int main (int argc, char* argv[]) { + /* Get system information using the uts system interface.*/ + /* Declare a buffer to store information about the system. */ + struct utsname buf; + /* Declare a pointer to the user information. */ + char *usr; + /* Populate the buffer with data from the system. */ + uname(&buf); + /* Get information about the user from the system. */ + usr=getenv("USER"); + /* Print out system information to the console. */ + printf("Hello %s:%s:%s:%s:z%s\n", buf.sysname, buf.nodename, + buf.release,buf.version,buf.machine); + printf("The size of the UTS structure is %lu.\n", sizeof(buf)); + /* Print out the user information if the pointer is not NULL. */ + if (usr != NULL) { + printf("%s\n",usr); + } else { + printf("User information not returned by the operating system."); + } + /* Return to O/S */ + return 0; +} \ No newline at end of file diff --git a/01-StackMachine/.DS_Store b/01-StackMachine/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3c3c98c81c6554bdc6709e63ff5465c189023f2d GIT binary patch literal 6148 zcmeHKJx{|x47E#!RxD*>yotR#L#V>aQYNO-2EmY!N|gP60zZl$#`D>#ddig%p~{wg z@8XZU%S#l;M8wO_c0n{JqA65xGQ&_1@r#aRVis|-tkJzLR@^COJ=6?e|^oZ-4dg-j3gmHBxCtdwRj%d)m@75cB*5H;?70 z6K5%`*AK;06(Y0q@t2&>#Tjr0oPl#?05w}=da3B6GvEw30|y4=`w*alwP93DpAHPE z1prnsC&65L3CRhDwP93*2f~^P)Ks<>gEbxYU~#o!RMd20Yd+X^X6sNm?T+ +#include "stackm.h" + +int main(void) +{ + stackm mystack; + smInit(&mystack); + + smPush(&mystack, 2); + smPush(&mystack, 3); + smPush(&mystack, 4); + smPrint(&mystack); + + smPop(&mystack); + smPrint(&mystack); + smAdd(&mystack); + smPrint(&mystack); + + int value = 0; + smTop(&mystack, &value); + printf("%d\n", value); + + smPush(&mystack, 10); + smPush(&mystack, 11); + smPrint(&mystack); + smMult(&mystack); + smPrint(&mystack); + + smPush(&mystack, 10); + smPush(&mystack, 11); + smPrint(&mystack); + smRotate(&mystack, 5); + smPrint(&mystack); + + smClear(&mystack); + smPrint(&mystack); + return 0; +} +``` + +You should have already picked an editor or IDE to use. Compiling at the command line is sometimes easier than using an IDE as IDEs sometimes hide error messages. Edit, compile, and run your program entirely from the Linux VM. Using Windows to edit the file and then transferring to Linux can cause formatting problems with the code and might introduce unexpected errors. + +You can invoke the compiler at the command line directly: + +```text +gcc hello.c +``` + +This command will build hello.c and product an executable name a.out in the same directory. Errors and warning will be reported to the console. You can run a.out by issuing the command: + +```text +./a.out +``` + +Here, the '.' refers to the current directory. + +We can get fancier. Instead of the default output name, we can specify the name of the executable: + +```text +gcc -o hello hello.c +``` + +If we have more than one source file, just list them all: + +```text +gcc -o hello hello.c goodbye.c +``` + +By default, gcc doesn't report all possible warnings. If you want more warnings (hint, you do), do this: + +```text +gcc -Wall -o hello hello.c goodbye.c +``` + +Another option for compiling your program is to use a Makefile. Doing so is completely optional for this lab but can be very helpful for building your programs. Dr. Schilling has an excellent tutorial on Makefiles that you can watch here: [https://www.youtube.com/watch?v=gT2roSrSYfo&feature=youtu.be](https://www.youtube.com/watch?v=gT2roSrSYfo&feature=youtu.be) + +Here is a skeleton Makefile that you can use to get you started. + +```text +CC=gcc +CFLAGS=-c -Wall +LDFLAGS= +SOURCES=source1.c source2.c +OBJECTS=$(SOURCES:.c=.o) +EXECUTABLE=exename + +all: $(SOURCES) $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) -o $@ + +.c.o: + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm -rf $(OBJECTS) $(EXECUTABLE) +``` + +## Testing and Debugging + +As stated above, you must write a driver that completely tests your stack machine. So what is complete testing? How do you go about this? You will have to put some thought into this and use your experience to guide you. It would make sense that you will have to call every method at least once, probably many times under different conditions. Look for boundary cases. For example, be sure to test ```smPop()``` with an empty stack as well as a non-empty stack. + +Given that we are using C and not Java, there are few protections we can build in to prevent misuse of the stack. For example, there is no perfect way to make sure ```smInit()``` is called before adding items to the stack. + +So, you are calling all the methods, and your program crashes. What now? Well, you must track down where it is crashing. An IDE with debugging will be helpful, but you can also do this with gdb from the command. + +NOTE: The gdb program requires additional debug symbols to be included in your program in order to correctly display information about variable names and function names in call stacks. To compile your program with additional debugging information, use the -g flag. For example: + +```text +gcc -g -Wall -o hello hello.c goodbye.c +``` + +The following shows a sample session using gdb to debug a segmentation fault: + +```text +~/dev/labs/stack$ ./a.out +Segmentation fault +~/dev/labs/stack$ gdb ./a.out +GNU gdb (Debian 7.12-6) 7.12.0.20161007-git + +== chopped out copyright stuff == + +Reading symbols from ./a.out...done. +(gdb) run +Starting program: ~/dev/labs/stack/a.out + +Program received signal SIGSEGV, Segmentation fault. +0x0000555555554b3b in smPush (myStack=0x7fffffffe120, toStore=4) at stackm.c:123 +123 myStack->top->next = newNode; +(gdb) bt +#0 0x0000555555554b3b in smPush (myStack=0x7fffffffe120, toStore=4) at stackm.c:123 +#1 0x00005555555548a4 in main () at smTester.c:30 +(gdb) +``` + +- Running the program directly with ```./a.out``` from the command line produces a Segmentation fault output. This is not particularly helpful. +- Running ```gdb``` with the program as a command line argument runs the GNU debugger. Notice the ```(gdb)``` prompt. +- Using the ```run``` command will execute the program in the debugger +- When the program hits the Segmentation fault, using the backtrace (```bt```) command prints a trace similar to the stack trace received from a ```NullPointerException``` in Java outlining exactly where the problem happened. + +Another, highly recommended, tool for you to use is valgrind. Valgrind will monitor the heap and report memory leaks. The program must run to completion for this to be useful. Sample output is below: + +```text +==10565== Memcheck, a memory error detector +==10565== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==10565== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==10565== Command: ./a.out +==10565== +==10565== +==10565== HEAP SUMMARY: +==10565== in use at exit: 100 bytes in 10 blocks +==10565== total heap usage: 10 allocs, 0 frees, 100 bytes allocated +==10565== +==10565== LEAK SUMMARY: +==10565== definitely lost: 100 bytes in 10 blocks +==10565== indirectly lost: 0 bytes in 0 blocks +==10565== possibly lost: 0 bytes in 0 blocks +==10565== still reachable: 0 bytes in 0 blocks +==10565== suppressed: 0 bytes in 0 blocks +==10565== Rerun with --leak-check=full to see details of leaked memory +==10565== +==10565== For lists of detected and suppressed errors, rerun with: -s +==10565== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +``` + +## Deliverables + +You should have at least three source files in your project: + +1. smTester.c – The test driver for your stack machine and should contain the 'main' function. Make sure your implemented test driver tests more than just the sample +2. stackm.c – the implementation file for your stack machine operations +3. stackm.h – the header file that defines the stack machine operations + +A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission. + +All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file, including the given header file. + +NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report. + +Prepare a lab report and submit it along with your source code. The report should include the following: + +- Your name, date, and lab title +- Introduction – a description of the lab in your own words +- Design and Testing Methodology – a description of your design decisions and the process you took to create your test driver +- Resources – a description of any external resources you used to complete the lab +- Build – instructions on how to build and run your program. Include the exact commands that are necessary +- Analysis – Discuss the key concepts from the lab and answers to the following questions + - All the stack machine functions need a "reference" to the stack structure, and according to this design, that stack reference is passed as a pointer. Why is this necessary? Do all the stack functions need this to be passed as a pointer? Any exceptions? Be specific in your answer. + - Unlike a Java or C++ implementation, this implementation cannot "hide" any of the internal structure of the stack. That is, users of the stack could mess up the next pointers if they are careless. Can you think of any way we could hide the structure of the stack to lessen the chances a user will mess up the stack? Describe in brief detail. + - What if all smClear() did was assign NULL to top in the stack structure and nothing else. Would the program crash? Would there be any side effects? Try it and report results. + - Give an example of why it might be helpful to provide an iterator or random access to elements stored in the stack (rather than always accessing the top) and outline how you could implement such a feature. +- Conclusion + - Summary of what you learned in the lab + - What specifically was challenging about this lab? + - What did you like about it? + - What could we do to improve it for others? + +NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting. + +Create a zip file containing your source files and your report and submit the zip file per your instructor's instructions. + +## Grading Criteria (100 Points) + +- (35 Points) Report + - (5 Points) Report Introduction - Thorough description of the lab in your own words. + - (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation. + - (20 Points) Analysis - Answers to the analysis questions + - (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements. +- (5 Points) Documented Resources - Description of external resources used to complete the lab +- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted) +- (5 Points) Build - Code compiles without warnings or errors +- (10 Points) Test Cases - Thoroughness of submitted test driver +- (35 Points) Instructor Tests - Implementation passes all instructor test cases +- (5 Points) Memory Management - Program execution is free from memory leaks \ No newline at end of file diff --git a/01-StackMachine/smTester.c b/01-StackMachine/smTester.c new file mode 100644 index 0000000..c31b0ef --- /dev/null +++ b/01-StackMachine/smTester.c @@ -0,0 +1,37 @@ +#include +#include "stackm.h" + +int main() { + stackm mystack; + smInit(&mystack); + + smPush(&mystack, 2); + smPush(&mystack, 3); + smPush(&mystack, 4); + smPrint(&mystack); + + smPop(&mystack); + smPrint(&mystack); + smAdd(&mystack); + smPrint(&mystack); + + int value = 0; + smTop(&mystack, &value); + printf("%d\n", value); + + smPush(&mystack, 10); + smPush(&mystack, 11); + smPrint(&mystack); + smMult(&mystack); + smPrint(&mystack); + + smPush(&mystack, 10); + smPush(&mystack, 11); + smPrint(&mystack); + smRotate(&mystack, 5); + smPrint(&mystack); + + smClear(&mystack); + smPrint(&mystack); + return 0; +} \ No newline at end of file diff --git a/01-StackMachine/stackm.h b/01-StackMachine/stackm.h new file mode 100644 index 0000000..e47d298 --- /dev/null +++ b/01-StackMachine/stackm.h @@ -0,0 +1,195 @@ +/* stackm.h + * + * External (public) declarations for stack machine in C. + * + * This stack will know about the top. Each element must point + * to the one below it in the stack. + * + * Note that the pop operations do not return a reference to the + * popped node. This would require storage for the node to be + * released by the user, which could lead to memory mishandling. + * The stack size is unbounded so memory must be allocated and + * freed as appropriate when operations are performed. + * + * This stack will only hold integers. Mathematical operations are + * performed on elements on the top of the stack as described in the + * function definitions. + * + */ + +#ifndef STACKM_H +#define STACKM_H + +/* Structures */ + +/* a stack node */ +typedef struct node { + int value; + struct node* next; +} node; + +/* The stack itself */ +typedef struct stackm { + struct node *top; +} stackm; + +/* Stack Machine methods + * + * These methods are used to create and operate on the stack machine as a whole. + */ + +/* smInit() + * Initialize a stack machine structure. An empty stack will + * be characterized by top being NULL. + * Parameters: myStack - a pointer to the structure to be init + * Returns: void + */ +void smInit(struct stackm *myStack); + +/* smSize() + * Reports the current size of the stack. Will need to iterate + * the stack to get this data size there is no size property, nor + * can there really be one given that users can access nodes. + * Parameters: myStack - the stack + * Returns: int, size of stack + */ +int smSize(struct stackm *myStack); + +/* smPush() + * Add a new node with provided data to the top of the stack. + * This method should allocate memory as needed and check to + * make sure that the memory was allocated successfully. + * Parameters: myStack - the stack + * toStore - the value to store + * Returns: int - 0 if no push could be performed + * (failed to allocate memory) or non-zero + * if push was successful + */ +int smPush(struct stackm *myStack, int toStore); + +/* smPop() + * Removes top item in stack. Note, this does not return + * any data from the stack. If the data in the node is needed + * it should be accessed prior to the pop (smTop). + * Parameters: myStack - the stack + * Returns: int - 0 if no pop (stack was empty) or non-zero + * if pop successful + */ +int smPop(struct stackm *myStack); + +/* smTop() + * return the value at the top of the stack. NOTE: the value + * must be returned by dereferencing the passed in pointer. + * The function must make sure the pointer is not NULL prior to + * dereferencing to avoid memory violations. + * Parameters: myStack - the stack + * toStore - a point to store the stack top value + * Returns: int - 0 if top could not be retrieved + * (toStore was NULL or stack is empty) or + * non-zero retrieval was successful + */ +int smTop(struct stackm *myStack, int* toStore); + +/* smClear() + * Clears all nodes and releases all dynamic memory. Stack + * structure should be NULLed and can be reused. + * Parameters: myStack - the stack + * Returns: nothing + */ +void smClear(struct stackm *myStack); + +/* smPrint() + * Prints the contents of the stack machine to standard output. + * When printing it should be clear what value contains the top + * as well which which values are stacked on top of other values + * Parameters: myStack - the stack + * Returns: nothing + */ +void smPrint(struct stackm *myStack); + +/* Stack Machine manipulation methods + * + * These methods perform operations that manipulate the stack + * (math or element ordering). + */ + +/* smAdd() + * Add together the top two elements of the stack and push + * the result. + * The stack must contain at least 2 elements for this + * operation to be successful. + * Any removed element must be freed (no memory leaks) + * Parameters: myStack - the stack + * Returns: int - 0 if operation could not be performed + * (not enough elements on the stack) + * non-zero if successful + */ +int smAdd(struct stackm* myStack); + +/* smSub() + * Subtract the top two elements of the stack and push + * the result. + * The stack must contain at least 2 elements for this + * operation to be successful. + * Operation is TOS (top of stack) - 2nd from TOS + * if the stack contained the values: + * top -> 6 + * 5 + * 4 + * bottom -> 3 + * The result after a smSub operation would be: + * top -> 1 + * 4 + * bottom -> 3 + * 6 - 5 = 1 + * Any removed element must be freed (no memory leaks) + * Parameters: myStack - the stack + * Returns: int - 0 if operation could not be performed + * (not enough elements on the stack) + * non-zero if successful + */ +int smSub(struct stackm* myStack); + +/* smMult() + * Multiply the top two elements of the stack and push + * the result. + * The stack must contain at least 2 elements for this + * operation to be successful. + * Any removed element must be freed (no memory leaks) + * Parameters: myStack - the stack + * Returns: int - 0 if operation could not be performed + * (not enough elements on the stack) + * non-zero if successful + */ +int smMult(struct stackm* myStack); + +/* smRotate() + * Rotate the top 'n' elements of the stack. For example, + * if the stack contained the values: + * top -> 6 + * 5 + * 4 + * bottom -> 3 + * The result after a rotate 3 operation would be: + * top -> 5 + * 4 + * 6 + * bottom -> 3 + * NOTE: the top element on the stack goes to the 'nth' + * location and every element above the 'nth' location + * gets moved up one + * The stack must contain at least 'n' elements for this + * operation to be successful. + * 'n' must be greater than or equal to 1. A value of 1 + * does nothing, but is still successfull. + * Any removed element must be freed (no memory leaks) + * Parameters: myStack - the stack + * depth - the depth of the rotation + * Returns: int - 0 if operation could not be performed + * (not enough elements on the stack + * or depth is too small) + * non-zero if successful + */ +int smRotate(struct stackm* myStack, int depth); + +#endif \ No newline at end of file diff --git a/01-StackMachine/testcases/tc1.c b/01-StackMachine/testcases/tc1.c new file mode 100644 index 0000000..3a6d770 --- /dev/null +++ b/01-StackMachine/testcases/tc1.c @@ -0,0 +1,8 @@ +#include +#include "stackm.h" + +int main() { + stackm mystack; + smInit(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc10.c b/01-StackMachine/testcases/tc10.c new file mode 100644 index 0000000..f9019db --- /dev/null +++ b/01-StackMachine/testcases/tc10.c @@ -0,0 +1,30 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + smPrint(&mystack); + doPush(&mystack, 2); + smPrint(&mystack); + doPush(&mystack, 3); + smPrint(&mystack); + doPop(&mystack); + smPrint(&mystack); + doPop(&mystack); + smPrint(&mystack); + doPop(&mystack); + smPrint(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc11.c b/01-StackMachine/testcases/tc11.c new file mode 100644 index 0000000..df13d55 --- /dev/null +++ b/01-StackMachine/testcases/tc11.c @@ -0,0 +1,27 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doAdd(stackm* s) +{ + printf("Add Ret: %d\n", smAdd(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + doAdd(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc12.c b/01-StackMachine/testcases/tc12.c new file mode 100644 index 0000000..f840846 --- /dev/null +++ b/01-StackMachine/testcases/tc12.c @@ -0,0 +1,39 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doAdd(stackm* s) +{ + printf("Add Ret: %d\n", smAdd(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doTop(stackm* s, int* v) +{ + printf("Top Ret: %d\n", smTop(s, v)); +} + +int main() { + int val = 0; + stackm mystack; + smInit(&mystack); + for(int i = 0 ; i < 10; i++) { + doPush(&mystack, i); + } + for(int i = 0; i < 9; i++) { + doAdd(&mystack); + } + doTop(&mystack, &val); + printf("Final Val: %d\n", val); + doPop(&mystack); + + return 0; +} diff --git a/01-StackMachine/testcases/tc13.c b/01-StackMachine/testcases/tc13.c new file mode 100644 index 0000000..60b9ad1 --- /dev/null +++ b/01-StackMachine/testcases/tc13.c @@ -0,0 +1,27 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doSub(stackm* s) +{ + printf("Sub Ret: %d\n", smSub(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + doSub(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc14.c b/01-StackMachine/testcases/tc14.c new file mode 100644 index 0000000..87f3a23 --- /dev/null +++ b/01-StackMachine/testcases/tc14.c @@ -0,0 +1,39 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doSub(stackm* s) +{ + printf("Sub Ret: %d\n", smSub(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doTop(stackm* s, int* v) +{ + printf("Top Ret: %d\n", smTop(s, v)); +} + +int main() { + int val = 0; + stackm mystack; + smInit(&mystack); + for(int i = 0 ; i < 10; i++) { + doPush(&mystack, i); + } + for(int i = 0; i < 9; i++) { + doSub(&mystack); + } + doTop(&mystack, &val); + printf("Final Val: %d\n", val); + doPop(&mystack); + + return 0; +} diff --git a/01-StackMachine/testcases/tc15.c b/01-StackMachine/testcases/tc15.c new file mode 100644 index 0000000..4948f5a --- /dev/null +++ b/01-StackMachine/testcases/tc15.c @@ -0,0 +1,27 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doMult(stackm* s) +{ + printf("Mult Ret: %d\n", smMult(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + doMult(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc16.c b/01-StackMachine/testcases/tc16.c new file mode 100644 index 0000000..a0a3bfd --- /dev/null +++ b/01-StackMachine/testcases/tc16.c @@ -0,0 +1,39 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doMult(stackm* s) +{ + printf("Mult Ret: %d\n", smMult(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doTop(stackm* s, int* v) +{ + printf("Top Ret: %d\n", smTop(s, v)); +} + +int main() { + int val = 0; + stackm mystack; + smInit(&mystack); + for(int i = 1 ; i < 11; i++) { + doPush(&mystack, i); + } + for(int i = 0; i < 9; i++) { + doMult(&mystack); + } + doTop(&mystack, &val); + printf("Final Val: %d\n", val); + doPop(&mystack); + + return 0; +} diff --git a/01-StackMachine/testcases/tc17.c b/01-StackMachine/testcases/tc17.c new file mode 100644 index 0000000..4dd3542 --- /dev/null +++ b/01-StackMachine/testcases/tc17.c @@ -0,0 +1,21 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doAdd(stackm* s) +{ + printf("Add Ret: %d\n", smAdd(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doAdd(&mystack); + doPush(&mystack, 10); + doAdd(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc18.c b/01-StackMachine/testcases/tc18.c new file mode 100644 index 0000000..882b9f8 --- /dev/null +++ b/01-StackMachine/testcases/tc18.c @@ -0,0 +1,21 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doSub(stackm* s) +{ + printf("Sub Ret: %d\n", smSub(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doSub(&mystack); + doPush(&mystack, 10); + doSub(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc19.c b/01-StackMachine/testcases/tc19.c new file mode 100644 index 0000000..b835e41 --- /dev/null +++ b/01-StackMachine/testcases/tc19.c @@ -0,0 +1,26 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doMult(stackm* s) +{ + printf("Mult Ret: %d\n", smMult(s)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doMult(&mystack); + doPush(&mystack, 10); + doMult(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc2.c b/01-StackMachine/testcases/tc2.c new file mode 100644 index 0000000..f9aebc7 --- /dev/null +++ b/01-StackMachine/testcases/tc2.c @@ -0,0 +1,20 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc20.c b/01-StackMachine/testcases/tc20.c new file mode 100644 index 0000000..53a722c --- /dev/null +++ b/01-StackMachine/testcases/tc20.c @@ -0,0 +1,30 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doRotate(stackm *s, int d) +{ + printf("Rotate Ret: %d\n", smRotate(s, d)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + smPrint(&mystack); + doRotate(&mystack, 2); + smPrint(&mystack); + doPop(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc21.c b/01-StackMachine/testcases/tc21.c new file mode 100644 index 0000000..a3c12b0 --- /dev/null +++ b/01-StackMachine/testcases/tc21.c @@ -0,0 +1,34 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doRotate(stackm *s, int d) +{ + printf("Rotate Ret: %d\n", smRotate(s, d)); +} + +int main() { + stackm mystack; + smInit(&mystack); + for(int i = 0 ; i < 10; i++) { + doPush(&mystack, i); + } + smPrint(&mystack); + for(int i = 0; i < 10; i++) { + doRotate(&mystack, i+1); + smPrint(&mystack); + } + for(int i = 0; i < 10; i++) { + doPop(&mystack); + } + return 0; +} diff --git a/01-StackMachine/testcases/tc22.c b/01-StackMachine/testcases/tc22.c new file mode 100644 index 0000000..dc6cbc2 --- /dev/null +++ b/01-StackMachine/testcases/tc22.c @@ -0,0 +1,31 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doRotate(stackm *s, int d) +{ + printf("Rotate Ret: %d\n", smRotate(s, d)); +} + +int main() { + stackm mystack; + smInit(&mystack); + for(int i = 0 ; i < 10; i++) { + doPush(&mystack, i); + } + smPrint(&mystack); + doRotate(&mystack, 100); + for(int i = 0; i < 10; i++) { + doPop(&mystack); + } + return 0; +} diff --git a/01-StackMachine/testcases/tc23.c b/01-StackMachine/testcases/tc23.c new file mode 100644 index 0000000..6a521a0 --- /dev/null +++ b/01-StackMachine/testcases/tc23.c @@ -0,0 +1,31 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doRotate(stackm *s, int d) +{ + printf("Rotate Ret: %d\n", smRotate(s, d)); +} + +int main() { + stackm mystack; + smInit(&mystack); + for(int i = 0 ; i < 10; i++) { + doPush(&mystack, i); + } + smPrint(&mystack); + doRotate(&mystack, 0); + for(int i = 0; i < 10; i++) { + doPop(&mystack); + } + return 0; +} diff --git a/01-StackMachine/testcases/tc24.c b/01-StackMachine/testcases/tc24.c new file mode 100644 index 0000000..6397380 --- /dev/null +++ b/01-StackMachine/testcases/tc24.c @@ -0,0 +1,42 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doMult(stackm* s) +{ + printf("Mult Ret: %d\n", smMult(s)); +} + +void doRotate(stackm *s, int d) +{ + printf("Rotate Ret: %d\n", smRotate(s, d)); +} + +void doTop(stackm* s, int* v) +{ + printf("Top Ret: %d\n", smTop(s, v)); +} + +int main() { + int val = 0; + stackm mystack; + smInit(&mystack); + for(int i = 1 ; i <= 10; i++) { + doPush(&mystack, i); + doPush(&mystack, i); + doMult(&mystack); + } + smPrint(&mystack); + doTop(&mystack, &val); + while(val > 25) { + doRotate(&mystack, 10); + doTop(&mystack, &val); + } + smPrint(&mystack); + smClear(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc25.c b/01-StackMachine/testcases/tc25.c new file mode 100644 index 0000000..3eabdc8 --- /dev/null +++ b/01-StackMachine/testcases/tc25.c @@ -0,0 +1,16 @@ +#include +#include "stackm.h" + +int main() { + stackm mystack; + smInit(&mystack); + for(int i = 0 ; i < 1000; i++) { + smPush(&mystack, i); + } + smPrint(&mystack); + for(int i = 0 ; i < 1000; i++) { + smPop(&mystack); + } + smPrint(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc3.c b/01-StackMachine/testcases/tc3.c new file mode 100644 index 0000000..8df1880 --- /dev/null +++ b/01-StackMachine/testcases/tc3.c @@ -0,0 +1,24 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + doPush(&mystack, 3); + doPop(&mystack); + doPop(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc4.c b/01-StackMachine/testcases/tc4.c new file mode 100644 index 0000000..912cab8 --- /dev/null +++ b/01-StackMachine/testcases/tc4.c @@ -0,0 +1,14 @@ +#include +#include "stackm.h" + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc5.c b/01-StackMachine/testcases/tc5.c new file mode 100644 index 0000000..1a8e1a4 --- /dev/null +++ b/01-StackMachine/testcases/tc5.c @@ -0,0 +1,9 @@ +#include +#include "stackm.h" + +int main() { + stackm mystack; + smInit(&mystack); + printf("SIZE: %d\n", smSize(&mystack)); + return 0; +} diff --git a/01-StackMachine/testcases/tc6.c b/01-StackMachine/testcases/tc6.c new file mode 100644 index 0000000..a79036d --- /dev/null +++ b/01-StackMachine/testcases/tc6.c @@ -0,0 +1,25 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + doPush(&mystack, 3); + printf("SIZE: %d\n", smSize(&mystack)); + doPop(&mystack); + doPop(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc7.c b/01-StackMachine/testcases/tc7.c new file mode 100644 index 0000000..2488229 --- /dev/null +++ b/01-StackMachine/testcases/tc7.c @@ -0,0 +1,36 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +void doPop(stackm* s) +{ + printf("Pop Ret: %d\n", smPop(s)); +} + +void doTop(stackm* s, int* v) +{ + printf("Top Ret: %d\n", smTop(s, v)); +} + +int main() { + int val = 0; + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doTop(&mystack, &val); + printf("TOP: %d\n", val); + doPush(&mystack, 2); + doTop(&mystack, &val); + printf("TOP: %d\n", val); + doPush(&mystack, 3); + doTop(&mystack, &val); + printf("TOP: %d\n", val); + doPop(&mystack); + doPop(&mystack); + doPop(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc8.c b/01-StackMachine/testcases/tc8.c new file mode 100644 index 0000000..db55513 --- /dev/null +++ b/01-StackMachine/testcases/tc8.c @@ -0,0 +1,9 @@ +#include +#include "stackm.h" + +int main() { + stackm mystack; + smInit(&mystack); + smClear(&mystack); + return 0; +} diff --git a/01-StackMachine/testcases/tc9.c b/01-StackMachine/testcases/tc9.c new file mode 100644 index 0000000..a3b0038 --- /dev/null +++ b/01-StackMachine/testcases/tc9.c @@ -0,0 +1,19 @@ +#include +#include "stackm.h" + +void doPush(stackm* s, int v) +{ + printf("Push Ret: %d\n", smPush(s, v)); +} + +int main() { + stackm mystack; + smInit(&mystack); + doPush(&mystack, 1); + doPush(&mystack, 2); + doPush(&mystack, 3); + printf("SIZE: %d\n", smSize(&mystack)); + smClear(&mystack); + printf("SIZE: %d\n", smSize(&mystack)); + return 0; +} diff --git a/02-TeenyTinyShell/.DS_Store b/02-TeenyTinyShell/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f2b4d18b26d7d30c9ed48ebeaa90d8183da09bd1 GIT binary patch literal 6148 zcmeHKOHRW;47E!Zt&plBv0yn@=nX;@PS71IXoFypFqLTca}*B4hFkGGwyKVjvP7t| zCC{7qGc$RK;+Tkdb!eAF3nH3A1t&8MBO-p$flSOIPL?&g*X4Q}``sYY4gZw^d3F_j zP^6CD%jY-$KK1pnX*ONlz=oXkc+-B}m;Uxw|L*Pd-3Umf8SUu>d+%vW&p^z}6Y%YL z)S0u4tk=iUQ;kHH=lhiNxi|yPfHQEZ44`I;Z-ur^GJ`O|?R zw*bHj<}8>?FCjU>ur^GJ@IY8oftt$JVz8#e9xSdlOp2OLY|RJT&TJhD=iRY>$l=7b zqL0piGf*;crI!n-{}1Q;|1!z1oB?Oxq8Q++SvM=(lGWD1%}K2d&?l&f#3jXJ3MRP} fBUVcB9W)E ls -l +``` + +This is translated to an execution of the 'ls' command with command line arguments: 'ls' and '-l' + +## Development Requirements + +1. While most shells allow the user to customize the prompt, you shell will always use the following prompt string: + + ```text + $> + ``` + + A dollar sign ($), followed by a greater than (>), followed by a space ( ) +3. Your 'ttsh' must support up to 10 command line arguments for each command (separated by spaces) +4. Your 'ttsh' must support up to 5 commands run sequentially (separated by semicolon) +5. While there many 'flavors' of the exec() system call, for this lab you are required to use execvp(). See the man page for the specifics of how execvp() works. +6. Your shell must support a single internal command called 'quit' which stops the execution loop +7. You must use fork() and execvp() to create child processes and execute commands. The use of the system() function is not allowed for this lab. +8. Your 'ttsh' must be free of memory leaks and segmentation faults. +9. Your 'ttsh' only needs to support a max user input of 256 characters. + +## Getting Started + +Parsing the user's input can be kind of complicated. Using the string tokenizer function (strtok) can be helpful. For help on how to use strtok see the man page: + +- man strtok + +Start by downloading the [starter files](ttsh.zip) which includes a source file (ttsh.c) with some code to help you parse the command line. The starter code also contains a Makefile to help you build your shell. + +## Sample Execution + +Here is a sample output for an execution of 'ttsh'. Note the first line and last line shows the prompt presented from 'bash' prior to running 'ttsh'. + +```text +user@pc:~/Desktop/cs3840/labs$ ./ttsh +$> ls +ttsh ttsh.c +$> ls -l +total 500 +-rwxrwxr-x 1 user user 17240 Sep 17 12:59 ttsh +-rw-rw-r-- 1 user user 7053 Sep 17 12:47 ttsh.c +$> echo hello world +hello world +$> ps -f -l +F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD +0 S user 43181 43170 0 80 0 - 5173 do_wai 08:59 pts/0 00:00:00 bash +0 R user 46683 43181 0 80 0 - 5029 - 11:59 pts/0 00:00:00 ps -f -l +$> which ls +/usr/bin/ls +$> mkdir testdir +$> ls -l +total 504 +-rwxrwxr-x 1 user user 17240 Sep 17 12:59 ttsh +-rw-rw-r-- 1 user user 7053 Sep 17 12:47 ttsh.c +drwxrwxr-x 2 user user 4096 Sep 18 12:02 testdir +$> rmdir testdir +$> ls -l +total 500 +-rwxrwxr-x 1 user user 17240 Sep 17 12:59 ttsh +-rw-rw-r-- 1 user user 7053 Sep 17 12:47 ttsh.c +$> asdfasdfasdfasdf +asdfasdfasdfasdf: failed to execute command +$> quit +user@pc:~/Desktop/cs3840/labs$ +``` + +## Development Tips + +Consider breaking the lab up into pieces: + +1. Create your shell input/execute loop +2. Implement the 'quit' command +3. Read and parse user input for commands + 1. Break apart commands by semicolon + 2. Break apart command line arguments by spaces +4. Get fork() and execvp() working to create a child process + 1. Build the array of command line arguments + 1. A single command with no command line arguments (remember that even without command line arguments explicitly specified there is always 1 passed to the new process) + 2. A single command with multiple command line arguments (remember that this includes the command name AND the actual command line arguments) + 3. Make sure you end your array of command line arguments with a NULL pointer + 2. Run multiple commands in sequence with or without command line arguments +5. Handle command not found + +Additional tips: + +- Your shell has limitations on string length requirements. Use this to your advantage +- A max of 256 characters of user input +- A max of 10 command line arguments (this max includes the first argument for the command name itself, effectively making the number that the user can specify to be 9 arguments) +- A max of 5 commands executed in sequence +- Don't forget about using gdb to help with debugging (compile with -g to get additional debug symbols) + + NOTE: when using gdb it is helpful to compile your program with additional debug symbols included. These allow gdb to show you more information when running commands like backtrace (bt). To compile with additional debug symbols use the -g flag on gcc. For example: + + ```text + gcc -Wall -g -o myprog mysourcefile1.c mysourcefile2.c mysourcefile3.c + ``` + +- Using valgrind will be helpful in this lab to ensure you do not have any memory leaks. + +## Testing and Debugging + +Make sure your shell supports all the features listed in the "Development Requirements". Make sure you test boundary cases and print appropriate error messages to the user as needed. For example, if the user attempts to execute a command with more than 10 command line arguments, print an error message to the user and wait for a new command (without executing the command). + +## Deliverables + +You will need to include all your source files and any other resources you used to complete lab. Please don't just google search for a solution, but if you do use Google for any help, include a description and URL of what you used to help you. + +A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission. + +All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file. + +NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report. + +Prepare a lab report and submit it along with your source code. The report should include the following: + +- Your name, section, date, and lab title +- Introduction – a description the lab in your own words +- Design – a description of your design decisions in creating your solution +- Resources – a description of any external resources you used to complete the lab +- Build – instructions on how to build and run your program. Include the exact commands that are necessary +- Analysis – Discuss the key concepts from the lab and answers to the following questions + - Commands in TTSH are executed by a call to ```fork()``` followed by a call to ```exec()```. What would bee the behavior of teeny tiny shell if the calls were reversed? + - There are many 'flavors' of ```exec()```. For this lab you used ```execvp```, research the other 'flavors' of ```exec()```. What is each used for? Be sure to site your sources: + - execl + - execlp + - execle + - execv + - execvp + - execvpe + - For this lab you used the ```fork()``` system call to create a child process to execute the command. There is another version of fork called ```vfork()```. Research this system call and describe how it works. Be sure to site your sources. When would you choose to use ```vfork()``` instead of ```fork()```. +- Conclusion + - Summary of what you learned in the lab + - What specifically was challenging about this lab? + - What did you like about it? + - What could we do to improve it for others? + +NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting. + +Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions. + +## Grading Criteria + +- (35 Points) Report + - (5 Points) Report Introduction - Thorough description of the lab in your own words. + - (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation. + - (20 Points) Analysis - Answers to the analysis questions + - (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements. +- (5 Points) Documented Resources - Description of external resources used to complete the lab +- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted) +- (5 Points) Build - Code compiles without warnings or errors +- (45 Points) Instructor Tests - Implementation passes all instructor test cases +- (5 Points) Memory Management - Program execution is free from memory leaks \ No newline at end of file diff --git a/02-TeenyTinyShell/testcases/tc1 b/02-TeenyTinyShell/testcases/tc1 new file mode 100644 index 0000000..3db49b3 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc1 @@ -0,0 +1,2 @@ +quit + diff --git a/02-TeenyTinyShell/testcases/tc10 b/02-TeenyTinyShell/testcases/tc10 new file mode 100644 index 0000000..6b1c402 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc10 @@ -0,0 +1,3 @@ +ls; ls; ls; ls; ls; ls; ls; ls; ls; ls; ls; +quit + diff --git a/02-TeenyTinyShell/testcases/tc2 b/02-TeenyTinyShell/testcases/tc2 new file mode 100644 index 0000000..4d70643 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc2 @@ -0,0 +1,3 @@ +ls +quit + diff --git a/02-TeenyTinyShell/testcases/tc3 b/02-TeenyTinyShell/testcases/tc3 new file mode 100644 index 0000000..b744f28 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc3 @@ -0,0 +1,3 @@ +ls -l +quit + diff --git a/02-TeenyTinyShell/testcases/tc4 b/02-TeenyTinyShell/testcases/tc4 new file mode 100644 index 0000000..3c2f820 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc4 @@ -0,0 +1,5 @@ +ls -l -a +echo hi +echo bye +quit + diff --git a/02-TeenyTinyShell/testcases/tc5 b/02-TeenyTinyShell/testcases/tc5 new file mode 100644 index 0000000..0244b89 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc5 @@ -0,0 +1,4 @@ +ps aux +ls -l +quit + diff --git a/02-TeenyTinyShell/testcases/tc6 b/02-TeenyTinyShell/testcases/tc6 new file mode 100644 index 0000000..9ac18aa --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc6 @@ -0,0 +1,3 @@ +slkjlkjfslkjslkjfskj +quit + diff --git a/02-TeenyTinyShell/testcases/tc7 b/02-TeenyTinyShell/testcases/tc7 new file mode 100644 index 0000000..6e86d58 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc7 @@ -0,0 +1,3 @@ +ls -l -l -l -l -l -l -l -l -l -l -l -l -l -l -l +quit + diff --git a/02-TeenyTinyShell/testcases/tc8 b/02-TeenyTinyShell/testcases/tc8 new file mode 100644 index 0000000..ba5414a --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc8 @@ -0,0 +1,3 @@ +echo hi; ls; echo bye +quit + diff --git a/02-TeenyTinyShell/testcases/tc9 b/02-TeenyTinyShell/testcases/tc9 new file mode 100644 index 0000000..ee48c34 --- /dev/null +++ b/02-TeenyTinyShell/testcases/tc9 @@ -0,0 +1,3 @@ +echo hi; ls -l; ps aux; echo bye +quit + diff --git a/02-TeenyTinyShell/ttsh.c b/02-TeenyTinyShell/ttsh.c new file mode 100644 index 0000000..f6c92af --- /dev/null +++ b/02-TeenyTinyShell/ttsh.c @@ -0,0 +1,102 @@ +/************************************* + * + * Class: CS3840 - YOUR SECTION HERE + * + * Name(s): YOUR NAME(S) HERE + * + * Lab: Teeny Tiny Shell + * + *************************************/ + +#include +#include + +#define INPUT_MAX 256 +#define CMD_MAX 5 + +/* read_cmd_string() + * Reads a line of text from the user + * Parameters: dest - target location for the input + * Returns: int - 0 on success or + * -1 on error + */ +int read_cmd_string(char dest[INPUT_MAX]) +{ + // Read user input + if(fgets(dest, INPUT_MAX, stdin) == NULL) { + fprintf(stderr, "Unable to read user input\n"); + return -1; + } + + // Remove trailing return character + int len = strlen(dest); + if(dest[len-1] == '\n') { + dest[len - 1] = '\0'; + } + + return 0; +} + +/* parse_commands() + * Reads a line of text from the user + * Parameters: input - string containing user input + * cmd_strs - the target array for command strings + * Returns: int - The number of commands found or + * -1 on error + */ +int parse_commands(char input[INPUT_MAX], char cmd_strs[CMD_MAX][INPUT_MAX]) +{ + // Chop the input into command strings + int cmd_count = 0; + char* cmd_ptr = strtok(input, ";"); + while(cmd_ptr) { + if(cmd_count >= CMD_MAX) { + fprintf(stderr, "Too many commands\n"); + return -1; + } + strncpy(cmd_strs[cmd_count], cmd_ptr, INPUT_MAX); + cmd_count++; + cmd_ptr = strtok(NULL, ";"); + } + + return cmd_count; +} + +int main() +{ + char user_input[INPUT_MAX]; + char cmd_strs[CMD_MAX][INPUT_MAX]; + + // TODO need to be able to get input from + // the user in a loop + + // Print the input prompt + printf("$> "); + + // Read user input + if(read_cmd_string(user_input) == -1) { + return 1; + } + + // TODO: Figure out how to handle the 'quit' command + + // Chop the input into command strings + int cmd_count = parse_commands(user_input, cmd_strs); + if(cmd_count == -1) { + return 1; + } + + // Chop the commands into arguments and execute one at a time + for(int i = 0; i < cmd_count; i++) { + + // TODO: + // 1) Chop the command into command line arguments + // need to handle up to 10 arguments + // NOTE: the command name is always the first argument + // 2) fork a process + // 3) execute the command with execvp + + } + + return 0; +} diff --git a/03-MatrixAddition/.DS_Store b/03-MatrixAddition/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1bbad1ddd5516d7c10071a11753841b59c49e9bc GIT binary patch literal 6148 zcmeHKOHPD95Pdzez_=NA#<=J!a08s+-h`biox!LH$i&e-C-F3%$20h zs*>v0)Q6%Uq?-cZR&P}XECHlc!NoC$2@${ONEXo|P8aU+gbnVos~@s*6m5q8$bi1w z26uSH3-;dMrfs(R!0#8t6yIW+wkXzhyAD3!=Ct~_oQ|u06t{iM%DyJQCQ5=GTGV)! z@2U6U{Bz%T;5qu-rk$+c`v-M#9SYlE3>X8(z|0xYT^8xd%-3nlGX{)--!mZlgQp7S z5j(}Ob#MqR05PFC2T^c8Zz~7n=_kE4$dC zxKN$<_aPiESG3U>Fb0MU9O>m!&i|{!{r@n@u8aX=U{(ycq$rCOmlV&|(cij] is an m x n matrix and B = [bij] is an m x n matrix, the sum of A + B is an m x n matrix. +A + B = [cij], where cij = aij + bij + +The definition of matrix addition indicates a cell by cell addition. For each cell in A, the value is added to the value in the corresponding cell of B. To add A and B they must be the same dimensions. + +For example: + +$$ +A = \begin{bmatrix} +1 & 10 & 0 \\ +3 & -2 & 6 +\end{bmatrix} +B = \begin{bmatrix} +1 & 4 & 0\\ +1 & 2 & 3 +\end{bmatrix} +$$ +$$ +A + B = \begin{bmatrix} +1 + 1 & 10 + 4 & 0 + 0 \\ +3 + 1 & -2 + 2 & 6 + 3 +\end{bmatrix} += +\begin{bmatrix} +2 & 14 & 0 \\ +4 & 0 & 9 +\end{bmatrix} +$$ + +Matrix addition is commutative. So, A + B does is always equal B + A. + +Your task is to create two programs that will perform matrix addition for two matrices given to you as two files and print the result. Each program must also record the amount of time it took to perform the matrix addition. + +- The first program will perform the matrix addition with a single process. +- The second program will perform the matrix addition with multiple processes – one process for each row. + +The format for each matrix file is: + +- The first line will contain two numbers: the number of rows in the matrix followed by the number of columns +- The rest of the file will contain rows of numbers representing the numbers in the matrix + +For the example given above the file for A would be: + +```text +2 3 +1 10 0 +3 -2 6 +``` + +And the file for B would be: +```text +2 3 +1 4 0 +1 2 3 +``` + +All numbers in the file will be separated by spaces. + +## Development: Single Process + +It's simplest to break down the development into pieces: + +1. Read the matrices +2. Perform the matrix addition +3. Print the result + +### 4.1 Read the Matrix Files + +A simple way to read integers from a file is to use the ```fscanf``` function. This function allows you to do formatted reading from a file. We'll use this to read numbers. To use ```fscanf``` you first must open a FILE* with ```fopen``` (take a look at 'man fopen' for more information). Then, like printf for printing a number you use the “%d” format as a parameter to ```fscanf``` to read a number. Here is an example: + +```c +#include + +int main(int argc, char* argv[]) +{ + int value; + FILE* input = fopen(argv[1], "r"); + fscanf(input, "%d", &value); + fclose(input); +} +``` + +NOTE: the matrix file names will be given on the command line as arguments. For example: ./a.out matA matB +Command line arguments are passed to main through the argc and argv values (see example above). The argc value tells the program the number of command line arguments, and argv is an array of character pointers for the argument strings. There is always 1 argument passed to your program (argv[0]) which contains the name of your program. So your matrix input files will be in argv[1] and argv[2]. If the user didn't provide enough arguments (e.g. argc != 3) then print an error and exit. + +You can use this ```fscanf``` to read in all the numbers you need from the file. It takes care of all the white space for you. So, to read your matrix file you can start with: + +```c +#include + +int main(int argc, char* argv[]) +{ + int rows, columns; + FILE* input = fopen(argv[1], "r"); + fscanf(input, "%d", &rows); + fscanf(input, "%d", &columns); + for(int i = 0; i < rows; i++) { + for(int j = 0; j < columns; j++) { + int value; + fscanf(input, "%d", &value); + } + } + fclose(input); +} +``` + +Obviously, you'll need to store the row and column values somewhere. Since the matrix can be any size (within reason), you'll need to store the matrix in memory on the heap allocating a space for it using malloc. Remember that malloc creates a contiguous space in memory on the heap for the given size. Think about how much memory you'll need to malloc to store each matrix. When storing the values in the malloc'ed space you'll also have to do some math to make sure the indexing is correct. + +### Adding the Matrices + +When you store the matrices in the space created by malloc they are in one contiguous space in memory. So, to perform the matrix math, you'll also need to correctly compute the correct memory offset. Thankfully to access the memory at an index you can just reference it like an array: + +```c +#include + +int main(int argc, char* argv[]) +{ + // malloc a space + int* space = malloc(sizeof(int) * 100); + + // Store data in the space + for(int i = 0; i < 100; i++) { + space[i] = i + 10; + } + + // Read data from the space + for(int i = 0; i < 100; i++) { + printf("%d\n", space[i]); + } + return 0; +} +``` + +For this assignment, you'll just need to do the index calculation for the correct index based on the value's row and column. From there the calculation is just based on the matrix addition formula. + +### Print the Result + +It's probably easiest to store the matrix for the addition result in its own malloc'ed space. Once you have the result, you'll need to perform the index math to print out the matrix elements to the screen. For our example, that would be: + +```text +2 14 0 +4 0 9 +``` + +Print out each element in the rows and columns separated by a space. Don't worry about making sure they line up. You will also need to print out the amount of time it took to perform the matrix addition. For that you will use the ```clock_gettime``` function to get the ```CLOCK_REALTIME``` for the system before and after you do the matrix addition. You only need to record the time for the addition, don't include the time it took to read the matrix files or to print the result. + +## Development: Multi-Process + +Once you get your single process program working you'll follow the same steps for the multiprocess version, except that now you have use ```fork()``` to create a process for each row in the matrix element. Breaking this down into pieces: + +1. Read the matrices +2. ```fork()``` child processes to perform the matrix addition (one per row in the result matrix) +3. Child processes perform the matrix addition for their given row +4. The child processes write their results to the result matrix stored in shared memory +5. The parent waits for all child process to finish +6. Parent prints the result + +NOTE: Recall that heap space is not shared between parent and child processes. So the result matrix is to be created in shared memory. Do this by creating a named share memory segment using ```shm_open``` and ```mmap```. Choose an appropriate name for the segment. + +It is up to you to decide how the matrix is organized in the shared memory space. You can organize it as a one-dimensional array and use index calculation to find the row and column or as a two-dimensional array. However, remember that a shared memory segment is a single contiguous address range. + +NOTE: Use only a single shared memory segment. Do ***NOT*** use a separate shared memory segment for each row. + +### Read the Matrix Files + +This is the same as the single process version + +### Create child processes to perform the matrix addition + +You will need to ```fork()``` a process for each row in the matrices. For our example above A + B has 2 rows so that requires 2 child processes. You'll need to ```fork()``` in a loop, make sure you keep track of the pid for each child process because the parent will need to wait for them to finish. Since you won't know how many processes you need when the program starts, you'll need to malloc a space to store the child process identifiers (pids). + +### Child processes perform the matrix addition for their given row + +Once you ```fork()``` the child processes you'll need to figure out how to make sure that each child process performs the matrix addition calculation each element in their given row. The formula for the calculation is the same as the single process version. + +### Child processes write their computation to the shared result matrix + +Allocated and mapped shared memory persists after a ```fork()``` system call so all child processes have access to a result matrix created in shared memory. The child processes can write their result directly to the shared memory space for the result matrix. The parent does not need to collect results. + +### The parent waits for all child process to finish + +The parent needs to keep track of all the process identifiers (pids) for all child processes and perform a waitpid for each one. This will require a loop and call to ```waitpid()```. See the man page for ``waitpid()``` for additional information. + +### Parent prints the result + +Once the child processes have finished, printing the result is the same as the single process program. Make sure the parent waits for the children to finish otherwise the result matrix won't be correct. + +## Development Tips + +- Remember that to successfully add two matrices the dimensions must match. So an m x n matrix can be added to an m x n matrix, but an m x n matrix cannot be added to a m x p matrix unless n == p. If the input matrices are not the correct size, print an error message to the user and quit. +- Don't forget to free your mallocs! Remember that when a parent malloc's space on the heap, the child will get an EXACT COPY of that data. The child also inherits the responsibility to free the storage. Don't forget to free your mallocs! +- Don't forget to ```munmap``` your ```mmap``` spaces! Remember that when a parent maps an address space, the children processes also gets that ```mmap```. The child must therefore ```munmap``` the address space AND close any used file descriptors when it is done. Don't forget to do this in your code! +- Don't forget to close your file descriptors! When you call shm_open you get back a file descriptor. The children inherit file descriptors after a ```fork()```. All opened file descriptors must be closed by all processes when they are done using them (the parent too). +- Don't forget to ```shm_unlink``` your named shared memory segments! Named shared memory segments are persistent (they live beyond the life of your process). Make sure you ```shm_unlink()``` your named shared memory segments. BUT make sure you don't ```shm_unlink``` before you need to. Don't remove a shared memory segment until you are absolutely sure that nobody else is using it! +- Don't forget about using gdb to help with debugging (compile with -g to get additional debug symbols) + + NOTE: when using gdb it is helpful to compile your program with additional debug symbols included. These allow gdb to show you more information when running commands like backtrace (bt). To compile with additional debug symbols use the -g flag on gcc. For example: + + ```text + gcc -Wall -g -o myprog mysourcefile1.c mysourcefile2.c mysourcefile3.c + ``` + +- Using valgrind will be helpful in this lab to ensure you do not have any memory leaks. +- When compiling your shared memory program you will need to include an additional compiler flag: -lrt. This tells the compiler to use the real-time c library where the wrapper function calls for the shared memory system calls. The examples use this in the Makefile, so you can see how to use it there as well. For example: + + ```text + gcc -Wall -g -o myprog mysourcefile1.c mysourcefile2.c mysourcefile3.c -lrt + ``` + + NOTE: the -lrt flag must be the LAST thing on the command line. If it is not, your program will not compile. + +## Testing and Debugging + +There are [several matrix files](matrices.zip) located provided along with this specification. You can use those to help get your programs working. You are also required to create some of your own and include those in your submission. Don't forget to test large matrices. + +## Deliverables + +You will need to include all your source files, test case matrix files, and any other resources you used to complete lab. Please don't just google search for a solution, but if you do use Google for any help, include a description and URL of what you used to help you. + +A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission. + +All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file. + +NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report. + +Prepare a lab report and submit it along with your source code. The report should include the following: + +- Your name, section, date, and lab title +- Introduction – a description of the lab in your own words +- Design – a description of your design decisions in creating your solution +- Resources – a description of any external resources you used to complete the lab +- Build – instructions on how to build and run your programs. Include the exact commands that are necessary +- Analysis – Your two programs (single process and multiprocess) need to print out the time to perform the matrix addition. Use this information to evaluate the usefulness of multiprocess programming. Is there an advantage to using multiprocessing for matrix addition? Be thorough. +
In addition, answer the following in your analysis + - How does the runtime of the single process compare to the multiple process version? Faster? Slower? Why do you think this is the case? Think in terms of operating system overhead. + - How could identifying patterns in the source matrices be used to speed up the computation? + - How does shared memory affect the overall heap needed by the process? If you run your program using valgrind, it will print out a summary of the total heap used. What conclusions can you draw from this? +- Conclusion + - Summary of what you learned in the lab + - What specifically was challenging about this lab? + - What did you like about it? + - What could we do to improve it for others? + +NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting. + +Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions. + +## Grading Criteria + +- (35 Points) Report + - (5 Points) Report Introduction - Thorough description of the lab in your own words. + - (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation. + - (20 Points) Analysis - Answers to the analysis questions + - (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements. +- (5 Points) Documented Resources - Description of external resources used to complete the lab +- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted) +- (5 Points) Build - Code compiles without warnings or errors +- (10 Points) Test Cases - Thoroughness of submitted test cases +- (35 Points) Instructor Tests - Implementation passes all instructor test cases +- (5 Points) Memory Management - Program execution is free from memory leaks. All shared memory segments are cleaned up. \ No newline at end of file diff --git a/03-MatrixAddition/matrices/matA b/03-MatrixAddition/matrices/matA new file mode 100644 index 0000000..2d1166b --- /dev/null +++ b/03-MatrixAddition/matrices/matA @@ -0,0 +1,3 @@ +2 3 +1 10 0 +3 -2 6 diff --git a/03-MatrixAddition/matrices/matB b/03-MatrixAddition/matrices/matB new file mode 100644 index 0000000..5e89c55 --- /dev/null +++ b/03-MatrixAddition/matrices/matB @@ -0,0 +1,3 @@ +2 3 +1 4 0 +1 2 3 diff --git a/03-MatrixAddition/matrices/matC b/03-MatrixAddition/matrices/matC new file mode 100644 index 0000000..a14be79 --- /dev/null +++ b/03-MatrixAddition/matrices/matC @@ -0,0 +1,11 @@ +10 10 +0 0 3 2 2 3 3 2 3 1 +0 2 3 1 2 2 2 3 2 0 +3 1 3 0 2 2 0 1 0 3 +2 0 1 3 0 2 2 1 0 0 +2 2 2 1 3 0 0 3 0 0 +3 1 2 2 3 1 1 0 0 3 +1 1 1 2 1 2 0 0 0 3 +3 1 2 0 2 0 0 2 3 1 +1 2 1 3 3 2 3 1 1 3 +3 1 0 2 3 2 3 1 1 0 diff --git a/03-MatrixAddition/matrices/matD b/03-MatrixAddition/matrices/matD new file mode 100644 index 0000000..6a6965b --- /dev/null +++ b/03-MatrixAddition/matrices/matD @@ -0,0 +1,11 @@ +10 10 +3 3 3 3 1 2 3 0 0 2 +1 2 0 2 4 1 4 2 2 2 +4 0 0 0 4 1 3 4 3 1 +2 1 3 1 2 3 1 2 3 4 +0 3 2 2 3 2 1 2 2 0 +2 2 1 2 1 1 1 4 1 4 +4 0 2 2 4 1 0 1 0 2 +4 4 3 0 2 3 3 4 0 4 +2 4 0 1 0 4 3 2 0 4 +3 2 4 4 0 1 3 3 4 4 diff --git a/03-MatrixAddition/matrices/matE b/03-MatrixAddition/matrices/matE new file mode 100644 index 0000000..4fc5473 --- /dev/null +++ b/03-MatrixAddition/matrices/matE @@ -0,0 +1,101 @@ +100 100 +7 8 6 5 5 6 5 4 8 9 9 1 4 5 9 9 3 5 3 2 3 1 1 1 8 0 7 0 7 6 3 7 5 3 0 9 3 7 4 7 7 1 8 1 3 0 4 8 0 1 1 9 1 5 7 7 2 5 4 7 3 4 1 6 5 6 9 1 6 7 7 6 1 5 1 6 3 0 5 6 4 9 1 2 5 4 2 9 3 6 9 8 0 0 4 5 2 9 3 7 +8 6 5 4 3 1 7 2 7 7 8 1 9 7 8 6 3 1 0 5 1 4 7 3 7 8 6 7 8 5 7 1 0 0 1 2 5 6 9 1 1 6 7 1 7 5 0 6 3 5 6 0 0 7 8 0 3 4 0 3 1 1 3 8 6 6 9 6 0 6 7 4 2 3 2 6 7 8 9 6 3 2 2 9 0 8 2 1 9 1 2 7 2 9 6 9 2 1 0 7 +6 6 8 6 4 1 1 0 9 4 9 5 9 0 4 1 1 8 5 9 5 8 2 2 0 9 6 1 5 1 4 2 6 1 5 9 9 6 6 0 0 8 7 8 1 2 6 8 0 8 1 0 5 0 8 1 4 9 4 2 0 2 5 6 3 9 7 3 6 7 8 8 1 5 4 0 5 3 4 1 5 6 4 3 5 4 4 1 6 1 8 3 6 0 0 0 6 2 4 8 +4 7 1 4 9 6 6 2 7 2 3 1 5 5 1 4 6 8 5 9 8 3 6 8 5 4 6 1 7 9 9 7 7 5 6 8 6 7 3 1 1 6 9 3 7 9 0 9 4 3 7 1 2 0 3 9 5 6 4 7 1 3 0 0 4 6 2 9 7 5 0 6 0 6 0 8 8 8 5 9 9 6 0 4 2 1 9 3 2 7 0 4 1 5 3 1 3 4 3 2 +1 7 4 7 9 0 9 1 5 4 1 3 3 2 7 7 3 8 4 9 3 9 5 3 9 5 0 1 3 0 8 5 0 1 2 6 2 6 4 9 3 8 5 2 5 0 0 0 8 0 1 6 7 3 9 1 1 5 9 5 1 8 8 6 0 7 1 8 6 2 8 6 2 6 3 5 8 4 6 4 4 8 1 3 3 4 2 7 9 1 5 2 1 7 4 2 1 3 3 8 +2 6 9 2 4 7 0 3 7 8 9 5 3 5 2 0 2 3 8 4 2 5 9 2 2 8 9 3 8 5 2 2 8 0 1 6 8 6 6 6 1 4 1 7 0 2 4 5 0 4 7 0 5 2 1 7 2 4 4 0 4 9 2 1 8 3 5 6 8 4 4 7 5 6 2 7 9 9 6 0 0 4 1 3 4 0 6 4 0 5 5 1 2 0 9 8 0 6 5 5 +6 2 3 2 1 8 4 9 2 7 6 2 9 9 5 1 6 0 6 1 2 6 2 9 8 7 9 4 8 6 2 4 8 2 5 2 1 0 0 3 0 4 0 8 9 0 8 3 0 7 0 7 0 2 2 7 4 8 9 1 0 3 6 7 1 5 3 5 3 0 5 5 2 5 0 4 8 9 5 0 3 4 2 0 3 2 0 4 3 9 7 6 4 0 3 5 2 8 4 8 +5 3 1 1 6 3 6 0 0 8 8 3 1 8 9 1 8 0 4 6 5 0 1 5 8 8 2 1 0 0 2 8 3 3 9 4 6 1 3 9 2 1 6 7 9 4 8 6 6 6 7 1 1 3 4 4 3 8 3 6 3 4 8 4 5 3 1 8 4 7 6 3 0 3 6 5 8 0 7 4 9 2 9 3 2 1 3 6 2 5 6 1 4 5 2 9 7 4 2 7 +3 2 7 2 4 0 7 2 0 3 0 4 2 5 5 6 7 0 7 8 2 7 0 1 8 3 6 6 2 3 5 8 5 9 9 2 3 4 6 0 9 7 8 2 2 2 9 2 5 3 1 1 5 1 6 1 8 3 9 1 4 5 7 7 1 6 0 5 4 3 1 8 5 4 9 0 0 7 4 3 8 9 5 3 0 9 5 9 1 3 8 5 7 0 0 1 1 0 9 9 +6 4 4 5 8 0 9 2 4 5 7 9 0 8 7 0 3 2 5 6 4 7 5 7 6 0 4 8 0 0 3 1 5 8 1 2 4 1 3 6 4 0 2 8 9 3 3 3 0 3 7 9 2 2 2 1 1 8 0 8 1 6 7 6 5 7 3 7 9 0 8 1 4 8 7 9 9 4 3 2 6 8 8 5 8 7 2 7 9 6 9 8 6 6 9 9 5 6 5 6 +7 3 2 2 3 2 9 4 0 7 0 5 9 8 7 5 5 4 6 4 1 1 7 4 9 0 5 5 1 1 4 3 0 4 0 5 3 9 8 6 1 5 7 2 1 2 7 1 1 5 7 9 2 9 2 0 4 3 0 3 4 0 7 4 1 8 3 0 4 6 7 4 6 9 8 4 0 7 9 6 4 0 0 2 7 9 8 0 2 1 3 1 7 8 2 9 4 7 4 6 +9 0 4 2 5 4 7 3 3 0 4 7 8 4 1 0 8 0 4 7 4 6 4 4 2 2 7 4 2 9 2 8 8 2 3 2 6 7 2 0 0 6 4 4 0 7 6 3 3 7 2 4 8 2 0 8 1 1 7 1 3 3 1 7 6 2 0 1 9 5 3 1 1 4 8 1 7 1 5 1 1 3 3 0 5 0 4 9 5 8 5 7 8 6 6 5 4 1 6 7 +8 1 3 5 6 0 5 9 2 9 8 1 9 6 0 8 4 1 1 6 5 0 6 8 3 1 0 6 2 3 3 9 5 4 7 7 9 7 1 7 4 5 0 2 0 2 4 0 5 3 6 3 5 8 0 2 0 1 4 4 6 1 2 9 2 5 9 1 6 9 7 6 1 6 1 9 6 1 8 6 9 7 6 8 1 7 4 9 2 9 9 5 7 5 1 0 4 5 4 7 +1 2 1 6 2 6 5 9 3 9 8 3 2 2 7 4 6 2 9 2 7 6 6 3 1 4 4 9 0 8 1 0 1 0 0 0 9 5 4 6 6 5 7 4 0 9 7 6 9 1 8 3 7 2 2 5 3 1 0 9 3 0 6 8 4 3 0 0 3 9 4 7 0 5 1 8 7 4 6 6 8 8 6 4 6 4 8 1 9 9 8 4 0 3 5 0 1 3 9 4 +7 2 0 1 4 2 2 9 9 2 8 9 0 2 5 5 7 0 1 0 6 3 9 4 4 6 5 3 0 4 8 5 2 0 8 1 2 7 5 8 3 1 3 3 3 9 7 1 5 8 6 4 3 1 3 3 6 9 8 3 1 5 2 2 5 0 5 7 8 1 6 0 5 4 6 8 8 0 0 1 2 2 4 2 7 6 1 9 7 5 8 6 9 7 8 6 2 8 0 0 +6 0 3 5 8 2 0 6 8 7 6 5 8 9 0 1 2 9 9 8 5 4 7 2 0 0 5 0 8 0 9 1 0 5 5 3 9 6 3 9 0 4 7 2 5 7 3 4 0 3 0 2 7 2 2 9 3 6 8 5 6 2 7 7 1 3 6 2 0 1 2 0 7 4 6 0 4 8 0 6 5 6 3 3 8 6 0 4 6 9 5 8 3 2 4 1 2 2 7 5 +6 4 1 8 6 5 8 0 3 5 5 4 8 7 6 5 0 4 9 0 2 3 1 1 6 2 6 1 0 2 7 6 9 7 9 1 3 1 2 5 8 9 6 9 3 1 1 1 1 6 6 8 9 6 1 5 3 8 0 4 7 3 1 7 8 3 8 6 8 5 3 4 1 3 1 5 4 3 7 1 4 4 9 9 8 4 6 2 3 8 6 6 3 5 0 9 1 4 5 4 +6 9 8 9 7 7 1 5 0 5 6 5 9 4 9 8 5 2 9 0 5 0 4 3 6 7 7 6 9 7 2 7 3 1 2 6 3 1 6 1 9 8 2 8 5 5 4 4 3 6 1 4 4 9 7 6 8 0 4 9 8 7 1 7 6 3 1 1 2 9 5 8 6 5 2 4 7 4 7 1 8 9 7 9 6 7 4 0 8 3 8 1 3 3 7 8 7 1 7 7 +4 4 5 9 4 5 1 6 8 8 1 6 9 5 9 1 7 7 3 8 2 3 6 7 0 4 1 0 0 4 7 9 7 9 0 5 6 3 4 5 8 8 7 5 4 2 4 4 2 6 7 6 3 6 5 4 7 2 3 1 9 4 8 8 5 6 9 1 7 6 7 3 9 3 1 7 5 8 2 7 9 7 0 0 1 1 2 2 3 4 2 6 2 0 1 6 3 6 5 0 +5 9 8 4 7 4 3 5 9 5 3 2 4 1 5 1 7 6 6 1 1 9 9 3 8 3 4 6 6 6 1 0 6 9 8 1 9 6 7 5 5 0 9 5 0 3 6 1 2 9 2 3 3 0 7 2 0 2 9 6 9 8 7 9 4 2 1 7 4 7 0 6 9 3 5 6 7 7 2 4 4 6 6 4 4 9 3 4 6 6 3 7 7 5 0 0 1 7 0 5 +7 8 9 1 8 6 8 0 2 3 9 8 7 1 8 2 4 2 1 3 4 1 0 7 6 5 7 6 0 0 8 2 3 2 0 0 3 2 8 2 4 4 6 7 7 4 4 5 5 1 0 0 8 4 3 4 7 9 1 7 5 8 3 0 9 1 5 7 2 3 9 0 6 3 5 6 4 9 4 9 2 8 9 9 2 7 2 2 0 1 1 8 5 7 1 1 3 6 9 9 +8 6 6 7 0 1 1 3 3 8 4 6 4 4 4 7 1 4 3 0 8 3 5 3 9 7 7 3 2 2 4 1 6 5 7 2 2 3 0 3 2 2 5 9 4 6 5 7 6 9 3 7 6 2 5 5 3 7 2 0 9 0 1 1 4 6 4 6 4 0 1 7 8 9 5 3 6 9 0 5 5 2 5 4 5 6 4 2 6 6 2 0 9 7 0 0 6 4 6 7 +7 0 4 0 4 0 9 2 0 6 7 2 3 2 1 9 3 4 0 2 2 2 9 6 3 7 6 1 3 6 3 8 6 6 1 1 5 4 9 6 4 0 3 9 4 7 6 0 2 1 5 5 7 6 0 6 4 4 9 8 8 4 6 7 4 9 5 7 3 8 3 3 7 8 0 5 2 0 5 1 4 8 9 2 7 6 5 7 7 0 3 9 3 0 4 7 7 5 6 7 +7 6 3 6 7 3 0 0 1 2 9 2 6 8 9 5 0 0 9 4 9 9 9 6 8 2 5 0 3 7 6 0 0 2 2 7 7 3 2 6 7 4 6 6 6 2 5 9 2 7 4 9 9 0 0 7 9 0 2 3 1 0 5 4 9 8 6 3 1 9 5 1 8 1 4 3 7 6 0 8 9 8 6 8 2 7 0 2 9 3 7 3 5 5 4 3 7 4 7 3 +2 7 4 5 9 4 6 9 2 2 4 1 3 4 1 2 2 0 3 3 5 2 9 6 3 8 1 0 9 4 4 4 5 1 8 9 1 8 9 8 0 8 9 2 3 5 1 4 0 0 9 5 4 7 7 6 6 9 4 5 4 1 7 0 9 9 4 4 0 4 9 4 7 4 6 0 9 1 2 9 2 4 1 4 8 8 0 0 9 5 5 2 0 5 9 4 0 1 0 7 +1 9 7 0 3 6 8 0 2 4 2 0 7 2 2 0 4 3 2 1 8 7 7 9 1 0 8 9 9 5 7 1 6 6 6 2 7 8 2 5 1 3 8 6 8 7 8 1 2 3 3 6 5 6 4 2 6 0 3 2 3 5 9 3 5 2 2 9 1 1 8 2 7 3 8 3 8 4 3 9 6 2 2 7 4 7 2 7 5 7 8 0 3 5 8 4 0 9 0 6 +9 9 7 1 3 5 9 7 1 2 0 3 7 2 3 0 9 9 0 3 8 4 5 9 6 3 5 4 6 0 2 0 2 1 9 6 0 1 2 3 4 7 6 1 4 8 5 4 0 0 7 4 2 1 4 1 1 2 4 9 7 0 3 5 8 9 1 0 7 2 3 8 9 6 3 9 8 7 7 3 6 8 0 7 9 3 6 8 7 8 1 3 0 4 4 2 7 9 4 6 +9 0 9 9 5 7 9 6 9 7 2 6 7 8 3 9 1 7 1 3 6 8 3 8 1 1 3 3 4 7 6 0 6 3 3 1 5 3 4 2 6 2 1 3 9 2 3 4 2 8 1 7 4 6 7 3 9 6 5 3 8 5 3 7 9 9 5 8 5 6 2 3 0 8 5 8 6 3 8 3 8 7 3 6 3 2 1 7 3 9 7 4 4 5 4 6 1 5 2 6 +3 1 6 0 8 9 6 0 5 1 9 7 7 3 6 9 8 8 8 7 6 0 1 5 9 5 7 6 7 5 2 3 5 5 4 7 7 2 7 4 7 6 4 5 9 0 6 9 7 4 1 8 2 0 0 9 2 1 4 8 0 1 8 4 9 1 1 9 0 8 3 8 8 2 0 5 7 6 3 9 3 3 9 5 8 3 1 3 7 6 9 7 4 4 8 7 2 4 1 1 +6 0 2 3 7 6 3 3 5 4 5 9 0 0 7 7 5 2 5 9 9 4 4 1 6 7 2 9 7 2 0 6 4 1 0 4 8 3 1 8 4 7 1 3 0 8 2 5 3 2 4 6 4 9 2 8 6 3 1 5 2 3 8 5 9 5 8 6 1 3 0 6 5 5 9 8 6 5 2 8 7 8 5 4 7 1 1 1 6 4 5 2 0 7 2 7 5 5 7 3 +4 5 2 6 5 8 9 1 7 2 5 1 6 1 5 5 4 1 8 1 4 8 1 7 7 5 3 1 5 9 5 1 1 3 1 2 8 1 8 3 0 9 4 9 8 1 6 7 6 8 2 9 3 0 1 3 9 1 6 0 7 4 1 3 3 8 8 8 4 0 0 9 6 5 9 2 2 6 7 3 8 3 2 0 7 5 2 3 2 5 7 8 3 8 1 7 4 7 5 8 +1 8 3 0 5 1 6 0 7 1 2 8 2 4 2 6 3 2 5 0 1 5 1 1 2 6 8 6 4 8 3 8 0 8 6 1 3 6 2 4 0 8 2 4 9 3 4 7 8 9 1 1 9 5 6 2 1 7 4 6 9 3 9 2 8 1 5 4 2 9 9 0 3 8 4 8 1 7 0 3 9 1 6 1 6 8 4 2 8 9 5 2 1 9 3 7 9 8 5 9 +7 2 7 0 2 3 6 4 3 7 2 7 7 6 4 7 0 3 8 6 8 4 8 5 0 9 4 5 1 6 4 8 5 2 6 1 3 6 1 5 2 6 7 6 0 5 8 3 4 5 8 5 3 6 9 8 4 2 5 1 1 9 5 0 4 8 5 7 4 6 5 8 1 5 1 5 1 0 3 0 6 2 9 8 9 9 6 1 4 3 1 5 4 5 0 2 9 4 2 1 +4 6 3 2 5 8 1 2 2 0 5 6 3 3 5 2 5 8 2 2 8 0 7 8 4 6 0 5 3 6 9 8 9 7 4 9 3 1 9 9 8 9 6 2 1 8 4 3 1 3 1 6 5 3 6 6 0 5 1 3 8 2 0 1 1 0 5 7 0 4 7 5 7 5 1 2 6 9 0 3 3 1 4 1 4 8 1 0 6 1 1 4 5 4 0 0 2 9 1 9 +8 2 2 5 0 7 7 8 2 0 7 0 6 8 0 7 2 6 4 3 3 9 9 8 7 2 3 0 4 4 7 3 4 4 8 1 5 7 2 7 1 0 9 3 9 9 4 4 9 2 8 1 7 2 4 7 3 9 6 1 4 9 9 1 6 5 6 7 2 6 0 4 9 9 1 6 2 8 1 5 6 1 8 4 5 3 0 9 2 8 8 1 8 1 7 0 9 5 5 2 +9 1 2 8 2 0 8 0 6 2 9 2 3 1 6 2 6 0 2 7 4 0 6 4 9 5 9 1 2 1 3 5 6 6 6 6 9 8 4 0 9 0 0 9 7 5 7 0 9 9 6 1 5 5 5 7 2 9 3 5 2 8 6 7 1 4 9 5 7 9 0 6 2 2 9 9 2 6 2 7 9 6 1 5 5 7 2 9 3 8 8 0 9 7 4 0 9 3 8 8 +5 9 9 1 0 4 9 7 0 0 9 2 6 3 8 4 1 7 2 4 7 8 9 6 3 8 3 5 7 1 6 7 5 2 2 7 0 2 4 6 0 1 1 0 0 4 7 5 8 3 2 4 9 5 9 5 7 5 0 8 3 4 3 6 9 9 2 8 8 1 7 5 4 2 9 4 3 7 6 4 5 3 2 5 5 2 9 2 7 4 1 3 4 3 1 6 6 2 3 7 +0 8 2 0 6 7 6 4 4 6 2 9 2 9 5 7 4 4 7 0 7 5 3 8 9 7 6 0 2 2 1 4 7 6 6 1 1 0 6 3 0 6 9 6 9 9 9 5 6 4 1 0 1 2 6 7 4 4 1 4 2 7 6 8 0 5 5 7 0 1 8 1 9 5 6 7 5 4 0 1 8 0 0 7 0 5 9 4 9 1 6 0 1 3 5 1 3 6 7 4 +4 3 9 2 7 7 5 9 0 4 5 9 7 1 1 7 5 3 8 2 8 6 3 8 0 2 1 8 1 5 5 5 3 9 5 3 2 2 2 9 1 2 7 4 5 0 5 5 8 0 7 8 5 7 3 7 6 4 9 2 0 5 7 1 6 6 8 4 2 8 9 6 4 4 6 7 9 1 9 8 6 0 5 3 3 8 3 8 4 7 5 8 2 5 9 9 2 5 5 7 +3 1 3 8 2 6 7 2 0 1 0 5 6 2 2 2 5 9 3 7 9 4 2 6 3 5 6 2 3 2 6 2 2 9 7 6 3 6 7 8 8 9 5 8 8 0 9 1 1 4 4 0 8 3 7 3 1 0 9 6 7 9 4 8 9 3 3 3 6 1 3 0 3 3 9 5 3 3 7 5 8 3 5 4 5 5 7 5 8 3 9 3 0 6 0 7 0 6 5 2 +7 1 9 7 0 8 8 0 2 6 4 8 5 5 2 7 3 6 9 8 8 2 6 4 9 1 1 2 5 9 1 9 9 9 5 7 2 8 0 0 1 6 5 1 2 3 2 5 2 9 6 7 5 1 4 0 8 2 6 7 8 1 0 0 3 3 8 0 4 4 2 3 1 2 3 3 0 1 8 6 2 3 2 9 5 0 3 7 5 9 9 5 9 6 9 5 7 6 7 4 +7 8 0 0 6 0 0 4 6 3 6 6 1 6 5 2 4 8 9 8 1 0 4 7 1 4 9 8 5 3 2 4 9 0 2 2 3 9 3 8 2 3 7 6 1 9 4 3 5 2 0 7 7 0 5 7 9 7 6 6 2 6 7 3 5 2 5 2 7 5 1 7 4 0 3 0 7 5 2 9 7 6 3 8 0 2 5 6 9 6 4 4 8 1 7 0 0 2 6 8 +5 9 6 9 3 1 8 8 7 7 5 9 8 6 1 2 2 5 7 6 9 2 4 8 6 2 1 4 7 5 3 1 1 6 0 9 5 0 2 6 8 3 5 7 3 9 6 3 7 9 1 8 4 0 4 7 5 0 1 0 2 7 8 2 8 4 9 9 7 2 8 3 8 8 0 7 4 1 6 1 3 5 3 9 8 9 2 1 2 5 9 3 8 4 3 8 5 8 0 8 +2 8 6 2 9 9 1 5 9 4 3 8 5 3 0 3 8 0 1 8 9 0 5 6 2 5 4 5 9 6 8 6 0 4 4 2 7 5 6 3 8 6 8 8 9 5 8 9 9 2 4 8 5 5 7 4 5 1 2 5 5 7 0 1 2 8 8 6 3 9 4 7 6 6 1 7 7 7 7 7 6 3 6 3 7 1 1 1 6 7 2 8 5 4 6 6 8 9 0 8 +2 6 5 5 5 7 5 6 8 3 0 2 3 5 1 2 0 8 1 7 2 1 6 5 5 6 2 6 9 9 3 7 6 5 1 6 8 5 6 6 0 1 9 6 0 7 9 4 9 4 7 0 7 8 3 6 0 1 1 3 9 7 2 1 9 6 0 2 1 6 4 2 1 1 4 7 5 5 0 2 2 3 8 4 6 0 2 2 2 8 7 4 8 2 9 5 9 3 6 0 +9 5 2 6 8 5 8 7 9 1 4 5 0 7 3 2 9 6 5 4 1 5 9 1 8 3 5 7 3 4 2 5 1 1 4 6 6 6 4 2 5 5 4 9 2 9 3 0 4 0 3 0 1 2 4 8 8 8 4 9 0 7 0 3 0 1 2 6 6 7 9 3 8 0 1 7 2 4 3 1 3 4 7 3 1 8 8 1 0 3 2 9 2 5 9 7 9 6 0 2 +3 9 8 4 7 5 2 8 5 6 0 3 4 3 0 1 0 4 3 7 2 5 4 6 2 6 6 4 1 9 3 6 9 4 6 2 9 3 1 2 8 6 0 2 5 1 1 8 7 3 4 1 7 5 7 2 7 7 0 6 8 0 2 9 7 3 4 4 5 0 3 2 7 6 3 0 8 0 0 7 6 4 8 3 1 1 5 0 4 3 9 4 3 6 0 6 0 4 2 8 +9 8 9 8 8 6 5 7 6 1 6 7 3 1 3 9 5 6 6 4 8 8 0 9 0 8 9 9 4 4 6 7 0 0 2 2 3 0 6 9 3 9 2 3 2 8 3 3 8 0 8 7 1 3 4 7 6 8 8 7 9 2 7 2 5 7 1 7 8 7 1 1 8 5 0 9 2 6 2 5 2 1 4 6 5 8 7 7 2 8 1 0 4 4 3 8 8 0 7 7 +4 6 9 1 6 8 4 7 7 6 5 0 5 8 3 3 6 5 9 3 4 1 9 7 6 4 0 2 4 9 2 8 3 1 9 5 6 7 0 8 2 9 8 8 9 7 5 2 0 0 3 2 4 5 6 2 6 5 9 3 3 8 5 1 1 9 1 0 6 0 8 3 7 2 0 9 9 6 6 3 2 9 7 5 4 6 0 7 9 6 5 3 6 5 9 4 0 6 3 7 +4 2 2 8 9 5 4 0 4 1 3 9 1 9 5 4 7 4 0 1 9 7 1 1 1 5 5 4 5 9 2 8 6 8 2 3 3 1 7 7 4 5 8 4 2 8 6 7 1 1 6 4 1 8 9 5 0 8 0 2 0 6 7 2 8 1 3 8 1 2 9 9 4 6 6 1 4 4 0 4 9 8 7 7 2 5 4 8 4 7 9 0 0 0 8 1 0 2 1 9 +2 0 3 0 8 5 5 2 8 6 2 7 9 6 5 1 0 8 9 5 3 2 9 0 5 2 4 0 1 5 2 7 4 7 9 9 8 0 0 6 4 1 6 5 2 4 8 4 2 7 3 4 2 3 4 7 5 6 8 8 4 6 1 5 4 6 8 8 4 4 2 2 1 4 5 0 0 9 7 6 4 1 8 6 0 1 6 8 3 1 8 3 1 7 1 1 1 9 3 8 +4 7 3 1 3 1 5 2 0 1 8 9 2 0 3 5 6 7 7 1 9 5 8 0 6 0 5 6 6 2 9 9 2 5 6 2 5 7 1 4 4 2 6 6 9 6 3 8 8 5 6 3 4 6 4 8 1 9 0 3 8 7 6 3 9 0 7 0 2 2 9 8 1 3 8 6 2 9 6 7 7 5 0 6 9 8 9 2 8 8 4 3 1 4 2 9 5 2 8 9 +3 6 8 7 2 6 1 7 6 8 1 0 7 9 8 4 3 4 1 5 9 0 6 6 4 7 1 6 8 7 5 0 6 1 1 0 5 6 5 3 1 9 7 8 1 8 1 3 1 3 0 3 5 6 5 1 1 9 5 5 7 0 1 9 6 3 4 1 5 9 0 9 2 7 3 3 6 2 4 2 8 7 9 6 3 4 9 0 9 5 1 8 5 0 1 4 0 3 6 1 +0 3 5 5 8 7 3 2 4 5 8 3 8 3 8 1 4 8 1 9 4 8 8 5 2 9 8 8 9 8 7 4 3 1 7 8 3 6 2 5 8 9 2 7 5 1 4 4 3 6 7 0 7 1 0 5 2 2 1 6 4 1 1 0 2 5 5 3 8 9 5 0 5 4 8 6 4 6 1 1 9 4 7 4 2 8 9 0 6 9 3 0 6 4 1 5 2 3 7 9 +5 9 4 5 1 0 9 9 8 4 8 7 2 5 2 3 8 0 1 4 0 3 6 4 6 5 1 6 9 2 4 1 6 0 7 9 6 6 1 3 5 1 1 7 6 6 5 0 8 8 3 8 7 6 5 6 7 1 3 3 4 3 2 2 0 1 8 6 4 8 6 8 3 8 8 5 6 5 6 3 6 7 5 9 7 4 5 9 5 0 5 0 4 6 8 1 6 7 2 5 +4 0 2 0 8 8 6 5 2 0 7 9 9 4 0 6 6 9 9 7 8 7 1 6 7 7 6 8 0 6 4 2 9 5 9 1 6 6 0 0 9 2 3 7 4 6 2 4 0 8 2 8 3 8 5 6 7 0 6 4 8 1 6 9 7 6 6 7 1 1 3 3 9 3 6 3 0 3 9 3 6 1 1 5 4 9 5 2 0 0 4 1 8 9 7 2 1 7 3 2 +3 7 0 5 1 9 9 0 5 8 1 7 2 9 0 2 0 6 9 3 6 0 6 6 3 8 9 9 3 6 6 6 8 6 4 9 3 3 6 7 9 0 2 2 3 1 0 1 5 2 4 0 6 9 1 2 1 4 1 9 9 0 4 3 7 9 4 9 2 7 8 9 1 7 0 2 2 6 7 4 8 9 3 4 1 2 5 3 8 7 8 3 2 0 6 1 7 4 3 9 +6 4 0 5 5 0 3 4 1 8 2 4 2 8 0 8 5 9 1 9 4 1 8 2 4 9 8 9 7 0 1 9 8 0 9 7 3 7 5 5 2 8 3 7 9 7 1 1 8 9 3 7 4 6 2 9 4 7 7 6 5 1 7 3 1 8 2 8 2 4 0 1 6 4 2 6 2 7 0 8 8 2 1 0 7 4 1 3 8 6 4 5 0 3 6 3 9 2 1 2 +0 1 7 5 2 0 8 3 4 7 9 1 8 3 0 4 4 2 0 5 7 9 3 6 8 6 4 4 5 5 6 1 4 4 0 4 8 2 7 3 3 0 4 9 8 8 4 1 9 8 4 0 9 4 3 3 4 1 3 1 2 0 7 1 9 6 1 9 5 0 4 1 4 6 0 7 6 3 3 5 8 8 9 5 9 0 4 6 4 5 7 8 3 0 0 4 0 1 6 2 +4 6 6 9 5 1 9 6 8 0 3 1 4 4 1 7 0 5 3 7 0 6 4 3 3 5 2 6 0 9 0 5 1 7 1 3 4 7 5 0 7 3 1 0 7 0 8 8 1 4 1 8 6 4 9 1 4 7 7 1 5 1 2 6 9 1 5 1 9 0 5 8 7 4 2 6 3 7 3 1 3 7 2 7 3 9 4 8 5 6 5 4 3 7 9 1 1 4 8 3 +8 2 5 8 7 2 9 8 9 7 2 0 8 0 6 2 9 3 1 0 1 9 1 8 1 6 6 2 0 0 8 1 6 8 3 8 0 6 3 3 1 4 8 8 8 2 0 0 0 9 4 7 5 2 5 1 0 8 0 9 0 6 3 4 6 2 3 3 8 5 9 0 7 3 7 2 2 3 5 3 8 0 6 6 9 6 4 4 3 5 4 3 2 5 3 0 5 9 2 5 +9 7 2 9 7 0 4 5 4 3 1 4 2 5 7 8 3 0 0 1 7 5 7 5 4 4 5 4 0 7 6 7 7 3 2 7 1 0 8 5 0 3 7 8 8 2 1 3 9 5 0 4 6 2 4 8 5 0 7 4 4 9 0 4 5 6 6 4 4 5 9 0 5 0 6 4 8 9 8 7 1 7 5 5 5 7 0 5 7 5 9 8 0 3 9 9 7 9 4 2 +5 1 9 3 3 5 8 7 6 2 9 9 6 0 1 5 0 0 7 0 2 8 7 1 3 2 4 8 2 2 4 9 4 0 6 3 9 4 1 8 1 7 4 0 2 8 0 0 0 8 2 7 2 9 6 6 3 9 8 0 5 6 5 9 3 8 1 1 3 9 1 8 8 6 9 2 2 9 6 3 8 1 9 0 4 3 4 7 8 2 3 9 7 3 1 4 4 5 4 3 +4 3 6 4 7 7 1 3 8 3 5 2 6 3 2 5 6 0 4 2 1 8 2 6 5 0 0 5 3 6 7 4 2 2 4 5 1 4 3 6 3 7 7 5 7 6 8 3 6 0 9 8 1 6 1 2 9 0 4 7 9 1 6 1 4 3 6 6 9 1 2 0 6 5 3 1 6 3 9 9 0 5 0 3 2 0 5 0 0 5 7 2 7 9 2 4 0 0 2 9 +1 5 1 0 1 2 0 5 0 6 2 2 7 2 7 0 5 1 2 4 4 7 7 2 4 2 4 5 1 5 3 4 7 1 4 1 2 1 6 8 4 5 6 5 0 2 6 2 2 3 9 6 6 4 3 2 7 7 1 1 3 9 3 4 5 6 0 0 1 8 2 2 8 7 7 7 8 0 7 1 5 7 6 8 9 6 1 5 0 1 9 4 4 5 7 0 5 2 6 7 +5 1 4 5 3 7 7 6 0 7 0 1 7 5 7 6 0 1 4 8 4 2 4 2 1 3 7 7 5 2 3 8 9 0 7 1 0 2 4 4 3 7 0 1 8 8 2 6 5 6 1 8 8 0 3 1 6 5 4 9 4 8 0 7 0 6 5 2 7 1 2 5 1 6 4 9 2 4 9 6 4 8 0 0 1 1 3 4 6 8 4 8 9 8 4 2 0 0 0 6 +7 8 6 3 2 7 3 5 3 7 4 4 8 9 5 9 1 2 8 7 2 0 6 7 4 8 9 5 4 6 0 9 1 0 4 9 7 4 9 3 6 9 7 1 8 9 0 7 7 1 9 6 5 1 2 1 0 6 1 4 7 0 4 8 6 1 4 4 5 4 3 0 5 6 9 9 9 4 4 3 4 3 2 5 2 1 0 0 1 0 7 7 4 4 5 9 1 0 3 9 +3 4 6 6 1 3 1 4 1 9 4 4 0 2 1 4 5 2 3 9 9 2 3 8 9 8 7 1 3 5 8 4 7 8 2 5 8 2 8 3 4 0 0 0 0 1 0 0 5 2 9 8 0 4 1 0 3 1 3 2 9 4 6 8 5 4 9 7 9 0 6 7 8 9 2 6 7 1 8 4 2 7 1 9 4 8 4 3 4 3 4 4 0 8 7 2 6 0 8 2 +4 7 6 6 7 3 8 4 5 3 0 1 3 1 0 0 4 7 8 9 4 5 2 3 5 9 7 0 0 3 9 3 8 2 8 9 2 0 8 7 3 0 8 8 3 5 1 7 3 2 6 6 1 0 8 3 9 4 4 1 8 0 9 4 1 3 8 7 8 2 2 8 6 4 7 8 5 8 7 5 1 9 5 2 1 0 1 5 5 7 7 1 1 3 9 7 6 1 7 9 +8 6 3 8 8 9 9 6 1 7 7 3 3 4 4 6 4 8 9 1 7 1 2 4 7 6 3 6 5 7 6 3 1 0 1 5 3 8 1 0 5 7 0 6 9 7 7 3 1 0 3 0 4 6 6 3 5 2 5 2 8 6 4 0 2 7 0 2 1 7 0 9 5 4 3 2 9 8 1 2 4 7 8 8 0 1 2 6 2 7 6 5 8 7 8 1 4 8 9 7 +3 9 6 6 0 0 9 2 5 7 9 5 5 8 4 6 3 5 1 7 3 4 8 2 9 7 8 5 1 1 8 7 1 0 8 7 3 9 4 7 3 9 3 9 6 0 2 3 3 3 1 1 9 8 7 8 2 8 6 9 4 9 0 0 3 8 4 3 6 7 9 8 9 1 0 9 2 7 7 8 3 3 7 5 8 5 1 3 9 7 3 4 3 9 0 2 6 8 3 6 +7 6 0 4 3 9 4 0 3 3 2 8 6 8 4 8 5 7 5 7 1 3 1 9 3 0 5 7 4 9 0 2 3 3 6 3 4 5 3 5 2 4 9 8 9 9 5 1 9 4 9 7 8 5 3 6 3 1 0 0 3 0 0 8 3 7 6 2 9 8 0 8 8 8 7 2 8 9 2 9 9 3 5 2 7 7 7 7 6 6 4 7 2 7 3 7 5 3 4 6 +1 9 8 3 4 4 4 7 6 3 6 6 7 9 1 9 9 2 3 0 7 0 4 0 6 2 6 8 9 7 8 8 7 4 4 7 8 8 1 5 0 1 1 1 2 2 7 5 6 6 3 8 3 6 8 7 7 6 2 9 2 5 3 3 7 9 9 1 2 4 6 4 4 8 2 5 9 4 3 4 5 2 4 6 4 0 8 9 4 3 7 5 5 1 6 4 4 1 1 4 +8 5 9 6 8 4 8 4 7 0 2 8 9 9 0 8 0 9 0 9 8 0 4 6 7 7 3 9 2 9 5 0 3 6 5 8 7 8 8 1 0 3 4 8 8 2 7 4 9 2 7 1 7 6 4 5 2 7 9 9 0 1 2 8 2 8 9 2 1 2 7 3 9 5 8 7 0 2 6 8 0 6 2 5 9 3 3 7 0 2 6 4 5 5 2 0 8 2 2 7 +9 6 6 2 9 5 3 8 7 3 2 6 9 6 1 2 1 7 9 3 1 7 8 1 1 9 3 5 4 6 5 2 2 6 4 0 5 0 1 6 8 0 1 4 0 4 1 2 7 0 2 4 7 6 7 9 1 5 6 1 9 0 0 5 1 5 3 8 2 3 9 8 6 6 3 0 6 0 2 3 6 7 0 9 1 6 9 2 9 5 5 0 4 3 0 5 0 4 6 3 +4 1 4 9 7 1 9 8 9 7 2 0 7 6 1 3 9 1 8 0 2 4 6 3 0 9 5 2 9 1 7 9 8 1 6 9 4 3 7 4 0 3 7 9 4 2 1 3 9 7 1 0 7 6 7 2 1 8 1 2 9 4 5 8 9 2 9 7 1 9 5 2 6 9 9 2 2 1 2 4 7 5 5 0 6 6 4 0 7 7 6 4 7 1 9 7 7 9 9 2 +1 2 3 9 9 8 6 9 6 0 5 5 3 8 5 8 2 3 4 2 3 7 2 8 4 0 0 7 8 8 3 3 6 9 5 8 9 1 0 6 0 1 7 5 9 6 8 9 5 8 2 7 1 6 7 2 3 5 7 9 8 7 3 3 1 7 7 1 3 4 8 0 2 1 4 3 3 0 3 5 1 4 5 5 1 9 2 7 3 8 5 1 6 3 0 3 5 3 9 5 +4 1 7 3 9 8 3 5 8 4 1 0 2 8 0 8 4 4 4 0 8 5 9 8 0 1 2 9 1 5 5 6 2 7 5 7 7 1 9 2 8 7 9 5 4 2 3 3 9 2 5 2 8 7 6 4 5 8 5 8 6 8 6 0 9 3 6 7 9 0 5 5 5 9 7 3 7 3 4 3 3 3 1 7 1 4 1 6 3 9 9 0 2 1 3 8 3 5 7 5 +3 4 9 7 4 3 6 3 7 6 6 1 8 0 7 9 3 7 3 8 6 2 0 7 9 0 5 6 7 2 3 9 2 3 8 4 0 5 4 3 5 6 5 2 6 7 5 6 1 4 9 9 0 0 2 7 4 3 9 4 7 1 2 6 0 1 9 2 2 1 9 2 0 6 7 2 7 8 8 2 5 0 8 6 1 9 6 5 7 5 5 3 5 7 1 6 8 9 2 9 +3 6 3 6 8 8 0 9 9 0 7 6 3 3 0 4 8 0 8 6 8 1 8 4 4 7 8 7 6 7 2 3 1 6 4 3 9 4 2 1 1 0 4 5 9 4 5 6 1 8 6 0 6 7 9 7 3 4 4 7 8 7 1 6 1 6 8 3 6 6 3 1 6 7 2 3 8 4 4 9 3 4 0 0 1 4 9 0 4 8 6 5 1 2 2 0 6 8 6 2 +3 0 5 3 9 1 6 5 2 6 4 4 8 5 0 7 0 7 0 1 7 2 6 7 3 7 1 0 1 8 1 2 2 5 3 8 0 8 2 0 6 4 5 0 9 8 8 5 2 4 2 9 7 5 9 0 0 3 7 2 4 7 5 8 3 2 4 7 6 5 8 7 0 4 5 0 2 6 8 5 5 2 9 1 7 4 8 1 8 7 9 2 7 5 0 2 9 3 0 8 +2 2 8 5 8 4 9 9 0 7 1 9 5 3 4 6 7 0 6 8 7 3 8 8 6 1 2 0 0 3 4 0 2 0 3 8 3 1 1 6 4 3 9 5 3 6 8 9 7 8 6 2 5 7 8 3 6 2 0 7 5 9 5 9 6 7 2 2 0 7 5 9 3 2 1 7 1 8 9 6 8 2 3 7 1 5 8 3 7 7 9 4 0 0 7 0 5 3 0 4 +6 0 1 7 5 9 7 1 4 9 8 3 8 5 1 8 5 5 0 1 8 2 4 7 3 2 1 4 6 6 8 2 7 0 5 3 8 7 1 7 6 9 4 0 3 9 2 1 0 7 9 0 0 8 0 8 5 5 8 6 4 0 4 8 0 1 0 7 1 2 5 6 5 3 5 3 8 8 1 2 7 9 2 3 9 5 6 5 9 5 6 0 7 3 6 4 3 1 6 7 +4 8 9 5 9 4 8 4 1 6 5 8 7 1 0 0 5 9 6 9 4 0 4 1 2 9 2 2 9 4 5 7 6 9 5 5 6 8 8 7 0 2 5 3 7 4 2 5 0 6 8 9 9 6 1 1 3 0 1 0 6 1 1 1 9 2 2 8 6 6 1 3 9 8 7 6 2 7 4 9 5 5 6 3 9 2 3 9 3 9 2 4 8 3 0 2 5 2 8 2 +8 1 1 6 1 9 8 2 5 0 7 0 4 8 1 3 7 8 3 3 6 9 3 6 5 5 5 3 6 1 4 8 7 7 2 6 8 2 0 7 0 4 4 9 3 2 3 9 1 5 9 1 1 3 4 9 1 7 7 4 7 7 9 1 3 7 8 1 5 0 0 0 2 2 2 7 1 1 9 9 7 7 0 4 8 7 1 2 2 2 1 3 8 6 5 3 0 7 5 3 +7 2 5 0 9 6 6 1 6 7 8 5 5 6 5 8 5 0 7 6 9 4 1 9 8 3 2 2 9 2 8 9 0 8 2 8 1 9 6 9 1 1 9 2 0 4 1 0 2 2 6 4 7 5 6 3 7 2 8 1 8 8 4 6 3 2 1 2 3 7 7 0 5 8 0 7 3 8 3 0 9 7 9 1 8 2 7 4 0 2 6 0 1 6 1 7 2 0 0 0 +7 3 0 2 2 0 5 1 0 0 1 5 6 9 0 3 4 8 9 1 6 8 3 0 6 5 2 6 7 5 2 3 5 5 3 6 2 4 0 7 1 9 2 3 7 8 4 8 1 1 5 6 9 4 1 5 4 6 5 5 6 2 0 1 6 8 3 8 1 8 8 9 8 6 9 9 3 2 4 9 5 5 3 3 7 6 8 0 3 8 0 4 9 1 8 5 8 0 0 8 +7 3 1 1 9 9 5 8 9 2 2 3 9 6 4 6 8 6 8 1 8 5 1 7 4 5 5 8 4 4 3 1 9 2 1 1 7 3 9 4 6 4 6 6 3 4 0 3 4 3 2 4 2 0 2 4 4 9 5 0 6 8 6 6 0 8 4 1 5 4 6 5 5 9 7 8 2 9 2 0 1 2 3 0 6 8 3 5 0 4 4 3 3 5 9 2 3 7 5 9 +6 8 5 2 4 7 2 4 7 5 8 1 2 4 4 1 6 9 5 9 4 5 5 8 3 1 8 1 3 7 6 8 3 1 3 0 1 0 1 5 0 7 0 9 8 1 7 5 6 2 9 5 0 3 5 5 9 9 7 2 5 1 2 7 7 6 5 3 1 4 1 5 0 8 1 3 7 3 9 4 2 0 3 8 8 4 6 4 7 5 1 5 4 0 2 7 2 0 4 1 +2 8 6 9 2 4 1 6 5 4 4 4 2 4 2 8 9 4 5 4 8 2 2 9 9 3 2 5 5 7 1 2 9 1 8 0 0 0 6 2 0 5 8 0 5 5 9 3 3 2 0 6 7 5 4 7 7 8 8 9 5 0 7 5 5 7 9 0 4 3 7 3 7 1 6 3 1 1 1 0 3 1 9 7 6 4 7 7 9 6 8 4 8 6 9 3 4 0 9 0 +8 5 3 2 1 7 2 0 6 2 4 2 5 6 6 1 6 4 4 1 2 7 7 2 1 6 9 1 7 2 7 2 0 1 2 3 5 2 9 6 2 5 5 8 0 0 9 9 9 7 4 3 3 9 8 2 5 0 6 6 0 0 3 5 0 2 3 1 4 3 4 5 8 3 9 0 1 1 3 3 4 7 9 8 2 8 5 2 3 4 7 4 0 9 0 5 9 5 9 9 +2 8 8 1 0 8 3 1 3 9 5 3 3 6 4 9 8 8 9 0 3 6 1 9 3 8 8 8 4 0 2 0 2 1 5 1 4 5 6 6 4 0 2 6 2 5 6 7 0 5 9 0 3 6 5 4 8 6 7 0 9 3 5 6 7 9 8 5 0 2 3 2 1 4 4 6 1 0 3 4 8 3 7 5 4 4 5 0 1 5 8 5 5 0 6 2 9 3 0 1 +1 2 8 7 0 9 3 5 9 2 1 1 8 0 4 6 8 3 8 1 1 7 5 0 3 4 0 5 2 6 7 8 4 7 2 0 7 8 3 9 4 1 3 2 6 9 5 5 3 2 2 0 9 1 6 4 9 9 7 0 8 4 3 6 5 4 8 2 5 4 2 1 7 3 7 9 6 8 4 3 8 6 1 9 1 5 5 9 9 1 0 1 6 5 3 8 3 2 5 6 +9 9 5 4 0 3 4 7 9 9 0 7 8 7 2 8 5 6 4 9 6 4 5 5 8 7 7 0 1 3 3 1 6 6 6 8 7 0 8 9 0 9 0 6 1 0 5 5 3 9 3 5 2 1 8 0 4 6 1 1 8 5 4 8 8 4 0 9 3 2 2 9 1 0 8 2 6 7 7 7 3 7 3 1 9 5 9 8 6 7 8 0 1 8 2 5 1 1 9 5 +4 7 7 6 1 5 7 1 9 5 8 7 2 7 9 6 9 5 0 7 7 9 3 7 4 8 1 3 4 2 7 5 4 4 5 4 7 9 2 0 5 9 9 1 7 7 6 9 4 5 7 9 0 2 6 7 0 3 5 1 9 6 9 4 1 6 8 5 9 0 1 1 5 8 7 8 9 6 8 8 1 4 0 7 8 9 0 1 1 8 7 0 0 6 4 6 0 4 3 1 +7 2 3 5 3 9 6 8 6 0 8 1 8 1 9 1 6 1 8 9 6 6 9 7 3 0 1 6 4 9 1 6 3 3 7 7 0 8 0 6 1 7 4 3 5 7 4 7 1 3 3 0 4 0 0 2 4 8 6 0 9 8 6 0 6 9 5 9 4 4 5 8 2 1 4 0 2 8 3 6 3 3 1 1 9 8 1 8 7 7 6 2 5 8 3 6 4 1 1 4 +0 6 9 4 6 2 4 1 8 8 6 6 0 2 0 0 9 0 0 8 5 2 2 7 9 2 8 5 1 7 2 7 6 5 7 4 1 2 4 2 7 8 6 6 0 5 5 7 0 8 9 0 6 9 1 7 9 3 3 3 3 9 4 0 3 9 4 1 7 3 2 8 9 6 2 5 5 5 3 4 9 8 5 8 8 6 9 1 1 2 1 1 3 0 9 4 4 0 7 2 +4 9 8 9 2 7 5 2 2 0 3 7 5 5 1 6 1 2 8 2 4 9 9 7 0 4 6 4 6 1 0 2 7 7 5 1 4 7 9 1 4 9 3 2 2 8 4 2 7 9 9 5 3 1 3 6 4 2 1 1 4 9 6 9 6 1 6 5 5 8 3 9 9 6 9 7 9 7 0 5 3 7 3 5 3 3 2 2 9 9 6 0 9 1 8 5 6 9 9 2 +3 1 3 3 6 8 8 4 1 0 4 2 1 8 9 7 2 8 0 9 6 8 2 0 2 5 0 5 7 0 6 0 0 1 0 7 6 0 9 4 3 1 6 0 3 9 2 3 2 2 3 6 7 1 3 2 9 3 7 0 3 7 0 2 2 1 6 4 2 3 6 0 9 7 8 4 9 1 9 2 4 7 9 6 6 8 5 4 8 6 3 6 3 2 9 0 5 3 9 1 +7 4 3 2 2 6 5 6 0 3 0 5 6 7 9 3 0 9 7 3 9 5 6 8 1 9 2 3 1 2 9 2 3 7 7 4 0 3 1 8 1 5 2 2 9 1 2 1 2 8 0 8 4 3 4 6 6 2 0 3 1 6 9 1 7 4 1 8 6 5 9 5 1 8 5 5 5 2 4 8 0 0 7 5 3 9 1 5 1 7 4 6 3 6 9 6 2 6 0 5 \ No newline at end of file diff --git a/03-MatrixAddition/matrices/matF b/03-MatrixAddition/matrices/matF new file mode 100644 index 0000000..5ccca09 --- /dev/null +++ b/03-MatrixAddition/matrices/matF @@ -0,0 +1,101 @@ +100 100 +5 5 3 7 1 8 3 5 2 6 6 8 3 9 8 3 5 1 2 9 0 1 2 5 2 4 4 7 0 0 9 0 8 2 7 2 1 1 4 8 6 7 2 8 1 7 0 3 6 3 3 4 2 5 6 1 0 6 5 8 2 5 1 0 2 6 4 2 8 5 9 4 8 2 2 2 8 6 2 7 1 2 1 7 1 4 7 4 6 4 3 8 1 5 7 6 0 7 7 7 +8 9 1 2 1 7 3 8 8 0 5 5 0 7 7 0 6 8 8 5 8 8 9 6 5 6 4 6 9 8 1 0 1 1 2 9 4 1 6 0 0 2 2 3 3 1 9 4 9 7 7 2 7 5 3 5 4 3 0 8 7 6 4 9 3 5 4 6 4 5 6 6 4 1 7 9 1 6 2 4 8 9 9 6 8 2 3 3 0 9 3 0 4 4 6 2 9 4 0 5 +0 9 5 6 6 1 9 6 5 7 9 2 0 3 1 2 6 4 3 8 6 1 7 6 3 6 4 9 0 0 4 0 5 3 7 3 1 9 0 1 2 3 1 4 5 3 7 9 7 0 0 0 6 4 5 9 2 2 6 5 3 1 7 8 4 9 5 4 6 0 8 8 1 7 2 9 7 2 6 5 7 8 0 1 1 3 5 2 8 6 1 9 4 2 4 9 4 7 6 1 +0 9 1 3 7 1 4 3 3 0 6 7 1 0 1 6 5 2 3 7 8 9 8 7 3 0 9 2 2 1 4 5 3 0 9 1 7 0 9 4 7 2 9 0 7 9 4 1 2 8 1 4 4 7 0 0 6 0 8 1 2 7 8 9 4 6 0 6 2 7 8 2 2 0 9 6 7 3 7 1 7 6 0 1 0 2 9 4 7 5 9 3 1 9 7 2 9 8 3 9 +3 2 2 6 4 4 1 9 2 3 9 3 7 8 3 8 8 6 1 6 1 0 2 0 6 1 0 2 7 5 3 8 4 6 0 9 5 2 5 5 2 7 4 9 1 2 1 0 7 1 5 4 3 5 0 6 4 5 0 3 7 9 4 3 5 8 8 3 7 3 7 8 8 1 4 1 2 1 4 5 5 4 2 3 0 9 5 8 9 9 2 7 0 0 3 9 8 4 7 6 +2 6 1 2 7 7 0 8 1 9 9 4 9 2 3 0 1 6 5 6 2 1 6 8 7 6 3 7 7 8 1 1 2 0 0 8 5 2 7 9 9 4 1 8 6 7 4 9 7 0 4 2 9 0 9 8 2 7 2 9 4 7 9 6 1 1 2 2 4 3 2 3 9 0 9 5 8 2 9 4 8 8 8 4 0 6 8 2 9 5 9 2 2 0 0 7 7 8 0 8 +9 9 6 7 3 0 1 1 5 4 1 0 0 6 5 7 6 9 7 1 7 7 1 0 7 6 1 8 7 8 5 9 3 8 8 0 0 8 1 6 0 4 0 9 6 4 5 4 1 8 4 6 6 3 5 0 1 5 5 9 1 0 4 9 5 4 1 1 2 9 5 4 0 4 6 8 4 9 7 0 9 9 9 8 0 6 7 3 2 7 7 6 9 0 4 7 2 1 8 6 +2 2 9 3 0 2 1 4 0 1 5 3 5 4 8 2 7 4 8 8 3 4 3 7 9 4 3 5 7 0 9 4 9 9 9 6 3 7 3 0 0 0 6 4 1 9 9 7 9 8 6 5 2 2 6 0 9 0 6 7 1 0 1 7 4 7 2 9 9 7 1 1 4 6 9 2 6 9 3 6 5 6 4 2 4 1 8 0 0 8 6 3 6 9 9 8 9 0 6 0 +5 0 6 5 2 8 6 0 8 8 0 6 0 0 7 4 9 9 8 0 9 7 7 2 8 8 3 4 8 4 1 1 4 4 7 9 8 0 3 5 6 9 3 7 5 2 6 9 5 6 0 1 9 9 4 7 2 0 6 7 8 1 5 8 1 6 4 5 7 0 6 6 3 6 6 7 7 0 8 9 1 8 5 9 1 0 1 3 6 5 5 1 1 6 8 2 1 4 9 0 +2 3 0 5 1 3 0 9 1 1 6 6 2 8 8 9 1 8 5 1 1 0 9 4 9 5 9 2 3 7 1 8 5 8 3 5 3 7 2 0 4 2 5 5 5 2 1 7 6 7 9 3 2 7 5 2 1 3 8 4 1 7 9 0 6 6 5 4 6 3 0 9 0 8 4 8 0 8 0 0 7 9 6 9 4 1 1 9 2 9 7 2 3 4 6 8 0 4 5 7 +3 0 9 8 2 7 3 3 4 4 4 8 3 4 9 4 3 5 3 2 4 1 0 1 0 4 9 2 6 9 8 4 8 3 7 4 3 8 0 4 9 5 4 2 1 2 7 8 1 1 5 7 2 7 0 4 4 6 9 5 0 6 7 6 7 6 4 3 9 7 6 4 4 9 0 2 7 2 5 8 3 5 0 4 2 5 0 5 6 9 3 2 7 3 9 1 2 5 0 0 +9 9 7 4 3 8 5 5 9 8 6 2 7 2 1 0 2 5 9 5 5 6 4 1 4 0 1 1 1 7 4 5 6 2 0 5 3 7 1 2 7 4 7 7 2 7 8 8 2 0 7 6 6 7 6 5 0 5 6 2 5 3 0 2 3 7 0 7 3 7 9 0 4 6 2 9 0 4 9 0 8 8 2 1 0 5 2 1 9 6 5 2 9 0 2 5 3 5 3 5 +3 5 3 2 2 9 3 2 9 4 9 1 2 8 9 3 1 8 9 0 7 3 5 5 9 5 3 3 0 1 2 0 4 8 7 3 3 3 6 7 6 7 5 8 4 8 0 4 6 8 9 7 3 4 3 0 6 4 2 8 0 5 2 0 8 9 1 2 1 1 1 0 1 5 4 6 5 5 4 9 9 9 9 2 2 3 8 6 4 7 8 8 9 2 4 1 3 1 9 0 +0 9 2 3 5 3 5 5 4 4 2 2 5 6 0 4 2 7 8 9 1 8 2 1 0 3 4 6 2 5 8 9 1 1 1 3 1 8 4 7 4 8 2 2 4 9 5 9 2 1 2 1 7 8 2 4 9 1 6 1 6 8 0 0 2 6 0 1 4 2 2 7 4 6 2 3 8 3 0 4 9 7 1 5 5 0 0 0 4 7 3 7 9 3 4 6 5 6 8 4 +1 2 2 9 2 4 3 0 9 7 4 3 1 3 0 1 2 9 7 5 9 8 8 1 7 1 9 6 3 1 2 8 7 0 0 5 5 6 1 6 6 8 8 9 2 8 6 5 7 0 7 1 0 9 6 1 1 7 8 6 6 7 4 6 5 1 4 0 6 0 8 9 7 6 4 6 8 4 1 0 5 2 5 5 3 7 9 8 6 2 1 7 5 3 2 5 0 5 4 5 +0 0 0 5 1 5 6 1 9 0 4 7 7 5 8 9 8 6 9 3 6 3 8 3 3 1 2 0 7 3 0 7 0 5 9 2 8 3 0 5 4 0 8 8 1 7 5 7 0 9 3 1 4 8 3 0 0 5 9 7 5 6 3 2 0 9 4 9 4 5 3 1 2 6 5 6 6 2 9 3 6 4 1 7 5 9 4 1 4 5 4 0 5 4 0 9 7 5 8 5 +5 1 0 9 9 7 0 7 9 6 8 7 2 8 4 0 5 0 7 3 9 8 0 0 1 9 3 5 8 7 4 8 8 2 4 6 4 6 0 9 4 5 2 2 5 7 9 6 1 1 3 2 9 9 2 9 7 7 7 6 9 6 4 5 7 3 0 1 8 7 6 5 4 4 4 3 1 2 1 1 9 2 2 6 5 1 2 3 5 2 6 3 0 5 1 1 4 1 3 0 +1 5 2 2 5 5 8 6 9 0 3 1 0 9 8 4 4 0 0 2 7 3 4 8 2 3 4 3 9 0 4 4 1 7 4 3 6 2 6 0 7 0 8 2 6 8 4 3 8 1 5 3 4 9 5 1 2 5 9 9 8 1 5 6 6 4 8 4 1 6 7 6 5 9 3 5 7 2 2 3 8 8 7 0 3 9 0 4 3 9 9 5 8 8 4 1 8 2 7 8 +2 1 4 2 8 1 4 6 2 7 1 6 2 6 2 9 4 3 4 3 6 1 1 5 2 2 1 2 8 0 1 8 4 2 5 3 1 3 8 8 6 3 7 4 0 6 9 9 1 0 4 6 9 7 6 8 1 9 4 9 7 4 9 2 9 9 3 7 9 7 2 8 7 8 5 0 1 5 6 3 1 2 2 5 3 9 9 8 7 3 6 1 7 4 5 3 3 1 8 6 +4 0 5 3 7 9 5 8 6 2 9 9 4 9 3 6 4 1 6 1 2 1 1 5 9 9 2 3 0 8 5 2 7 8 4 4 9 4 0 8 2 8 5 2 0 1 8 3 5 1 2 2 9 7 9 5 3 1 7 4 6 3 9 9 8 3 8 5 5 7 5 7 9 2 2 3 1 0 0 6 9 9 2 1 1 7 1 5 3 8 3 0 0 7 3 1 8 8 4 0 +9 0 8 5 2 7 4 4 1 6 5 0 1 5 4 9 2 2 7 1 3 2 4 0 2 5 0 2 5 0 4 1 4 5 0 7 3 8 6 2 5 7 5 3 1 4 0 4 5 2 1 7 9 0 2 1 9 1 8 0 7 5 1 2 6 5 9 2 3 5 6 0 7 4 5 3 1 6 0 7 0 4 4 7 0 4 8 2 4 1 6 1 1 7 5 5 1 9 6 9 +1 6 1 9 4 2 0 5 3 4 9 8 8 3 3 1 0 4 5 1 9 0 6 9 5 8 4 6 3 7 1 5 5 0 6 7 3 1 6 6 3 4 4 4 2 8 9 2 4 7 7 6 8 0 9 9 6 3 8 5 4 1 1 2 0 9 7 4 7 8 0 3 1 6 0 9 9 4 3 5 1 3 3 4 1 9 1 2 4 2 7 7 9 3 0 8 2 0 6 4 +7 5 2 4 5 2 0 9 8 8 3 5 3 5 8 0 1 7 3 8 3 8 9 4 8 4 2 8 2 2 2 9 8 5 3 7 3 1 5 7 4 8 5 3 2 1 6 8 6 4 8 9 9 5 4 8 5 1 9 9 8 6 9 6 7 1 4 9 0 7 8 7 6 0 9 3 1 8 5 2 2 1 1 3 5 6 3 0 4 3 4 7 5 7 4 0 3 6 9 6 +0 0 4 2 2 0 6 6 8 1 8 4 1 9 5 0 3 0 3 3 8 9 8 5 9 7 7 6 5 8 5 8 9 4 7 4 1 2 6 6 6 9 6 2 0 0 7 4 7 0 2 4 0 1 7 8 2 2 9 2 5 2 5 9 4 8 5 5 6 7 4 3 2 8 3 3 2 3 7 8 4 9 6 3 3 8 4 1 8 4 0 1 5 1 9 8 8 5 9 5 +6 3 5 0 8 5 4 2 7 3 5 8 6 9 6 4 2 2 1 8 9 8 8 8 4 5 0 8 7 2 6 3 2 9 7 7 7 4 9 6 9 2 2 8 0 2 7 4 7 2 6 6 3 0 2 3 1 6 6 2 0 6 3 1 4 3 5 4 5 7 9 3 2 4 4 3 0 6 1 1 9 3 5 0 1 1 4 3 0 2 5 2 2 3 2 9 0 4 8 9 +2 6 1 1 0 6 2 0 9 3 3 2 8 9 7 6 8 5 6 5 9 5 7 6 6 6 9 1 2 8 0 9 2 4 1 8 6 4 4 8 9 7 3 1 0 9 7 7 4 5 6 6 3 9 0 7 2 3 4 4 5 7 2 2 3 2 7 3 6 0 9 9 0 4 1 8 2 2 8 7 8 3 5 2 6 5 4 5 5 7 0 9 3 2 8 5 5 6 3 9 +5 7 5 0 1 9 3 0 2 8 5 3 0 3 7 5 6 7 1 2 4 8 5 1 2 0 2 1 1 1 8 9 4 9 7 7 0 2 8 4 2 0 8 6 9 7 7 0 5 6 4 2 1 6 0 1 2 6 3 8 8 4 1 0 9 4 0 2 7 7 9 1 6 6 6 6 6 8 7 3 9 9 7 8 5 3 7 3 0 2 0 5 5 4 0 0 5 9 3 3 +0 9 9 3 1 1 1 2 7 2 6 5 3 9 6 6 1 6 8 0 4 8 2 2 0 5 9 5 0 2 2 5 5 0 2 9 7 6 6 5 1 1 6 6 4 6 6 6 6 8 1 1 4 7 7 7 7 3 3 4 9 7 7 4 2 8 5 1 9 8 8 9 5 5 9 9 9 3 7 1 5 0 0 1 4 1 2 8 4 4 3 7 2 6 5 4 8 3 9 5 +3 8 8 5 3 6 5 3 5 7 7 2 6 3 7 1 1 5 1 7 4 3 6 7 3 4 7 3 1 9 8 1 3 9 7 3 9 7 6 2 2 4 7 2 2 0 4 8 4 5 3 7 7 9 1 2 4 9 7 9 9 6 3 6 8 7 9 7 3 5 7 9 5 8 8 2 5 4 2 7 4 6 5 7 5 9 4 5 8 2 9 5 4 8 0 5 7 5 0 4 +6 8 3 7 4 5 5 3 7 7 1 4 8 2 0 0 0 7 7 8 6 6 7 0 0 5 0 3 7 2 5 7 1 3 3 5 9 4 6 4 5 5 2 7 2 4 6 3 7 8 8 0 0 8 9 1 4 1 8 5 6 4 1 3 2 0 2 7 4 2 2 0 4 2 8 9 4 1 3 0 5 5 7 7 1 7 2 5 7 9 9 1 9 5 3 8 1 3 3 8 +4 2 7 8 3 5 2 8 0 1 7 8 0 0 7 5 4 9 6 8 7 9 6 9 0 7 1 7 3 7 2 5 7 8 9 9 6 1 9 8 3 3 4 2 6 5 2 7 5 6 5 3 5 5 3 1 6 6 8 4 8 7 3 3 4 6 0 4 8 5 1 7 8 7 7 6 3 2 9 0 8 7 4 2 9 6 7 7 2 3 2 4 8 7 4 2 5 7 4 0 +9 6 9 8 9 0 7 7 0 5 3 1 6 7 4 4 2 4 0 1 0 2 7 1 9 4 5 6 0 2 7 8 9 8 2 6 9 0 6 6 2 8 1 3 1 4 3 8 2 0 8 3 8 9 9 3 0 0 1 2 6 4 5 8 0 0 6 5 4 5 9 8 6 9 8 2 0 7 5 6 3 0 0 9 8 5 3 3 0 8 2 9 8 2 3 3 3 5 2 3 +0 6 9 9 0 4 2 2 5 4 1 4 1 1 8 0 1 2 6 8 2 1 3 7 4 7 5 2 5 4 6 8 4 8 9 3 1 4 7 8 3 1 8 8 6 7 0 3 1 5 5 9 1 7 3 2 5 7 0 8 2 4 0 8 5 5 0 8 1 8 6 9 5 1 5 4 1 9 5 4 2 0 7 1 7 4 8 2 6 9 6 8 3 2 1 8 6 4 5 1 +0 5 4 0 6 2 8 3 0 0 1 5 6 4 1 0 3 7 2 1 0 8 2 6 8 6 7 0 2 0 5 1 6 7 9 6 9 6 9 5 1 7 1 0 1 8 6 6 9 5 8 1 8 2 9 1 7 3 7 2 1 8 2 7 0 8 3 7 4 6 1 6 5 2 0 3 0 9 6 0 8 8 6 2 0 4 5 2 8 6 9 6 8 2 3 7 5 3 2 2 +6 0 2 3 6 4 9 3 3 0 7 8 2 5 8 2 2 4 2 1 4 3 2 0 5 8 0 1 9 8 2 5 6 5 4 9 3 9 5 1 7 5 7 2 3 8 6 0 8 0 0 0 8 5 3 6 4 0 8 5 4 9 4 2 9 4 3 3 2 4 0 5 4 2 4 4 9 0 8 4 3 9 4 6 9 6 2 6 9 5 1 4 6 5 0 8 3 9 4 3 +0 1 2 8 0 3 3 8 7 1 1 0 9 0 1 1 7 1 1 5 1 5 0 3 5 1 8 2 4 0 6 5 0 9 7 0 1 5 6 1 0 3 2 9 0 3 0 0 1 9 5 6 0 2 0 8 2 4 1 5 0 1 6 8 3 8 4 8 4 1 9 7 4 6 4 3 2 7 9 9 6 1 5 6 8 2 8 9 0 7 6 1 2 4 9 4 7 4 6 5 +6 8 0 3 8 0 6 6 5 1 1 6 7 6 2 1 7 0 7 0 8 9 5 8 6 3 4 0 9 5 2 9 8 5 4 7 5 1 3 1 3 5 0 8 1 9 1 2 8 4 8 7 2 3 5 8 9 3 7 8 5 3 5 7 1 3 9 6 0 1 1 1 6 4 2 6 1 3 4 5 0 6 5 2 5 7 3 0 5 9 4 5 4 3 1 8 9 5 8 0 +4 6 7 8 9 3 8 7 2 2 9 1 7 4 9 4 8 8 8 5 6 6 4 2 3 3 8 6 7 0 8 2 4 6 2 9 2 6 9 1 9 8 7 6 5 3 1 4 9 9 5 5 2 3 5 4 0 7 4 3 8 6 7 1 6 3 7 0 4 7 7 1 8 4 3 9 0 7 2 8 2 0 2 7 0 2 9 8 3 4 8 9 1 6 6 4 0 1 2 5 +7 9 5 9 3 8 2 1 4 0 4 0 3 8 0 0 5 2 2 9 2 1 9 4 3 7 1 8 0 5 4 8 8 9 8 6 3 9 3 7 2 0 0 9 7 2 7 6 2 6 9 7 0 8 6 9 7 2 9 1 6 3 4 3 5 6 7 6 7 9 5 9 4 1 3 0 1 0 2 9 0 3 4 1 7 8 2 4 8 2 4 4 3 5 6 7 8 7 2 6 +3 2 4 1 7 1 5 4 0 0 6 8 1 1 9 0 9 0 7 5 3 4 5 2 0 6 2 6 0 8 8 4 7 0 2 4 1 0 7 5 9 9 1 4 3 8 5 2 6 0 3 5 0 6 1 7 9 1 3 5 3 8 1 9 0 4 7 8 1 8 0 4 7 8 1 5 8 2 9 9 6 0 2 9 6 2 5 1 5 8 1 9 9 6 6 7 3 8 2 7 +0 5 9 2 3 4 1 0 2 1 1 4 1 0 4 3 7 3 2 8 2 5 5 8 1 6 7 0 0 8 5 5 6 6 3 4 5 8 6 3 5 8 5 8 6 1 4 7 4 0 9 8 4 3 8 6 7 0 6 1 1 4 7 9 1 9 2 4 9 7 7 9 2 9 7 4 9 1 6 7 4 9 1 7 1 2 3 0 2 0 9 3 9 1 1 7 5 1 4 0 +2 2 8 7 3 4 2 9 8 7 6 8 2 3 3 2 0 0 8 4 8 9 2 1 9 9 4 8 9 1 6 9 0 4 5 9 1 3 7 6 1 1 7 0 2 0 3 9 0 8 6 8 0 6 3 7 4 6 5 6 2 7 4 6 1 1 6 5 1 8 7 2 8 9 2 0 7 1 0 2 5 4 3 1 6 0 2 4 6 8 1 5 4 5 8 1 2 4 9 3 +6 9 9 4 1 0 6 1 8 5 9 5 7 5 9 5 7 3 2 5 7 1 4 5 6 1 6 8 1 8 2 5 5 6 6 4 7 8 3 0 8 9 6 7 8 3 3 3 8 2 8 1 5 1 1 3 8 6 6 4 4 4 4 9 6 8 2 5 0 5 7 2 8 4 1 0 4 2 8 4 4 3 1 9 6 9 0 5 5 5 0 6 7 2 4 2 8 0 7 4 +6 6 4 5 7 0 0 9 6 8 0 0 6 6 0 9 8 1 3 1 2 0 0 5 7 0 3 1 5 4 7 1 2 3 2 1 1 2 2 1 4 5 4 1 7 4 1 6 1 4 3 7 8 2 8 9 1 1 0 8 4 7 1 5 0 1 9 0 7 4 7 5 5 0 2 3 7 5 1 7 6 4 0 7 4 2 3 4 3 3 7 8 1 4 8 4 5 2 9 8 +0 0 9 1 0 5 5 6 0 2 5 3 4 6 9 4 3 7 1 0 3 5 0 0 7 9 1 8 3 9 0 4 1 5 1 1 3 4 8 7 1 4 2 8 3 9 3 5 9 7 3 3 0 8 7 8 3 3 5 9 9 3 5 0 6 8 5 8 4 3 5 7 5 3 3 5 7 4 9 6 7 5 1 1 4 2 1 2 2 4 1 5 8 2 9 4 8 6 8 5 +0 1 2 3 7 3 5 1 7 7 6 9 5 6 3 6 4 6 2 3 6 5 8 2 6 7 8 7 1 6 0 8 6 5 7 0 3 4 4 4 6 2 1 4 4 1 0 8 2 8 4 8 9 5 2 5 1 2 9 2 2 2 1 4 2 6 3 7 7 4 9 4 6 8 5 1 8 1 8 1 6 3 6 8 8 4 3 0 6 2 0 6 1 7 9 5 2 7 7 9 +5 4 4 3 3 0 2 7 2 5 7 1 6 2 4 3 0 4 1 3 7 4 5 7 0 9 8 6 8 2 0 0 8 4 7 9 2 3 5 1 8 9 4 0 7 8 0 2 6 5 4 4 2 3 3 3 7 3 2 2 2 5 0 0 3 4 0 3 3 4 9 4 1 4 8 7 6 8 0 1 0 4 0 5 9 3 5 2 0 0 7 9 4 0 6 5 8 1 7 8 +8 5 7 3 4 0 8 5 1 6 2 1 4 3 6 6 4 3 6 4 7 5 8 7 3 1 1 1 8 1 8 2 1 9 7 1 7 7 6 1 6 4 9 7 8 8 5 7 1 2 1 7 2 9 3 5 6 5 0 3 9 7 8 8 8 0 2 7 8 1 0 7 6 0 1 7 8 1 3 8 2 4 9 7 0 4 5 8 6 0 0 0 8 6 5 1 9 0 2 2 +9 9 7 7 7 6 8 3 3 5 9 9 4 4 8 5 6 0 3 6 9 1 3 4 8 7 1 6 8 7 6 0 4 8 4 6 0 9 1 2 2 0 6 1 1 0 9 5 4 2 5 0 7 1 1 1 8 5 0 3 6 3 9 5 6 0 6 6 5 4 7 5 0 0 4 0 3 6 4 0 6 6 2 2 4 8 1 7 8 7 1 7 1 0 2 8 0 2 9 0 +2 4 5 1 1 6 9 4 3 6 5 0 4 7 7 0 4 3 4 6 0 5 6 1 0 0 0 3 0 9 2 3 0 2 6 4 8 2 1 4 0 1 3 2 3 1 8 6 0 8 3 9 9 9 7 9 0 5 7 3 2 0 0 2 9 7 1 7 6 8 9 5 4 4 0 1 8 1 2 7 1 9 1 2 6 4 1 5 5 5 5 6 3 1 8 1 3 0 9 2 +4 4 5 4 1 4 4 1 7 1 6 6 0 4 8 1 7 6 8 6 6 2 0 6 0 4 5 2 6 8 2 4 1 6 2 8 9 6 6 8 2 1 6 3 3 5 3 9 4 4 7 6 6 7 0 4 4 7 7 9 4 2 9 1 2 2 8 6 2 7 9 9 9 7 3 7 1 8 3 7 7 6 3 9 7 5 5 8 6 2 2 0 3 1 2 5 0 9 1 4 +0 6 1 0 9 4 6 0 7 0 9 7 4 0 8 3 0 5 8 4 7 9 3 0 6 0 1 4 3 7 8 9 3 9 7 8 0 1 2 9 2 3 3 1 9 2 2 6 8 4 2 3 4 9 8 7 1 5 5 0 2 1 0 2 1 0 5 8 0 4 3 3 2 6 3 4 3 8 1 4 1 7 4 6 7 2 9 3 7 5 2 0 7 6 4 6 1 4 6 5 +0 0 9 1 0 6 3 4 0 7 3 9 0 6 4 0 3 1 1 3 1 0 3 4 4 0 8 6 8 5 5 6 7 9 1 7 6 1 9 3 6 6 8 5 9 3 0 1 4 2 3 5 5 6 1 9 2 0 3 8 5 5 7 0 0 8 2 5 1 3 9 1 9 5 4 9 4 6 8 4 9 6 5 9 2 3 9 3 8 1 9 7 8 5 5 8 4 4 8 0 +9 3 0 8 7 3 4 0 3 9 9 1 4 6 4 8 0 8 0 8 0 1 9 2 8 0 9 8 7 1 7 0 7 9 0 2 8 3 0 9 9 0 2 3 9 8 6 0 1 9 7 2 5 5 8 6 7 8 5 2 6 8 0 7 8 1 6 1 9 5 7 7 9 0 9 1 8 5 2 9 1 6 6 9 7 5 3 5 1 5 8 5 1 6 7 5 8 4 2 6 +8 2 6 9 9 5 8 8 4 6 3 8 9 4 9 9 2 8 6 5 2 8 0 0 2 8 9 2 5 2 9 1 8 9 3 8 8 4 0 5 2 0 5 8 7 1 7 5 4 0 0 6 2 3 5 7 2 3 3 8 9 3 9 9 9 0 2 3 7 9 8 2 9 8 7 2 3 2 5 9 0 7 6 1 7 6 5 0 6 5 3 4 6 0 2 3 2 6 1 0 +6 4 2 6 7 0 5 6 0 2 8 7 9 9 5 7 4 7 5 4 1 5 5 4 6 7 4 7 0 9 4 6 6 5 7 6 8 7 9 7 8 0 5 0 1 2 7 0 5 0 6 3 9 4 2 4 4 5 4 4 6 4 1 0 8 5 5 3 0 3 6 3 2 2 0 1 8 6 8 0 2 2 4 9 6 7 8 9 2 0 8 8 0 7 4 0 8 5 1 2 +8 6 1 0 5 0 1 9 1 0 1 2 4 2 5 6 3 9 1 6 8 6 7 1 0 2 2 1 9 2 1 8 8 0 8 0 3 8 3 4 2 9 1 9 1 8 5 5 4 0 1 9 9 1 6 2 3 0 6 9 7 4 7 5 7 9 3 6 3 1 9 0 1 4 8 5 2 5 5 7 7 6 3 8 0 0 7 8 8 4 7 0 7 0 8 9 2 2 2 4 +2 4 9 2 8 7 9 8 0 3 0 9 0 5 3 6 7 2 0 4 6 0 0 6 4 9 3 7 5 8 7 0 5 7 8 3 4 8 3 4 7 4 8 9 8 2 8 3 0 4 6 9 1 8 0 8 3 2 1 0 7 9 3 6 2 0 3 4 4 3 4 3 4 0 9 1 0 9 2 7 5 3 1 3 6 5 1 9 6 5 6 9 9 7 5 9 5 6 5 1 +0 7 8 9 3 3 3 8 0 5 4 0 3 1 8 6 0 8 6 0 7 3 6 6 5 8 4 7 9 7 8 5 8 3 6 5 1 2 0 4 1 4 5 0 6 6 9 6 9 3 5 1 5 3 0 5 7 7 9 4 0 0 7 9 2 3 7 7 3 4 8 3 0 5 0 8 9 3 8 2 7 6 3 0 8 2 2 5 1 9 7 6 4 6 7 3 2 7 9 2 +8 5 9 5 6 7 4 8 6 4 3 9 7 3 8 6 1 3 0 8 8 3 0 6 9 5 5 1 3 5 0 8 9 2 0 0 7 2 7 7 0 6 2 8 3 6 9 6 4 8 0 9 8 8 2 1 9 4 1 4 0 8 0 7 0 7 5 3 9 2 9 8 6 5 2 0 3 9 8 6 2 0 0 8 9 5 2 4 9 0 9 3 1 8 1 3 2 6 9 5 +9 7 4 4 4 1 1 5 7 8 1 4 7 1 0 3 7 2 8 7 9 2 9 3 7 7 0 7 2 6 6 9 1 9 3 6 9 9 7 0 4 4 2 7 2 2 4 8 9 7 4 1 6 7 6 3 8 7 9 6 6 6 3 7 5 4 1 9 6 5 0 5 1 2 1 7 9 9 2 1 4 0 5 3 6 2 3 5 2 9 5 0 9 1 3 7 5 3 5 1 +6 6 6 3 1 5 2 0 3 1 8 1 6 3 2 5 4 7 7 3 9 8 8 5 3 1 9 4 4 1 7 2 1 8 5 4 6 6 3 8 4 4 7 5 8 8 7 3 9 8 3 3 5 4 1 0 5 4 3 5 5 5 6 6 5 0 3 8 4 1 8 2 2 6 0 8 6 6 7 5 0 8 4 0 5 6 6 4 7 6 8 1 9 6 3 5 4 7 1 5 +6 0 5 7 0 0 2 4 2 0 8 6 5 2 2 6 8 6 7 7 8 7 8 9 7 0 2 5 9 2 4 8 2 6 9 2 2 3 1 9 8 4 2 8 1 1 5 0 9 1 1 7 0 1 4 3 1 7 5 6 2 6 7 2 6 2 9 5 0 3 7 0 1 8 4 2 5 9 1 7 9 8 7 3 3 4 8 5 4 6 5 1 3 3 8 3 9 0 3 5 +8 8 7 9 6 9 1 1 3 9 9 1 8 2 5 1 1 3 4 5 5 6 4 5 6 5 3 3 1 9 2 5 6 3 6 4 6 0 4 7 8 2 2 7 4 7 1 0 4 0 5 2 3 1 7 5 5 7 6 6 9 0 0 6 3 8 3 5 3 7 9 9 7 6 9 9 8 7 2 4 4 1 5 7 4 7 4 0 8 5 5 6 6 7 6 8 5 2 9 6 +0 5 2 1 9 0 2 4 1 9 2 0 7 0 9 9 6 7 1 2 5 1 6 2 5 0 5 6 3 3 6 4 6 1 5 3 6 9 2 8 2 8 4 7 9 9 5 0 2 1 4 3 0 5 4 6 6 6 6 6 9 5 2 9 4 6 3 7 4 6 2 9 8 4 7 6 5 0 8 8 6 0 3 9 9 7 4 7 6 8 0 1 3 5 3 8 6 6 6 5 +6 0 5 1 5 9 0 2 0 7 3 5 6 9 9 0 0 3 0 2 0 6 0 3 0 4 5 2 4 6 7 5 1 9 0 6 2 1 1 7 5 0 6 2 7 0 5 9 9 0 6 7 4 5 9 3 3 9 8 6 0 1 5 3 1 4 7 8 8 0 9 1 8 9 2 4 3 2 2 9 2 5 2 2 1 3 5 1 5 0 8 4 3 2 8 1 1 7 0 1 +0 4 3 2 7 1 0 1 9 2 2 1 6 8 6 8 6 1 7 2 3 0 3 2 8 4 8 5 6 3 7 6 9 3 9 8 8 6 8 7 1 7 8 7 1 2 3 9 2 8 6 0 5 4 6 6 3 3 1 2 7 4 7 7 2 4 7 4 5 3 7 9 1 3 3 2 5 9 1 1 8 6 8 2 0 1 8 9 6 7 0 4 3 3 9 4 4 3 3 9 +7 8 4 9 3 4 9 5 1 9 6 3 8 7 3 7 6 9 2 3 1 4 0 5 1 2 2 7 0 9 3 0 7 2 7 7 3 4 6 8 5 2 1 7 5 5 0 8 9 8 8 6 5 8 6 4 0 6 0 2 7 1 6 7 5 3 8 8 8 1 7 4 1 9 8 7 2 9 9 8 2 8 2 4 0 0 3 4 0 2 5 6 5 5 4 7 4 9 1 1 +0 9 8 9 7 1 1 6 0 5 7 0 7 4 0 8 9 0 1 0 6 5 7 2 9 8 5 8 3 5 3 3 8 4 2 7 4 6 2 8 4 6 3 5 2 3 7 2 8 9 8 2 3 2 6 3 8 4 3 6 5 4 5 1 4 6 2 3 9 1 8 9 5 5 6 6 9 4 8 5 1 2 7 9 9 4 3 6 6 6 1 5 2 8 7 3 5 9 8 2 +9 9 1 3 8 0 6 8 0 8 6 6 2 3 5 4 1 8 2 6 9 7 1 0 6 8 8 6 4 7 3 1 0 0 9 5 2 5 1 6 1 8 9 1 3 2 3 4 6 2 0 0 2 5 0 5 8 6 8 9 1 7 9 1 6 3 3 0 8 6 2 1 7 6 0 3 6 0 9 0 1 6 4 2 5 1 7 1 2 3 3 1 5 3 0 0 4 5 0 5 +4 4 6 0 2 7 1 3 5 0 8 6 4 3 7 1 7 4 4 3 1 0 1 8 8 4 3 0 7 1 8 6 1 4 4 8 5 2 9 9 0 3 0 8 2 0 4 3 7 2 7 4 5 7 7 5 0 1 5 8 4 5 3 4 1 2 9 9 0 0 7 4 9 8 9 2 6 9 9 0 3 6 1 9 2 5 1 2 5 9 5 0 4 6 4 4 6 1 8 6 +6 9 8 5 1 7 8 8 1 9 4 7 0 6 4 7 2 4 5 7 1 8 1 4 9 2 3 3 5 4 8 8 2 2 9 5 6 1 5 2 9 7 8 5 5 0 4 1 9 8 5 5 5 7 7 6 9 1 3 9 5 0 8 0 7 7 6 2 3 7 2 0 3 6 9 8 6 2 5 5 3 0 6 5 0 7 4 4 3 4 4 3 2 0 4 0 3 8 8 5 +6 8 0 9 9 2 9 6 3 9 2 1 7 6 8 6 2 5 7 4 9 3 3 8 3 8 0 8 4 8 3 2 0 2 2 1 6 6 3 2 3 0 6 4 0 8 3 8 4 9 7 9 9 2 0 7 8 4 4 0 1 8 4 2 9 2 8 4 2 8 1 0 3 5 2 3 6 3 9 6 9 6 1 3 2 7 0 7 9 2 8 1 8 2 4 8 2 2 9 8 +7 2 8 2 8 4 3 2 4 1 1 4 4 1 7 0 4 5 9 0 7 0 1 2 3 3 9 2 1 3 5 7 6 0 2 4 3 3 5 1 8 7 6 3 3 7 6 5 1 3 4 5 0 0 6 4 2 0 7 9 1 5 4 7 2 6 5 4 0 2 6 1 6 7 2 6 4 7 2 5 4 9 1 0 8 9 5 7 6 4 4 2 0 3 3 5 9 2 3 0 +7 7 3 2 7 5 1 5 9 2 9 7 7 7 6 5 6 3 1 3 4 1 8 3 2 5 7 6 7 3 7 7 9 5 3 6 3 5 6 0 5 1 3 1 9 9 5 2 2 3 4 7 6 7 8 9 2 5 1 0 7 0 6 9 2 5 3 6 7 0 6 7 7 2 3 2 9 3 0 1 2 8 6 8 5 7 5 6 9 9 6 4 2 2 2 3 4 8 5 3 +4 0 5 1 9 8 9 6 8 9 8 8 0 1 2 0 8 7 7 5 5 6 8 8 4 9 9 2 7 8 0 3 6 8 2 6 8 1 4 8 7 5 3 6 2 0 7 2 7 8 1 2 8 3 8 4 3 9 8 7 5 6 7 9 7 7 2 2 1 6 2 2 6 0 0 6 9 2 1 2 7 3 6 3 6 5 5 5 8 0 0 2 6 6 7 9 6 4 4 4 +6 3 5 0 0 4 2 2 1 1 2 2 7 9 5 6 9 6 6 5 6 5 3 5 0 0 0 1 2 4 9 0 5 3 2 8 8 1 7 9 4 4 9 1 5 5 5 6 1 0 0 1 2 6 7 4 5 5 6 5 3 4 6 6 3 6 1 9 2 8 5 4 2 8 9 0 6 0 4 2 7 1 6 7 5 1 4 4 3 0 2 3 3 3 2 5 4 0 7 2 +2 4 1 0 3 2 0 5 4 6 8 3 5 8 2 1 1 5 4 5 4 9 4 6 4 3 6 3 6 1 7 9 3 0 4 6 1 2 7 9 8 5 6 8 0 6 7 8 0 5 9 9 0 3 6 3 6 3 3 2 4 8 0 2 3 9 1 9 7 0 1 7 1 5 5 1 9 8 4 8 3 8 5 9 6 2 8 5 3 0 1 8 4 3 5 7 8 7 1 3 +1 0 4 7 4 2 1 0 9 8 5 7 6 3 7 5 9 5 1 2 8 5 7 5 6 9 4 1 6 6 7 8 3 6 3 2 3 7 4 7 2 2 8 2 5 1 3 1 5 2 9 1 1 7 3 5 8 0 0 1 6 7 4 3 8 6 0 3 0 6 3 5 5 8 8 9 1 3 4 0 7 9 2 6 0 1 6 2 6 2 6 9 2 6 2 0 0 9 4 8 +9 8 5 2 5 4 4 6 3 8 6 9 1 5 7 2 1 6 5 2 8 0 5 1 5 8 2 6 4 7 9 9 5 2 0 1 6 0 9 3 9 8 6 7 5 9 1 2 3 6 7 7 7 4 7 3 4 5 9 7 4 6 3 3 4 1 3 2 1 3 1 1 3 9 1 7 0 0 1 4 0 5 6 0 6 6 1 0 4 0 9 3 1 7 9 3 6 8 1 0 +8 1 1 2 4 2 7 2 4 9 0 4 4 6 2 4 8 8 3 1 4 3 8 3 1 3 9 7 5 5 4 1 7 3 8 9 4 1 5 9 4 5 1 8 8 1 9 1 0 8 4 8 7 4 9 4 5 9 7 0 2 1 3 0 4 3 3 7 1 9 0 2 6 7 6 0 3 5 5 2 9 0 2 5 4 6 2 1 3 1 1 3 4 7 2 4 1 0 5 5 +5 4 0 7 8 5 1 5 6 0 8 4 1 3 6 1 7 0 3 8 0 2 9 0 2 7 0 6 5 3 4 0 5 3 9 6 4 2 8 7 4 7 8 7 4 2 8 2 5 8 0 6 3 2 7 0 4 5 2 6 5 5 8 8 3 3 4 4 3 9 3 5 3 2 3 5 3 8 1 7 2 2 6 0 9 4 6 7 7 0 2 7 9 5 9 7 6 7 8 2 +6 3 6 7 1 4 8 8 5 5 4 3 5 1 7 4 1 9 1 8 4 0 2 8 1 5 9 1 8 0 6 7 5 1 2 2 3 6 3 0 2 2 6 7 0 9 4 1 9 2 2 6 0 5 1 1 9 1 8 5 3 9 8 6 3 1 4 3 7 0 3 8 1 2 9 7 7 9 2 1 8 2 6 4 0 1 2 6 5 0 6 8 0 1 7 5 6 2 0 0 +2 3 7 6 8 8 1 7 3 1 7 1 4 4 2 6 5 1 6 6 7 2 3 3 0 3 9 0 1 7 8 8 4 5 0 4 7 9 6 0 0 5 6 3 1 3 8 8 2 7 0 4 2 0 8 9 9 8 9 1 4 9 1 2 1 5 9 0 3 9 2 9 9 0 9 9 9 3 7 7 1 0 1 1 7 1 5 2 5 3 2 1 8 4 3 4 1 0 0 2 +6 2 1 6 8 4 9 7 9 2 2 3 4 2 2 6 8 9 5 0 3 4 0 9 9 1 8 0 7 5 2 7 2 7 8 1 9 6 1 4 6 3 6 6 1 8 1 8 6 0 1 6 7 8 8 6 6 1 5 0 1 6 7 2 7 2 1 0 7 6 0 4 0 6 7 5 5 5 4 7 1 3 7 8 8 0 3 1 1 0 4 2 1 3 8 2 9 7 4 2 +8 0 2 7 8 8 5 7 0 7 0 3 1 5 4 7 1 5 7 5 3 5 8 3 8 7 4 6 7 4 0 0 5 4 1 9 7 8 0 1 6 2 0 0 2 1 3 7 4 1 7 5 3 7 4 1 0 8 1 8 2 6 4 5 0 6 3 3 1 0 0 5 7 7 6 6 5 9 6 3 8 8 9 7 7 8 3 9 7 2 0 5 4 1 7 7 3 1 8 0 +9 5 6 9 4 3 6 0 5 0 9 1 4 3 7 1 4 9 6 2 7 7 4 9 3 3 1 3 4 8 7 7 6 0 8 8 0 6 8 4 7 8 5 9 9 1 3 0 7 5 0 0 4 7 9 6 1 7 3 8 9 8 6 5 4 4 7 2 5 8 8 3 6 5 4 9 1 2 6 2 6 9 1 9 8 7 3 2 6 0 9 8 2 9 9 7 5 8 9 7 +8 0 9 3 5 3 5 1 1 5 0 2 2 0 2 0 4 4 9 5 6 0 1 5 2 0 1 1 1 6 7 5 0 0 0 4 8 5 6 9 6 3 0 2 0 7 5 8 1 3 3 8 4 1 7 3 5 9 6 5 0 1 6 2 9 9 4 4 5 9 8 9 3 7 7 9 8 1 7 8 7 8 7 7 2 8 6 6 9 3 1 3 7 2 0 5 6 3 9 7 +8 8 5 7 5 1 5 6 9 3 9 9 7 2 9 7 3 8 7 9 7 1 6 0 3 7 4 8 2 5 3 8 4 9 6 2 3 1 5 8 9 9 4 2 4 0 9 0 9 3 4 4 2 8 2 4 8 0 7 4 8 8 3 6 1 2 0 1 4 3 8 7 3 4 9 8 2 1 3 3 3 0 4 9 0 1 6 9 8 9 2 7 4 1 3 9 3 1 6 4 +1 0 7 2 1 0 0 4 6 0 2 0 5 8 4 8 6 5 8 7 2 7 1 8 5 5 4 3 9 7 6 4 1 7 4 1 8 7 6 4 5 1 8 5 6 7 9 9 0 3 0 4 3 2 7 3 2 8 3 3 4 8 8 3 4 9 0 8 8 4 1 1 2 6 3 9 5 9 2 3 0 3 7 2 9 4 9 0 7 9 0 9 1 3 2 7 3 8 6 2 +1 7 6 1 5 1 7 1 3 0 6 0 8 0 7 7 2 7 7 8 1 6 3 1 7 0 0 4 9 7 8 7 6 3 0 9 4 4 7 9 0 1 7 5 3 2 6 3 1 9 2 7 2 2 3 5 9 7 7 9 8 3 6 9 4 6 9 0 6 4 2 9 9 7 6 1 4 7 8 8 5 2 7 1 7 8 7 3 1 8 5 7 5 3 6 6 4 1 8 6 +2 9 4 7 1 2 1 3 1 6 0 1 5 1 1 4 5 7 2 9 8 0 9 0 0 7 2 4 1 7 6 1 0 4 8 3 1 8 2 6 8 3 2 9 8 4 2 9 3 5 9 2 4 3 6 3 6 5 1 9 3 6 7 3 9 5 5 2 0 5 2 1 6 7 9 9 2 0 0 3 1 3 1 5 6 6 4 2 7 4 8 5 2 8 6 7 9 3 1 5 +7 3 6 4 3 3 1 6 1 9 4 1 5 8 3 7 7 4 9 5 3 1 1 8 7 8 5 7 5 0 0 7 0 4 1 5 5 8 3 9 3 7 7 1 9 7 5 8 6 2 9 1 0 2 7 8 7 0 9 7 4 0 3 8 9 0 8 2 2 3 2 0 8 7 8 8 3 5 8 0 3 4 5 3 6 7 8 3 5 4 8 2 4 1 9 8 9 8 7 9 +2 3 6 2 1 1 8 4 7 3 0 1 0 4 3 0 3 1 7 3 1 8 5 7 5 3 4 7 8 5 1 0 3 1 3 0 6 4 5 9 7 3 0 4 3 6 5 1 7 3 3 6 9 7 8 0 8 6 1 8 1 1 2 8 5 1 5 1 1 1 2 8 9 2 6 8 9 8 3 8 7 6 2 8 9 5 5 9 5 3 1 8 9 4 4 9 1 0 8 3 +5 1 9 3 7 6 9 4 0 4 1 9 7 2 6 6 4 7 9 7 7 8 4 8 2 4 6 9 3 9 2 9 2 8 8 6 6 1 6 0 6 2 8 3 8 7 2 4 7 2 0 6 6 2 1 6 5 2 0 0 9 8 3 9 6 3 4 4 4 5 8 1 9 2 3 2 8 1 5 7 8 0 9 7 4 2 9 4 0 6 3 3 0 3 3 7 2 5 4 8 +6 2 5 7 2 0 6 1 0 2 4 5 2 8 3 3 5 7 1 5 1 7 8 9 2 0 0 3 3 9 1 7 8 9 3 9 2 1 8 5 1 8 2 2 5 5 3 0 9 5 5 0 4 1 9 8 1 5 5 9 2 1 5 7 3 4 9 0 3 2 8 4 0 5 5 4 9 8 6 6 8 7 0 1 0 5 0 9 9 3 5 6 6 8 5 5 5 0 0 9 +6 8 3 2 1 1 3 9 4 9 3 9 0 6 1 2 3 2 5 9 3 6 3 2 0 1 1 1 8 9 4 2 2 2 7 6 0 4 5 2 8 1 8 8 1 4 3 3 0 9 1 4 8 3 6 6 1 6 7 1 7 0 4 9 1 9 2 2 4 5 0 7 5 2 4 5 9 7 5 1 6 9 0 0 5 8 1 4 6 1 5 1 9 2 0 9 2 6 1 2 +3 3 4 5 5 7 6 4 7 3 1 6 5 4 5 6 8 0 9 5 7 9 6 2 4 8 2 0 1 9 0 7 9 6 4 3 7 2 5 2 4 0 0 1 0 9 5 1 8 9 1 8 3 5 8 9 3 6 2 0 3 0 2 8 4 3 3 5 5 0 3 3 2 1 0 6 2 8 2 7 1 2 2 6 4 4 3 2 4 1 2 8 9 7 0 9 1 4 6 9 +6 3 8 6 6 0 3 6 0 6 7 7 6 3 8 9 7 9 4 8 2 2 8 3 2 4 0 1 1 7 5 4 2 7 7 6 9 2 0 2 4 4 8 2 6 5 2 2 9 3 5 8 6 9 2 9 7 0 7 9 6 4 8 6 5 5 3 4 9 0 9 0 8 7 5 7 8 8 5 1 2 0 3 7 9 4 8 9 6 6 2 8 2 4 7 8 7 1 3 4 +9 9 1 4 2 6 0 9 1 0 0 5 2 9 1 7 6 9 0 6 6 4 9 3 7 3 7 5 3 5 2 1 6 7 4 4 5 4 6 5 8 2 3 8 4 3 8 5 2 7 7 9 2 3 8 2 5 2 5 7 6 8 2 1 3 4 3 5 5 3 5 7 5 9 6 4 8 8 3 8 5 3 8 8 7 9 0 2 3 5 2 4 8 8 2 9 8 0 1 9 \ No newline at end of file diff --git a/03-MatrixAddition/matrices/vector1 b/03-MatrixAddition/matrices/vector1 new file mode 100644 index 0000000..fb72f9c --- /dev/null +++ b/03-MatrixAddition/matrices/vector1 @@ -0,0 +1,3 @@ +2 1 +1 +2 diff --git a/03-MatrixAddition/matrices/vector2 b/03-MatrixAddition/matrices/vector2 new file mode 100644 index 0000000..1ec5c89 --- /dev/null +++ b/03-MatrixAddition/matrices/vector2 @@ -0,0 +1,3 @@ +2 1 +5 +8 diff --git a/05-RootVegFarm/.DS_Store b/05-RootVegFarm/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..85b325a8ca0eda791af45342fa3aafcca306d169 GIT binary patch literal 6148 zcmeHKy-veG47S@0tys#&cr#lU=1_$v=*9$X5DW>aM7!T3@en)|BcIP!)l;sF2vxS^ z`!4>uT)vCqn230FXqQ9_BAP)3Cvyx15x?k2CT0;Q%NpJ5a=jh;-6+xx|CIqbyNW(& zppM@2^Siw}_4Py3Y`S3so8&xRw_o?Uzx~y}dpmtMK9Ndu+S3c}y{9cb12NBcz~AMl zGkYnl*AK;A6(aNf`7103E`(9T-vz z0IXn6g1Ph(k`oMT!>9-kgf$hYscbC$IB~7$ zqch+PFRpbb}QJBlb)`dulv&9{OaGmpS~OU6`9hWUa|I`*7O3zyxhU# z0V@ndo!QG^~;8qL0piGvEvy8IbQofC@&#q?kV) z7;*~$tYFT9x%3i}6AYtaQiKP>nhMlZwibgm9rj>x(J(1$Iy@!)p8=%in5s6ER#}rI* gDMqZ6;#+7I*n>=f(J(2(0`VV#OoI>3z@IYk1JEQ$Pyhe` literal 0 HcmV?d00001 diff --git a/06-MemoryManager/Makefile b/06-MemoryManager/Makefile new file mode 100644 index 0000000..1cae673 --- /dev/null +++ b/06-MemoryManager/Makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-Wall -g -pthread + +all: testmemmgr pthread_testmemmgr + +testmemmgr: memory_manager.o testmemmgr.o + $(CC) -o testmemmgr $^ + +pthread_testmemmgr: memory_manager.o pthread_testmemmgr.o + $(CC) -pthread -o pthread_testmemmgr $^ + +%: %.c + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -f testmemmgr pthread_testmemmgr *.o diff --git a/06-MemoryManager/MemoryManager.drawio b/06-MemoryManager/MemoryManager.drawio new file mode 100644 index 0000000..32d6764 --- /dev/null +++ b/06-MemoryManager/MemoryManager.drawio @@ -0,0 +1 @@ +7VxRc6M2EP41nvE95AaBhM2jneQu7aSdzKSd9p46ipGBO4xckBO7v74SCGMQTogvIBv7JUGLJMTuftK3K+GBdb1Yf43x0v+NuiQcmIa7Hlg3A9N0DMT/CsEmE9gjMxN4ceBmIlAIHoP/iBQaUroKXJKUKjJKQxYsy8IZjSIyYyUZjmP6Uq42p2H5qUvsEUXwOMOhKv0rcJmfScfIKOR3JPD8/MnAkHcWOK8sBYmPXfqyI7JuB9Z1TCnLrhbraxIK3eV6ydp92XN3O7CYRKxJg1+fvvs/nLvknz+eNuaN/7AGzrcrU1ojYZv8jYnLFSCLNGY+9WiEw9tCOo3pKnKJ6NbgpaLOPaVLLgRc+J0wtpHWxCtGuchni1DeJeuA/b1z/U109RnJ0s1a9pwWNnkhYvFGNLoyPhswF+y0FMWiaVoqtX0gcbAgjMRSOKcRkyMEor9MEeLt9ypYihK6imfkFa2OpKPi2CPslXoAbP2A44dQPrx4wxvGJMQseC4PBEtP9rb1CmPzC2nvd9hejvIZhyv5pC8xIVwyDensx8CaDEw75MOfPsUlD7H/XQmfTRV4laQa5FUNAJfrVI35fX7lif+PRRUBjo/pk+uWBZHH60xcNyZJknVvKO5cdtYXP2DkcYlT873wGavsmPU+8UxiRtave4VqRNmAT4FZEzkB5jPHSzGbgJGU+TsziW20ZPaxYnZ1CojciZg7eWkW4iQJZhX85lg03ofDwyH3JpRG9UbY0TKqUXIuaww4+YQHGvABFjYGZRuPK7bLJgzZaHeKrvRjW+V+AKh0lKlB6Sj1g+1bH+4aACi+8fuf9/eKf3A0sLJH4DDwIuEu3HBihp0KzAR8GZ3IG4vAdbPFg3B446e0K+ETS/Ey6euh6QDdiL74epFIL2kHk6hir5GKyTpvMduCJDAVvd8R7PZO72bOBnMyqFnvJrqwn49nP6bdcM42xzrpTz7MDvmP0zL9AcdHf2CF/oAazHfLf0yV9/aBAFlGvR30MCDgHEqBzHJHyuTfMgUyVXrcSwo0qhpsrHstds6TAwHd5NMCio6PnQR1Nuu+yXXygO1trmPr5Dr5MHfANQk5y8GM27DVhM/Z53v0Ex44vgD8YIDDpgCHWgEONQEcorOPaOqyRx0DXE3bqYg/vYgGono76IloLOODIhrL6jaigWpysZcRjWNUcOloJtbQUhR/FhGNqTuUhPBCeA4nPKjp9Lwn4dQR4UF6CM8lojkCwoNUJR0pwNsEatNtlowAaANq99ssbQclSN021I1R+/gwekkrHo5tZDbENnJ0Yjsf5iXr0HnWwaoh2R0DXA1vVMSfXtYBHdVJMlg9AXZo1gHCbrMOCCrecRZZB2hoDn6RGhidRdbB0p3uQfaF8BxOeJoemUdagxmk48z82SccjoDrnMwWapsYdZpiFGrFqHqQ6JJwaD3hoB+j9slg9JQOc9tNQT/S+i2b3T3oLx+zcYKt/XBT/rCeZSHsPXk9PVkIdPBp7soHbXbHp7lHZ/pBG9K9BZ9/5X9uWQik+zT3SP1+YQg+ccEvUcACHL7DAiGZs2PXf2V+qdF+3WrUnvZVGjI0hfYXWOyLDIHxqd8GqPuMZPuTGJ2YYKwSgqG1YwKIem6CunNvHZtAXXWHUJhgzin5UFzgbJcwoFEqpQv+L52m+myYuq2B7Xdy3RhGXZWHaAcbSExPxhWPS/BCBBNeFqUYcxyESc+NU4eaTlfusbqfOrRz1OzDjNVzzNQR2e0a85Nm4cXi15eyiKP4CSvr9n8= \ No newline at end of file diff --git a/06-MemoryManager/MemoryManager.md b/06-MemoryManager/MemoryManager.md new file mode 100644 index 0000000..edefec7 --- /dev/null +++ b/06-MemoryManager/MemoryManager.md @@ -0,0 +1,287 @@ +## Introduction + +The purpose of this lab is to develop a dynamic memory manager. This memory manager will replace the functionality of the malloc and free routines built into the operating system. + +The heap is considered a contiguous chunk of memory from which storage is allocated using malloc and deallocated using free. As storage is malloc'ed and freed, memory fragments may appear. A memory manager needs to keep track of the allocated spaces and fragments in order efficiently satisfy memory requests. Furthermore, as memory is freed, fragments must be coalesced to ensure optimal memory use. + +Your goal for the lab is to implement a memory manager, provide a means for a user to allocate and free memory all while keeping statistics of the memory management system. + +## References + +Your memory manager will have to mimic the behavior of malloc and free. It might be helpful to refresh your memory on how malloc and free work. Furthermore, you will need to ensure synchronized access to the memory manager in the case where a client application is using pthreads. + +The following man pages might be helpful for review: + +- man malloc +- man free +- man pthread_mutex_init +- man pthread_mutex_destroy +- man pthread_mutex_lock +- man pthread_mutex_unlock + +To view the man pages for the pthread library, they must be installed on your OS image. You can do that by running the command: + +```text +sudo apt-get install manpages-posix manpages-posix-dev +``` +## The Exercise + +You must implement a set of functions that a program can call to access the memory manager used to allocate and free storage. In addition, you will need to keep track of allocated and free blocks of memory. + +There are several ways this can be done; one way is to use a linked list. Elements in the list record, the size of the allocated and free blocks and the memory address at the start of the block. Calls to allocate and free storage modify the list based on the request size. + +For example: +1. Consider a heap of 100 bytes that starts at address 1000. Initially all heap memory is unallocated (free). So, there is 1 large free block of storage that is 100 bytes long. The list consists of one element. +2. A call to malloc for 10 bytes modifies the free block to reduce it by 10 bytes and allocates memory to the process. The free block now has only 90 free bytes. In addition, an element for the allocated block is added to the list. +3. Another call to malloc, this time for 45 bytes modifies the free block to reduce it by 45 bytes (leaving 45 left). The list would not have 3 elements: 1 for the first allocated block, 1 for the second allocated block, and one for the free block. +4. A call to free the 10-byte block would convert the allocated block into a free block. A memory allocation request for 10 bytes or less could be satisfied by that free block. +5. However, a call to malloc 50 bytes at this point would fail because there are no free blocks big enough to satisfy the request. +6. If a call to free is made to free the 45-byte block allocated in step 3, now there are free blocks next to each other. These should be coalesced (combined) into a single free block + +Here's what the list might look like at each step from the example: + +![Memory Manager Example](MemoryManager.png) + +Allocating from a free block essentially splits the block into two: One block for the allocated space and one block for the remaining free space. + +NOTE: This splitting is correct except for cases where you have a free block that exactly matches the allocation request. You should not have any zero sized blocks in your data structure. If you find a free block that exactly matches the size that you need for an allocation, then there should be no free blocks after it. + +As with malloc and free, the caller should not be aware of the mechanism that is being used for memory block record keeping. Whatever structure you choose to use should be hidden in your memory manager implementation. This can be done by creating a static structure in your memory manager implementation file. The internal implementation of the data structure that you use to keep track of blocks is up to you. Internally to the memory manager, you are free to use malloc and free (the system versions). This will simulate the overhead that the operating system uses to manage memory. Just make sure you have no memory leaks within your memory manager. + +Normally the size of the heap is controlled using system calls to request modifications to the process address space. Your memory manager will work a little bit differently. A user of your memory manager will be required to pass a pointer to a location in memory and a size. This storage must be pre-allocated by the user. + +Your implementation must support 3 different types of placement algorithms to satisfy allocation requests: + +1. First fit – allocates from the first free block that is big enough +2. Worst fit – allocates from the largest free block +3. Best fit – allocates from the smallest free block that is large enough to satisfy the request + +A summary of all required functions (including statistics functions) is below: + +- ```void mmInit(void* start, int size)``` – Initialize the memory manager +- ```void mmDestroy()``` – cleans up any storage used by the memory manager +- ```void* mymalloc_ff(int nbytes)``` – Requests a block of memory be allocated using first fit placement algorithm +- ```void* mymalloc_wf(int nbytes)``` – Requests a block of memory be allocated using worst fit placement algorithm +- ```void* mymalloc_bf(int nbytes)``` – Requests a block of memory be allocated using best fit placement algorithm +- ```void myfree(void* ptr)``` – Free the storage address by ptr +- ```int get_allocated_space()``` – Returns the amount of currently allocated space in bytes +- ```int get_remaining_space()``` – Returns the amount of current free space in bytes (sum of all free blocks) +- ```int get_fragment_count()``` – Returns the number of free blocks (the count of all the blocks, not the size) +- ```int get_mymalloc_count()``` – Returns the number of successful malloc's made (since the last ```mmInit```) + +## Error Checking + +Your memory manager can't trust the user so it must perform error checking. If the user tries to malloc storage that can't be satisfied, return a NULL pointer just like the system malloc. + +Furthermore, if a user tries to free a block that isn't allocated this should cause a segmentation fault. In this case, your memory manager should send SIGSEGV to the process (see the man page for the kill system call in section 2): + +```text +man 2 kill +``` +## Getting Started + +Start by downloading the [starter files](memory_manager.zip) which includes a source file (memory_manager.c) and a header file (memory_manager.h) that contain a skeleton for the required functions for your memory manager. The starter code also contains the sample test cases (testmemmgr.c and pthread_testmemmgr.c see below) and a Makefile to help you build your project. + +## Sample Usage + +Here is a sample client program that uses the memory manager. This file is provided along with the starter code: + +```c +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("1 -- Available Memory: %d, Fragment Count: %d\n", + get_remaining_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_ff(10); + if(ptr1 == NULL) { + printf("ptr1 - mymalloc_ff(10) failed\n"); + exit(EXIT_FAILURE); + } + + strncpy(ptr1, "HELLO", 10); + printf("ptr1 is %s\n", ptr1); + + printf("2 -- Available Memory: %d, Fragment Count: %d\n", + get_remaining_space(), get_fragment_count()); + + // Allocate 45 bytes + // shouldn't fail + char* ptr2 = mymalloc_wf(45); + if(ptr2 == NULL) { + printf("ptr2 - mymalloc_ff(45) failed\n"); + exit(EXIT_FAILURE); + } + + strncpy(ptr2, "GOODBYE", 45); + printf("ptr2 is %s\n", ptr2); + + printf("3 -- Available Memory: %d, Fragment Count: %d\n", + get_remaining_space(), get_fragment_count()); + + // Attempt to allocate 50 bytes + // should fail + char* ptr3 = mymalloc_bf(50); + if(ptr3 == NULL) { + printf("ptr3 - mymalloc_bf(50) failed\n"); + } + + printf("4 -- Available Memory: %d, Fragment Count: %d\n", + get_remaining_space(), get_fragment_count()); + + // Free the first two pointers + myfree(ptr1); + myfree(ptr2); + + printf("5 -- Available Memory: %d, Fragment Count: %d\n", + get_remaining_space(), get_fragment_count()); + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + + // Double free, should cause a segmentation fault + myfree(ptr2); + + mmDestroy(); + + return 0; +} +``` + +This should produce the output: + +```text +1 -- Available Memory: 100, Fragment Count: 1 +ptr1 is HELLO +2 -- Available Memory: 90, Fragment Count: 1 +ptr2 is GOODBYE +3 -- Available Memory: 45, Fragment Count: 1 +ptr3 - mymalloc_bf(50) failed +4 -- Available Memory: 45, Fragment Count: 1 +5 -- Available Memory: 100, Fragment Count: 1 +Total successful mallocs: 2 +Segmentation fault (core dumped) +``` + +## Thread Safety + +Your memory manager should be thread safe. In other words, all calls to any memory manager function must work correctly with a multithreaded program. Race conditions might exist if two threads attempt to allocate or free memory at the same time. Furthermore, depending on how you implement your statistics, there might be race conditions in those functions as well. Make sure you use concurrency mechanisms (semaphores, mutex locks, condition variables, etc.) to ensure that your block allocation data structure is never corrupted. + +NOTE: you can assume mmInit() and mmDestroy() will only ever be called by a single thread. Mutual exclusion is not needed for those functions. + +A sample test driver using pthreads is included with the starter code. + +## Development Tips + +- You'll need to come up with an efficient data structure to use. If you use the system malloc, make sure you don't have memory leaks. An OS should NEVER have memory leaks. Don't forget to free your mallocs! +- You need to ensure thread safety so synchronize access to your memory manager. +- Don't forget about using gdb to help with debugging (compile with -g to get additional debug symbols) + + NOTE: when using gdb it is helpful to compile your program with additional debug symbols included. These allow gdb to show you more information when running commands like backtrace (bt). To compile with additional debug symbols use the -g flag on gcc. For example: + + ```text + gcc -Wall -g -o myprog mysourcefile1.c mysourcefile2.c mysourcefile3.c + ``` + +- Using valgrind will be helpful in this lab to ensure you do not have any memory leaks. +- When compiling your program you will need to include an additional compiler flag: -pthread. This tells the compiler to use the pthreads library. The examples use this in the Makefile, so you can see how to use it there as well. For example: + + ```text + gcc -Wall -g -o myprog -pthread mysourcefile1.c mysourcefile2.c mysourcefile3.c + ``` + + NOTE: the -pthread flag can be anywhere on the command line. It does NOT need to be the last thing on the command line. + +## Testing + +Use the included test drivers to get you started with testing your lab. You are also required to create and submit your own test driver(s). Don't forget to test single threaded and multithreaded programs as well as each of the placement algorithms. Include your test driver(s) in your submission. Don't forget to test large and small amounts of memory (both for the managed space and for requests). + +## Experimentation + +Each of the three placement algorithms have advantages and disadvantages. + +- First Fit – Relatively fast for malloc since it stops at the first block that fits the request but could potentially result in more fragments +- Best Fit – Requires searching through all blocks but attempts to reduce the number of memory fragments by keeping as many larger fragments free as possible +- Worst Fit – Requires searching through all blocks but attempts to keep the memory fragments as big as possible (on average) to allow more requests to be satisfied. + +Despite the advantages and disadvantages, there is no perfect placement algorithm. It is possible to come with a combination of allocations and frees that cause lots of wasted space. + +As part of your lab report, perform some experiments with the different placement algorithms. Create a series of allocations and frees and report the number of fragments, number of successful allocations along with the total amount of free space. A placement algorithm is considered 'bad' for a set of allocations and frees if the total amount of free space is large enough to satisfy requests, but the fragments themselves are not big enough to satisfy a contiguous block. + +## Deliverables + +You will need to include all your source files, test case parameter files, and any other resources you used to complete lab. Please don't just google search for a solution, but if you do use Google for any help, include a description and URL of what you used to help you. + +A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission. + +All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file. + +NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report. + +Prepare a lab report and submit it along with your source code. The report should include the following: + +- Your name, section, date, and lab title +- Introduction – a description of the lab in your own words +- Design – a description of your design decisions in creating your solution +- Resources – a description of any external resources you used to complete the lab +- Build – instructions on how to build and run your program. Include the exact commands that are necessary +- Analysis - Discuss the key concepts from the lab and your experimental results and answer the following questions. + - What placement algorithm worked the best for your experimental allocations and frees in terms of the number allocations that were successful? Why do you think this is the case? + - The time complexity for an algorithm defines an estimate for how long it will run based on the input size. It is advantages to keep the OS CPU overhead as low as possible. Any OS algorithm that runs in longer than constant time O(1) is often considered to be too high although sometimes this is not possible. + - What is the time complexity of your mymalloc and myfree? + - Is your algorithm acceptable? Why or why not? + - How could you implement your memory manager differently to improve the time for mymalloc and myfree? + - The memory overhead consists of the amount of extra memory needed by the OS for keeping track of memory blocks. It is advantageous to keep the OS memory overhead as low as possible. + - For a set of 'n' successful memory allocations, about how much additional memory (on average) does your memory manager use? + - Can you think of a better way to implement your memory manager that uses less memory overhead with the potential cost of additional CPU usage? + - Memory leaks can be a problem especially for long-lived processes (those that run for a long time or forever). Could you use the structures in your memory manager to detect client memory leaks? Explain your algorithm or explain why it's not possible. +- Conclusion + - Summary of what you learned in the lab + - What specifically was challenging about this lab? + - What did you like about it? + - What could we do to improve it for others? + +NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting. + +Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions. + +## Extra Credit + +While dynamic memory allocation (e.g. the use of malloc) within the OS kernel is possible, it is often advantageous to limit the use of this as much as possible to avoid any potential for memory leaks within the kernel. + +For example, internally in the Linux kernel kmalloc() is used ([https://www.kernel.org/doc/htmldocs/kernel-api/API-kmalloc.html](https://www.kernel.org/doc/htmldocs/kernel-api/API-kmalloc.html)) as a way to dynamically allocate blocks within the OS kernel's address space. + +As a bonus challenge, can you find a way to implement your bookkeeping data structure so that it does not need to use malloc and free internally? + +- It must still be able to manage a region of memory that is of varying size. The memory manager doesn't know how big the region is until the call to mmInit is made. +- It must still be able to keep track of a potentially unlimited number of memory fragments and allocated blocks. +- must still be thread safe +- It must keep track of all required statistics + +HINT: You can use a portion of the memory region given to you by the user. This will reduce the total amount of storage that can be allocated from the block, but that is fine provided you can avoid using malloc and free internally. + +## Grading Criteria + +- (35 Points) Report + - (5 Points) Report Introduction - Thorough description of the lab in your own words. + - (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation. + - (20 Points) Analysis - Answers to the analysis questions + - (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements. +- (5 Points) Documented Resources - Description of external resources used to complete the lab +- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted) +- (5 Points) Build - Code compiles without warnings or errors +- (10 Points) Test Cases - Thoroughness of submitted test cases +- (35 Points) Instructor Tests - Implementation passes all instructor test cases +- (5 Points) Memory Management - Program execution is free from memory leaks \ No newline at end of file diff --git a/06-MemoryManager/MemoryManager.png b/06-MemoryManager/MemoryManager.png new file mode 100644 index 0000000000000000000000000000000000000000..a3a64a6c7ff314b3a93530ff5c003dd87bb351af GIT binary patch literal 41494 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 +#include +#include "memory_manager.h" + +/* + * Using static causes the compiler to + * limit visibility of the variables to this file only + * This can be used to simulate 'private' variables in c + */ +static int allocation_count = 0; + +/* TODO Define additional structure definitions here */ + +/* mmInit() + * Initialize the memory manager to "manage" the given location + * in memory with the specified size. + * Parameters: start - the start of the memory to manage + * size - the size of the memory to manage + * Returns: void + */ +void mmInit(void* start, int size) +{ + allocation_count = 0; + + // TODO more initialization needed +} + +/* mmDestroy() + * Cleans up any storage used by the memory manager + * After a call to mmDestroy: + * all allocated spaces become invalid + * future allocation attempts fail + * future frees result in segmentation faults + * NOTE: after a call to mmDestroy a call to mmInit + * reinitializes the memory manager to allow allocations + * and frees + * Parameters: None + * Returns: void + */ +void mmDestroy() +{ + +} + +/* mymalloc_ff() + * Requests a block of memory be allocated using + * first fit placement algorithm + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: nbytes - the number of bytes in the requested memory + * Returns: void* - a pointer to the start of the allocated space + */ +void* mymalloc_ff(int nbytes) +{ + return NULL; +} + +/* mymalloc_wf() + * Requests a block of memory be allocated using + * worst fit placement algorithm + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: nbytes - the number of bytes in the requested memory + * Returns: void* - a pointer to the start of the allocated space + */ +void* mymalloc_wf(int nbytes) +{ + return NULL; +} + +/* mymalloc_bf() + * Requests a block of memory be allocated using + * best fit placement algorithm + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: nbytes - the number of bytes in the requested memory + * Returns: void* - a pointer to the start of the allocated space + */ +void* mymalloc_bf(int nbytes) +{ + return NULL; +} + +/* myfree() + * Requests a block of memory be freed and the storage made + * available for future allocations + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: ptr - a pointer to the start of the space to be freed + * Returns: void + * Signals a SIGSEGV if a free is not valid + * - memory manager is not initialized + * - memory manager has been destroyed + * - ptr is not allocated (e.g. double free) + */ +void myfree(void* ptr) +{ + +} + +/* get_allocated_space() + * Retrieve the current amount of space allocated by the memory manager (in bytes) + * Parameters: None + * Returns: int - the current number of allocated bytes + */ +int get_allocated_space() +{ + return 0; +} + +/* get_remaining_space() + * Retrieve the current amount of available space in the memory manager (in bytes) + * (e.g. sum of all free blocks) + * Parameters: None + * Returns: int - the current number of free bytes + */ +int get_remaining_space() +{ + return 0; +} + +/* get_fragment_count() + * Retrieve the current amount of free blocks (i.e. the count of all the block, not the size) + * Parameters: None + * Returns: int - the current number of free blocks + */ +int get_fragment_count() +{ + return 0; +} + +/* get_mymalloc_count() + * Retrieve the number of successful malloc calls (for all placement types) + * Parameters: None + * Returns: int - the total number of successful mallocs + */ +int get_mymalloc_count() +{ + return allocation_count; +} diff --git a/06-MemoryManager/memory_manager.h b/06-MemoryManager/memory_manager.h new file mode 100644 index 0000000..6fb9a6b --- /dev/null +++ b/06-MemoryManager/memory_manager.h @@ -0,0 +1,119 @@ +#ifndef MEMORY_MANAGER_H +#define MEMORY_MANAGER_H + +/* memory_manager.h + * + * External (public) declarations for a memory manager in c. + * + * Clients begin by initializing the memory manager. They can + * then allocate and free blocks of memory. The memory manager + * keeps track of allocated and free blocks to maintain efficient + * use of memory. + * + */ + +/* Structures */ +/* No "public" structure, the user of the memory manager + * should have no knowledge of the structures used for managing + * allocated and free blocks + */ + +/* Memory Manager Methods */ + +/* mmInit() + * Initialize the memory manager to "manage" the given location + * in memory with the specified size. + * Parameters: start - the start of the memory to manage + * size - the size of the memory to manage + * Returns: void + */ +void mmInit(void* start, int size); + +/* mmDestroy() + * Cleans up any storage used by the memory manager + * After a call to mmDestroy: + * all allocated spaces become invalid + * future allocation attempts fail + * future frees result in segmentation faults + * NOTE: after a call to mmDestroy a call to mmInit + * reinitializes the memory manager to allow allocations + * and frees + * Parameters: None + * Returns: void + */ +void mmDestroy(); + +/* mymalloc_ff() + * Requests a block of memory be allocated using + * first fit placement algorithm + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: nbytes - the number of bytes in the requested memory + * Returns: void* - a pointer to the start of the allocated space + */ +void* mymalloc_ff(int nbytes); + +/* mymalloc_wf() + * Requests a block of memory be allocated using + * worst fit placement algorithm + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: nbytes - the number of bytes in the requested memory + * Returns: void* - a pointer to the start of the allocated space + */ +void* mymalloc_wf(int nbytes); + +/* mymalloc_bf() + * Requests a block of memory be allocated using + * best fit placement algorithm + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: nbytes - the number of bytes in the requested memory + * Returns: void* - a pointer to the start of the allocated space + */ +void* mymalloc_bf(int nbytes); + +/* myfree() + * Requests a block of memory be freed and the storage made + * available for future allocations + * The memory manager must be initialized (mmInit) + * for this call to succeed + * Parameters: ptr - a pointer to the start of the space to be freed + * Returns: void + * Signals a SIGSEGV if a free is not valid + * - memory manager is not initialized + * - memory manager has been destroyed + * - ptr is not allocated (e.g. double free) + */ +void myfree(void* ptr); + +/* get_allocated_space() + * Retrieve the current amount of space allocated by the memory manager (in bytes) + * Parameters: None + * Returns: int - the current number of allocated bytes + */ +int get_allocated_space(); + +/* get_remaining_space() + * Retrieve the current amount of available space in the memory manager (in bytes) + * (e.g. sum of all free blocks) + * Parameters: None + * Returns: int - the current number of free bytes + */ +int get_remaining_space(); + +/* get_fragment_count() + * Retrieve the current amount of free blocks (i.e. the count of all the block, not the size) + * Parameters: None + * Returns: int - the current number of free blocks + */ +int get_fragment_count(); + +/* get_mymalloc_count() + * Retrieve the number of successful malloc calls (for all placement types) + * Parameters: None + * Returns: int - the total number of successful mallocs + */ +int get_mymalloc_count(); + +#endif diff --git a/06-MemoryManager/pthread_testmemmgr.c b/06-MemoryManager/pthread_testmemmgr.c new file mode 100644 index 0000000..792d46a --- /dev/null +++ b/06-MemoryManager/pthread_testmemmgr.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define ALLOC_SIZE 1024 +#define THREAD_COUNT 10 + +void* thread_routine(void* args) +{ + for(int i = 0; i < 25; i++) { + char* myptr = mymalloc_ff(ALLOC_SIZE); + usleep(20); + if(myptr != NULL) { + printf("Thread %lu allocated %d byte(s): %p\n", pthread_self(), ALLOC_SIZE, myptr); + *myptr = 'a' + i; + printf("Thread %lu write %c\n", pthread_self(), *myptr); + myfree(myptr); + printf("Thread %lu freed %p\n", pthread_self(), myptr); + } else { + printf("Thread %lu could not allocate %d byte(s)\n", pthread_self(), ALLOC_SIZE); + } + } + + return NULL; +} + +int main() +{ + pthread_t mythreads[THREAD_COUNT]; + + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + for(int i = 0; i < THREAD_COUNT; i++) { + if(pthread_create(&mythreads[i], NULL, thread_routine, NULL) == -1) { + printf("COULD NOT CREATE A THREAD\n"); + exit(EXIT_FAILURE); + } + } + + for(int i = 0; i < THREAD_COUNT; i++) { + pthread_join(mythreads[i], NULL); + } + + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/pthread_testmemmgr.c b/06-MemoryManager/testcases/pthread_testmemmgr.c new file mode 100644 index 0000000..792d46a --- /dev/null +++ b/06-MemoryManager/testcases/pthread_testmemmgr.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define ALLOC_SIZE 1024 +#define THREAD_COUNT 10 + +void* thread_routine(void* args) +{ + for(int i = 0; i < 25; i++) { + char* myptr = mymalloc_ff(ALLOC_SIZE); + usleep(20); + if(myptr != NULL) { + printf("Thread %lu allocated %d byte(s): %p\n", pthread_self(), ALLOC_SIZE, myptr); + *myptr = 'a' + i; + printf("Thread %lu write %c\n", pthread_self(), *myptr); + myfree(myptr); + printf("Thread %lu freed %p\n", pthread_self(), myptr); + } else { + printf("Thread %lu could not allocate %d byte(s)\n", pthread_self(), ALLOC_SIZE); + } + } + + return NULL; +} + +int main() +{ + pthread_t mythreads[THREAD_COUNT]; + + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + for(int i = 0; i < THREAD_COUNT; i++) { + if(pthread_create(&mythreads[i], NULL, thread_routine, NULL) == -1) { + printf("COULD NOT CREATE A THREAD\n"); + exit(EXIT_FAILURE); + } + } + + for(int i = 0; i < THREAD_COUNT; i++) { + pthread_join(mythreads[i], NULL); + } + + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc0.c b/06-MemoryManager/testcases/tc0.c new file mode 100644 index 0000000..3524655 --- /dev/null +++ b/06-MemoryManager/testcases/tc0.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + printf("TC0: init and destroy\n"); + + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc1.c b/06-MemoryManager/testcases/tc1.c new file mode 100644 index 0000000..0ec9972 --- /dev/null +++ b/06-MemoryManager/testcases/tc1.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC1: Single allocate with mymalloc_ff\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_ff(10); + if(ptr1 == NULL) { + printf("ptr1 - mymalloc_ff(10) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr1, "HELLO", 10); + printf("ptr1 is %s\n", ptr1); + + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + myfree(ptr1); + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc10.c b/06-MemoryManager/testcases/tc10.c new file mode 100644 index 0000000..2df0ff8 --- /dev/null +++ b/06-MemoryManager/testcases/tc10.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define MUL_COUNT 100 + +int* heap_multiply(int a, int b) +{ + int* result = mymalloc_ff(sizeof(int)); + if(result == NULL) { + printf("COULD NOT mymalloc_ff an int\n"); + exit(EXIT_FAILURE); + } + *result = a * b; + return result; +} + +int main() +{ + int* results[MUL_COUNT]; + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC10: allocate multiple integers and perform multiplications\n"); + + for(int i = 0; i < MUL_COUNT; i++) { + printf("%d -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", i, get_remaining_space(), get_allocated_space(), get_fragment_count()); + results[i] = heap_multiply(i, i + 2); + } + + for(int i = 0; i < MUL_COUNT; i++) { + printf("%d * %d = %d\n", i, i+2, *results[i]); + } + + for(int i = 0; i < MUL_COUNT; i++) { + myfree(results[i]); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc11.c b/06-MemoryManager/testcases/tc11.c new file mode 100644 index 0000000..934c1c7 --- /dev/null +++ b/06-MemoryManager/testcases/tc11.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define MUL_COUNT 100 + +int* results[MUL_COUNT]; +int ids[MUL_COUNT]; + +int* heap_multiply(int a, int b) +{ + int* result = mymalloc_ff(sizeof(int)); + if(result == NULL) { + printf("COULD NOT mymalloc_ff an int\n"); + exit(EXIT_FAILURE); + } + *result = a * b; + return result; +} + +void* thread_function(void* args) +{ + int* localId = mymalloc_ff(sizeof(int)); + if(localId == NULL) { + printf("%lu could not allocate space for local ID\n", pthread_self()); + exit(EXIT_FAILURE); + } + *localId = *(int*)args; + printf("%d -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", *localId, get_remaining_space(), get_allocated_space(), get_fragment_count()); + results[*localId] = heap_multiply(*localId, *localId + 2); + myfree(localId); + return NULL; +} + +int main() +{ + pthread_t mythreads[MUL_COUNT]; + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC11: pthreads allocate multiple integers and perform multiplications\n"); + + for(int i = 0; i < MUL_COUNT; i++) { + ids[i] = i; + if(pthread_create(&mythreads[i], NULL, thread_function, (void*)&ids[i]) == -1) { + printf("Could not create thread %d\n", i); + exit(EXIT_FAILURE); + } + } + + for(int i = 0; i < MUL_COUNT; i++) { + pthread_join(mythreads[i], NULL); + } + + for(int i = 0; i < MUL_COUNT; i++) { + printf("%d * %d = %d\n", i, i+2, *results[i]); + } + + for(int i = 0; i < MUL_COUNT; i++) { + myfree(results[i]); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc12.c b/06-MemoryManager/testcases/tc12.c new file mode 100644 index 0000000..12e513f --- /dev/null +++ b/06-MemoryManager/testcases/tc12.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define MUL_COUNT 1 + +int* results[MUL_COUNT]; +int ids[MUL_COUNT]; + +int* heap_multiply(int a, int b) +{ + int* result = mymalloc_ff(sizeof(int)); + if(result == NULL) { + printf("COULD NOT mymalloc_ff an int\n"); + exit(EXIT_FAILURE); + } + *result = a * b; + return result; +} + +void* thread_function(void* args) +{ + int* localId = mymalloc_ff(sizeof(int)); + if(localId == NULL) { + printf("%lu could not allocate space for local ID\n", pthread_self()); + exit(EXIT_FAILURE); + } + *localId = *(int*)args; + printf("%d -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", *localId, get_remaining_space(), get_allocated_space(), get_fragment_count()); + results[*localId] = heap_multiply(*localId, *localId + 2); + myfree(localId); + return NULL; +} + +int main() +{ + pthread_t mythreads[MUL_COUNT]; + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC12: pthreads allocate single integer and perform multiplication\n"); + + for(int i = 0; i < MUL_COUNT; i++) { + ids[i] = i; + if(pthread_create(&mythreads[i], NULL, thread_function, (void*)&ids[i]) == -1) { + printf("Could not create thread %d\n", i); + exit(EXIT_FAILURE); + } + } + + for(int i = 0; i < MUL_COUNT; i++) { + pthread_join(mythreads[i], NULL); + } + + for(int i = 0; i < MUL_COUNT; i++) { + printf("%d * %d = %d\n", i, i+2, *results[i]); + } + + for(int i = 0; i < MUL_COUNT; i++) { + myfree(results[i]); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc2.c b/06-MemoryManager/testcases/tc2.c new file mode 100644 index 0000000..bc3a5ac --- /dev/null +++ b/06-MemoryManager/testcases/tc2.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC2: Single allocate with mymalloc_bf\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_bf(10); + if(ptr1 == NULL) { + printf("ptr1 - mymalloc_ff(10) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr1, "HELLO", 10); + printf("ptr1 is %s\n", ptr1); + + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + myfree(ptr1); + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc3.c b/06-MemoryManager/testcases/tc3.c new file mode 100644 index 0000000..6ae27e5 --- /dev/null +++ b/06-MemoryManager/testcases/tc3.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC3: Single allocate with mymalloc_wf\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_wf(10); + if(ptr1 == NULL) { + printf("ptr1 - mymalloc_ff(10) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr1, "HELLO", 10); + printf("ptr1 is %s\n", ptr1); + + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + myfree(ptr1); + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc4.c b/06-MemoryManager/testcases/tc4.c new file mode 100644 index 0000000..907e515 --- /dev/null +++ b/06-MemoryManager/testcases/tc4.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC4: Large allocation should fail\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_ff(200); + if(ptr1 != NULL) { + printf("ptr1 - mymalloc_ff(10) succeeded\n"); + myfree(ptr1); + } + + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc5.c b/06-MemoryManager/testcases/tc5.c new file mode 100644 index 0000000..59d7a68 --- /dev/null +++ b/06-MemoryManager/testcases/tc5.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define ALLOC_COUNT 100 +#define ALLOC_SIZE 10 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + void* ptr[ALLOC_COUNT]; + + printf("TC5: Heap size: %d: allocation count: %d, allocation size: %d - Lots of small allocationsl\n", MY_HEAP_SIZE, ALLOC_COUNT, ALLOC_SIZE); + + for(int i = 0 ; i < ALLOC_COUNT; i++) { + + printf("%d - 1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", i, get_remaining_space(), get_allocated_space(), get_fragment_count()); + + ptr[i] = mymalloc_ff(ALLOC_SIZE); + if(ptr[i] == NULL) { + printf("ptr[%d] - mymalloc_ff(%d) failed\n", i, ALLOC_SIZE); + exit(EXIT_FAILURE); + } + + printf("%d 2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", i, get_remaining_space(), get_allocated_space(), get_fragment_count()); + } + for(int i = 0; i < ALLOC_COUNT; i++) { + printf("Freeing ptr[%d]\n", i); + myfree(ptr[i]); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc6.c b/06-MemoryManager/testcases/tc6.c new file mode 100644 index 0000000..259fa6c --- /dev/null +++ b/06-MemoryManager/testcases/tc6.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 4096 +#define ALLOC_COUNT 100 +#define ALLOC_SIZE 10 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + void* ptr[ALLOC_COUNT]; + + printf("TC6: Heap size: %d: allocation count: %d, allocation size: %d - Lots of small allocations with interleaved frees\n", MY_HEAP_SIZE, ALLOC_COUNT, ALLOC_SIZE); + + for(int i = 0 ; i < ALLOC_COUNT; i++) { + + printf("%d - 1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", i, get_remaining_space(), get_allocated_space(), get_fragment_count()); + + ptr[i] = mymalloc_ff(ALLOC_SIZE); + if(ptr[i] == NULL) { + printf("ptr[%d] - mymalloc_ff(%d) failed\n", i, ALLOC_SIZE); + exit(EXIT_FAILURE); + } + + printf("%d 2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", i, get_remaining_space(), get_allocated_space(), get_fragment_count()); + } + for(int i = 0; i < ALLOC_COUNT; i += 2) { + printf("Freeing ptr[%d], Fragment Count: %d\n", i, get_fragment_count()); + myfree(ptr[i]); + } + for(int i = 1; i < ALLOC_COUNT; i += 2) { + myfree(ptr[i]); + printf("Freeing ptr[%d], Fragment Count: %d\n", i, get_fragment_count()); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc7.c b/06-MemoryManager/testcases/tc7.c new file mode 100644 index 0000000..eb902f4 --- /dev/null +++ b/06-MemoryManager/testcases/tc7.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC7: Test interleaved allocations FF\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + void* ptr1 = mymalloc_ff(20); + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr2 = mymalloc_ff(10); + printf("3 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr3 = mymalloc_ff(10); + printf("4 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + if(ptr1 == NULL) { + printf("Unable to allocate ptr1\n"); + } else { + myfree(ptr1); + } + if(ptr3 == NULL) { + printf("Unable to allocate ptr3\n"); + } else { + myfree(ptr3); + } + printf("5 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + void* ptr4 = mymalloc_ff(10); + printf("6 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr5 = mymalloc_ff(20); + printf("7 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + if(ptr4 == NULL) { + printf("Unable to allocate ptr1\n"); + } else { + myfree(ptr4); + } + + if(ptr2 == NULL) { + printf("Unable to allocate ptr2\n"); + } else { + myfree(ptr2); + } + if(ptr5 == NULL) { + printf("Unable to allocate ptr5\n"); + } else { + myfree(ptr5); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc8.c b/06-MemoryManager/testcases/tc8.c new file mode 100644 index 0000000..f9038af --- /dev/null +++ b/06-MemoryManager/testcases/tc8.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC8: Test interleaved allocations BF\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + void* ptr1 = mymalloc_bf(20); + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr2 = mymalloc_bf(10); + printf("3 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr3 = mymalloc_bf(10); + printf("4 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + if(ptr1 == NULL) { + printf("Unable to allocate ptr1\n"); + } else { + myfree(ptr1); + } + if(ptr3 == NULL) { + printf("Unable to allocate ptr3\n"); + } else { + myfree(ptr3); + } + printf("5 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + void* ptr4 = mymalloc_bf(10); + printf("6 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr5 = mymalloc_bf(20); + printf("7 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + if(ptr4 == NULL) { + printf("Unable to allocate ptr1\n"); + } else { + myfree(ptr4); + } + + if(ptr2 == NULL) { + printf("Unable to allocate ptr2\n"); + } else { + myfree(ptr2); + } + if(ptr5 == NULL) { + printf("Unable to allocate ptr5\n"); + } else { + myfree(ptr5); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/tc9.c b/06-MemoryManager/testcases/tc9.c new file mode 100644 index 0000000..b1d8979 --- /dev/null +++ b/06-MemoryManager/testcases/tc9.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("TC9: Test interleaved allocations WF\n"); + printf("1 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + void* ptr1 = mymalloc_wf(20); + printf("2 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr2 = mymalloc_wf(10); + printf("3 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr3 = mymalloc_wf(10); + printf("4 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + if(ptr1 == NULL) { + printf("Unable to allocate ptr1\n"); + } else { + myfree(ptr1); + } + if(ptr3 == NULL) { + printf("Unable to allocate ptr3\n"); + } else { + myfree(ptr3); + } + printf("5 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + + void* ptr4 = mymalloc_wf(10); + printf("6 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + void* ptr5 = mymalloc_wf(20); + printf("7 -- Available Memory: %d, Alloc Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_allocated_space(), get_fragment_count()); + if(ptr4 == NULL) { + printf("Unable to allocate ptr1\n"); + } else { + myfree(ptr4); + } + + if(ptr2 == NULL) { + printf("Unable to allocate ptr2\n"); + } else { + myfree(ptr2); + } + if(ptr5 == NULL) { + printf("Unable to allocate ptr5\n"); + } else { + myfree(ptr5); + } + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testcases/testmemmgr.c b/06-MemoryManager/testcases/testmemmgr.c new file mode 100644 index 0000000..ec5902f --- /dev/null +++ b/06-MemoryManager/testcases/testmemmgr.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("1 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_ff(10); + if(ptr1 == NULL) { + printf("ptr1 - mymalloc_ff(10) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr1, "HELLO", 10); + printf("ptr1 is %s\n", ptr1); + + printf("2 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Allocate 45 bytes + // shouldn't fail + char* ptr2 = mymalloc_wf(45); + if(ptr2 == NULL) { + printf("ptr2 - mymalloc_ff(45) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr2, "GOODBYE", 45); + printf("ptr2 is %s\n", ptr2); + + printf("3 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Attempt to allocate 50 bytes + // should fail + char* ptr3 = mymalloc_bf(50); + if(ptr3 == NULL) { + printf("ptr3 - mymalloc_bf(50) failed\n"); + } + printf("4 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Free the first two pointers + myfree(ptr1); + myfree(ptr2); + printf("5 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + + // Double free, should cause a segmentation fault + //myfree(ptr2); + + mmDestroy(); + + return 0; +} diff --git a/06-MemoryManager/testmemmgr.c b/06-MemoryManager/testmemmgr.c new file mode 100644 index 0000000..e85db0a --- /dev/null +++ b/06-MemoryManager/testmemmgr.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "memory_manager.h" + +#define MY_HEAP_SIZE 100 + +int main() +{ + char my_heap[MY_HEAP_SIZE]; + mmInit(my_heap, MY_HEAP_SIZE); + + printf("1 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Allocate 10 bytes + // shouldn't fail + char* ptr1 = mymalloc_ff(10); + if(ptr1 == NULL) { + printf("ptr1 - mymalloc_ff(10) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr1, "HELLO", 10); + printf("ptr1 is %s\n", ptr1); + + printf("2 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Allocate 45 bytes + // shouldn't fail + char* ptr2 = mymalloc_wf(45); + if(ptr2 == NULL) { + printf("ptr2 - mymalloc_ff(45) failed\n"); + exit(EXIT_FAILURE); + } + strncpy(ptr2, "GOODBYE", 45); + printf("ptr2 is %s\n", ptr2); + + printf("3 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Attempt to allocate 50 bytes + // should fail + char* ptr3 = mymalloc_bf(50); + if(ptr3 == NULL) { + printf("ptr3 - mymalloc_bf(50) failed\n"); + } + printf("4 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + // Free the first two pointers + myfree(ptr1); + myfree(ptr2); + printf("5 -- Available Memory: %d, Fragment Count: %d\n", get_remaining_space(), get_fragment_count()); + + printf("Total successful mallocs: %d\n", get_mymalloc_count()); + + // Double free, should cause a segmentation fault + myfree(ptr2); + + mmDestroy(); + + return 0; +} diff --git a/07-FunWithFileSystems/FunWithFileSystems.md b/07-FunWithFileSystems/FunWithFileSystems.md new file mode 100644 index 0000000..04cc347 --- /dev/null +++ b/07-FunWithFileSystems/FunWithFileSystems.md @@ -0,0 +1,337 @@ +## Introduction and Background + +A mass storage device such as a disk drive, solid state drive, or USB "stick" can be considered a large contiguous block of storage like memory. Like memory, mass storage devices are accessed via an address, however mass storage devices address are for 'blocks' not bytes. A read from a block device reads the entire block and a write, writes an entire block. For mass storage devices, a block is typically 512 bytes. The OS creates an abstraction of 'files' and 'directories' (folder) over the top of mass storage devices to give the user (and applications) the appearance of a file system. A contemporary operating system such as Linux contains drivers for many file systems, with many being quite complex. + +In this lab you will experiment with creating different file systems in Linux as well as interpret a file system architecture for a brand-new file system, teeny tiny file system (TTFS). + +In Linux the file system is organized as a tree of files and directories starting at the root directory (/). The "mount" command allows a system administrator to hang (mount) file systems from a branch of the tree. Kind of like how you might hang an ornament on a tree during the holidays. To mount a file system, you first need to create what is known as a "mount point" i.e., an empty directory that will serve as the entry point for the file system. + +## Create and Mount a RAM Disk + +A RAM disk creates a functional file system directly in random access memory (RAM). Reads and writes to this file system will be an order of magnitude faster than mass storage device operations. This fast access speed is a huge advantage. + +What are the drawbacks? 1) Size – all file systems are limited based on the size of their backing media. For a RAM disk that backing media is RAM which is on the order of a few gigabytes. 2) Persistence – When the system is shutdown or rebooted, the data stored in RAM is lost. For a RAM disk this means that any files stored the file system will also be lost. + +Why use a RAM disk then? Temporary files – many applications use short-lived files, either for inter process communication, storing intermediate results, or logging status. For example, gcc runs through several phases to build an executable program: 1) running the processor, 2) generating assembly, 3) building object code 4) linking the final executable. The output from each of these phases is one or more temporary files that are ultimately thrown away when the final executable is built. Storing these intermediate files in a RAM disk may be able to increase compile speeds. RAM disks are also used during boot to place a minimal system in memory which can then start loading the actual system. + +To start, see how much free memory you have. + +```text +user@pc:~$ free -h + total used free shared buff/cache available +Mem: 3.9G 263M 3.1G 7.8M 469M 3.4G +Swap: 4.3G 0B 4.3G +``` + +You should see two rows in the output. One for physical memory and one for swap (the disk space reserved for the kernel to use for 'kicking out' pages from memory). + +For a description of what each field in the table means you can run: man free + +There are two file system drivers that can be used for RAM disks, ramfs and tmpfs. Large tmpfs disks can actually be swapped out to physical disk, which sort of defeats the purpose, but it is a little more full-featured than ramfs. + +Now, make a mount point for the RAM disk. /media is a common location for mount points. To do this you will need administrator (root) authority. The 'sudo' command allows you to temporarily escalate your system privileges to admin. You'll need to type your password to escalate your privileges. + +```text +user@pc:/$ sudo mkdir /media/ramdisk +``` + +Now we can mount the drive with the mount command and proper options. The following will create a 512 MB RAM disk with file system type tmpfs in /media/ramdisk. See man mount for full details. + +```text +user@pc:/$ sudo mount -t tmpfs -o size=512m tmpfs /media/ramdisk +``` + +The disk is now usable. + +Because the disk was made transiently, it will not be recreated on a reboot. This is because Linux does not keep a record of file systems that were mounted when it shuts down. There is, however, a file that Linux uses determine which file systems to mount at boot up. This file is the file system table (fstab) and is locate in the /etc directory. You can have a look opening /etc/fstab or just use the "cat" command to print it out. You can have a RAM disk be created on every boot by adding an entry to /etc/fstab. If you do this, the ram disk will be there on every boot, but any files present will be gone. + +To complete this activity, perform the following and record your answers to the questions: + +1. View the man page for free with "man free". What does each column mean? In your own words, what is the difference between free memory and available memory? +2. View the man page for mount with "man mount". Use the information in the man page to record which file system types your Linux installation supports. +3. Pick one of the file systems supported by our Linux installation and learn more about how it works (use Google to help). Give a summary of the file system. Document your resources. +4. Create the RAM disk as outlined above. What do each of the parameters to "mount" mean? +5. Record the output of free -h after creation of the RAM disk. What is different? Why? +6. Based on the observation of the free command before adding the ram disk, and after adding it and adding files to it, in which category of memory does the ram drive appear to reside? +7. Record the status of the RAM disk with the command df -h. What can you learn about the file system by running df? +8. Copy or download a large file into the RAM disk. I suggest a large pdf file (maybe around 25M). Interact with this file (such as opening a pdf with a viewer) in the RAM disk as well as a copy on the normal file system. What differences do you notice (e.g. performance, etc.)? Why do you think these difference happen or not? +9. Record the output of free -h and df -h now that the RAM disk has a file in it. How does the output compare to what you recorded before? Does the output make sense? Why? +10. Record the contents /etc/fstab. What does each entry mean? Consult "man fstab" for help. +11. What would an entry in /etc/fstab need to look like to create the 512MB tmpfs RAM disk when the system boots? + +When done, the drive should be unmounted to tell Linux that it's no longer needed: + +```text +user@pc:/media$ sudo umount /media/ramdisk +``` + +Remember, that since this is a RAM disk, unmounting the file system will destroy the contents of the file system. + +## Mount a File as a File System + +Linux represents all block devices as a file in a special file system directory '/dev'. This directory contains a representation of devices on the system. + +List the contents of '/dev' on your Linux VM, you should see several 'files' sdaX (X will be a number). These represent the disk partitions of the disk on your system. Partitioning a disk is a way to create logical sub-disks that can each contain a file system that Linux can mount into the directory tree. The 'file' in '/dev' will contain the binary representation of the file system. + +The entire disk (all partitions) is represented by the file '/dev/sda'. View the partitions created on the disk by running the following: + +```text +user@pc:/$ sudo fdisk -l /dev/sda +``` + +Run the following to view the binary data by reading from the file: + +```text +user@pc:/$ sudo hexdump -C /dev/sda1 +``` + +This will print out the contents of the device '/dev/sda1' in hexadecimal. + +Run 'mount' (with no arguments) to see all the file systems currently mounted on your Linux VM. Several of them are RAM disks used for temporary file systems. You should be able to see where your sdaX partitions are mounted. + +While a file system will typically be backed by a physical device represented in '/dev', it doesn't have to be. A file system can also be created using an ordinary file. This could be used to create an image to be written to an optical disk or a removable flash drive, or to simply explore file systems without having to install and partition a physical hard drive. + +Run the following to create a FAT16 image file: + +```text +user@pc:~$ sudo mkdir /media/myimage +user@pc:~$ sudo mkdosfs -C -s 1 -S 512 -F 16 flash.img 5000 +mkfs.fat 4.1 (2017-01-24) +``` + +This will create a file called flash.img which contains the raw bytes for a FAT16 file system with a sector size of 512 bytes and 5000 data blocks (a data block in FAT16 is 1024 bytes). A disk drive is organized as an array of logical blocks indexed by logical block address (LBA), however this image file is a contiguous array of the bytes that would be placed in the logical blocks if it were to be stored on a disk drive. On Linux, we can view the file bytes by using hexdump: + +```text +hexdump –C flash.img +``` + +Now mount the image into the Linux directory tree and list its contents by running the following: + +```text +user@pc:~$ sudo mount flash.img /media/myimage -o uid=YOURUSERNAME +user@pc:~$ cd /media/myimage/ +user@pc:/media/myimage$ ls -al +total 20 +drwxr-xr-x 2 root 0 16384 Dec 31 1969 . +drwxr-xr-x 8 root 0 4096 Nov 4 19:21 .. +``` + +NOTE: replace YOURUSERNAME with the name of your logged-in user. + +Now add some files to the file system image that you mounted. You can use touch to create an empty file or cp to copy a file into the /media/myimage directory. While this appears to be just creating or copying files into the directory, since the flash.img is mounted at /media/myimage, the files will be written to the file system image (flash.img) using the FAT16 file system driver. + +**Specifically, add four text files, and delete two of them. Also create at least one file with a long filename (longer than 8 characters).** + +Unmount the file system with umount when done. When you have completed the steps above answer the following questions: + +1. Where are the mounted partitions of '/dev/sda' mounted? Why do suspect that two partitions are used? What is an advantage of partitioning the disk in this way? +2. Look at the image file with hexdump (hexdump –C flash.img | more). NOTE: make sure the image is **unmounted** before you do this. Can you find your files? How about the ones you deleted? How did you find them or why couldn't you? +3. Show a capture of the hexdump (of the flash.img) containing the directory entries for the files you added to the image as well as the ones you added and then deleted. What is different? +4. Remount the image, change directory to the directory where the file system is mounted. Now try to unmount the file system with "umount /media/myimage". Did it work successfully? Why or why not? + +## Interpreting a File System - TTFS + +Linux supports many file system types. Each has their own intended use along with advantages and disadvantages. New file systems are being developed all the time to fit the needs of newer backing storage and application purposes. In this activity you will be given the format for a new file system (teeny tiny file system – TTFS). Study the file system format and use the information to interpret a binary file containing a TTFS file system image. + +TTFS stores files and directories of varying sizes. Each file is allocated one or more blocks of data. An index node (inode) stores information about a file or directory in the file system. A TTFS file system image is a binary file divided into the following regions: + +1. File system super block – contains information about the entire file system +2. inode bitmap – a bit map that indicates which inodes are free and which are used to store file information +3. block bitmap – a bit map that indicates which blocks are free and which hare used to store file data +4. inode table – an array of inodes for files and directories in the file system +5. block array – the array of data blocks for files and directories in the file system + +An image for TTFS is laid out like this: + +![TTFS Image](ttfs.png) + +Regions of the file system follow immediately after each other. The super block contains offset values that can be used to find where regions begin. Data blocks are 512 bytes long and are accessed via their block index. The block index is zero based, so the first block is block 0, the second is block 1, etc. + +### TTFS Super Block + +Each field in the super block is 4 bytes. The offset numbers indicate where the region begins from the ***start of the file system image***. Here is a diagram of each of the fields contained in the super block. + + + + + + + + + + + + + + + +
TTFS Super Block
TTFS Magic Value
inode count
block count
offset to inode bitmap
offset to block bitmap
offset to inode table
offset to data blocks
unused pads to 32 bytes
+ +- TTFS Magic Value – an eye-catcher – must contain the string value "TTFS" +- inode count – The total number of index nodes in the file system (used or unused) +- block count – the total number of blocks in the file system (used or not) +- offset to inode bitmap – the offset (in bytes) from the start of the file system image to the start of the inode bitmap +- offset to block bitmap – the offset (in bytes) from the start of the file system image to the start of the block bitmap +- offset to inode table – the offset (in bytes) from the start of the file system image to the start of the inode table +- offset to data blocks – the offset (in bytes) from the start of the file system image to the start of the data block array + +The last field "unused" is just a padding to make the super block 64 bytes (makes it easier to read when printed via a hex dump). + +To be a valid TTFS file system the image must begin with the characters "TTFS", this is a common way for operating systems to know which driver to load to interpret file a file system. + +The inode count represents the total number of index nodes in the file system. Each file or directory in the file system needs to have an index node. This count tells how many files or directories the file system can support. + +The block count represents the total number of data blocks that are in the file system. Each file or directory needs to be allocated at least one block to store data. This count tells how much space is available in the file system. + +The inode and block bitmap are arrays of bit representing which inodes and blocks are used for files, and which are not. For example, if a file system had 16 inodes and 2 were used for files, then the remaining inodes would be free. Used inodes are represented with a bit value of 1 and free inodes have a bit value of 0. So, for this example the inode bitmap would contain 2 bytes (8 bits per byte and 16 inodes requires 2 bytes) and would look like this: + +```text + Byte 0 Byte 1 + Binary: 00000011 00000000 +Hexadecimal: 03 00 +``` + +Notice that the numbers are in little endian. In other words, the byte ordering goes from low to high from left to the right, but the bit ordering goes from low to high from right to left. + +The super block for a TTFS image consisting of 20 inodes and 100 data blocks would look like this in a hexadecimal dump. NOTE: numbers in an x86 created binary image are little endian. + +
+54 54 46 53 14 00 00 00  64 00 00 00 20 00 00 00  |TTFS....d... ...|
+23 00 00 00 30 00 00 00  30 05 00 00 00 00 00 00  |#...0...0.......|
+
+ +54 54 46 53 is the TTFS magic value
+14 00 00 00 is the number of inodes – hex 00 00 00 14 -> 20 in decimal
+64 00 00 00 is the number of blocks – hex 00 00 00 64 -> 100 in decimal
+20 00 00 00 is the offset to the inode bitmap – hex 00 00 00 20 -> 32 in decimal
+23 00 00 00 is the offset to the block bitmap – hex 00 00 00 23 -> 35 in decimal
+30 00 00 00 is the offset to the inode table – hex 00 00 00 30 -> 48 in decimal
+30 05 00 00 is the offset to the block array – hex 00 00 05 30 -> 1328 in decimal + +### TTFS Index Node + +An index node contains metadata (data about the data) for a file or directory. The inode table contains an array of inodes, each inode is 64 bytes long and contains several fields. + +The structure of an inode is as follows: + +![TTFS inode](inode.png) + +- U – used bit – a single bit that indicates if this inode is used for a file (or directory) or not +- D – directory bit – a single bit that indicates if this inode is for a regular file or a directory +- block count – (1 byte) the total number of data blocks this file is using +- file name – (22 bytes) a string of characters representing the name of the file (null terminated). The file name in TTFS cannot be longer than 21 characters to make room for the null terminator +- file size – (4 bytes – little endian) represents the total size of the file in bytes. Block are 512 bytes long and a file might not end exactly at the end of a block +- allocated block table – (up to 9 entries 4 bytes each little endian) represents the block numbers that are allocated to this file. The block count indicates which entries in this table are valid. NOTE: Entries in the table indicate the block number for the allocated block number, not an offset in bytes. + +The inode for a file consisting of 1 data block, that is using 10 bytes might look like this in a hexadecimal dump: + +
+01 01 74 65 73 74 2e 74  78 74 00 00 00 00 00 00  |..test.txt......|
+00 00 00 00 00 00 00 00  0a 00 00 00 01 00 00 00  |................|
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+..... rest of the inode is zeros .....
+
+ +01 shows the used bit is on but the directory bit is not
+01 indicates the is 1 used block in the file
+74 65 73 74 2e 74 78 74 is the name of the file - ASCII text "test.txt"
+0a 00 00 00 is the size of the file in bytes – hex 00 00 00 0a -> 10 in decimal
+01 00 00 00 is the index of the first (and only) data block – hex 00 00 00 01 -> 1 in decimal + +### TTFS Directory + +Directories (folders) in TTFS are special files. The inode for a directory has the directory bit flipped to indicate that is a directory and not an ordinary file. The data blocks for a directory entry to not contain file data. Instead, they indicate the inodes for the files (or directories) that are contained in the directory. The structure for a directory entry data block is: + +![TTFS Directory Block](dirblock.png) + +The first 4 bytes indicates an integer number (little endian) of the number of entries contained in the block. The rest of the data block contains 4-byte integers (little endian) for the inodes for entries (files or directories). + +For example, consider a directory 'mydir' that contains two files 'file1.txt' and 'file2.txt' + +![Directory](dir.png) + +The inode for 'mydir' (inode 3) would contain a single data block. The directory data block would look like: + +
+02 00 00 00 05 00 00 00  06 00 00 00 00 00 00 00  |................|
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+..... rest of the block is zeros .....
+
+ +02 00 00 00 is the number of files in the block
+05 00 00 00 is the inode number for file1.txt – hex 00 00 00 05 -> 5 in decimal
+06 00 00 00 is the inode number for file2.txt – hex 00 00 00 06 -> 6 in decimal
+ +TTFS always contains a single special directory with no name (the file name is all zeros). This directory represents the root directory of the file system. All files and directories are contained in the root directory. The root director will always use inode 0. + +NOTE: a TTFS directory might use multiple data blocks. Each data block has the same structure. This allows for more than 127 entries in a directory (512 / 4 = 128 but one 4-byte value is used for the entry count). + +Download the [ttfs.img](ttfs.img) file. This contains a binary image for a TTFS file system. Using the output from hexdump -C and the specification for TTFS answer the following questions: + +NOTE: All integers are stored as little endian on x86. So, make sure you read the values correctly + +1. What is the largest file that TTFS can support? How did you compute this number? +2. What is the maximum number of files that can exist in a single TTFS directory? HINT: a TTFS directory might have more than one data block. + +For the following questions refer to the [ttfs.img](ttfs.img) provided: + +5. How may inodes and data blocks are in the file system? +6. How many inodes are free (not used by files or directories? +7. Draw a diagram of the directory hierarchy, include this diagram with your submission. +8. What are the names and sizes of each file in the file system? +9. How many blocks is each file in the file system? +10. For each file, what is the offset (from the start of the file system) for each data block? How did you compute this? +11. Find one of the text files in the file system. Write the data (as a string) for the file contents. How were you able to find the data? + +## Extra Credit - TTFS Dump + +Using the specification from "Interpreting a File System - TTFS" and the included header file [ttfs.h](ttfs.h) that defines the file system structures, write a program that will read in a TTFS file system image and print the directory structure and contents for each file. For example: + +```text +user@pc:~$ ttfsdump ./ttfstest.img +/file2.txt – 10 bytes +(the contents of file2.txt printed here) +/dir1/file1.txt – 100 bytes +(the contents of file1.txt printed here) +/dir1/dir2/file3.txt – 20 bytes +(the contents of file3.txt printed here) +(continue for all files) +``` + +Also add the following in your report: + +- Design – a description of your design decisions in creating your solution +- Build – instructions on how to build and run your program. Include the exact commands that are necessary + +Include your source code along with your report in your Canvas submission. + +## Deliverables + +You will need to include all your source files (if any) and any resources you used to complete lab. Please don't just google search for a solution, but if you do use Google for any help, include a description and URL of what you used to help you. + +Once you've completed all the lab activities and have answers to all the lab questions, create a report (text, doc, or pdf file) including the following: + +- Your name, section, date, and lab title +- Introduction – a description the lab in your own words +- Resources – a description of any external resources you used to complete the lab +- Analysis – a description of your experiences working with file systems in Linux as a result of this lab + - Include the answers to the questions asked in the lab. +- Conclusion + - Summary of what you learned in the lab + - What specifically was challenging about this lab? + - What did you like about it? + - What could we do to improve it for others? + +Be sure to include documentation of any external resources (man pages, stackoverflow, etc.) that you used to complete the lab. + +Upload your report to Canvas per your instructor's instructions. + +## Grading Criteria + +- (5 Points) Report Introduction - Thorough description of the lab in your own words. +- (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements. +- (5 Points) Documentation of Resources - Description of external resources used to complete the lab. +- (25 Points) Create and Mount a RAM disk - Responses to the "create a RAM disk" questions +- (25 Points) Mount a File as a File System - Responses to the "file as a file system" questions +- (35 Points) Interpreting a File System - TTFS - Responses to the TTFS interpretation questions +- (10 Points) Bonus - Implementation of the extra credit \ No newline at end of file diff --git a/07-FunWithFileSystems/dir.drawio b/07-FunWithFileSystems/dir.drawio new file mode 100644 index 0000000..ae762dc --- /dev/null +++ b/07-FunWithFileSystems/dir.drawio @@ -0,0 +1 @@ +7VZdb9MwFP01eezkxHFZH/sxQEhIQ5sEPCEvvkuMkjhy3TbZr+e6dpqvThswAZN4iu+x77HvuSdOArou6neaV9lHJSAPIiLqgG6CKArJ5RwfFmkcckk8kGop/KIOuJEP0GZ6dCcFbAcLjVK5kdUQTFRZQmIGGNdaHYbL7lU+3LXiKUyAm4TnU/SzFCbzVTDS4e9Bplm7c0j8TMHbxR7YZlyoQw+iVwFda6WMGxX1GnIrXquLy3v7yOzpYBpK85yE6sPtIa7iu1vCE6LfLMn3T99mnmXP850vuGiE1AjNbGqJ/cQn9RWYppXFQI2brjJT5AiEOOS5TEscJ3gc0AjsQRuJQi79RCGFsOkrDVv5wO+OVATjSsnSHNvEVgHbWK6dUVtnBUvtz4h8UD9afHiSFL0IqgCjG1ziE9B3LsXbMKQ+PnRNXXgo6/WzbR73NkpPzJ3SOPBi/4Tw0UT4e5lDeGFQ16H47PWLT0biL6bin96bP6I+Pat+dEb9+atXn7J/Tf14ov5EZCjF0t7eGJWqhKHeWLhuvlgJL2I2b4GvR2DRhpvaa+yiph9dg5ZYiu2VA2tpHB8LfWjZZuQi8mHHZoOmF4y5XCkgJp+VUb+wXLXTCTx9RxiuUzBPXeLT/vf6y860t8U05NzI/fC453rud7i2nu3sFY9e7jge2caV6bP636cx0cindDEicjpMiI4WPJX9665kL+dKNvIk+z1TxiNTxn/TlPS/KV/ElBh2/35uefcHTa9+AA== \ No newline at end of file diff --git a/07-FunWithFileSystems/dir.png b/07-FunWithFileSystems/dir.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1e6a9f557036a5d7516c65d07d9cea5a76241a GIT binary patch literal 4521 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 C*~eM{ literal 0 HcmV?d00001 diff --git a/07-FunWithFileSystems/dirblock.drawio b/07-FunWithFileSystems/dirblock.drawio new file mode 100644 index 0000000..30cb086 --- /dev/null +++ b/07-FunWithFileSystems/dirblock.drawio @@ -0,0 +1 @@ +7ZhRU6MwEMc/DY/eAGmqfZTq1dO70RmdUx9TkkLOlMWQ2uKnvwRCKdDW6mg9Z64vZf+ETfLb3XSpg4bTxUiSNP4FlAnHd+nCQSeO73vuUV9/GSUvlSPXCpHk1A6qhWv+zKonrTrjlGWNgQpAKJ42xRCShIWqoREpYd4cNgHRnDUlEesI1yERXfWWUxXbXWC31s8Yj+JqZs+1d6akGmyFLCYU5isSOnXQUAKo8mq6GDJh4FVcyue+b7i7XJhkidrlgQM2uJgNB7/Pb3iWg1Kj+x/BgfXyRMTMblh7k3kBdKb9litXeYVDapUy49F1UDCPuWLXKQnN3blOAK3Faiq05enL7gqr6ZhUbLEi2RWPGExZOf0ygSy9ZfqU5ryOhdezWrwSh0ojNvzR0nNNSF9YSK8A5m8ExhOd/I4JAvrnsHn+HrmNLwN0e5aeBxe9Y4pvLifh4+OaROtAYlRXnjVBqhgiSIg4rdWgibEe8xMgtfD+MKVye4yQmYJ1aM1EG4vIShnMZMi2JAK2hxGREVNbxvXXB0oyQRR/aq7j3al3s/U/9Xelvm2RX+2M6H/22dr/ktx89NncDneo8oQem25IWwkkpqopyeKCmtckZPQrohSTSaH4LtJqpiQ8LDsgTScoQnNnqH/DlXlvfRTGycKGpLRya7299vs71j5ee95047kSL7wmXJW285lhZ7gCbhqnKl16rXTptdOg3Ld9arV/azvCTUdo0HJUguk4KlJque23Z9lRJ8t62gxypdvzdrrpXjc1l6GELBsT+XJh1lVsLEHGTAQkfIgKfQgCZOEZTYrPx1Qy3rGQ/Y8q5MHLhbwHshKUTngw5T/YWrGvIN3Hrd8a3EU92Cfq6v1yhTX2/I0JrfepmliJ4JFBFGoqzITB0OD6xfHY3phySsv+iWX8mYwLV4Znaiq02A8OHHxifOmWKSu7p/1lv49aMVmT/ofvExJt1u+55XlU/1uATv8C \ No newline at end of file diff --git a/07-FunWithFileSystems/dirblock.png b/07-FunWithFileSystems/dirblock.png new file mode 100644 index 0000000000000000000000000000000000000000..65c4f5ebea6a43c924a6997ca770eb90b6762920 GIT binary patch literal 7496 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 \ No newline at end of file diff --git a/07-FunWithFileSystems/inode.png b/07-FunWithFileSystems/inode.png new file mode 100644 index 0000000000000000000000000000000000000000..6e0512061097f61588f2746465310d4ebf3c9f12 GIT binary patch literal 23964 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 Jp=W;ie*hL$S3m#& literal 0 HcmV?d00001 diff --git a/07-FunWithFileSystems/ttfs.drawio b/07-FunWithFileSystems/ttfs.drawio new file mode 100644 index 0000000..603ef81 --- /dev/null +++ b/07-FunWithFileSystems/ttfs.drawio @@ -0,0 +1 @@ +3ZnbcpswEIafhst2QAISX8bOoZ3paepO0+ZOBhk0EYgRIrbz9JVAGINwm6SxIc7kAi1Ch2//RcvagrNkfcNRFn9mIaYWsMO1BS8tABwXAEv92+GmspzXhoiTUHdqDHPyiLXR1taChDhvdRSMUUGytjFgaYoD0bIhztmq3W3JaHvWDEXYMMwDRE3rLQlFrHfh2Y39AyZRXM/s2PpOgurO2pDHKGSrHRO8suCMMyaqq2Q9w1TBq7lUz13vubtdGMepeMoDDNwtv35Pi+Uq/xHdLW6+kE8X7/QoD4gWesN5kWEuTQvKgnu9crGpcXBWpCFWI9oWnK5iIvA8Q4G6u5ICkLZYJFS2HHlprrCeDnOB1zsmveIbzBIs+EZ2qe8Cr3pEy8c50zRXjTMcV9viHUf42oa0/6Pt0A0ieaEpPYMYMIiRVKpeESMikQjGhgzAoZFBA5kW12iRTYZG5u5VmUALiWlsxKA3NDFvr8jkMYA2oyPmOkMT8w1iBiR5ZmXqMuAszxeI/5tUg7VqCSQIS2VzYr8OR+B3ToSeWPV7MIJDYZwYGKFqTzdC5i1doHKTog0MURIpPhQv1R0Fgsj040KbExKG6uEpxzl5LGO/UmzGSCrKvXhTy7tUIxWC5VUCpQamaIHpFAX3UemTGaOMl4uAy/LvddwB7ZG5ow6rNy5r0PNCPS5HMzX8iTipTh+7TNSBT5VkFzJd9CN15VRHeplnqxwSoyBW81RH13ChcACdA9czX9+gx0HwYA4yM9G3KHTYcw4eV+hm5vBSofd/M71toW/bwwn9NBIV2PPpelyhnz1f6HL75Z5O/n0O/cFlfn4SMnd7yg3HlbmZkL9M5qf4NnfB0DIHT8jPcRpeqNqtUjpFeU6CNvHSXb8Uxvde3fytqZaNy3WrtdGtvUAF4hEWfxNV1Q+HrWqxiX0Hq9dDtbZxTGUcPrRrzH2o9QzflFQarzqTzkdX11s5K3iA9VNgpybcGcjvFiUmnYEqMMZApee32/4PMZgfGXM5pVohWyq/xCpmPyaqSA/sa9JT+dofj4H0MuZji0gHdnzXVweCx3xhArM++2oR6RwsIr1RR6TnvDAiQbeecn7kiDQrz1dpeNLxaPd77gDxKJvN732Vx5pfTeHVHw== \ No newline at end of file diff --git a/07-FunWithFileSystems/ttfs.h b/07-FunWithFileSystems/ttfs.h new file mode 100644 index 0000000..75a1735 --- /dev/null +++ b/07-FunWithFileSystems/ttfs.h @@ -0,0 +1,37 @@ +#ifndef TTFS_H +#define TTFS_H + +#include + +#define TTFS_MAGIC "TTFS" +#define FILE_NAME_MAX_LENGTH 22 +#define MAX_FILE_BLOCKS 9 +#define BLOCK_SIZE 512 + +typedef struct __attribute__((packed)) ttfs_super_block { + char ttfs_magic[4]; + uint32_t inode_count; + uint32_t block_count; + uint32_t offset_to_inode_map; + uint32_t offset_to_block_map; + uint32_t offset_to_inode_table; + uint32_t offset_to_data_blocks; + uint32_t unused; +} ttfs_super_block; + +typedef struct __attribute__((packed)) ttfs_inode { + uint8_t inode_used:1; + uint8_t is_directory:1; + uint8_t unused:6; + uint8_t block_count; + char file_name[FILE_NAME_MAX_LENGTH]; + uint32_t file_size; + uint32_t blocks[MAX_FILE_BLOCKS]; +} ttfs_inode; + +typedef struct __attribute__((packed)) ttfs_directory_block { + uint32_t entry_count; + uint32_t inodes_inodes[BLOCK_SIZE/sizeof(uint32_t) - 1]; +} ttfs_directory_block; + +#endif // TTFS_H diff --git a/07-FunWithFileSystems/ttfs.img b/07-FunWithFileSystems/ttfs.img new file mode 100644 index 0000000000000000000000000000000000000000..61e3de89f768a57f2eb5a0c3418d2af976b20d3a GIT binary patch literal 52528 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md new file mode 100644 index 0000000..a91d6c3 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Labs + +Lab assignments for CS3841 - Design of Operating Systems \ No newline at end of file diff --git a/TTOS/.DS_Store b/TTOS/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cbc84723429f27520e00103b83f5d0614a855200 GIT binary patch literal 6148 zcmeHKO-jR15T0oZR@~H`3m5MSJ%A8PJVAG^q=~4Inxb_7?&4MSUVih_U`PtCM05t` zeJ}I#ruh;w9U|h@zFrb7h-eNKoSb4A5%G%-Wa1WavYxT0n(mv2<+^GI(P8+F49K%P zp(lE#iW>Uz{I)y$xtDLlh;3Vzo2K2sgZzAZUcX|5DWwZ|BeClY?1kyVXVPGFc1uM49NE(K?MuPY^a|O zEII-JXE3W^FSCT?B*(%r8^Qx&O9fgg`-s7o4tw&r!Z90KI + +#include "errorCode.h" + +/* https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html */ + +/* ELF Data Types */ +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* ELF Magic */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +/* Class */ +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +/* Data encoding */ +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +/* Version */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Type */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xfe00 +#define ET_HIOS 0xfeff +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +#define EI_NIDENT 16 + +typedef struct { + uint8_t e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* Program header types */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +typedef struct { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +/* Section header type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* Section header name index */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +/* Section header flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MERGE 0x10 +#define SHF_STRINGS 0x20 +#define SHF_INFO_LINK 0x40 +#define SHF_LINK_ORDER 0x80 +#define SHF_OS_NONCONFORMING 0x100 +#define SHF_GROUP 0x200 +#define SHF_TLS 0x400 +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xf0000000 + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +/* Symbol table index values */ +#define STN_UNDEF 0 + +typedef struct { + Elf64_Word st_name; + uint8_t st_info; + uint8_t st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DPTMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 +#define R_X86_64_TLSLD 20 +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 +#define R_X86_64_TPOFF32 23 +#define R_X86_64_PC64 24 +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_SIZE32 32 +#define R_X86_64_SIZE64 33 + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s,t) (((s)<<32)+((t)&0xffffffffL)) + +typedef struct elf_file { + int size; + void* contents; + Elf64_Ehdr* ehdr; + Elf64_Phdr* phdr; + Elf64_Shdr* shdr; +} elf_file; + +errorCode_t load_elf(const char* filename, elf_file* file); +errorCode_t get_elf_proc_size(elf_file* file, uint64_t* size); +errorCode_t populate_elf_proc(elf_file* file, void* tgt_addr); +errorCode_t find_symbol(elf_file* file, const char* name, uint64_t* offset); +errorCode_t free_elf(elf_file* file); + +#endif \ No newline at end of file diff --git a/TTOS/include/errorCode.h b/TTOS/include/errorCode.h new file mode 100644 index 0000000..76b9fd6 --- /dev/null +++ b/TTOS/include/errorCode.h @@ -0,0 +1,15 @@ +#ifndef _ERRORCODE_H +#define _ERRORCODE_H + +typedef int errorCode_t; + +#define IS_ERROR(n) (n < SUCCESS) + +#define SUCCESS 0 +#define EBADPARM -1 +#define ENOTFOUND -2 +#define EBADEXEC -3 +#define EMEMORY -4 +#define EFILESYS -5 + +#endif \ No newline at end of file diff --git a/TTOS/include/fs/fs.h b/TTOS/include/fs/fs.h new file mode 100644 index 0000000..e37b3c9 --- /dev/null +++ b/TTOS/include/fs/fs.h @@ -0,0 +1,22 @@ +#ifndef _FS_H +#define _FS_H + +#include "errorCode.h" + +/* fs_open flags */ +#define O_RDONLY 00000000 +#define O_WRONLY 00000001 +#define O_RDWR 00000002 + +/* fs_seek whence */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +errorCode_t fs_open(const char* path, int flags, int* fd); +errorCode_t fs_write(int fd, const void *buf, int count, int* bytes_written); +errorCode_t fs_read(int fd, void *buf, int count, int* bytes_read); +errorCode_t fs_seek(int fd, int offset, int whence, int* distance); +errorCode_t fs_close(int fd); + +#endif \ No newline at end of file diff --git a/TTOS/include/memory.h b/TTOS/include/memory.h new file mode 100644 index 0000000..0d80da4 --- /dev/null +++ b/TTOS/include/memory.h @@ -0,0 +1,15 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#include "errorCode.h" + +#define PAGE_SIZE 4096 +#define PAGE_ALIGN(n) (n + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1) + +errorCode_t allocate_user_memory(int size, void** addr); +errorCode_t free_user_memory(void* addr, int size); + +errorCode_t get_kernel_memory(int size, void** addr); +errorCode_t free_kernel_memory(void* addr, int size); + +#endif \ No newline at end of file diff --git a/TTOS/include/process.h b/TTOS/include/process.h new file mode 100644 index 0000000..159d570 --- /dev/null +++ b/TTOS/include/process.h @@ -0,0 +1,19 @@ +#ifndef _PROCESS_H +#define _PROCESS_H + +#define STACK_SIZE 8192 + +#include "elf.h" + +typedef struct process { + void* entry_point; + void* exec_start; + void* stack_start; + void* stack_end; + int size; +} process; + +errorCode_t create_process(const char* file, process* proc); +errorCode_t free_process(process* proc); + +#endif diff --git a/TTOS/include/syscall.h b/TTOS/include/syscall.h new file mode 100644 index 0000000..28ed785 --- /dev/null +++ b/TTOS/include/syscall.h @@ -0,0 +1,6 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +long system_call(long n, ...); + +#endif \ No newline at end of file diff --git a/TTOS/ld.script b/TTOS/ld.script new file mode 100644 index 0000000..5bfe7fc --- /dev/null +++ b/TTOS/ld.script @@ -0,0 +1,5 @@ +ENTRY(main) +SECTIONS +{ + . = 0x000000; /* Image starts here */ +} \ No newline at end of file diff --git a/TTOS/makefile b/TTOS/makefile new file mode 100644 index 0000000..4c5fc37 --- /dev/null +++ b/TTOS/makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-g -Wall -Iinclude +LFLAGS= + +OBJS=$(patsubst %.c,%.o,$(wildcard src/*.c)) $(patsubst %.c,%.o,$(wildcard src/fs/*.c)) + +all: ttos + +ttos: $(OBJS) + $(CC) $(LFLAGS) -o ttos $(OBJS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f $(OBJS) ttos \ No newline at end of file diff --git a/TTOS/src/elf.c b/TTOS/src/elf.c new file mode 100644 index 0000000..8750a31 --- /dev/null +++ b/TTOS/src/elf.c @@ -0,0 +1,307 @@ +#include +#include +#include + +#include "fs/fs.h" +#include "syscall.h" +#include "elf.h" +#include "process.h" +#include "memory.h" + +static int validate_magic(uint8_t e_ident[EI_NIDENT]) { + // ELF Magic must match + if(e_ident[0] != ELFMAG0 || e_ident[1] != ELFMAG1 || e_ident[2] != ELFMAG2 || e_ident[3] != ELFMAG3) { + return -1; + } + // Currently, only support 64 bit executables + if(e_ident[4] != ELFCLASS64) { + return -1; + } + // Currently, only support LSB byte order executables + if(e_ident[5] != ELFDATA2LSB) { + return -1; + } + // Currently, only support ELF current version + if(e_ident[6] != EV_CURRENT) { + return -1; + } + return 0; +} + +static errorCode_t get_file_data(const char* path, elf_file* file) { + int rc; + + // Open the file + int fd = 0; + rc = fs_open(path, O_RDONLY, &fd); + if(IS_ERROR(rc)) { + return rc; + } + + // Seek to the beginning and then the end + // to get the file size + fs_seek(fd, 0, SEEK_SET, 0); + rc = fs_seek(fd, 0, SEEK_END, &file->size); + if(IS_ERROR(file->size) || file->size == 0) { + return EBADEXEC; + } + + rc = get_kernel_memory(file->size, &file->contents); + if(IS_ERROR(rc)) { + return rc; + } + + // Seek to the beginning and read the file data + fs_seek(fd, 0, SEEK_SET, 0); + int bytes_read = 0; + rc = fs_read(fd, file->contents, file->size, &bytes_read); + + // Check error if error use error code if one was returned + if(IS_ERROR(rc)) { + free_kernel_memory(file->contents, file->size); + fs_close(fd); + return rc; + } + + // Check error ELIBBAD if data read != size + if(bytes_read != file->size) { + free_kernel_memory(file->contents, file->size); + fs_close(fd); + return EBADEXEC; + } + + // Close the file and return + fs_close(fd); + return 0; +} + +static Elf64_Phdr* get_program_header(elf_file* file, int index) { + return (Elf64_Phdr*)((char*)file->phdr + index * file->ehdr->e_phentsize); +} + +static Elf64_Shdr* get_section_header(elf_file* file, int index) { + return (Elf64_Shdr*)((char*)file->shdr + index * file->ehdr->e_shentsize); +} + +static void* find_external_symbol(elf_file* file, Elf64_Shdr *symtbl_shdr, Elf64_Word st_name) { + + if(symtbl_shdr->sh_link == 0) { + return 0; + } + + Elf64_Shdr* strtbl_hdr = get_section_header(file, symtbl_shdr->sh_link); + char* strtbl = (char*)((uint8_t*)file->contents + strtbl_hdr->sh_offset); + char* symbol_name = &(strtbl[st_name]); + + if(strncmp(symbol_name, "system_call", 7) == 0) { + return system_call; + } + return 0; +} + +static errorCode_t relocate_symbols(elf_file* file, void* tgt_addr) { + + for(int i = 0; i < file->ehdr->e_shnum; i++) { + + Elf64_Shdr* shdr = get_section_header(file, i); + + if(shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) { + + // Retrieve the sections headers for the relocation section, linked symbol table, and target section + Elf64_Shdr* rel_shdr = shdr; + Elf64_Shdr *symtbl_shdr = get_section_header(file, rel_shdr->sh_link); + Elf64_Shdr *tgt_shdr = get_section_header(file, rel_shdr->sh_info); + + // Retrieve the linked symbol table + Elf64_Sym* symtbl = (Elf64_Sym*)((uint8_t*)file->contents + symtbl_shdr->sh_offset); + + // Loop through each relocation entry and update the target + int entry_count = rel_shdr->sh_size / rel_shdr->sh_entsize; + for (int j = 0; j < entry_count; j++) { + + Elf64_Rela* relhdr = (Elf64_Rela*)((uint8_t*)file->contents + rel_shdr->sh_offset + j*rel_shdr->sh_entsize); + Elf64_Xword symbol = ELF64_R_SYM(relhdr->r_info); + Elf64_Xword type = ELF64_R_TYPE(relhdr->r_info); + + // Symbol address + // For relocatable files - start of the exec + offset to the section containing the symbol + offset to the symbol in the section (aka symbol value) + // For all other files - start of the exec + symbol value (aka virtual address) + // For undefined symbols - search for the symbol externally + void* symbol_address = 0; + if(file->ehdr->e_type == ET_REL) { + symbol_address = (void*)((uint8_t*)tgt_addr + file->shdr[symtbl[symbol].st_shndx].sh_offset + symtbl[symbol].st_value); + } else if(symtbl[symbol].st_shndx == STN_UNDEF) { + symbol_address = find_external_symbol(file, symtbl_shdr, symtbl[symbol].st_name); + } else { + symbol_address = (void*)((uint8_t*)tgt_addr + symtbl[symbol].st_value); + } + if(symbol_address == 0) { + return -1; + } + + // Location in section to patch + // For relocatable files - start of exec + offset to patch section + offset in the section + // For all other files - start of the exec + relocation offset value (aka virtual address) + void* patch_location = file->ehdr->e_type == ET_REL ? + (void*)((uint8_t*)tgt_addr + tgt_shdr->sh_offset + relhdr->r_offset) : + (void*)((uint8_t*)tgt_addr + relhdr->r_offset); + + // retrieve the addend, only applies to RELA entries + Elf64_Sxword addend = file->shdr[i].sh_type == SHT_RELA ? relhdr->r_addend : 0; + + // https://refspecs.linuxbase.org/elf/x86_64-abi-0.98.pdf page 69 + switch(type) { + case R_X86_64_PC8: + *(uint8_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location; + break; + case R_X86_64_PC16: + *(uint16_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location; + case R_X86_64_PC32: + case R_X86_64_PLT32: + *(uint32_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location; + break; + case R_X86_64_PC64: + *(uint64_t*)patch_location = (uint8_t*)symbol_address + addend - (uint8_t*)patch_location; + break; + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + *(uint64_t*)patch_location = (uint64_t)symbol_address; + break; + } + +// printf("%lX %lX %016lX %016lX\n", symbol, type, (uint64_t)symbol_address, (uint64_t)patch_location); + } + } + } + return SUCCESS; +} + +errorCode_t load_elf(const char* path, elf_file* file) { + if(file == 0 || path == 0) { + return EBADPARM; + } + + // Initialize the file and retrieve the file data + memset(file, 0x00, sizeof(elf_file)); + int rc = get_file_data(path, file); + if(IS_ERROR(rc)) { + return rc; + } + + // Validate the file magic value + if(validate_magic(file->contents) != 0) { + free_elf(file); + return EBADEXEC; + } + + file->ehdr = (Elf64_Ehdr*)file->contents; + + /* Only support dynamic linked files */ + if(file->ehdr->e_type != ET_DYN) { + free_elf(file); + return EBADEXEC; + } + + if(file->ehdr->e_phoff == 0) { + free_elf(file); + return EBADEXEC; + } + file->phdr = (Elf64_Phdr*)((uint8_t*)file->contents + file->ehdr->e_phoff); + + if(file->ehdr->e_shoff == 0) {; + free_elf(file); + return EBADEXEC; + } + file->shdr = (Elf64_Shdr*)((uint8_t*)file->contents + file->ehdr->e_shoff); + + return SUCCESS; +} + +errorCode_t get_elf_proc_size(elf_file* file, uint64_t* size) { + + if(file == 0 || size == 0) { + return EBADPARM; + } + + // Determine the size to allocate for the process + // Determined by the highest address of any memory segment in the program header + Elf64_Phdr* highest_header = 0; + for(int i = 0; i < file->ehdr->e_phnum; i++) { + Elf64_Phdr *phdr = get_program_header(file, i); + if (phdr->p_type == PT_LOAD) { + if (highest_header == 0 || highest_header->p_vaddr < phdr->p_vaddr) { + highest_header = phdr; + } + } + } + + *size = (uint64_t)highest_header->p_vaddr + (uint64_t)highest_header->p_memsz; + return SUCCESS; +} + +errorCode_t populate_elf_proc(elf_file* file, void* tgt_addr) { + + if(file == 0 || tgt_addr == 0) { + return EBADPARM; + } + + // Copy program sections into the process + for(int i = 0; i < file->ehdr->e_shnum; i++) { + Elf64_Shdr* shdr = get_section_header(file, i); + if(shdr && (shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr > 0) { + memcpy(((uint8_t*)tgt_addr) + shdr->sh_addr, ((uint8_t*)file->contents) + shdr->sh_offset, shdr->sh_size); + } + } + + // Relocate symbols + return relocate_symbols(file, tgt_addr); +} + +errorCode_t find_symbol(elf_file* file, const char* name, uint64_t* offset) { + + if(offset == 0) { + return EBADPARM; + } + + // Search for a symbol + // Iterate through each section + for(int i = 0; i < file->ehdr->e_shnum; i++) { + + // Find a section that represents a symbol table + Elf64_Shdr* shdr = get_section_header(file, i); + if(shdr->sh_type == SHT_SYMTAB) { + + // Retrieve the corresponding string table + Elf64_Shdr* strtbl_hdr = get_section_header(file, shdr->sh_link); + char* strtbl = (char*)((uint8_t*)file->contents + strtbl_hdr->sh_offset); + + // Iterate through each entry searching for the symbol string + int entry_count = shdr->sh_size / shdr->sh_entsize; + for(int j = 0; j < entry_count; j++) { + Elf64_Sym* symtbl = (Elf64_Sym*)((uint8_t*)file->contents + shdr->sh_offset + j*shdr->sh_entsize); + char* symbol_name = &(strtbl[symtbl->st_name]); + + // Check symbol name and return offset + // For relocatable files - offset to symbol table + offset to the symbol (aka symbol value) + // For all other files - symbol value (aka virtual address) + if(strcmp(symbol_name, name) == 0) { + if(file->ehdr->e_type == ET_REL) { + *offset = file->shdr[symtbl->st_shndx].sh_offset + symtbl->st_value; + } else { + *offset = symtbl->st_value; + } + return SUCCESS; + } + } + } + } + + return ENOTFOUND; +} + +errorCode_t free_elf(elf_file* file) { + free_kernel_memory(file->contents, file->size); + memset(file, 0x00, sizeof(elf_file)); + return SUCCESS; +} + diff --git a/TTOS/src/fs/fs.c b/TTOS/src/fs/fs.c new file mode 100644 index 0000000..b9bab91 --- /dev/null +++ b/TTOS/src/fs/fs.c @@ -0,0 +1,57 @@ +#include +#include + +#include "errorCode.h" + +errorCode_t fs_open(const char* path, int flags, int* fd) { + if(fd == 0) { + return EBADPARM; + } + int rc = syscall(SYS_open, path, flags); + if(rc == -1) { + return EFILESYS; + } + *fd = rc; + return SUCCESS; +} + +errorCode_t fs_write(int fd, const void *buf, int count, int* bytes_written) { + int rc = syscall(SYS_write, fd, buf, count); + if(rc == -1) { + return EFILESYS; + } + if(bytes_written != 0) { + *bytes_written = rc; + } + return SUCCESS; +} + +errorCode_t fs_read(int fd, void *buf, int count, int* bytes_read) { + int rc = syscall(SYS_read, fd, buf, count); + if(rc == -1) { + return EFILESYS; + } + if(bytes_read != 0) { + *bytes_read = rc; + } + return SUCCESS; +} + +errorCode_t fs_seek(int fd, int offset, int whence, int* distance) { + int rc = syscall(SYS_lseek, fd, offset, whence); + if(rc == -1) { + return EFILESYS; + } + if(distance != 0) { + *distance = rc; + } + return SUCCESS; +} + +errorCode_t fs_close(int fd) { + int rc = syscall(SYS_close, fd); + if(rc == -1) { + return EFILESYS; + } + return SUCCESS; +} \ No newline at end of file diff --git a/TTOS/src/main.c b/TTOS/src/main.c new file mode 100644 index 0000000..bfe6d6e --- /dev/null +++ b/TTOS/src/main.c @@ -0,0 +1,16 @@ +#include + +#include "process.h" + +int main(int argc, char* argv[]) { + process out; + printf("%d\n", create_process("test", &out)); + + int (*main_exec)() = out.entry_point; + int ret_val = main_exec(); + + printf("%d\n", ret_val); + + free_process(&out); + return 0; +} \ No newline at end of file diff --git a/TTOS/src/memory.c b/TTOS/src/memory.c new file mode 100644 index 0000000..02710f4 --- /dev/null +++ b/TTOS/src/memory.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include "errorCode.h" +#include "memory.h" + +int allocate_user_memory(int size, void** addr) { + if(addr == 0) { + return EBADPARM; + } + + uint64_t aligned_size = PAGE_ALIGN(size); + *addr = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if(*addr == MAP_FAILED) { + *addr = 0; + return EMEMORY; + } + + return SUCCESS; +} + +int free_user_memory(void* addr, int size) { + if(addr == 0) { + return EBADPARM; + } + int rc = munmap(addr, size); + if(rc == -1) { + return EMEMORY; + } + return SUCCESS; +} + +int get_kernel_memory(int size, void** addr) { + if(addr == 0) { + return EBADPARM; + } + *addr = malloc(size); + if(*addr == 0) { + return EMEMORY; + } + return SUCCESS; +} + +int free_kernel_memory(void* addr, int size) { + if(addr == 0) { + return EBADPARM; + } + free(addr); + return SUCCESS; +} \ No newline at end of file diff --git a/TTOS/src/process.c b/TTOS/src/process.c new file mode 100644 index 0000000..9b37a11 --- /dev/null +++ b/TTOS/src/process.c @@ -0,0 +1,80 @@ +#include +#include + +#include "errorCode.h" +#include "elf.h" +#include "process.h" +#include "memory.h" + +static errorCode_t allocate_process(int size, process* proc) { + int aligned_size = PAGE_ALIGN(size); + int rc = allocate_user_memory(aligned_size + STACK_SIZE, &(proc->exec_start)); + if(IS_ERROR(rc)) { + return rc; + } + proc->stack_start = ((uint8_t*)(proc->exec_start) + aligned_size); + proc->stack_end = ((uint8_t*)(proc->stack_start) + STACK_SIZE); + proc->size = aligned_size + STACK_SIZE; + return SUCCESS; +} + +int create_process(const char* path, process* proc) { + if(proc == 0) { + return EBADPARM; + } + + // Load the executable file + elf_file file; + int rc = load_elf(path, &file); + if(IS_ERROR(rc)) { + return rc; + } + + // Allocate the process address space + uint64_t proc_size = 0; + rc = get_elf_proc_size(&file, &proc_size); + if(IS_ERROR(rc)) { + free_elf(&file); + return rc; + } + memset(proc, 0x00, sizeof(process)); + rc = allocate_process(proc_size, proc); + if(IS_ERROR(rc)) { + free_elf(&file); + return rc; + } + + // Populate the process address space + rc = populate_elf_proc(&file, proc->exec_start); + if(IS_ERROR(rc)) { + free_elf(&file); + free_process(proc); + return rc; + } + + // Set the process entry point + uint64_t offset_to_main = 0; + rc = find_symbol(&file, "main", &offset_to_main); + if(IS_ERROR(rc)) { + free_elf(&file); + free_process(proc); + return rc; + } + proc->entry_point = (void*)((uint8_t*)proc->exec_start + offset_to_main); + + // Free the executable - no longer needed since process has been created + free_elf(&file); + return SUCCESS; +} + +errorCode_t free_process(process* proc) { + if(proc == 0) { + return EBADPARM; + } + free_user_memory(proc->exec_start, proc->size); + proc->exec_start = 0; + proc->stack_start = 0; + proc->stack_end = 0; + proc->size = 0; + return SUCCESS; +} \ No newline at end of file diff --git a/TTOS/src/syscall.c b/TTOS/src/syscall.c new file mode 100644 index 0000000..0c7bf9e --- /dev/null +++ b/TTOS/src/syscall.c @@ -0,0 +1,21 @@ +#include +#include + +#include "fs/fs.h" + +long system_call(long n, ...) { + long rc = 0; + + va_list ap; + va_start(ap, n); + + if(n == 1) { + int fd = va_arg(ap, int); + const char* buf = va_arg(ap, const char*); + int count = va_arg(ap, int); + int* bytes_written = va_arg(ap, int*); + rc = fs_write(fd, buf, count, bytes_written); + } + + return rc; +} \ No newline at end of file diff --git a/TTOS/test.c b/TTOS/test.c new file mode 100644 index 0000000..190e342 --- /dev/null +++ b/TTOS/test.c @@ -0,0 +1,27 @@ +//#include + +long system_call(long n, ...); + +int j = 3; +int i = 10; + +int foo3(int b); + +int foo2(int b) { + return foo3(b) + 2; +} + +int foo1(int a) { + return foo2(a) + 2 + i; +} + +int main(int argc, char* argv[]) { +// printf("hi\n"); +// j = 10; + system_call(1, 1, "abc\n", 4); + int result = foo1(5 + j); + system_call(1, 1, result, 4); + system_call(1, 1, "\n", 1); + return foo1(5 + j); +// return foo1(5 + j); +} \ No newline at end of file diff --git a/TTOS/test2.c b/TTOS/test2.c new file mode 100644 index 0000000..5f85d24 --- /dev/null +++ b/TTOS/test2.c @@ -0,0 +1,3 @@ +int foo3(int b) { + return b + 3; +} \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..1db9d7a --- /dev/null +++ b/build.bat @@ -0,0 +1 @@ +pandoc --webtex --ascii -f markdown -t html5 -o .\%1.html .\%1.md \ No newline at end of file