├── README.md ├── lab1 ├── README.md ├── bin │ ├── hello_world.exe │ ├── test_exec.exe │ ├── test_pid.exe │ ├── test_system.exe │ ├── thread1.exe │ └── thread2.exe ├── images │ ├── process │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── exec1.png │ │ ├── exec2.png │ │ ├── exec3.png │ │ ├── exec4.png │ │ ├── sys1.png │ │ ├── sys2.png │ │ ├── sys3.png │ │ └── sys4.png │ └── thread │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ ├── 9.png │ │ ├── exec.png │ │ └── sys.png ├── process │ ├── hello_world.c │ ├── test_exec.c │ ├── test_pid.c │ └── test_system.c └── thread │ ├── test_thread1.c │ └── test_thread2.c ├── lab2 ├── README.md ├── images │ ├── mem │ │ ├── alloc1.png │ │ ├── alloc10.png │ │ ├── alloc11.png │ │ ├── alloc12.png │ │ ├── alloc13.png │ │ ├── alloc14.png │ │ ├── alloc15.png │ │ ├── alloc16.png │ │ ├── alloc17.png │ │ ├── alloc18.png │ │ ├── alloc2.png │ │ ├── alloc3.png │ │ ├── alloc4.png │ │ ├── alloc5.png │ │ ├── alloc6.png │ │ ├── alloc7.png │ │ ├── alloc8.png │ │ └── alloc9.png │ ├── pipe │ │ ├── pipe_with_lock.png │ │ └── pipe_without_lock.png │ └── sig │ │ ├── sig_alarm1.png │ │ ├── sig_alarm2.png │ │ ├── sig_quit1.png │ │ └── sig_quit2.png ├── memory │ ├── .gitignore │ ├── CMakeLists.txt │ ├── Example.md │ ├── include │ │ ├── Allocator.h │ │ └── VarSizeAllocMngr.h │ └── src │ │ ├── Allocator.cpp │ │ ├── VarSizeAllocMngr.cpp │ │ └── main.cpp ├── pipe │ ├── pipe.c │ ├── pipe.exe │ ├── pipe_lock.c │ ├── pipe_lock.exe │ └── shared.txt └── sig │ ├── sig_receive.c │ └── sig_receive.exe └── lab3 ├── CTP ├── .gitignore ├── CMakeLists.txt ├── Core │ ├── CMakeLists.txt │ ├── include │ │ └── CTP │ │ │ ├── ThreadPool.hpp │ │ │ ├── details │ │ │ └── ThreadPool.inl │ │ │ └── function2 │ │ │ └── function2.hpp │ └── src │ │ └── ThreadPool.cpp ├── README.md └── Test │ ├── CMakeLists.txt │ ├── include │ ├── test.h │ └── test_func.h │ └── test.cpp ├── FileSystem ├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── include │ ├── Ext2.h │ ├── Log.h │ ├── Shell.h │ └── Test.h └── src │ ├── Ext2.cpp │ ├── Shell.cpp │ └── main.cpp ├── README.md └── images ├── ctp ├── 0.png ├── 1.png ├── a.png ├── ans.png ├── ans0.png ├── err.png ├── res0.png ├── res1.png └── xxx.png └── fs ├── entry.png ├── ext2.png ├── impl0.png ├── impl1.png ├── inode.png ├── loc.png ├── run.png └── str.png /README.md: -------------------------------------------------------------------------------- 1 | # OS_Lab -------------------------------------------------------------------------------- /lab1/README.md: -------------------------------------------------------------------------------- 1 | # OS_Lab1 2 | 3 | ## Part 1 Process 4 | 5 | --- 6 | 7 | 运行课本 p103 3.7 的程序,结果如下 8 | 9 | 10 | 11 | 可以看出父进程和子进程是并发执行的,在父进程中 `fork()` 的返回值是子进程的pid,而在子进程中 `fork()` 的返回值是0 12 | 13 | 去除 `wait(NULL)` 后,并让父进程 `sleep(20)`, 然后运行程序,可以看到,子进程运行结束后由于父进程没有执行 `wait()`, 因此其变成了僵尸进程(Z+) 14 | 15 | 16 | 17 | --- 18 | 19 | 在程序中添加一个全局变量 20 | ```cpp 21 | int global = 0; 22 | ``` 23 | 24 | 在父进程中 25 | ```cpp 26 | global += 2; 27 | ``` 28 | 29 | 在子进程中 30 | ```cpp 31 | global += 1; 32 | ``` 33 | 34 | 并打印输出 `global` 的值如下: 35 | 36 | 37 | 38 | 可以看到父进程和子进程中的值并不相同,即这两个 `global` 并不是同一个变量。但是它们的地址却一致,这是因为此地址仅为 `global` 在其各自的进程地址空间内的相对地址。而子进程是从父进程 `fork()` 而来的,因此他们的 `global` 的相对地址也一致. 39 | 40 | --- 41 | 42 | 在 `return` 前对 `global` 操作 43 | ```cpp 44 | global += 1; 45 | printf("final: global = %d\n", global); 46 | ``` 47 | 48 | 49 | 50 | 可以看出父子进程分别对其各自的变量进行了 +1 操作. 51 | 52 | --- 53 | 54 | ### **exec** 55 | 56 | 在子进程中开始处调用 `execl("./bin/hello_world.exe",NULL);`, 此处的 `"./bin/hello_world.exe"` 的作用是输出 helloworld 和进程的 pid 值. 57 |
58 | 59 | 结果如下: 60 |
61 | 62 | 63 | 可以看到子进行直接去执行了 `hello_world.exe`,不会执行源程序中打印 pid 的部分. 64 | 65 | 如果我们换成在子进程的末尾处调用,则: 66 |
67 | 68 | 结果如下: 69 |
70 | 71 | 72 | 则子进程会把原来进程中打印 pid 的部分执行完再去执行 `hello_world.exe`, 这两项工作都是在同一个进程(子进程)中进行的(两次打印的 pid 值相同) 73 | 74 | --- 75 | 76 | ### **system** 77 | 78 | 同 exec,在子进行的开始处调用 `system("./bin/hello_world.exe");`, `hello_world.exe`的作用同上。 79 |
80 | 81 | 结果如下: 82 |
83 | 84 | 85 | 可以看到子进程先执行了 `hello_world.exe`,在执行了源代码中的打印 pid 值。不同之处在于, `system(...)` 内实际上调用了一次 `fork()`,也就是子进程创建出来一个自己的子进程,父进程的"子子进程"去执行 `hello_world.exe` (因为 `hello_world.exe` 中输出的 pid 不同于 子进程执行源程序时输出的 pid). 86 | 87 | 把 `system("./bin/hello_world.exe");` 放到子进程末尾 88 |
89 | 90 | 结果如下: 91 |
92 | 93 | 94 | 区别不大,仅仅是 `hello_world` 和打印 pid 的顺序变了而已, 这是理所当然的. 95 | 96 | --- 97 | 98 | ## Part 2 Thread 99 | 100 | --- 101 | 创建两个线程,并在其中对全局变量 `sum` 执行 5000 次不同操作 102 | 103 | 104 | 105 | 106 | 107 | 调用 `pthread_join(tid, NULL)` 对两个线程进行阻塞等待,并在结束后分别打印 `sum` 的值,结果如下: 108 | 109 | 110 | 111 | 可以看到 `sum` 在有时候并没有按预期被加到 15000. 112 | 再将程序修改为在两个线程都结束后再打印 `sum`. 113 | 114 | 115 | 116 | 运行结果还是在有时候加不到 15000. 117 | 118 | 119 | 120 | 初步分析原因在于两个线程都要修改全局变量 `sum`, 即就是进入临界区,但是由于没有进行互斥,因此对 `sum` 的操作有些并没有生效. 因此考虑给两个线程加锁如下: 121 | 122 | 123 | 124 | 再次运行后可以看到每次输出都是两个 15000 了 125 | 126 | 127 | 128 | --- 129 | 130 | 修改 Part1 中 exec 和 system 部分的代码改为在线程中执行. 131 | 132 | ### exec 133 | 134 | 135 | 136 | 线程中执行以下代码,输出 tid 值, 然后执行进程切换去执行 `hello_world.exe`, 其作用是输出 pid 和 hello_world. 137 | 138 | 139 | 140 | 运行结果如下, 可以看到子进程创建了一个线程. 141 | 142 | 143 | 144 | 同 Part1,我们把线程创建和执行放到源程序的开头. 145 | 146 | 147 | 148 | 运行结果如下, 可以看到在子进程的线程中进行了进程切换, 因此源代码中两个打印 `pid` 的内容就不会被执行了. 149 | 150 | 151 | 152 | --- 153 | 154 | ### system 155 | 156 | 同 `exec`. 在子进程中创建一个线程. 157 | 158 | 159 | 160 | 线程中执行以下代码. 161 | 162 | 163 | 164 | 运行结果如下, 可以看到在子进程中进行了 `system(...)` 的调用后, 子进程调用 `fork()` 创建了一个自己的子进程,然后让这进程执行进程切换去执行 `hello_world.exe`. 可以看到在 `hello_world.exe` 中输出的 pid 和 子进程中 pid 并不相同. 165 | 166 | 167 | 168 | 同 Part1,我们把线程创建和执行放到源程序的开头. 但对于 `system()` 来说,并不会像 `exec()` 一样,只是输出的顺序改变了. 169 | 170 | 171 | 172 | 173 | 174 | --- 175 | 176 | ## Part 3 遇到的问题 177 | 178 | 在使用 vscode-remote 连接华为云时, 连接失败. 查看 vscode-remote 的输出日志可以看出一直在报这句错: 179 | 180 | ```shell 181 | open failed: administratively prohibited: open failed 182 | ``` 183 | 184 | 最后根据这篇 StackOverflow 上的回答解决了. 185 |
186 | [vs-code-remote-ssh-failed-to-set-up-socket-other-clients-are-ok.](https://stackoverflow.com/questions/64941796/vs-code-remote-ssh-failed-to-set-up-socket-other-clients-are-ok) 187 | 188 | --- 189 | 190 | ## Part 4 分析和思考 191 | 192 | * 计算机科学与技术即重科学也重技术,在课本上学来的理论知识,只有通过实际 Code 才能深入理解,掌握其用法 193 | 194 | * 多线程可以充分利用 CPU 资源,可以使得有及时的响应不至于让用户一直进行等待, 无论是在 Graphics 领域加速运算还是在Web开发中处理传来的 request 并给出相应的 response 都有很大的作用。但是在 Part2 中可以看到多线程在没有考虑互斥和同步或者考虑不当的情况下往往会出现意想不到的结果,而且难以调试。即使现在有很多多线程的库,但在使用多线程时还是要多加小心,合适处理同步和互斥。 195 | 196 | --- 197 | 198 | ## Part 5 Score 199 | 200 | 自评分: 20 201 | 202 | 203 | -------------------------------------------------------------------------------- /lab1/bin/hello_world.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/bin/hello_world.exe -------------------------------------------------------------------------------- /lab1/bin/test_exec.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/bin/test_exec.exe -------------------------------------------------------------------------------- /lab1/bin/test_pid.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/bin/test_pid.exe -------------------------------------------------------------------------------- /lab1/bin/test_system.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/bin/test_system.exe -------------------------------------------------------------------------------- /lab1/bin/thread1.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/bin/thread1.exe -------------------------------------------------------------------------------- /lab1/bin/thread2.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/bin/thread2.exe -------------------------------------------------------------------------------- /lab1/images/process/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/1.png -------------------------------------------------------------------------------- /lab1/images/process/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/2.png -------------------------------------------------------------------------------- /lab1/images/process/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/3.png -------------------------------------------------------------------------------- /lab1/images/process/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/4.png -------------------------------------------------------------------------------- /lab1/images/process/exec1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/exec1.png -------------------------------------------------------------------------------- /lab1/images/process/exec2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/exec2.png -------------------------------------------------------------------------------- /lab1/images/process/exec3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/exec3.png -------------------------------------------------------------------------------- /lab1/images/process/exec4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/exec4.png -------------------------------------------------------------------------------- /lab1/images/process/sys1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/sys1.png -------------------------------------------------------------------------------- /lab1/images/process/sys2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/sys2.png -------------------------------------------------------------------------------- /lab1/images/process/sys3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/sys3.png -------------------------------------------------------------------------------- /lab1/images/process/sys4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/process/sys4.png -------------------------------------------------------------------------------- /lab1/images/thread/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/1.png -------------------------------------------------------------------------------- /lab1/images/thread/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/10.png -------------------------------------------------------------------------------- /lab1/images/thread/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/11.png -------------------------------------------------------------------------------- /lab1/images/thread/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/12.png -------------------------------------------------------------------------------- /lab1/images/thread/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/13.png -------------------------------------------------------------------------------- /lab1/images/thread/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/14.png -------------------------------------------------------------------------------- /lab1/images/thread/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/15.png -------------------------------------------------------------------------------- /lab1/images/thread/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/16.png -------------------------------------------------------------------------------- /lab1/images/thread/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/17.png -------------------------------------------------------------------------------- /lab1/images/thread/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/2.png -------------------------------------------------------------------------------- /lab1/images/thread/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/3.png -------------------------------------------------------------------------------- /lab1/images/thread/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/4.png -------------------------------------------------------------------------------- /lab1/images/thread/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/5.png -------------------------------------------------------------------------------- /lab1/images/thread/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/6.png -------------------------------------------------------------------------------- /lab1/images/thread/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/7.png -------------------------------------------------------------------------------- /lab1/images/thread/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/8.png -------------------------------------------------------------------------------- /lab1/images/thread/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/9.png -------------------------------------------------------------------------------- /lab1/images/thread/exec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/exec.png -------------------------------------------------------------------------------- /lab1/images/thread/sys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab1/images/thread/sys.png -------------------------------------------------------------------------------- /lab1/process/hello_world.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | printf("\nHello World\n"); 8 | 9 | pid_t pid; 10 | 11 | pid = getpid(); 12 | printf("hello_world: pid = %d\n\n",pid); /* C */ 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /lab1/process/test_exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | pid_t pid, pid1; 9 | 10 | /* fork a child process */ 11 | pid = fork(); 12 | if (pid < 0) { 13 | /* error occurred */ 14 | fprintf(stderr, "Fork Failed"); 15 | return 1; 16 | } 17 | else if (pid == 0) { /* child process */ 18 | pid1 = getpid(); 19 | printf("child: pid = %d\n",pid); /* A */ 20 | printf("child: pid1 = %d\n",pid1); /* B */ 21 | execl("../bin/hello_world.exe",NULL); 22 | } 23 | else { /* parent process */ 24 | pid1 = getpid(); 25 | printf("parent: pid = %d\n",pid); /* C */ 26 | printf("parent: pid1 = %d\n",pid1); /* D */ 27 | wait(NULL); 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /lab1/process/test_pid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global = 0; 7 | 8 | int main() 9 | { 10 | pid_t pid, pid1; 11 | 12 | /* fork a child process */ 13 | pid = fork(); 14 | if (pid < 0) { 15 | /* error occurred */ 16 | fprintf(stderr, "Fork Failed"); 17 | return 1; 18 | } 19 | else if (pid == 0) { /* child process */ 20 | pid1 = getpid(); 21 | printf("child: pid = %d\n",pid); /* A */ 22 | printf("child: pid1 = %d\n",pid1); /* B */ 23 | global += 1; 24 | printf("child: global = 1\n"); 25 | printf("child: global_address = %x\n", &global); 26 | } 27 | else { /* parent process */ 28 | pid1 = getpid(); 29 | printf("parent: pid = %d\n",pid); /* C */ 30 | printf("parent: pid1 = %d\n",pid1); /* D */ 31 | global += 2; 32 | printf("parent: global = 2\n"); 33 | printf("parent: global_address = %x\n", &global); 34 | wait(NULL); 35 | } 36 | 37 | global += 1; 38 | printf("final: global = %d\n", global); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /lab1/process/test_system.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | pid_t pid, pid1; 9 | 10 | /* fork a child process */ 11 | pid = fork(); 12 | if (pid < 0) { 13 | /* error occurred */ 14 | fprintf(stderr, "Fork Failed"); 15 | return 1; 16 | } 17 | else if (pid == 0) { /* child process */ 18 | pid1 = getpid(); 19 | printf("child: pid = %d\n",pid); /* A */ 20 | printf("child: pid1 = %d\n",pid1); /* B */ 21 | system("../bin/hello_world.exe"); 22 | } 23 | else { /* parent process */ 24 | pid1 = getpid(); 25 | printf("parent: pid = %d\n",pid); /* C */ 26 | printf("parent: pid1 = %d\n",pid1); /* D */ 27 | wait(NULL); 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /lab1/thread/test_thread1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | pthread_mutex_t mutex; 6 | 7 | int sum; /* this data is shared by the thread(s) */ 8 | 9 | void *func1(void *); /* the thread1 */ 10 | void *func2(void *); /* the thread2 */ 11 | 12 | int main() { 13 | pthread_mutex_init(&mutex, NULL); 14 | 15 | pthread_t tid1, tid2; /* the thread identifier */ 16 | pthread_attr_t attr1, attr2; /* set of attributes for the thread */ 17 | 18 | /* get the default attributes */ 19 | pthread_attr_init(&attr1); 20 | pthread_attr_init(&attr2); 21 | 22 | /* create the thread */ 23 | pthread_create(&tid1, &attr1, func1, NULL); 24 | pthread_create(&tid2, &attr2, func2, NULL); 25 | 26 | /* now wait for the thread to exit */ 27 | // 第二个参数表示接收到的返回值 28 | pthread_join(tid1,NULL); 29 | printf("sum = %d\n",sum); 30 | 31 | pthread_join(tid2,NULL); 32 | printf("sum = %d\n",sum); 33 | 34 | pthread_mutex_destroy(&mutex); 35 | 36 | return 0; 37 | } 38 | 39 | void *func1(void *params) { 40 | 41 | for (int _i = 0; _i < 5000; _i++) { 42 | pthread_mutex_lock(&mutex); 43 | sum++; 44 | pthread_mutex_unlock(&mutex); 45 | } 46 | 47 | pthread_exit(0); 48 | } 49 | 50 | void *func2(void *params) { 51 | for (int _i = 0; _i < 5000; _i++) { 52 | pthread_mutex_lock(&mutex); 53 | sum += 2; 54 | pthread_mutex_unlock(&mutex); 55 | } 56 | 57 | pthread_exit(0); 58 | } 59 | -------------------------------------------------------------------------------- /lab1/thread/test_thread2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void *func(void *); 9 | 10 | int main() 11 | { 12 | pid_t pid, pid1; 13 | 14 | /* fork a child process */ 15 | pid = fork(); 16 | if (pid < 0) { 17 | /* error occurred */ 18 | fprintf(stderr, "Fork Failed"); 19 | return 1; 20 | } 21 | else if (pid == 0) { /* child process */ 22 | // exec 23 | pthread_t tid; 24 | pthread_attr_t attr; 25 | 26 | pthread_attr_init(&attr); 27 | 28 | pthread_create(&tid, &attr, func, NULL); 29 | 30 | pthread_join(tid,NULL); 31 | 32 | pid1 = getpid(); 33 | printf("child: pid = %d\n",pid); /* A */ 34 | printf("child: pid1 = %d\n",pid1); /* B */ 35 | } 36 | else { /* parent process */ 37 | pid1 = getpid(); 38 | printf("parent: pid = %d\n",pid); /* C */ 39 | printf("parent: pid1 = %d\n",pid1); /* D */ 40 | wait(NULL); 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | void *func(void *params) { 47 | pthread_t tid = pthread_self(); 48 | printf("Inner thread: tid = %ld\n", tid); 49 | // execlp("../bin/hello_world.exe", NULL); 50 | system("../bin/hello_world.exe"); 51 | 52 | pthread_exit(0); 53 | } 54 | -------------------------------------------------------------------------------- /lab2/README.md: -------------------------------------------------------------------------------- 1 | # OS_Lab2 2 | 3 | ## Part1 IPC 4 | 5 | --- 6 | 7 | ### 软中断通信 8 | 9 | 编写程序,在父进程中 10 | ```cpp 11 | signal(SIGALRM, father_handler); // 14 12 | signal(SIGQUIT, father_handler); // 3 13 | alarm(5); 14 | ``` 15 | 16 | 子进程中 17 | ```cpp 18 | /* child 2 process*/ 19 | signal(SIGUSR2, child2_handler); 20 | // signal(SIGQUIT, SIG_IGN); 21 | while (1) sleep(1); 22 | 23 | /* child 1 process*/ 24 | signal(SIGUSR1, child1_handler); 25 | // signal(SIGQUIT, SIG_IGN); 26 | while (1) sleep(1); 27 | ``` 28 | 29 | 运行程序,由于 `alarm(5)`, 因此 5s 后父进程收到软中断信号 `SIGALRM`, 父进程向子进程发送信号,子进程接收信号后退出,父进程随之退出,输出如下: 30 | 31 | 32 | 但是如果在时间内键盘按下 `Ctrl + \`, 向父进程发出信号 33 | `SIGQUIT`, 则父进程会退出,但是子进程不会打印。 34 | 经过查阅, `Ctrl + \`终端会向所有现在运行中的前台进程发送 `SIGQUIT`, 因此子进程直接退出,不会执行其剩下的语句 35 | 。在子进程里加上 36 | ```cpp 37 | signal(SIGQUIT, SIG_IGN); 38 | ``` 39 | 使其忽略 `SIGQUIT` 信号后问题解决. 40 | 41 | 42 | 43 | 44 | --- 45 | 46 | ### 管道通信 47 | 48 | 根据所给代码补充完在父(子)进程中读写的部分代码 49 | ```cpp 50 | lockf(fd[1],1,0); 51 | for (int i = 0; i < (BUFFER_SIZE - 1) / 2; ++i) 52 | { 53 | write(fd[WRITE_END], c1, 1); 54 | } 55 | lockf(fd[1],0,0); 56 | sleep(2); 57 | 58 | // ************************** 59 | 60 | lockf(fd[1],1,0); 61 | for (int i = 0; i < (BUFFER_SIZE - 1) / 2; ++i) 62 | { 63 | write(fd[WRITE_END], c2, 1); 64 | } 65 | lockf(fd[1],0,0); 66 | sleep(2); 67 | 68 | // ***************************** 69 | 70 | wait(NULL); 71 | lockf(fd[0],1,0); 72 | ssize_t size = read(fd[READ_END], InPipe, BUFFER_SIZE - 1); 73 | if(size > 0) 74 | InPipe[size] = '\0'; 75 | else if(size == 0) 76 | printf("quit\n"); 77 | else 78 | printf("error\n"); 79 | lockf(fd[0],0,0); 80 | printf("%s\n",InPipe); 81 | ``` 82 | 83 | 在父进程中,如果去掉lockf函数 84 | ```cpp 85 | // lockf(fd[0],1,0); 86 | // ............. 87 | // lockf(fd[0],0,0); 88 | ``` 89 | 90 | 则管道读写的互斥和同步出现问题,输出结果如下: 91 | 92 | 93 | 加上lockf函数后读写正常 94 | 95 | 96 | --- 97 | 98 | ## Part2 内存分配与回收 99 | 100 | 实现该部分实验主要有两个类 101 |
102 | `VarSizeAllocMngr` ---> 可变长度分配Manager 103 |
104 | `Allocator` ---> 继承自 `VarSizeAllocMngr`, 并且包装了对于"进程"pid的管理. 105 | 106 | --- 107 | 108 | ### *VarSizeAllocMngr* 109 | 110 | 该类的核心成员如下,其中对于每一个分配`(Allocation)`用一个偏移`(Offset)`和长度`(Size)`来表示, 类似 `std::span`, 对每一个空闲块`(FreeBlock)`也同样如此 111 | 112 | ```cpp 113 | using OffsetType = int; 114 | 115 | struct FreeBlockInfo; 116 | 117 | // Type of the map that keeps memory blocks sorted by their offsets 118 | using TFreeBlocksByOffsetMap = std::map; 119 | 120 | // Type of the map that keeps memory blocks sorted by their sizes 121 | using TFreeBlocksBySizeMap = std::multimap; 122 | 123 | using AllocatedMap = std::map; 124 | 125 | struct FreeBlockInfo { 126 | // Block size (no reserved space for the size of allocation) 127 | // actually Size == OrderBySizeIt->first 128 | OffsetType Size; 129 | // Iterator referencing this block in the multimap sorted by the block size 130 | TFreeBlocksBySizeMap::iterator OrderBySizeIt; 131 | 132 | FreeBlockInfo(OffsetType _Size) : Size(_Size) {} 133 | }; 134 | ``` 135 | 136 | 其中有三个核心成员 137 | ```cpp 138 | TFreeBlocksByOffsetMap m_FreeBlocksByOffset; 139 | TFreeBlocksBySizeMap m_FreeBlocksBySize; 140 | AllocatedMap m_Allocated; 141 | ``` 142 | 143 | * `m_FreeBlocksByOffset`记录每个空闲块, 其索引为空闲块的偏移(即起点). 144 | * `m_FreeBlocksBySize`其索引为空闲块的大小, 其类型是一个 `std::multimap<...>`, 使用 `multi` 是因为不同空闲块的大小可能一致,在此 map 中保存的块是按大小从小到大排序的,可以用于后续实现三种不同算法的 `Allocate` 145 | * `m_Allocated` 是一个 `std::map`, 记录了目前所有已分配的块, 其索引为块的 `Offset`, 值为块的 `Size` 146 |
147 | 148 | 三种 Allocate 的实现: 149 |
150 | * FF:遍历 `m_FreeBlocksByOffset`, 在容量足够的第一个块中分配 151 | * BF: 使用 `lower_bound(xxx)` 在 `m_FreeBlocksBySize` 中找到最小的容量足够的块,在其中分配即可 152 | * WF: 与 BF 恰好相反 153 | 154 | Free的实现: 155 |
156 | * 需要考虑在释放块时,该空闲块能不能与其紧挨的之前的空闲块合并,后者与之后的紧挨的空闲块合并。多判断几种情况即可 157 | 158 | --- 159 | 160 | ### *Allocator* 161 | 162 | 其核心数据成员如下: 163 | ```cpp 164 | std::set ChildPidList; 165 | std::map> Pid2Offsets; 166 | ``` 167 | 168 | 记录了所有存在的子进程的pid以及其该进程所占有的分配块, 169 | `Pid2Offsets`键值对中的值为块的`Offset`,根据该偏移即可在 `VarSizeAllocMngr` 中的 `m_FreeBlocksByOffset` 里查到该块的长度 170 |
171 | 核心方法如下: 172 | ```cpp 173 | int AddProcessAndAllocate(int size, Option option = Option::BF); 174 | 175 | int Allocate(int size, Option option = Option::BF); 176 | 177 | void NotDelProcessAndFree(pid_t pid, int offset, int size); 178 | 179 | void DelProcessAndFree(pid_t pid); 180 | 181 | void OutputGraph(); 182 | 183 | void Free(pid_t pid, OffsetType Offset, OffsetType Size); 184 | ``` 185 | 186 | 通过枚举类 187 | ```cpp 188 | enum class Option : uint8_t 189 | { 190 | FF = 0, 191 | BF, 192 | WF 193 | }; 194 | ``` 195 | 来设置不同的分配算法. 196 | 197 | --- 198 | 199 | ### *运行展示* 200 | 201 | 菜单界面 202 | 203 | 204 |
205 | 如果没有调用 `1`,即分配内存总大小就调用其他,则会提示 206 | Initilize the allocator first!!! 207 | 208 | 209 | 210 |
211 | 设置内存为`1024` 212 | 213 | 214 | 215 |
216 | 创建一个进程内存大小为100 217 | 218 | 219 | 220 |
221 | 创建一个进程内存大小为800 222 | 223 | 224 | 225 |
226 | 目前内存布局如下 227 | 228 | 229 | 230 |
231 | 把进程2的内存中 (300 --> 500)的部分释放 232 | 233 | 234 | 235 |
236 | 内存布局如下,可以看到进程2目前占有两个块 237 | 238 | 239 | 240 |
241 | 把进程2的内存中 (500 --> 800)的部分释放 242 | 243 | 244 | 245 |
246 | 目前内存布局如下 247 | 248 | 249 | 250 |
251 | 设置算法为 BF 252 | 253 | 254 | 255 |
256 | 分配一个大小的100的进程 257 | 258 | 259 | 260 |
261 | 内存布局如下,可以看到采用了 BF 算法,选择了最小的块, 即后面的那个块去分配这 100 的大小 262 | 263 | 264 | 265 |
266 | 设置算法为FF 267 | 268 | 269 | 270 |
271 | 分配一个大小为10的进程,可以看到根据 FF 算法,内存分配在了最前面的块里 272 | 273 | 274 | 275 |
276 | 设置为 WF 算法,可以看到分配在了最大的块里 277 | 278 | 279 | 280 |
281 | 终止进程1 282 | 283 | 284 | 285 |
286 | 查看内存布局如下,可以看到进程1的内存已经被全部释放 287 | 288 | 289 | 290 | --- 291 | 292 | ## Part 3 遇到的问题 293 | 294 | 在管道程序中,由于 `alarm(5)`, 因此 5s 后父进程收到软中断信号 `SIGALRM`, 父进程向子进程发送信号,子进程接收信号后退出,父进程随之退出,输出如下: 295 | 296 | 297 | 但是如果在时间内键盘按下 `Ctrl + \`, 向父进程发出信号 298 | `SIGQUIT`, 则父进程会退出,但是子进程不会打印。 299 | 经过查阅, `Ctrl + \`终端会向所有现在运行中的前台进程发送 `SIGQUIT`, 因此子进程直接退出,不会执行其剩下的语句 300 | 。在子进程里加上 301 | ```cpp 302 | signal(SIGQUIT, SIG_IGN); 303 | ``` 304 | 使其忽略 `SIGQUIT` 信号后问题解决. 305 | 306 | 307 | 308 | --- 309 | 310 | ## Part 4 分析和思考 311 | 312 | * 在写程序时要注意设计以及功能模块的划分,对于每一个功能要考虑各种情况,保证程序的健壮性. 313 | 314 | --- 315 | 316 | ## Part 5 Score 317 | 318 | 自评分: 30 319 | -------------------------------------------------------------------------------- /lab2/images/mem/alloc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc1.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc10.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc11.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc12.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc13.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc14.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc15.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc16.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc17.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc18.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc2.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc3.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc4.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc5.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc6.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc7.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc8.png -------------------------------------------------------------------------------- /lab2/images/mem/alloc9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/mem/alloc9.png -------------------------------------------------------------------------------- /lab2/images/pipe/pipe_with_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/pipe/pipe_with_lock.png -------------------------------------------------------------------------------- /lab2/images/pipe/pipe_without_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/pipe/pipe_without_lock.png -------------------------------------------------------------------------------- /lab2/images/sig/sig_alarm1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/sig/sig_alarm1.png -------------------------------------------------------------------------------- /lab2/images/sig/sig_alarm2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/sig/sig_alarm2.png -------------------------------------------------------------------------------- /lab2/images/sig/sig_quit1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/sig/sig_quit1.png -------------------------------------------------------------------------------- /lab2/images/sig/sig_quit2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/images/sig/sig_quit2.png -------------------------------------------------------------------------------- /lab2/memory/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .vscode -------------------------------------------------------------------------------- /lab2/memory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(MemoryAlloc) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | set(CMAKE_BUILD_TYPE "Debug") 8 | 9 | add_executable(${PROJECT_NAME} 10 | src/main.cpp 11 | src/VarSizeAllocMngr.cpp 12 | src/Allocator.cpp 13 | ) 14 | 15 | target_include_directories(${PROJECT_NAME} 16 | PUBLIC ${PROJECT_SOURCE_DIR}/include 17 | ) 18 | -------------------------------------------------------------------------------- /lab2/memory/Example.md: -------------------------------------------------------------------------------- 1 | ## WF 2 | 3 | ```cpp 4 | VarSizeAllocMngr allocMngr; 5 | 6 | allocMngr.AllocateBF(10); 7 | 8 | allocMngr.AllocateBF(900); 9 | 10 | allocMngr.Free(10, 200); 11 | allocMngr.Free(400, 300); 12 | 13 | allocMngr.OutputAllocGraph(); 14 | 15 | allocMngr.AllocateWF(50); 16 | 17 | allocMngr.OutputAllocGraph(); 18 | ``` -------------------------------------------------------------------------------- /lab2/memory/include/Allocator.h: -------------------------------------------------------------------------------- 1 | #include "VarSizeAllocMngr.h" 2 | #include 3 | #include 4 | #include 5 | 6 | class Allocator : public VarSizeAllocMngr 7 | { 8 | public: 9 | enum class Option : uint8_t 10 | { 11 | FF = 0, 12 | BF, 13 | WF 14 | }; 15 | 16 | Allocator(int capacity = 1024); 17 | ~Allocator(); 18 | 19 | int AddProcessAndAllocate(int size, Option option = Option::BF); 20 | 21 | std::vector Allocate(int size, Option option = Option::BF); 22 | 23 | void NotDelProcessAndFree(pid_t pid, int offset, int size); 24 | 25 | void DelProcessAndFree(pid_t pid); 26 | 27 | void OutputGraph(); 28 | 29 | void Free(pid_t pid, OffsetType Offset, OffsetType Size); 30 | 31 | int Extend2PowerOfTwo(int byteSize) { return (byteSize + 255) & ~255; } 32 | 33 | private: 34 | // father pid : 0 35 | std::set ChildPidList; 36 | std::map> Pid2Offsets; // 记录分配给子进程的 allocation 37 | 38 | static int source; 39 | }; 40 | -------------------------------------------------------------------------------- /lab2/memory/include/VarSizeAllocMngr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // The class handles free memory block management to accommodate variable-size allocation requests. 8 | // It keeps track of free blocks only and does not record allocation sizes. The class uses two ordered maps 9 | // to facilitate operations. The first map keeps blocks sorted by their offsets. The second multimap keeps blocks 10 | // sorted by their sizes. The elements of the two maps reference each other, which enables efficient block 11 | // insertion, removal and merging. 12 | // 13 | // 8 32 64 104 14 | // |<---16--->| |<-----24------>| |<---16--->| |<-----32----->| 15 | // 16 | // 17 | // size2freeblock offset2freeblock 18 | // size->offset offset->size 19 | // 20 | // 16 ------------------> 8 ----------> {size = 16, &size2freeblock[0]} 21 | // 22 | // 16 ------. .-------> 32 ----------> {size = 24, &size2freeblock[2]} 23 | // '.' 24 | // 24 -------' '--------> 64 ----------> {size = 16, &size2freeblock[1]} 25 | // 26 | // 32 ------------------> 104 ----------> {size = 32, &size2freeblock[3]} 27 | // 28 | 29 | class VarSizeAllocMngr { 30 | public: 31 | using OffsetType = int; 32 | 33 | protected: 34 | struct FreeBlockInfo; 35 | 36 | // Type of the map that keeps memory blocks sorted by their offsets 37 | using TFreeBlocksByOffsetMap = std::map; 38 | 39 | // Type of the map that keeps memory blocks sorted by their sizes 40 | using TFreeBlocksBySizeMap = std::multimap; 41 | 42 | using AllocatedMap = std::map; 43 | 44 | struct FreeBlockInfo { 45 | // Block size (no reserved space for the size of allocation) 46 | // actually Size == OrderBySizeIt->first 47 | OffsetType Size; 48 | // Iterator referencing this block in the multimap sorted by the block size 49 | TFreeBlocksBySizeMap::iterator OrderBySizeIt; 50 | 51 | FreeBlockInfo(OffsetType _Size) : Size(_Size) {} 52 | }; 53 | 54 | public: 55 | VarSizeAllocMngr(OffsetType capacity = 1024); 56 | 57 | VarSizeAllocMngr(VarSizeAllocMngr&&) noexcept; 58 | 59 | VarSizeAllocMngr& operator=(VarSizeAllocMngr&&) noexcept; 60 | 61 | VarSizeAllocMngr(const VarSizeAllocMngr&) = delete; 62 | VarSizeAllocMngr& operator=(const VarSizeAllocMngr&) = delete; 63 | 64 | void AddNewBlock(OffsetType Offset, OffsetType Size); 65 | 66 | std::vector AllocateFF(OffsetType Size); 67 | std::vector AllocateBF(OffsetType Size); 68 | std::vector AllocateWF(OffsetType Size); 69 | 70 | void Free(OffsetType Offset, OffsetType Size); 71 | 72 | void OutputAllocGraph(); 73 | 74 | OffsetType GetFreeSize() const { return freeSize; } 75 | OffsetType GetCapacity() const { return capacity; } 76 | 77 | // InvalidOffset For Allocate 78 | static OffsetType InvalidOffset; 79 | protected: 80 | TFreeBlocksByOffsetMap m_FreeBlocksByOffset; 81 | TFreeBlocksBySizeMap m_FreeBlocksBySize; 82 | AllocatedMap m_Allocated; 83 | 84 | OffsetType capacity = 0; 85 | OffsetType freeSize = 0; 86 | }; 87 | -------------------------------------------------------------------------------- /lab2/memory/src/Allocator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int Allocator::source = 0; 5 | 6 | Allocator::Allocator(int capacity) : VarSizeAllocMngr(capacity) {} 7 | 8 | Allocator::~Allocator() {} 9 | 10 | std::vector Allocator::Allocate(int size, Option option) 11 | { 12 | switch (option) { 13 | case Option::FF: 14 | return VarSizeAllocMngr::AllocateFF(size); 15 | case Option::BF: 16 | return VarSizeAllocMngr::AllocateBF(size); 17 | case Option::WF: 18 | return VarSizeAllocMngr::AllocateWF(size); 19 | default: 20 | break; 21 | } 22 | 23 | return {-1}; 24 | } 25 | 26 | int Allocator::AddProcessAndAllocate(int size, Option option) 27 | { 28 | int pid = ++source; 29 | auto offsets = Allocate(size, option); 30 | if (offsets[0] != InvalidOffset) 31 | { 32 | if (Pid2Offsets.find(pid) != Pid2Offsets.end()) 33 | { 34 | for (auto off : offsets) 35 | Pid2Offsets[pid].emplace(off); 36 | } 37 | else 38 | { 39 | Pid2Offsets[pid] = std::set(); 40 | for (auto off : offsets) 41 | Pid2Offsets[pid].emplace(off); 42 | } 43 | ChildPidList.emplace(pid); 44 | } 45 | return offsets[0]; 46 | } 47 | 48 | void Allocator::DelProcessAndFree(pid_t pid) 49 | { 50 | if (ChildPidList.find(pid) == ChildPidList.end()) 51 | { 52 | std::cerr << "Process not exsit!!!" << std::endl; 53 | return; 54 | } 55 | auto &offsetList = Pid2Offsets[pid]; 56 | for (auto &offset : offsetList) 57 | { 58 | if (m_Allocated.find(offset) != m_Allocated.end()) 59 | { 60 | VarSizeAllocMngr::Free(offset, m_Allocated.find(offset)->second); 61 | } 62 | } 63 | ChildPidList.erase(ChildPidList.find(pid)); 64 | Pid2Offsets.erase(Pid2Offsets.find(pid)); 65 | } 66 | 67 | void Allocator::NotDelProcessAndFree(pid_t pid, int offset, int size) 68 | { 69 | if (ChildPidList.find(pid) == ChildPidList.end()) 70 | { 71 | std::cerr << "Process not exsit!!!" << std::endl; 72 | return; 73 | } 74 | 75 | Free(pid, offset, size); 76 | } 77 | 78 | void Allocator::Free(pid_t pid, OffsetType Offset, OffsetType Size) 79 | { 80 | // Find the first element whose offset is greater than the specified offset 81 | auto NextBlockIt = m_FreeBlocksByOffset.upper_bound(Offset); 82 | auto PrevBlockIt = NextBlockIt; 83 | if(PrevBlockIt != m_FreeBlocksByOffset.begin()) 84 | --PrevBlockIt; 85 | else 86 | PrevBlockIt = m_FreeBlocksByOffset.end(); 87 | OffsetType NewSize, NewOffset; 88 | if(PrevBlockIt != m_FreeBlocksByOffset.end() && Offset == PrevBlockIt->first + PrevBlockIt->second.Size) 89 | { 90 | // PrevBlock.Offset Offset 91 | // | | 92 | // |<-----PrevBlock.Size----->|<------Size-------->| 93 | // 94 | NewSize = PrevBlockIt->second.Size + Size; 95 | NewOffset = PrevBlockIt->first; 96 | 97 | if (NextBlockIt != m_FreeBlocksByOffset.end() && Offset + Size == NextBlockIt->first) 98 | { 99 | // PrevBlock.Offset Offset NextBlock.Offset 100 | // | | | 101 | // |<-----PrevBlock.Size----->|<------Size-------->|<-----NextBlock.Size----->| 102 | // 103 | NewSize += NextBlockIt->second.Size; 104 | m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt); 105 | m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt); 106 | // Delete the range of two blocks 107 | ++NextBlockIt; 108 | m_FreeBlocksByOffset.erase(PrevBlockIt, NextBlockIt); 109 | } 110 | else 111 | { 112 | // PrevBlock.Offset Offset NextBlock.Offset 113 | // | | | 114 | // |<-----PrevBlock.Size----->|<------Size-------->| ~ ~ ~ |<-----NextBlock.Size----->| 115 | // 116 | m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt); 117 | m_FreeBlocksByOffset.erase(PrevBlockIt); 118 | } 119 | } 120 | else if (NextBlockIt != m_FreeBlocksByOffset.end() && Offset + Size == NextBlockIt->first) 121 | { 122 | // PrevBlock.Offset Offset NextBlock.Offset 123 | // | | | 124 | // |<-----PrevBlock.Size----->| ~ ~ ~ |<------Size-------->|<-----NextBlock.Size----->| 125 | // 126 | NewSize = Size + NextBlockIt->second.Size; 127 | NewOffset = Offset; 128 | m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt); 129 | m_FreeBlocksByOffset.erase(NextBlockIt); 130 | } 131 | else 132 | { 133 | // PrevBlock.Offset Offset NextBlock.Offset 134 | // | | | 135 | // |<-----PrevBlock.Size----->| ~ ~ ~ |<------Size-------->| ~ ~ ~ |<-----NextBlock.Size----->| 136 | // 137 | NewSize = Size; 138 | NewOffset = Offset; 139 | } 140 | 141 | AddNewBlock(NewOffset, NewSize); 142 | 143 | for (auto &allocation : m_Allocated) 144 | { 145 | if (Offset >= allocation.first && Size <= allocation.second && Offset + Size <= allocation.first + allocation.second) 146 | { 147 | if (Offset == allocation.first && Size < allocation.second) 148 | { 149 | // <---------------------------------------------------------> all 150 | // <----------------------------------------> To Free 151 | auto alloc_offset = Offset + Size; 152 | auto alloc_size = allocation.second - Size; 153 | m_Allocated.emplace(alloc_offset, alloc_size); 154 | m_Allocated.erase(m_Allocated.find(allocation.first)); 155 | Pid2Offsets[pid].erase(Pid2Offsets[pid].find(allocation.first)); 156 | Pid2Offsets[pid].emplace(alloc_offset); 157 | break; 158 | } 159 | else if (Offset > allocation.first && (Offset + Size) == (allocation.first + allocation.second)) 160 | { 161 | // <---------------------------------------------------------> all 162 | // <----------------------------------------> To Free 163 | m_Allocated[allocation.first] -= Size; 164 | break; 165 | } 166 | else if (Offset == allocation.first && Size == allocation.second) 167 | { 168 | m_Allocated.erase(m_Allocated.find(allocation.first)); 169 | Pid2Offsets[pid].erase(Pid2Offsets[pid].find(allocation.first)); 170 | break; 171 | } 172 | else 173 | { 174 | // <---------------------------------------------------------> all 175 | // <--------------------------------> To Free 176 | 177 | auto alloc_offset = Offset + Size; 178 | auto alloc_size = allocation.second - Size - (Offset - allocation.first); 179 | m_Allocated.emplace(alloc_offset, alloc_size); 180 | m_Allocated[allocation.first] = Offset - allocation.first; 181 | Pid2Offsets[pid].emplace(alloc_offset); 182 | break; 183 | } 184 | } 185 | } 186 | 187 | freeSize += Size; 188 | } 189 | 190 | void Allocator::OutputGraph() 191 | { 192 | std::cout << std::endl; 193 | 194 | std::cout << "-------[Free]-------" << std::endl; 195 | std::cout << " Offset Size" << std::endl; 196 | for (const auto& freeBlock : m_FreeBlocksByOffset) 197 | { 198 | printf(" %-7d %-10d\n", freeBlock.first, freeBlock.second.Size); 199 | } 200 | std::cout << "--------------------" << std::endl; 201 | 202 | std::cout << std::endl; 203 | 204 | std::cout << "-----[Allocated]----" << std::endl; 205 | std::cout << "Pid Offset Size" << std::endl; 206 | 207 | for (auto pid : ChildPidList) 208 | { 209 | auto& offsets = Pid2Offsets.find(pid)->second; 210 | for (auto offset : offsets) 211 | { 212 | auto size = m_Allocated[offset]; 213 | printf("%-7d %-6d %-6d\n", pid, offset, size); 214 | } 215 | } 216 | std::cout << "--------------------" << std::endl; 217 | } 218 | -------------------------------------------------------------------------------- /lab2/memory/src/VarSizeAllocMngr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | VarSizeAllocMngr::OffsetType VarSizeAllocMngr::InvalidOffset = -1; 7 | 8 | VarSizeAllocMngr::VarSizeAllocMngr(int capacity) : 9 | capacity(capacity), 10 | freeSize(capacity) 11 | { 12 | // Insert single maximum-size block 13 | AddNewBlock(0, capacity); 14 | } 15 | 16 | VarSizeAllocMngr::VarSizeAllocMngr(VarSizeAllocMngr&& rhs) noexcept : 17 | m_FreeBlocksByOffset{ std::move(rhs.m_FreeBlocksByOffset) }, 18 | m_FreeBlocksBySize{ std::move(rhs.m_FreeBlocksBySize) }, 19 | capacity{ rhs.capacity }, 20 | freeSize{ rhs.freeSize } 21 | { 22 | rhs.capacity = 0; 23 | rhs.freeSize = 0; 24 | } 25 | 26 | VarSizeAllocMngr& VarSizeAllocMngr::operator=(VarSizeAllocMngr&& rhs) noexcept { 27 | m_FreeBlocksByOffset = std::move(rhs.m_FreeBlocksByOffset); 28 | m_FreeBlocksBySize = std::move(rhs.m_FreeBlocksBySize); 29 | capacity = rhs.capacity; 30 | freeSize = rhs.freeSize; 31 | 32 | rhs.capacity = 0; 33 | rhs.freeSize = 0; 34 | 35 | return *this; 36 | } 37 | 38 | void VarSizeAllocMngr::AddNewBlock(OffsetType Offset, OffsetType Size) { 39 | auto NewBlockIt = m_FreeBlocksByOffset.emplace(Offset, Size); 40 | auto OrderIt = m_FreeBlocksBySize.emplace(Size, NewBlockIt.first); 41 | // set the FreeBlockInfo 42 | NewBlockIt.first->second.OrderBySizeIt = OrderIt; 43 | } 44 | 45 | 46 | // ********************************************************************************** 47 | // Allocate 48 | 49 | // FF 50 | std::vector VarSizeAllocMngr::AllocateFF(OffsetType Size) { 51 | if(freeSize < Size) 52 | return {InvalidOffset}; 53 | 54 | auto BiggestBlockItIt = --m_FreeBlocksBySize.end(); 55 | 56 | if (BiggestBlockItIt->first < Size) 57 | { 58 | // shrink 59 | auto RestSize = Size; 60 | auto Offset = 0; 61 | std::vector res; 62 | 63 | auto NewOffset = 0; 64 | auto NewSize = 0; 65 | 66 | bool isInit = false; 67 | 68 | std::vector offset2erase; 69 | 70 | for (const auto& freeBlock : m_FreeBlocksByOffset) 71 | { 72 | if (RestSize > freeBlock.second.Size) 73 | { 74 | isInit = true; 75 | res.push_back(freeBlock.first); 76 | m_Allocated.emplace(freeBlock.first, freeBlock.second.Size); 77 | m_FreeBlocksBySize.erase(freeBlock.second.OrderBySizeIt); 78 | offset2erase.push_back(freeBlock.first); 79 | } 80 | else 81 | { 82 | isInit = true; 83 | res.push_back(freeBlock.first); 84 | NewOffset = freeBlock.first + RestSize; 85 | NewSize = freeBlock.second.Size - RestSize; 86 | m_Allocated.emplace(freeBlock.first, RestSize); 87 | m_FreeBlocksBySize.erase(freeBlock.second.OrderBySizeIt); 88 | offset2erase.push_back(freeBlock.first); 89 | } 90 | RestSize -= freeBlock.second.Size; 91 | } 92 | 93 | if (isInit) 94 | { 95 | for (auto &off : offset2erase) m_FreeBlocksByOffset.erase(m_FreeBlocksByOffset.find(off)); 96 | if (NewSize > 0) 97 | { 98 | m_FreeBlocksByOffset.emplace(NewOffset, NewSize); 99 | auto OrderIt = m_FreeBlocksBySize.emplace(NewSize, m_FreeBlocksByOffset.find(NewOffset)); 100 | m_FreeBlocksByOffset.find(NewOffset)->second.OrderBySizeIt = OrderIt; 101 | } 102 | return res; 103 | } 104 | else 105 | return {InvalidOffset}; 106 | } 107 | else /* not shrink */ 108 | { 109 | for (const auto& freeBlock : m_FreeBlocksByOffset) 110 | { 111 | if (freeBlock.second.Size >= Size) 112 | { 113 | auto Offset = freeBlock.first; 114 | auto NewOffset = Offset + Size; 115 | auto NewSize = freeBlock.second.Size - Size; 116 | m_FreeBlocksBySize.erase(freeBlock.second.OrderBySizeIt); 117 | m_FreeBlocksByOffset.erase(m_FreeBlocksByOffset.find(freeBlock.first)); 118 | if (NewSize > 0) 119 | AddNewBlock(NewOffset, NewSize); 120 | freeSize -= Size; 121 | m_Allocated.emplace(Offset, Size); 122 | return {Offset}; 123 | } 124 | } 125 | } 126 | return {InvalidOffset}; 127 | } 128 | 129 | // BF 130 | std::vector VarSizeAllocMngr::AllocateBF(OffsetType Size) { 131 | if(freeSize < Size) 132 | return {InvalidOffset}; 133 | 134 | auto BiggestBlockItIt = --m_FreeBlocksBySize.end(); 135 | 136 | if (BiggestBlockItIt->first < Size) 137 | { 138 | // shrink 139 | auto RestSize = Size; 140 | auto Offset = 0; 141 | std::vector res; 142 | 143 | auto NewOffset = 0; 144 | auto NewSize = 0; 145 | 146 | bool isInit = false; 147 | 148 | std::vector iter2erase; 149 | 150 | for (const auto& freeBlock : m_FreeBlocksBySize) 151 | { 152 | if (RestSize > freeBlock.first) 153 | { 154 | isInit = true; 155 | res.push_back(freeBlock.second->first); 156 | m_Allocated.emplace(freeBlock.second->first, freeBlock.first); 157 | iter2erase.push_back(freeBlock.second->second.OrderBySizeIt); 158 | m_FreeBlocksByOffset.erase(freeBlock.second); 159 | } 160 | else 161 | { 162 | isInit = true; 163 | res.push_back(freeBlock.second->first); 164 | NewOffset = freeBlock.second->first + RestSize; 165 | NewSize = freeBlock.first - RestSize; 166 | m_Allocated.emplace(freeBlock.second->first, RestSize); 167 | iter2erase.push_back(freeBlock.second->second.OrderBySizeIt); 168 | m_FreeBlocksByOffset.erase(freeBlock.second); 169 | } 170 | RestSize -= freeBlock.first; 171 | } 172 | 173 | if (isInit) 174 | { 175 | for (auto &iter : iter2erase) m_FreeBlocksBySize.erase(iter); 176 | if (NewSize > 0) 177 | { 178 | m_FreeBlocksByOffset.emplace(NewOffset, NewSize); 179 | auto OrderIt = m_FreeBlocksBySize.emplace(NewSize, m_FreeBlocksByOffset.find(NewOffset)); 180 | m_FreeBlocksByOffset.find(NewOffset)->second.OrderBySizeIt = OrderIt; 181 | } 182 | return res; 183 | } 184 | else 185 | return {InvalidOffset}; 186 | } 187 | else 188 | { 189 | // Get the first block that is large enough to encompass Size bytes 190 | auto SmallestBlockItIt = m_FreeBlocksBySize.lower_bound(Size); 191 | auto SmallestBlockIt = SmallestBlockItIt->second; 192 | auto Offset = SmallestBlockIt->first; 193 | auto NewOffset = Offset + Size; 194 | auto NewSize = SmallestBlockIt->second.Size - Size; 195 | m_FreeBlocksBySize.erase(SmallestBlockItIt); 196 | m_FreeBlocksByOffset.erase(SmallestBlockIt); 197 | if (NewSize > 0) 198 | AddNewBlock(NewOffset, NewSize); 199 | 200 | freeSize -= Size; 201 | 202 | m_Allocated.emplace(Offset, Size); 203 | return {Offset}; 204 | } 205 | return {InvalidOffset}; 206 | } 207 | 208 | std::vector VarSizeAllocMngr::AllocateWF(OffsetType Size) { 209 | 210 | auto BiggestBlockItIt = --m_FreeBlocksBySize.end(); 211 | 212 | if (BiggestBlockItIt->first < Size) 213 | { 214 | // shrink 215 | auto RestSize = Size; 216 | auto Offset = 0; 217 | std::vector res; 218 | 219 | auto NewOffset = 0; 220 | auto NewSize = 0; 221 | 222 | bool isInit = false; 223 | 224 | std::vector iter2erase; 225 | 226 | for (auto iter = m_FreeBlocksBySize.rbegin(); iter != m_FreeBlocksBySize.rend(); ++iter) 227 | { 228 | if (RestSize > iter->first) 229 | { 230 | isInit = true; 231 | res.push_back(iter->second->first); 232 | m_Allocated.emplace(iter->second->first, iter->first); 233 | iter2erase.push_back(iter->second->second.OrderBySizeIt); 234 | m_FreeBlocksByOffset.erase(iter->second); 235 | } 236 | else 237 | { 238 | isInit = true; 239 | res.push_back(iter->second->first); 240 | NewOffset = iter->second->first + RestSize; 241 | NewSize = iter->first - RestSize; 242 | m_Allocated.emplace(iter->second->first, RestSize); 243 | iter2erase.push_back(iter->second->second.OrderBySizeIt); 244 | m_FreeBlocksByOffset.erase(iter->second); 245 | } 246 | RestSize -= iter->first; 247 | } 248 | 249 | if (isInit) 250 | { 251 | for (auto &iter : iter2erase) m_FreeBlocksBySize.erase(iter); 252 | if (NewSize > 0) 253 | { 254 | m_FreeBlocksByOffset.emplace(NewOffset, NewSize); 255 | auto OrderIt = m_FreeBlocksBySize.emplace(NewSize, m_FreeBlocksByOffset.find(NewOffset)); 256 | m_FreeBlocksByOffset.find(NewOffset)->second.OrderBySizeIt = OrderIt; 257 | } 258 | return res; 259 | } 260 | else 261 | return {InvalidOffset}; 262 | } 263 | else 264 | { 265 | auto BiggestBlockIt = BiggestBlockItIt->second; 266 | auto Offset = BiggestBlockIt->first; 267 | auto NewOffset = Offset + Size; 268 | auto NewSize = BiggestBlockIt->second.Size - Size; 269 | m_FreeBlocksBySize.erase(BiggestBlockItIt); 270 | m_FreeBlocksByOffset.erase(BiggestBlockIt); 271 | if (NewSize > 0) 272 | AddNewBlock(NewOffset, NewSize); 273 | 274 | freeSize -= Size; 275 | 276 | m_Allocated.emplace(Offset, Size); 277 | return {Offset}; 278 | } 279 | return {InvalidOffset}; 280 | } 281 | 282 | // ********************************************************************************** 283 | 284 | 285 | // 禁止跨块释放 286 | void VarSizeAllocMngr::Free(OffsetType Offset, OffsetType Size) 287 | { 288 | // Find the first element whose offset is greater than the specified offset 289 | auto NextBlockIt = m_FreeBlocksByOffset.upper_bound(Offset); 290 | auto PrevBlockIt = NextBlockIt; 291 | if(PrevBlockIt != m_FreeBlocksByOffset.begin()) 292 | --PrevBlockIt; 293 | else 294 | PrevBlockIt = m_FreeBlocksByOffset.end(); 295 | OffsetType NewSize, NewOffset; 296 | if(PrevBlockIt != m_FreeBlocksByOffset.end() && Offset == PrevBlockIt->first + PrevBlockIt->second.Size) 297 | { 298 | // PrevBlock.Offset Offset 299 | // | | 300 | // |<-----PrevBlock.Size----->|<------Size-------->| 301 | // 302 | NewSize = PrevBlockIt->second.Size + Size; 303 | NewOffset = PrevBlockIt->first; 304 | 305 | if (NextBlockIt != m_FreeBlocksByOffset.end() && Offset + Size == NextBlockIt->first) 306 | { 307 | // PrevBlock.Offset Offset NextBlock.Offset 308 | // | | | 309 | // |<-----PrevBlock.Size----->|<------Size-------->|<-----NextBlock.Size----->| 310 | // 311 | NewSize += NextBlockIt->second.Size; 312 | m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt); 313 | m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt); 314 | // Delete the range of two blocks 315 | ++NextBlockIt; 316 | m_FreeBlocksByOffset.erase(PrevBlockIt, NextBlockIt); 317 | } 318 | else 319 | { 320 | // PrevBlock.Offset Offset NextBlock.Offset 321 | // | | | 322 | // |<-----PrevBlock.Size----->|<------Size-------->| ~ ~ ~ |<-----NextBlock.Size----->| 323 | // 324 | m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt); 325 | m_FreeBlocksByOffset.erase(PrevBlockIt); 326 | } 327 | } 328 | else if (NextBlockIt != m_FreeBlocksByOffset.end() && Offset + Size == NextBlockIt->first) 329 | { 330 | // PrevBlock.Offset Offset NextBlock.Offset 331 | // | | | 332 | // |<-----PrevBlock.Size----->| ~ ~ ~ |<------Size-------->|<-----NextBlock.Size----->| 333 | // 334 | NewSize = Size + NextBlockIt->second.Size; 335 | NewOffset = Offset; 336 | m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt); 337 | m_FreeBlocksByOffset.erase(NextBlockIt); 338 | } 339 | else 340 | { 341 | // PrevBlock.Offset Offset NextBlock.Offset 342 | // | | | 343 | // |<-----PrevBlock.Size----->| ~ ~ ~ |<------Size-------->| ~ ~ ~ |<-----NextBlock.Size----->| 344 | // 345 | NewSize = Size; 346 | NewOffset = Offset; 347 | } 348 | 349 | AddNewBlock(NewOffset, NewSize); 350 | 351 | for (auto &allocation : m_Allocated) 352 | { 353 | if (Offset >= allocation.first && Size <= allocation.second && Offset + Size <= allocation.first + allocation.second) 354 | { 355 | if (Offset == allocation.first && Size < allocation.second) 356 | { 357 | // <---------------------------------------------------------> all 358 | // <----------------------------------------> To Free 359 | auto alloc_offset = Offset + Size; 360 | auto alloc_size = allocation.second - Size; 361 | m_Allocated.emplace(alloc_offset, alloc_size); 362 | m_Allocated.erase(m_Allocated.find(allocation.first)); 363 | break; 364 | } 365 | else if (Offset > allocation.first && Offset + Size == allocation.first + allocation.second) 366 | { 367 | // <---------------------------------------------------------> all 368 | // <----------------------------------------> To Free 369 | m_Allocated[allocation.first] -= Size; 370 | break; 371 | } 372 | else if (Offset == allocation.first && Size == allocation.second) 373 | { 374 | m_Allocated.erase(m_Allocated.find(allocation.first)); 375 | break; 376 | } 377 | else 378 | { 379 | // <---------------------------------------------------------> all 380 | // <--------------------------------> To Free 381 | 382 | auto alloc_offset = Offset + Size; 383 | auto alloc_size = allocation.second - Size - (Offset - allocation.first); 384 | m_Allocated.emplace(alloc_offset, alloc_size); 385 | m_Allocated[allocation.first] = Offset - allocation.first; 386 | break; 387 | } 388 | } 389 | } 390 | 391 | freeSize += Size; 392 | } 393 | 394 | void VarSizeAllocMngr::OutputAllocGraph() 395 | { 396 | std::cout << std::endl; 397 | 398 | std::cout << "-------[Free]-------" << std::endl; 399 | std::cout << " Offset Size" << std::endl; 400 | for (const auto& freeBlock : m_FreeBlocksByOffset) 401 | { 402 | printf(" %-7d %-10d\n", freeBlock.first, freeBlock.second.Size); 403 | } 404 | std::cout << "--------------------" << std::endl; 405 | 406 | std::cout << std::endl; 407 | 408 | std::cout << "-----[Allocated]----" << std::endl; 409 | std::cout << " Offset Size" << std::endl; 410 | for (const auto& allocation : m_Allocated) 411 | { 412 | printf(" %-7d %-10d\n", allocation.first, allocation.second); 413 | } 414 | std::cout << "--------------------" << std::endl; 415 | } 416 | -------------------------------------------------------------------------------- /lab2/memory/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::string info = std::string("\033[0m\033[1;32m[info] \033[0m"); 7 | std::string opt = std::string("\033[0m\033[1;32m[option] \033[0m"); 8 | std::string error = std::string("\033[0m\033[1;31m[error] \033[0m"); 9 | std::string warning = std::string("\033[0m\033[1;33m[warning] \033[0m"); 10 | 11 | Allocator::Option option = Allocator::Option::BF; 12 | std::string algo = "BF"; 13 | 14 | const int DEFAULT_MEM_SIZE = 1024; 15 | 16 | Allocator* alloc = nullptr; 17 | 18 | void DisplayMenu(); 19 | int Run(int num); 20 | 21 | int main() 22 | { 23 | int operation = 0; 24 | 25 | system("clear"); 26 | 27 | while (true) 28 | { 29 | DisplayMenu(); 30 | std::cin >> operation; 31 | if (!Run(operation)) 32 | break; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | void DisplayMenu() 39 | { 40 | printf("-----------------[Menu]-----------------\n"); 41 | printf("------------------[%s]------------------\n", algo.c_str()); 42 | printf("1 - Set memory size (default=%d)\n", DEFAULT_MEM_SIZE); 43 | printf("2 - Select memory allocation algorithm\n"); 44 | printf("3 - New process \n"); 45 | printf("4 - Terminate a process \n"); 46 | printf("5 - Free a Part of memory of a process \n"); 47 | printf("6 - Display memory usage \n"); 48 | printf("0 - Exit\n"); 49 | printf("-----------------[Menu]-----------------\n"); 50 | } 51 | 52 | int Run(int num) 53 | { 54 | std::string ignore; 55 | switch (num) 56 | { 57 | case 1: 58 | { 59 | if (!alloc) 60 | { 61 | int size = 0; 62 | std::cout << info << "Enter the value of size..." << std::endl; 63 | std::cin >> size; 64 | assert(size > 0); 65 | alloc = new Allocator(size); 66 | } 67 | else 68 | { 69 | std::cerr << warning << "Alloc has been Initilized!!!" << std::endl; 70 | } 71 | break; 72 | } 73 | case 2: 74 | { 75 | if (!alloc) 76 | { 77 | std::cerr << warning << "Initilize the allocator first!!!" << std::endl; 78 | break; 79 | }; 80 | std::cout << opt << "1: FF 2: BF 3: WF" << std::endl; 81 | int num = 0; 82 | std::cout << info << "Enter the Num..." << std::endl; 83 | std::cin >> num; 84 | if (num == 1) {option = Allocator::Option::FF; algo = "FF";} 85 | else if (num == 2) {option = Allocator::Option::BF; algo = "BF";} 86 | else if (num == 3) {option = Allocator::Option::WF; algo = "WF";} 87 | else std::cerr << error << "Out of Range!!!" << std::endl; 88 | break; 89 | } 90 | case 3: 91 | { 92 | if (!alloc) 93 | { 94 | std::cerr << warning << "Initilize the allocator first!!!" << std::endl; 95 | break; 96 | }; 97 | int size = 1; 98 | std::cout << info << "Enter the Size of the new Process..." << std::endl; 99 | std::cin >> size; 100 | if (size == 0) 101 | { 102 | std::cerr << error << "Size can not be zero!!!" << std::endl; 103 | break; 104 | } 105 | int res = alloc->AddProcessAndAllocate(size, option); 106 | if (res == -1) std::cerr << error << "Allocate Failed!!!" << std::endl; 107 | break; 108 | } 109 | case 4: 110 | { 111 | if (!alloc) 112 | { 113 | std::cerr << warning << "Initilize the allocator first!!!" << std::endl; 114 | break; 115 | }; 116 | int pid = 1; 117 | std::cout << info << "Enter the Pid of the selected Process..." << std::endl; 118 | std::cin >> pid; 119 | assert(pid > 0); 120 | alloc->DelProcessAndFree(pid); 121 | break; 122 | } 123 | case 5: 124 | { 125 | if (!alloc) 126 | { 127 | std::cerr << info << "Initilize the allocator first!!!" << std::endl; 128 | break; 129 | }; 130 | int pid = 0; 131 | int offset = 0; 132 | int size = 0; 133 | std::cout << info << "Enter the Pid, Offset, Size in order..." << std::endl; 134 | std::cin >> pid >> offset >> size; 135 | if (pid == 0 || size == 0) 136 | { 137 | std::cerr << error << "Input Error" << std::endl; 138 | break; 139 | } 140 | alloc->NotDelProcessAndFree(pid, offset, size); 141 | break; 142 | } 143 | case 6: 144 | { 145 | if (!alloc) 146 | { 147 | std::cerr << warning << "Initilize the allocator first!!!" << std::endl; 148 | break; 149 | }; 150 | alloc->OutputGraph(); 151 | break; 152 | } 153 | case 0: 154 | return 0; 155 | default: 156 | break; 157 | } 158 | std::cout << info << "Enter c To Continue......" << std::endl; 159 | while (ignore != std::string("c")) 160 | std::cin >> ignore; 161 | system("clear"); 162 | return num; 163 | } 164 | -------------------------------------------------------------------------------- /lab2/pipe/pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | /* 17 | 同步和互斥: 18 | * 进程锁 19 | * lockf() 20 | */ 21 | 22 | #define READ_END 0 23 | #define WRITE_END 1 24 | #define BUFFER_SIZE 4001 25 | 26 | pid_t pid1, pid2; 27 | 28 | int main() { 29 | 30 | int fd[2]; 31 | char InPipe[BUFFER_SIZE]; 32 | const char* c1="1"; 33 | const char* c2="2"; 34 | 35 | pipe(fd); 36 | 37 | while((pid1 = fork()) == -1); 38 | 39 | if(pid1 == 0) { /* child process1 */ 40 | lockf(fd[1],1,0); 41 | for (int i = 0; i < (BUFFER_SIZE - 1) / 2; ++i) 42 | { 43 | write(fd[WRITE_END], c1, 1); 44 | } 45 | lockf(fd[1],0,0); 46 | sleep(2); 47 | exit(0); 48 | } 49 | else { 50 | while((pid2 = fork()) == -1); 51 | if(pid2 == 0) { /* child process2 */ 52 | lockf(fd[1],1,0); 53 | for (int i = 0; i < (BUFFER_SIZE - 1) / 2; ++i) 54 | { 55 | write(fd[WRITE_END], c2, 1); 56 | } 57 | lockf(fd[1],0,0); 58 | sleep(2); 59 | exit(0); 60 | } 61 | else { /* father process */ 62 | wait(NULL); 63 | lockf(fd[0],1,0); 64 | ssize_t size = read(fd[READ_END], InPipe, BUFFER_SIZE - 1); 65 | if(size > 0) 66 | InPipe[size] = '\0'; 67 | else if(size == 0) 68 | printf("quit\n"); 69 | else 70 | printf("error\n"); 71 | lockf(fd[0],0,0); 72 | printf("%s\n",InPipe); 73 | exit(0); 74 | } 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /lab2/pipe/pipe.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/pipe/pipe.exe -------------------------------------------------------------------------------- /lab2/pipe/pipe_lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | /* 17 | 同步和互斥: 18 | * 进程锁 19 | * lockf() 20 | */ 21 | 22 | #define READ_END 0 23 | #define WRITE_END 1 24 | #define BUFFER_SIZE 4001 25 | 26 | struct mutexHolder { 27 | pthread_mutex_t mutex; // must be here !!!!!!!! 28 | }; 29 | 30 | pid_t pid1, pid2; 31 | 32 | int main() { 33 | struct mutexHolder *shared_mutex = NULL; 34 | pthread_mutexattr_t mutexattr; 35 | 36 | int shared_fd = open("shared.txt", O_CREAT | O_RDWR, 0777); 37 | (void)ftruncate(shared_fd, sizeof(*shared_mutex)); 38 | shared_mutex = (struct mutexHolder *)mmap(NULL, sizeof(*shared_mutex), PROT_READ | PROT_WRITE, MAP_SHARED, shared_fd, 0); 39 | close(shared_fd); 40 | 41 | /* Reset */ 42 | memset(shared_mutex, 0, sizeof(*shared_mutex)); 43 | pthread_mutexattr_init(&mutexattr); 44 | pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); 45 | pthread_mutex_init(&shared_mutex->mutex, &mutexattr); 46 | 47 | int fd[2]; 48 | char InPipe[BUFFER_SIZE]; 49 | const char* c1="1"; 50 | const char* c2="2"; 51 | 52 | pipe(fd); 53 | 54 | while((pid1 = fork()) == -1); 55 | 56 | if(pid1 == 0) { /* child process1 */ 57 | lockf(fd[1],1,0); 58 | for (int i = 0; i < (BUFFER_SIZE - 1) / 2; ++i) 59 | { 60 | // pthread_mutex_lock(&shared_mutex->mutex); 61 | write(fd[WRITE_END], c1, 1); 62 | // pthread_mutex_unlock(&shared_mutex->mutex); 63 | } 64 | sleep(5); 65 | lockf(fd[1],0,0); 66 | exit(0); 67 | } 68 | else { 69 | while((pid2 = fork()) == -1); 70 | if(pid2 == 0) { /* child process2 */ 71 | lockf(fd[1],1,0); 72 | for (int i = 0; i < (BUFFER_SIZE - 1) / 2; ++i) 73 | { 74 | // pthread_mutex_lock(&shared_mutex->mutex); 75 | write(fd[WRITE_END], c2, 1); 76 | // pthread_mutex_unlock(&shared_mutex->mutex); 77 | } 78 | sleep(5); 79 | lockf(fd[1],0,0); 80 | exit(0); 81 | } 82 | else { /* father process */ 83 | wait(NULL); 84 | // lockf(fd[0],1,0); 85 | read(fd[READ_END], InPipe, BUFFER_SIZE - 1); 86 | // lockf(fd[0],0,0); 87 | InPipe[BUFFER_SIZE - 1] = '\0'; 88 | printf("%s\n",InPipe); 89 | exit(0); 90 | } 91 | } 92 | 93 | pthread_mutex_destroy(&shared_mutex->mutex); 94 | 95 | munmap(shared_mutex, sizeof(*shared_mutex)); 96 | unlink("shared.txt"); 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /lab2/pipe/pipe_lock.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/pipe/pipe_lock.exe -------------------------------------------------------------------------------- /lab2/pipe/shared.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/pipe/shared.txt -------------------------------------------------------------------------------- /lab2/sig/sig_receive.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | pid_t child_pid1, child_pid2; 9 | 10 | void father_handler(int signum) { 11 | if (signum == SIGALRM) { 12 | kill(child_pid1, SIGUSR1); 13 | kill(child_pid2, SIGUSR2); 14 | wait(NULL); 15 | printf("[info] Parent process is killed!!\n"); 16 | exit(0); 17 | } 18 | else if (signum == SIGQUIT) { 19 | kill(child_pid1, SIGUSR1); 20 | kill(child_pid2, SIGUSR2); 21 | wait(NULL); 22 | printf("[info] Parent process is killed!!\n"); 23 | exit(0); 24 | } 25 | else 26 | printf("[info] error\n"); 27 | } 28 | 29 | void child1_handler(int signum) { 30 | if (signum == SIGUSR1) { 31 | printf("[info] Child process 1 is killed by parent!!\n"); 32 | exit(0); 33 | } 34 | } 35 | 36 | void child2_handler(int signum) { 37 | if (signum == SIGUSR2) { 38 | printf("[info] Child process 2 is killed by parent!!\n"); 39 | exit(0); 40 | } 41 | } 42 | 43 | int main(void) { 44 | child_pid1 = fork(); 45 | 46 | if (child_pid1 < 0) { 47 | fprintf(stderr, "[error] Child 1 Fork Failed"); 48 | return 1; 49 | } 50 | else if (child_pid1 == 0) { /* child process 1 */ 51 | signal(SIGUSR1, child1_handler); 52 | signal(SIGQUIT, SIG_IGN); 53 | // signal(SIGQUIT, SIG_DFL); 54 | while (1) sleep(1); 55 | } 56 | else { /* parent process */ 57 | child_pid2 = fork(); 58 | 59 | if (child_pid2 < 0) { 60 | fprintf(stderr, "[error] Child2 Fork Failed"); 61 | return 1; 62 | } 63 | else if (child_pid2 == 0) { /* child process 2 */ 64 | signal(SIGUSR2, child2_handler); 65 | signal(SIGQUIT, SIG_IGN); 66 | // signal(SIGQUIT, SIG_DFL); 67 | while (1) sleep(1); 68 | } 69 | else { /* parent process */ 70 | signal(SIGALRM, father_handler); // 14 71 | signal(SIGQUIT, father_handler); // 3 72 | alarm(5); 73 | 74 | int time = 0; 75 | 76 | while(1) { 77 | printf("[info] time passed: %d\n", ++time); 78 | sleep(1); 79 | } 80 | } 81 | } 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /lab2/sig/sig_receive.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab2/sig/sig_receive.exe -------------------------------------------------------------------------------- /lab3/CTP/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .cache 3 | .vscode -------------------------------------------------------------------------------- /lab3/CTP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(CTP) 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | set(CMAKE_BUILD_TYPE "Debug") 8 | 9 | IF(CMAKE_COMPILER_IS_GNUCXX) 10 | set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -pthread") 11 | ENDIF(CMAKE_COMPILER_IS_GNUCXX) 12 | 13 | add_subdirectory(Test) 14 | add_subdirectory(Core) 15 | -------------------------------------------------------------------------------- /lab3/CTP/Core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Set the project name 2 | project (CTP_Core) 3 | 4 | add_library(${PROJECT_NAME} src/ThreadPool.cpp) 5 | add_library(Chen::CTP ALIAS ${PROJECT_NAME}) 6 | 7 | target_include_directories(${PROJECT_NAME} 8 | PUBLIC 9 | ${PROJECT_SOURCE_DIR}/include 10 | ) 11 | -------------------------------------------------------------------------------- /lab3/CTP/Core/include/CTP/ThreadPool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "./function2/function2.hpp" 9 | 10 | namespace Chen { 11 | class ThreadPool { 12 | public: 13 | ThreadPool(size_t num); 14 | ~ThreadPool(); 15 | 16 | // return std::future 17 | template 18 | auto Submit(F&& f, Args&&... args); 19 | 20 | void BasicSubmit(fu2::unique_function task); 21 | // void BasicSubmit(std::function task); 22 | 23 | private: 24 | std::vector workers; 25 | std::queue> tasks; 26 | 27 | std::mutex mutex_tasks; 28 | std::condition_variable condition; // use with `std::unique_lock` 29 | bool stop{ false }; 30 | }; 31 | } 32 | 33 | #include "details/ThreadPool.inl" -------------------------------------------------------------------------------- /lab3/CTP/Core/include/CTP/details/ThreadPool.inl: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Chen { 4 | template 5 | auto ThreadPool::Submit(F&& f, Args&&... args) { 6 | using return_type = std::invoke_result_t; 7 | 8 | std::promise barrier; 9 | 10 | std::future fret = barrier.get_future(); 11 | 12 | // Here 13 | BasicSubmit([f = std::forward(f), barrier = std::move(barrier), ... args = std::forward(args)]() mutable { 14 | if constexpr (std::is_void_v) { 15 | std::invoke(std::forward(f), std::forward(args)...); 16 | barrier.set_value(); // only for Sync 17 | } 18 | else 19 | barrier.set_value(std::invoke(std::forward(f), std::forward(args)...)); 20 | }); 21 | 22 | return fret; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lab3/CTP/Core/src/ThreadPool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace Chen; 4 | 5 | ThreadPool::ThreadPool(size_t num) { 6 | assert(num <= std::thread::hardware_concurrency()); 7 | for (size_t i = 0; i < num; ++i) { 8 | workers.emplace_back([this] { 9 | while (true) { 10 | fu2::unique_function task; 11 | { // get task 12 | std::unique_lock lock(mutex_tasks); 13 | condition.wait(lock, [this] { return stop || !tasks.empty(); }); 14 | if (stop && tasks.empty()) 15 | return; 16 | task = std::move(tasks.front()); 17 | tasks.pop(); 18 | } 19 | 20 | task(); 21 | } 22 | }); 23 | } 24 | } 25 | 26 | void ThreadPool::BasicSubmit(fu2::unique_function task) { 27 | { 28 | std::lock_guard lock(mutex_tasks); 29 | 30 | if (stop) 31 | throw std::runtime_error("submit on stopped ThreadPool"); 32 | 33 | tasks.push(std::move(task)); 34 | } 35 | condition.notify_one(); 36 | } 37 | 38 | ThreadPool::~ThreadPool() { 39 | { 40 | std::lock_guard lock(mutex_tasks); 41 | stop = true; 42 | } 43 | condition.notify_all(); // 唤醒所有等待队列中阻塞的线程 44 | for (auto& worker : workers) 45 | worker.join(); 46 | } 47 | -------------------------------------------------------------------------------- /lab3/CTP/README.md: -------------------------------------------------------------------------------- 1 | # CTP 2 | *Thread Pool Impl* 3 | 4 | --- 5 | 6 | ## Usage 7 | 8 | ```cpp 9 | #include 10 | ``` 11 | -------------------------------------------------------------------------------- /lab3/CTP/Test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(Test) 4 | 5 | # Create the executable 6 | add_executable(${PROJECT_NAME} test.cpp) 7 | 8 | target_link_libraries(${PROJECT_NAME} 9 | Chen::CTP 10 | ) 11 | 12 | target_include_directories(${PROJECT_NAME} 13 | PUBLIC 14 | ${PROJECT_SOURCE_DIR}/include 15 | ) 16 | -------------------------------------------------------------------------------- /lab3/CTP/Test/include/test.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using namespace Chen; 9 | using namespace std; 10 | using namespace std::chrono; 11 | 12 | // ******************************** [Initial] ************************************************* 13 | 14 | template 15 | void test_func_impl(F&& f, Args&&... args) { 16 | std::invoke(std::forward(f), std::forward(args)...); 17 | } 18 | 19 | void test_func() { 20 | int res = 0; 21 | test_func_impl([&](int i) { std::cout << res + i << std::endl; return 0; }, 10); 22 | test_func_impl([&](int i) { std::cout << res + i << std::endl; return 1; }, 20); 23 | } 24 | 25 | class Base { 26 | public: 27 | Base(int _i = 0) : i(_i) {} 28 | Base(const Base&) = delete; 29 | Base& operator=(const Base&) = delete; 30 | private: 31 | int i; 32 | }; 33 | 34 | void execute(std::function&& f) { 35 | f(); 36 | } 37 | 38 | void test_copy() { 39 | Base b0(1); 40 | 41 | // execute([b0 = std::move(b0)]() { 42 | // std::cout << "Hello" << std::endl; 43 | // }); 44 | } 45 | 46 | // ******************************************************************************************** 47 | 48 | void test_thread_pool() { 49 | ThreadPool pool(4); 50 | 51 | int res = 0; 52 | 53 | auto result = pool.Submit([](int answer) { return answer; }, 2); 54 | 55 | pool.Submit([](int* r) { *r = 2; }, &res); 56 | 57 | std::cout << "result: " << result.get() << std::endl; 58 | std::cout << "res: " << res << std::endl; 59 | 60 | pool.Submit([](int answer) { std::cout << answer << std::endl; }, 2); 61 | pool.Submit([](int answer) { std::cout << answer << std::endl; }, 4); 62 | } 63 | 64 | class A { 65 | public: 66 | A() { constructMap(); } 67 | 68 | void execute() { 69 | int res = 0; 70 | for (int i = 0; i < 300; ++i) { 71 | for (const auto& ele: str2int) { 72 | std::string tmp = ele.first; 73 | res += ele.second; 74 | } 75 | } 76 | } 77 | 78 | private: 79 | void constructMap() { 80 | str2int["0"] = 0; 81 | str2int["1"] = 1; 82 | str2int["2"] = 2; 83 | str2int["3"] = 3; 84 | str2int["4"] = 4; 85 | str2int["5"] = 5; 86 | str2int["6"] = 6; 87 | str2int["7"] = 7; 88 | str2int["8"] = 8; 89 | str2int["9"] = 9; 90 | } 91 | 92 | std::unordered_map str2int; 93 | }; 94 | 95 | void test_efficiency_no_threadpool() { 96 | steady_clock::time_point start_time = steady_clock::now(); 97 | 98 | // ******************************************************************** 99 | 100 | for (int i = 0; i < 20000; ++i) { 101 | A tmp; 102 | tmp.execute(); 103 | } 104 | 105 | // ******************************************************************** 106 | 107 | steady_clock::time_point end_time = steady_clock::now(); 108 | 109 | duration time_span = duration_cast>(end_time - start_time); 110 | 111 | std::cout << "no_thread_pool_cost : " << time_span.count() << std::endl; 112 | } 113 | 114 | void test_efficiency_with_threadpool() { 115 | ThreadPool pool(std::thread::hardware_concurrency()); 116 | 117 | steady_clock::time_point start_time = steady_clock::now(); 118 | 119 | std::vector> rets; 120 | rets.reserve(20000); 121 | 122 | for (int i = 0; i < 20000; ++i) { 123 | rets.push_back(pool.Submit([]() { 124 | A tmp; 125 | tmp.execute(); 126 | })); 127 | } 128 | 129 | for (auto &r : rets) 130 | r.get(); 131 | 132 | steady_clock::time_point end_time = steady_clock::now(); 133 | 134 | duration time_span = duration_cast>(end_time - start_time); 135 | 136 | std::cout << "with_thread_pool_cost : " << time_span.count() << std::endl; 137 | } 138 | -------------------------------------------------------------------------------- /lab3/CTP/Test/include/test_func.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | -------------------------------------------------------------------------------- /lab3/CTP/Test/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | 6 | // test_func(); 7 | 8 | // test_thread_pool(); 9 | 10 | test_efficiency_no_threadpool(); 11 | test_efficiency_with_threadpool(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /lab3/FileSystem/.clang-format: -------------------------------------------------------------------------------- 1 | # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | 5 | AccessModifierOffset: -4 6 | 7 | AlignAfterOpenBracket: Align 8 | 9 | AlignConsecutiveAssignments: false 10 | 11 | AlignConsecutiveDeclarations: false 12 | 13 | AlignEscapedNewlines: Right 14 | 15 | AlignOperands: true 16 | 17 | AlignTrailingComments: true 18 | 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | 21 | AllowShortBlocksOnASingleLine: true 22 | 23 | AllowShortCaseLabelsOnASingleLine: true 24 | 25 | AllowShortFunctionsOnASingleLine: None 26 | 27 | AllowShortIfStatementsOnASingleLine: true 28 | 29 | AllowShortLoopsOnASingleLine: true 30 | 31 | AlwaysBreakAfterReturnType: None 32 | 33 | AlwaysBreakBeforeMultilineStrings: false 34 | 35 | AlwaysBreakTemplateDeclarations: true 36 | 37 | BinPackArguments: true 38 | 39 | BinPackParameters: true 40 | 41 | BraceWrapping: 42 | AfterClass: false 43 | AfterControlStatement: false 44 | AfterEnum: false 45 | AfterFunction: false 46 | AfterNamespace: false 47 | AfterStruct: false 48 | AfterUnion: false 49 | AfterExternBlock: false 50 | BeforeCatch: false 51 | BeforeElse: true 52 | IndentBraces: false 53 | SplitEmptyFunction: false 54 | SplitEmptyRecord: false 55 | SplitEmptyNamespace: false 56 | 57 | BreakBeforeBinaryOperators: NonAssignment 58 | 59 | BreakBeforeBraces: Custom 60 | 61 | BreakBeforeTernaryOperators: false 62 | 63 | BreakConstructorInitializers: AfterColon 64 | 65 | #BreakInheritanceList: AfterColon 66 | 67 | BreakStringLiterals: false 68 | 69 | ColumnLimit: 0 70 | 71 | CompactNamespaces: true 72 | 73 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 74 | 75 | ConstructorInitializerIndentWidth: 4 76 | 77 | ContinuationIndentWidth: 4 78 | 79 | Cpp11BracedListStyle: true 80 | 81 | DerivePointerAlignment: false 82 | 83 | FixNamespaceComments: true 84 | 85 | IndentCaseLabels: false 86 | 87 | IndentPPDirectives: None 88 | 89 | IndentWidth: 4 90 | 91 | IndentWrappedFunctionNames: false 92 | 93 | KeepEmptyLinesAtTheStartOfBlocks: false 94 | 95 | MaxEmptyLinesToKeep: 1 96 | 97 | NamespaceIndentation: None 98 | 99 | PointerAlignment: Left 100 | 101 | ReflowComments: true 102 | 103 | SortIncludes: false 104 | 105 | SortUsingDeclarations: false 106 | 107 | SpaceAfterCStyleCast: false 108 | 109 | SpaceAfterTemplateKeyword: true 110 | 111 | SpaceBeforeAssignmentOperators: true 112 | 113 | # SpaceBeforeCpp11BracedList: true 114 | 115 | # SpaceBeforeCtorInitializerColon: true 116 | 117 | # SpaceBeforeInheritanceColon: true 118 | 119 | SpaceBeforeParens: ControlStatements 120 | 121 | # SpaceBeforeRangeBasedForLoopColon: true 122 | 123 | SpaceInEmptyParentheses: false 124 | 125 | SpacesBeforeTrailingComments: 1 126 | 127 | SpacesInAngles: false 128 | 129 | SpacesInCStyleCastParentheses: false 130 | 131 | SpacesInContainerLiterals: true 132 | 133 | SpacesInParentheses: false 134 | 135 | SpacesInSquareBrackets: false 136 | 137 | Standard: Cpp11 138 | 139 | TabWidth: 4 140 | 141 | UseTab: Never -------------------------------------------------------------------------------- /lab3/FileSystem/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .vscode -------------------------------------------------------------------------------- /lab3/FileSystem/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | project(Ext2FileSystem) 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED True) 7 | set(CMAKE_BUILD_TYPE "Debug") 8 | 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | if(CMAKE_EXPORT_COMPILE_COMMANDS) 11 | set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) 12 | endif() 13 | 14 | add_executable(${PROJECT_NAME} 15 | src/main.cpp 16 | src/Ext2.cpp 17 | src/Shell.cpp 18 | ) 19 | 20 | target_include_directories(${PROJECT_NAME} 21 | PUBLIC ${PROJECT_SOURCE_DIR}/include 22 | ) -------------------------------------------------------------------------------- /lab3/FileSystem/include/Ext2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | Assume: 5 | - Only one group --> one group desc 6 | - Only one user 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define VOLUME_NAME "Ext2FileSystem" 18 | 19 | #define BLOCK_SIZE 512 20 | 21 | #define SUPER_BLOCK_START_ADDR 0 22 | #define SUPER_BLOCK_SIZE 32 23 | 24 | #define GROUP_DESC_START_ADDR 512 25 | #define GROUP_DESC_SIZE 32 26 | 27 | #define BLOCK_BITMAP_START_ADDR 1024 // 512 * 2 28 | 29 | #define INODE_BITMAP_START_ADDR 1536 // 512 * 3 30 | 31 | #define INODE_TABLE_START_ADDR 2048 // 512 * 4 32 | #define INODE_SIZE 64 33 | #define INODE_NUM 4096 34 | 35 | #define DATA_BLOCK_START_ADDR 264192 // 512 * 4 + 64 * 4096 36 | #define DATA_BLOCK_NUM 4096 37 | 38 | #define TOTAL_BLOCK_NUM 4612 // 4 + 512 + 4096 39 | 40 | #define USER_NUM 1 41 | #define FOPEN_TABLE_MAX 16 42 | 43 | #define MAX_FILE_CAPACITY 4096 44 | 45 | #define DIR_ENTRY_NUM_PER_BLOCK 32 46 | 47 | #define DIR_ENTRY_SIZE 16 48 | 49 | // 16 + 2 * 2 + 4 + 8 = 32 Byte 50 | struct ext2_super_block { 51 | char sb_volume_name[16]; 52 | uint32_t sb_disk_size; // uint32_t to store the large number 53 | uint16_t sb_size_per_block; 54 | uint16_t sb_blocks_per_group; 55 | char sb_pad[8]; 56 | }; 57 | 58 | // 16 + 2 * 6 + 4 = 32 Byte 59 | struct ext2_group_desc { 60 | char bg_volume_name[16]; //卷名 61 | uint16_t bg_block_bitmap; //保存块位图的块号 62 | uint16_t bg_inode_bitmap; //保存索引结点位图的块号 63 | uint16_t bg_inode_table; //索引结点表的起始块号 64 | uint16_t bg_free_blocks_count; //本组空闲块的个数 65 | uint16_t bg_free_inodes_count; //本组空闲索引结点的个数 66 | uint16_t bg_used_dirs_count; //本组目录的个数 67 | char bg_pad[4]; //填充(0xff) 68 | }; 69 | 70 | // 2 * 2 + 4 + 8 * 4 + 2 * 8 + 8 = 64 Byte 71 | struct ext2_inode { 72 | uint16_t i_mode; // 文件类型及访问权限 73 | uint16_t i_blocks; // 文件的数据块个数 74 | uint32_t i_size; // 大小(字节) 75 | uint64_t i_atime; // 访问时间 76 | uint64_t i_ctime; // 创建时间 77 | uint64_t i_mtime; // 修改时间 78 | uint64_t i_dtime; // 删除时间 79 | uint16_t i_block[8]; // 指向数据块的指针 --> [0,5](直接索引) [6](一级间接) 80 | // [7](二级间接) 81 | char i_pad[8]; // 填充1(0xff) 82 | }; 83 | 84 | // 2 * 3 + 1 + 9 = 16 Byte 85 | struct ext2_dir_entry { 86 | uint16_t inode; 87 | uint16_t record_len; 88 | uint16_t name_len; 89 | char file_type; 90 | char name[9]; 91 | }; 92 | 93 | enum class FileType : uint8_t { 94 | UNKNOWN = 0, 95 | FILE, 96 | DIR, 97 | OTHER, 98 | }; 99 | 100 | class Ext2 { 101 | public: 102 | static Ext2& GetInstance() { 103 | static Ext2 instance; 104 | return instance; 105 | } 106 | 107 | void init(); 108 | 109 | // load/update of super_block 110 | void updateSuperBlock(); 111 | void loadSuperBlock(); 112 | 113 | // load/update of group_desc 114 | void updateGroupDesc(); 115 | void loadGroupDesc(); 116 | 117 | // load/update of block_bitmap 118 | void updateBlockBitmap(); 119 | void loadBlockBitmap(); 120 | 121 | // load/update of inode_bitmap 122 | void updateInodeBitmap(); 123 | void loadInodeBitmap(); 124 | 125 | // load/update of inode 126 | void updateInode(size_t idx); 127 | void loadInode(size_t idx); 128 | 129 | // load/update of dir_entry_block 130 | void updateDirDataBlock(size_t idx); 131 | void loadDirDataBlock(size_t idx); 132 | 133 | // load/update of data_block 134 | void updateDataBlock(size_t idx); 135 | void loadDataBlock(size_t idx); 136 | 137 | // load/update of level1_index_block_buf 138 | void updateIndexBlock_Level1(size_t idx); 139 | void loadIndexBlock_Level1(size_t idx); 140 | 141 | // load/update of level2_index_block_buf 142 | void updateIndexBlock_Level2(size_t idx); 143 | void loadIndexBlock_Level2(size_t idx); 144 | 145 | // alloc and free 146 | size_t allocDataBlock(); 147 | void freeDataBlock(size_t idx); 148 | 149 | size_t allocInode(); 150 | void freeInode(size_t idx); 151 | 152 | // search 153 | uint16_t searchFile(char const tar[9], char file_type, uint16_t& inode_idx, 154 | uint16_t& block_idx, uint16_t& dir_idx); 155 | uint16_t searchInTable(uint16_t inode); 156 | 157 | // operations 158 | void ext2_cd(char const tar[9]); 159 | void ext2_cd_impl(char const tar[9]); 160 | 161 | void ext2_mkdir(char const tar[9]); 162 | void ext2_rmdir(char const tar[9]); 163 | 164 | void ext2_touch(char const tar[9], FileType type = FileType::FILE); 165 | void ext2_rm(char const tar[9], FileType type = FileType::FILE); 166 | 167 | void ext2_chmod(char const tar[9]); 168 | void ext2_chmod_impl(char const tar[9], uint16_t mode); 169 | 170 | void ext2_open(char const tar[9], FileType type = FileType::FILE); 171 | void ext2_close(char const tar[9], FileType type = FileType::FILE); 172 | void ext2_read(char const tar[9]); 173 | void ext2_write(char const tar[9]); 174 | void ext2_append(char const tar[9]); 175 | 176 | void ext2_ls(); 177 | void ext2_ll(); 178 | void ext2_l_open_file(); 179 | 180 | void showDiskInfo(); 181 | 182 | // print 183 | void printCurrPath(); 184 | 185 | private: 186 | Ext2() { 187 | fp = fopen("./Ext2", "w+"); 188 | assert(fp); 189 | fseek(fp, 0, SEEK_SET); 190 | } 191 | 192 | ~Ext2() { 193 | fclose(fp); 194 | } 195 | 196 | void init_fs(); 197 | 198 | void preProcess(uint16_t tar, uint16_t len, FileType type, 199 | std::string file_name = ""); 200 | 201 | void inputTargetProcess(std::string); 202 | 203 | std::string type2Str(FileType type); 204 | std::string mode2Str(uint16_t mode); 205 | int calcDirSize(uint16_t inode); 206 | 207 | private: 208 | ext2_super_block super_block[1]; 209 | ext2_group_desc group_desc_table[1]; 210 | ext2_inode inode_buf[1]; 211 | uint8_t block_bit_buf[512] = {0}; 212 | uint8_t inode_bit_buf[512] = {0}; 213 | ext2_dir_entry dir_buf[32]; // 32 * 16 = 512 Byte 214 | char data_buf[BLOCK_SIZE]; 215 | 216 | uint16_t file_open_table[FOPEN_TABLE_MAX]; 217 | std::set file_open_name_set; 218 | 219 | uint16_t level1_index_block_buf[256]; // 一级间接索引 220 | uint16_t level2_index_block_buf[256]; // 二级间接索引 221 | 222 | FILE* fp; // 用文件来模拟磁盘空间 223 | 224 | char current_path[256]; // 当前路径 225 | uint16_t current_dir{0}; // 当前目录 226 | uint16_t current_dirlen{0}; // 当前路径长度 227 | 228 | uint16_t last_alloc_block{0}; // 上次分配的数据块号 229 | uint16_t last_alloc_inode{0}; // 上次分配的节点号 230 | }; 231 | -------------------------------------------------------------------------------- /lab3/FileSystem/include/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define INFO(msg) printf("\033[0m\033[1;32m%s\033[0m", msg) 6 | #define WARN(msg) printf("\033[0m\033[1;33m%s\033[0m", msg) 7 | #define ERROR(msg) printf("\033[0m\033[1;31m%s\033[0m", msg) 8 | -------------------------------------------------------------------------------- /lab3/FileSystem/include/Shell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Command : uint16_t { 8 | CD = 0, 9 | MKDIR, 10 | RMDIR, 11 | RM, 12 | TOUCH, 13 | OPEN, 14 | CLOSE, 15 | READ, 16 | WRITE, 17 | APPEND, 18 | LS, 19 | LL, 20 | LS_OPEN_FILE, 21 | CHMOD, 22 | SHOW_DISK_INFO, 23 | HELP, 24 | CLEAR, 25 | EXIT, 26 | NONE, 27 | Count 28 | }; 29 | 30 | struct Pack { 31 | Pack() { memset(&(target[0]), 0, sizeof(target)/sizeof(target[0])); } 32 | 33 | bool is_valid{false}; 34 | Command command{Command::NONE}; 35 | char target[9]; 36 | }; 37 | 38 | class Shell { 39 | public: 40 | static Shell& GetInstance() { 41 | static Shell instance; 42 | return instance; 43 | } 44 | 45 | void init(); 46 | void run(); 47 | 48 | Pack inputProcess(std::string input); 49 | 50 | private: 51 | Shell() = default; 52 | ~Shell() = default; 53 | 54 | void constructMap(); 55 | 56 | void help(); 57 | 58 | private: 59 | bool is_init{false}; 60 | 61 | std::unordered_map input2command; 62 | }; 63 | -------------------------------------------------------------------------------- /lab3/FileSystem/include/Test.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void test01() { 8 | Ext2::GetInstance().init(); 9 | 10 | // ********************************************************** 11 | // Test 12 | 13 | // / 14 | // Ext2::GetInstance().ext2_cd("."); 15 | // INFO(Ext2::GetInstance().current_path); 16 | // INFO("\n"); 17 | 18 | // // /test/ 19 | // Ext2::GetInstance().ext2_mkdir("test"); 20 | // Ext2::GetInstance().ext2_cd("test"); 21 | // INFO(Ext2::GetInstance().current_path); 22 | // INFO("\n"); 23 | 24 | // // /test/a/ 25 | // Ext2::GetInstance().ext2_mkdir("a"); 26 | // Ext2::GetInstance().ext2_cd("a"); 27 | // Ext2::GetInstance().ext2_touch("a.txt"); 28 | // INFO(Ext2::GetInstance().current_path); 29 | // INFO("\n"); 30 | 31 | // // /test/ 32 | // Ext2::GetInstance().ext2_cd(".."); 33 | // INFO(Ext2::GetInstance().current_path); 34 | // INFO("\n"); 35 | 36 | // Ext2::GetInstance().ext2_ls(); 37 | // INFO(Ext2::GetInstance().current_path); 38 | // INFO("\n"); 39 | 40 | // Ext2::GetInstance().ext2_rmdir("a"); 41 | // INFO(Ext2::GetInstance().current_path); 42 | // INFO("\n"); 43 | 44 | // Ext2::GetInstance().ext2_ls(); 45 | // INFO(Ext2::GetInstance().current_path); 46 | // INFO("\n"); 47 | 48 | // // / 49 | // Ext2::GetInstance().ext2_cd(".."); 50 | // INFO(Ext2::GetInstance().current_path); 51 | // INFO("\n"); 52 | 53 | // Ext2::GetInstance().ext2_touch("a.txt"); 54 | // INFO(Ext2::GetInstance().current_path); 55 | // INFO("\n"); 56 | 57 | // Ext2::GetInstance().ext2_ls(); 58 | // INFO(Ext2::GetInstance().current_path); 59 | // INFO("\n"); 60 | 61 | // Ext2::GetInstance().ext2_open("a.txt"); 62 | // INFO(Ext2::GetInstance().current_path); 63 | // INFO("\n"); 64 | 65 | // Ext2::GetInstance().ext2_l_open_file(); 66 | 67 | // Ext2::GetInstance().ext2_write("a.txt"); 68 | // INFO(Ext2::GetInstance().current_path); 69 | // INFO("\n"); 70 | 71 | // Ext2::GetInstance().ext2_read("a.txt"); 72 | // INFO(Ext2::GetInstance().current_path); 73 | // INFO("\n"); 74 | 75 | // Ext2::GetInstance().ext2_close("a.txt"); 76 | // INFO(Ext2::GetInstance().current_path); 77 | // INFO("\n"); 78 | 79 | // Ext2::GetInstance().ext2_ll(); 80 | // INFO(Ext2::GetInstance().current_path); 81 | // INFO("\n"); 82 | 83 | // Ext2::GetInstance().showDiskInfo(); 84 | 85 | // Ext2::GetInstance().ext2_rm("a.txt"); 86 | // INFO(Ext2::GetInstance().current_path); 87 | // INFO("\n"); 88 | 89 | // Ext2::GetInstance().ext2_ll(); 90 | // INFO(Ext2::GetInstance().current_path); 91 | // INFO("\n"); 92 | 93 | // Ext2::GetInstance().ext2_rmdir("test"); 94 | // INFO(Ext2::GetInstance().current_path); 95 | // INFO("\n"); 96 | 97 | // Ext2::GetInstance().ext2_ll(); 98 | // INFO(Ext2::GetInstance().current_path); 99 | // INFO("\n"); 100 | 101 | // Ext2::GetInstance().showDiskInfo(); 102 | 103 | // ********************************************************** 104 | } 105 | 106 | void test02() { 107 | Ext2::GetInstance().init(); 108 | } 109 | -------------------------------------------------------------------------------- /lab3/FileSystem/src/Ext2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | /* 9 | 10 | */ 11 | 12 | /* 13 | type: 14 | - r+: write and load 文件必须存在 15 | - w+: write and load 如果文件不存在则创建一个,如果存在则以覆盖方式写入 16 | 17 | filetype: 18 | - 0: unknown 19 | - 1: common file 20 | - 2: directory 21 | - 3: char device 22 | - 4: block device 23 | - 5: pipe 24 | - 6: socket 25 | - 7: symbol pointer 26 | 27 | filemode: 28 | - 高8位(high_i_mode)是目录项中文件类型码的一个拷贝 29 | - 低8位(low_i_mode)中的最低3位分别用来标识rwx3个属性 30 | - 高5位不用,用0填充 31 | */ 32 | 33 | #define DIR_R_MODE 0b0000001000000100 34 | #define DIR_W_MODE 0b0000001000000010 35 | #define DIR_RW_MODE 0b0000001000000110 36 | 37 | #define FILE_R_MODE 0b0000000100000100 38 | #define FILE_W_MODE 0b0000000100000010 39 | #define FILE_X_MODE 0b0000000100000001 40 | #define FILE_RW_MODE 0b0000000100000110 41 | #define FILE_RWX_MODE 0b0000000100000111 42 | 43 | #define IS_READABLE 0b0000000000000100 44 | #define IS_WRITEABLE 0b0000000000000010 45 | #define IS_EXEABLE 0b0000000000000001 46 | 47 | // *************************************************************************** 48 | // load and update 49 | 50 | // load/update of super_block 51 | void Ext2::updateSuperBlock() { 52 | fseek(fp, SUPER_BLOCK_START_ADDR, SEEK_SET); 53 | fwrite(super_block, SUPER_BLOCK_SIZE, 1, fp); // 1 ---> only 1 group 54 | fflush(fp); 55 | } 56 | 57 | void Ext2::loadSuperBlock() { 58 | fseek(fp, SUPER_BLOCK_START_ADDR, SEEK_SET); 59 | fread(super_block, SUPER_BLOCK_SIZE, 1, fp); 60 | } 61 | 62 | // load/update of group_desc 63 | void Ext2::updateGroupDesc() { 64 | fseek(fp, GROUP_DESC_START_ADDR, SEEK_SET); 65 | fwrite(group_desc_table, GROUP_DESC_SIZE, 1, fp); // 1 ---> only 1 group 66 | fflush(fp); 67 | } 68 | 69 | void Ext2::loadGroupDesc() { 70 | fseek(fp, GROUP_DESC_START_ADDR, SEEK_SET); 71 | fread(group_desc_table, GROUP_DESC_SIZE, 1, fp); 72 | } 73 | 74 | // load/update of block_bitmap 75 | void Ext2::updateBlockBitmap() { 76 | fseek(fp, BLOCK_BITMAP_START_ADDR, SEEK_SET); 77 | fwrite(block_bit_buf, BLOCK_SIZE, 1, fp); 78 | fflush(fp); 79 | } 80 | 81 | void Ext2::loadBlockBitmap() { 82 | fseek(fp, BLOCK_BITMAP_START_ADDR, SEEK_SET); 83 | fread(block_bit_buf, BLOCK_SIZE, 1, fp); 84 | } 85 | 86 | // load/update of inode_bitmap 87 | void Ext2::updateInodeBitmap() { 88 | fseek(fp, INODE_BITMAP_START_ADDR, SEEK_SET); 89 | fwrite(inode_bit_buf, BLOCK_SIZE, 1, fp); 90 | fflush(fp); 91 | } 92 | 93 | void Ext2::loadInodeBitmap() { 94 | fseek(fp, INODE_BITMAP_START_ADDR, SEEK_SET); 95 | fread(inode_bit_buf, BLOCK_SIZE, 1, fp); 96 | } 97 | 98 | // load/update of inode 99 | void Ext2::updateInode(size_t idx) { 100 | fseek(fp, INODE_TABLE_START_ADDR + idx * INODE_SIZE, SEEK_SET); 101 | fwrite(inode_buf, INODE_SIZE, 1, fp); 102 | fflush(fp); 103 | } 104 | 105 | void Ext2::loadInode(size_t idx) { 106 | fseek(fp, INODE_TABLE_START_ADDR + idx * INODE_SIZE, SEEK_SET); 107 | fread(inode_buf, INODE_SIZE, 1, fp); 108 | } 109 | 110 | // load/update of data_block 111 | void Ext2::updateDataBlock(size_t idx) { 112 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 113 | fwrite(data_buf, BLOCK_SIZE, 1, fp); 114 | fflush(fp); 115 | } 116 | 117 | void Ext2::loadDataBlock(size_t idx) { 118 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 119 | fread(data_buf, BLOCK_SIZE, 1, fp); 120 | } 121 | 122 | // load/update of dir_entry_block 123 | void Ext2::updateDirDataBlock(size_t idx) { 124 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 125 | fwrite(dir_buf, BLOCK_SIZE, 1, fp); 126 | fflush(fp); 127 | } 128 | 129 | void Ext2::loadDirDataBlock(size_t idx) { 130 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 131 | fread(dir_buf, BLOCK_SIZE, 1, fp); 132 | } 133 | 134 | // load/update of level1_index_block_buf 135 | void Ext2::updateIndexBlock_Level1(size_t idx) { 136 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 137 | fwrite(level1_index_block_buf, BLOCK_SIZE, 1, fp); 138 | fflush(fp); 139 | } 140 | 141 | void Ext2::loadIndexBlock_Level1(size_t idx) { 142 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 143 | fread(level1_index_block_buf, BLOCK_SIZE, 1, fp); 144 | } 145 | 146 | // load/update of level2_index_block_buf 147 | void Ext2::updateIndexBlock_Level2(size_t idx) { 148 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 149 | fwrite(level2_index_block_buf, BLOCK_SIZE, 1, fp); 150 | fflush(fp); 151 | } 152 | 153 | void Ext2::loadIndexBlock_Level2(size_t idx) { 154 | fseek(fp, DATA_BLOCK_START_ADDR + idx * BLOCK_SIZE, SEEK_SET); 155 | fread(level2_index_block_buf, BLOCK_SIZE, 1, fp); 156 | } 157 | 158 | // *************************************************************************** 159 | 160 | // *************************************************************************** 161 | // alloc and free 162 | 163 | size_t Ext2::allocDataBlock() { 164 | uint16_t idx = last_alloc_block; 165 | uint8_t mask = 0b10000000; 166 | int flag = 0; 167 | 168 | if (group_desc_table[0].bg_free_blocks_count == 0) { 169 | ERROR("No Free Block to be allocated!!!\n"); 170 | return static_cast(-1); 171 | } 172 | 173 | loadBlockBitmap(); 174 | 175 | idx /= 8; // 除以8得到块的idx 176 | 177 | // 找空闲块 178 | while (block_bit_buf[idx] == 0b11111111) 179 | idx = (idx + 1) % DIR_ENTRY_NUM_PER_BLOCK; 180 | 181 | // find a bit with the value 1 182 | while (block_bit_buf[idx] & mask) { 183 | mask >>= 1; 184 | ++flag; 185 | } 186 | 187 | block_bit_buf[idx] = block_bit_buf[idx] + mask; 188 | updateBlockBitmap(); 189 | 190 | last_alloc_block = idx * 8 + flag; 191 | 192 | group_desc_table[0].bg_free_blocks_count--; 193 | updateGroupDesc(); 194 | 195 | return last_alloc_block; 196 | } 197 | 198 | void Ext2::freeDataBlock(size_t idx) { 199 | uint16_t bit_idx; 200 | bit_idx = idx / 8; // 除以8得到块idx 201 | loadBlockBitmap(); 202 | 203 | // bitset 的 index 是从最低位到最高位 204 | std::bitset<8> target = block_bit_buf[bit_idx]; 205 | target.flip(7 - idx % 8); 206 | block_bit_buf[bit_idx] = target.to_ulong(); 207 | 208 | updateBlockBitmap(); 209 | 210 | group_desc_table[0].bg_free_blocks_count++; 211 | updateGroupDesc(); 212 | } 213 | 214 | size_t Ext2::allocInode() { 215 | uint16_t idx = last_alloc_inode; 216 | uint8_t mask = 0b10000000; 217 | int flag = 0; 218 | 219 | if (group_desc_table[0].bg_free_inodes_count == 0) { 220 | ERROR("No Free Inode to be allocated!!!\n"); 221 | return static_cast(-1); 222 | } 223 | 224 | loadInodeBitmap(); 225 | 226 | idx /= 8; // 除以8得到块idx 227 | 228 | while (inode_bit_buf[idx] == 0b11111111) //先看该字节的8个位是否已经填满 229 | idx = (idx + 1) % DIR_ENTRY_NUM_PER_BLOCK; 230 | 231 | // find a bit with the value 1 232 | while (inode_bit_buf[idx] & mask) { 233 | mask >>= 1; 234 | ++flag; 235 | } 236 | 237 | inode_bit_buf[idx] = inode_bit_buf[idx] + mask; 238 | updateInodeBitmap(); 239 | 240 | last_alloc_inode = idx * 8 + flag; 241 | 242 | group_desc_table[0].bg_free_inodes_count--; 243 | updateGroupDesc(); 244 | 245 | return last_alloc_inode; 246 | } 247 | 248 | void Ext2::freeInode(size_t idx) { 249 | uint16_t bit_idx; 250 | bit_idx = idx / 8; 251 | loadInodeBitmap(); 252 | 253 | std::bitset<8> target = inode_bit_buf[bit_idx]; 254 | target.flip(7 - idx % 8); 255 | inode_bit_buf[bit_idx] = target.to_ulong(); 256 | 257 | updateInodeBitmap(); 258 | 259 | group_desc_table[0].bg_free_inodes_count++; 260 | updateGroupDesc(); 261 | } 262 | 263 | // *************************************************************************** 264 | 265 | // *************************************************************************** 266 | // init 267 | 268 | void Ext2::init() { 269 | memset(&file_open_table, 0, sizeof(file_open_table)); 270 | strcpy(current_path, "[yichenwu11@path: /"); 271 | loadSuperBlock(); 272 | if (strcmp(super_block[0].sb_volume_name, VOLUME_NAME)) { 273 | init_fs(); 274 | } 275 | } 276 | 277 | void Ext2::init_fs() { 278 | INFO("Init the File System now...\n"); 279 | // clear 280 | memset(&super_block, 0, sizeof(super_block)); 281 | memset(&group_desc_table, 0, sizeof(group_desc_table)); 282 | memset(&inode_buf, 0, sizeof(inode_buf)); 283 | memset(&block_bit_buf, 0, sizeof(block_bit_buf)); 284 | memset(&inode_bit_buf, 0, sizeof(inode_bit_buf)); 285 | memset(&dir_buf, 0, sizeof(dir_buf)); 286 | memset(&data_buf, 0, sizeof(data_buf)); 287 | memset(&file_open_table, 0, sizeof(file_open_table)); 288 | 289 | // clear the whole disk 290 | for (int i = 0; i < TOTAL_BLOCK_NUM; ++i) 291 | fwrite(data_buf, BLOCK_SIZE, 1, fp); 292 | 293 | loadSuperBlock(); 294 | loadGroupDesc(); 295 | 296 | strcpy(&(super_block[0].sb_volume_name[0]), VOLUME_NAME); 297 | super_block[0].sb_disk_size = BLOCK_SIZE * TOTAL_BLOCK_NUM; 298 | super_block[0].sb_size_per_block = BLOCK_SIZE; 299 | super_block[0].sb_blocks_per_group = TOTAL_BLOCK_NUM; 300 | updateSuperBlock(); 301 | 302 | strcpy(&(group_desc_table[0].bg_volume_name[0]), VOLUME_NAME); 303 | group_desc_table[0].bg_block_bitmap = BLOCK_BITMAP_START_ADDR; 304 | group_desc_table[0].bg_inode_bitmap = INODE_BITMAP_START_ADDR; 305 | group_desc_table[0].bg_inode_table = INODE_TABLE_START_ADDR; 306 | group_desc_table[0].bg_free_blocks_count = DATA_BLOCK_NUM; 307 | group_desc_table[0].bg_free_inodes_count = INODE_NUM; 308 | group_desc_table[0].bg_used_dirs_count = 0; 309 | updateGroupDesc(); 310 | 311 | loadInode(0); // 0号 inode给根目录 312 | 313 | inode_buf[0].i_mode = DIR_RW_MODE; // rw 314 | inode_buf[0].i_blocks = 0; 315 | inode_buf[0].i_size = DIR_ENTRY_SIZE * 2; // . and .. 316 | inode_buf[0].i_atime = 0; 317 | inode_buf[0].i_ctime = 0; 318 | inode_buf[0].i_mtime = 0; 319 | inode_buf[0].i_dtime = 0; 320 | inode_buf[0].i_block[0] = allocDataBlock(); // index 0 321 | inode_buf[0].i_blocks++; 322 | 323 | current_dir = allocInode(); 324 | updateInode(current_dir); 325 | 326 | // init dir 327 | loadDirDataBlock(0); // 0号 dataBlock 给根目录 328 | 329 | dir_buf[0].inode = current_dir; // 根目录的 . 和 .. 都是根目录 330 | dir_buf[0].name_len = 1; 331 | dir_buf[0].file_type = 2; // directory 332 | strcpy(dir_buf[0].name, "."); 333 | 334 | dir_buf[1].inode = current_dir; 335 | dir_buf[1].name_len = 1; 336 | dir_buf[1].file_type = 2; // directory 337 | strcpy(dir_buf[1].name, ".."); 338 | updateDirDataBlock(inode_buf[0].i_block[0]); // 根目录 339 | 340 | INFO("Init Done!!!\n"); 341 | INFO("-------------------------------------\n"); 342 | } 343 | 344 | // *************************************************************************** 345 | 346 | // *************************************************************************** 347 | // search 348 | 349 | void Ext2::inputTargetProcess(std::string) { 350 | } 351 | 352 | // search file in current dir 353 | uint16_t Ext2::searchFile(char const tar[9], char file_type, 354 | uint16_t& inode_idx, uint16_t& block_idx, 355 | uint16_t& dir_idx) { 356 | loadInode(current_dir); 357 | 358 | for (uint16_t b_idx = 0; b_idx < inode_buf[0].i_blocks; ++b_idx) { 359 | loadDirDataBlock(inode_buf[0].i_block[b_idx]); 360 | for (uint16_t d_idx = 0; d_idx < DIR_ENTRY_NUM_PER_BLOCK; ++d_idx) { 361 | if (dir_buf[d_idx].file_type != file_type || strcmp(dir_buf[d_idx].name, tar)) 362 | continue; 363 | inode_idx = dir_buf[d_idx].inode; 364 | block_idx = b_idx; 365 | dir_idx = d_idx; 366 | return 1; 367 | } 368 | } 369 | 370 | return 0; 371 | } 372 | 373 | // search file in file_open_table 374 | uint16_t Ext2::searchInTable(uint16_t inode) { 375 | uint16_t f_idx = 0; 376 | while (f_idx < FOPEN_TABLE_MAX && file_open_table[f_idx++] != inode) 377 | ; 378 | return (f_idx == FOPEN_TABLE_MAX) ? 0 : 1; 379 | } 380 | 381 | // *************************************************************************** 382 | 383 | // *************************************************************************** 384 | // ext2_operations 385 | 386 | void Ext2::ext2_cd(char const tar[9]) { 387 | std::string target(tar); 388 | std::string space_delimiter = "/"; 389 | std::vector inputs{}; 390 | 391 | size_t pos = 0; 392 | while ((pos = target.find(space_delimiter)) != std::string::npos) { 393 | inputs.push_back(target.substr(0, pos)); 394 | target.erase(0, pos + space_delimiter.length()); 395 | } 396 | inputs.push_back(target.substr(0, pos)); 397 | 398 | for (auto& ele : inputs) 399 | ext2_cd_impl(ele.data()); 400 | } 401 | 402 | void Ext2::ext2_cd_impl(char const tar[9]) { 403 | uint16_t inode_idx, block_idx, dir_idx, is_find; 404 | 405 | is_find = searchFile(tar, 2, inode_idx, block_idx, dir_idx); 406 | 407 | if (is_find) { 408 | current_dir = inode_idx; 409 | // case 1 : 410 | if (!strcmp(tar, "..") && dir_buf[dir_idx - 1].name_len && dir_buf[dir_idx - 1].inode) { 411 | current_path[strlen(current_path) - dir_buf[dir_idx - 1].name_len - 1] = 412 | '\0'; 413 | current_dirlen = dir_buf[dir_idx].name_len; 414 | } 415 | // case 2 : . 416 | else if (!strcmp(tar, ".")) { 417 | return; 418 | } 419 | // case 3 : xxx 420 | else if (strcmp(tar, "..")) { 421 | current_dirlen = strlen(tar); 422 | strcat(current_path, tar); 423 | strcat(current_path, "/"); 424 | } 425 | } 426 | else { 427 | WARN("directory not exsit!!!\n"); 428 | } 429 | } 430 | 431 | void Ext2::preProcess(uint16_t tar_node, uint16_t len, FileType type, 432 | std::string file_name) { 433 | loadInode(tar_node); 434 | 435 | if (type == FileType::DIR) { 436 | // dir 437 | inode_buf[0].i_size = DIR_ENTRY_SIZE * 2; 438 | inode_buf[0].i_blocks = 1; 439 | inode_buf[0].i_block[0] = allocDataBlock(); 440 | 441 | loadDirDataBlock(inode_buf[0].i_block[0]); 442 | 443 | dir_buf[0].inode = tar_node; 444 | dir_buf[0].name_len = len; 445 | dir_buf[1].inode = current_dir; 446 | dir_buf[1].name_len = current_dirlen; 447 | dir_buf[0].file_type = dir_buf[1].file_type = 2; 448 | 449 | for (int i = 2; i < DIR_ENTRY_NUM_PER_BLOCK; ++i) 450 | dir_buf[i].inode = 0; 451 | 452 | strcpy(dir_buf[0].name, "."); 453 | strcpy(dir_buf[1].name, ".."); 454 | 455 | updateDirDataBlock(inode_buf[0].i_block[0]); 456 | 457 | // 目录的权限默认为 可读可写 458 | inode_buf[0].i_mode = DIR_RW_MODE; 459 | } 460 | else { 461 | // file 462 | inode_buf[0].i_size = 0; 463 | inode_buf[0].i_blocks = 0; 464 | inode_buf[0].i_size = 0; 465 | inode_buf[0].i_atime = 0; 466 | inode_buf[0].i_ctime = 0; 467 | inode_buf[0].i_mtime = 0; 468 | inode_buf[0].i_dtime = 0; 469 | // 根据文件后缀设置 mode 470 | size_t pos = 0; 471 | pos = file_name.find("."); 472 | if (pos == std::string::npos) { 473 | inode_buf[0].i_mode = FILE_X_MODE; 474 | } 475 | else { 476 | file_name.erase(0, pos + 1); 477 | if (file_name == "txt" || file_name == "md") 478 | inode_buf[0].i_mode = FILE_RW_MODE; 479 | else if (file_name == "exe") 480 | inode_buf[0].i_mode = FILE_X_MODE; 481 | else 482 | inode_buf[0].i_mode = FILE_R_MODE; 483 | } 484 | } 485 | 486 | updateInode(tar_node); 487 | } 488 | 489 | void Ext2::ext2_mkdir(char const tar[9]) { 490 | uint16_t tar_node, idx1, idx2, idx3, flag; 491 | 492 | loadInode(current_dir); 493 | if (!searchFile(tar, 2, idx1, idx2, idx3)) { 494 | if (inode_buf[0].i_size == 4096) { 495 | WARN("Current Directory Buffer has been full!!!\n"); 496 | return; 497 | } 498 | flag = 1; 499 | if (inode_buf[0].i_size != inode_buf[0].i_blocks * BLOCK_SIZE) { 500 | idx1 = 0; 501 | while (flag && idx1 < inode_buf[0].i_blocks) { 502 | loadDirDataBlock(inode_buf[0].i_block[idx1]); 503 | // 从 2 开始是因为根目录下 . 和 .. 的根目录 inode 为 0 504 | idx2 = 2; 505 | while (idx2 < DIR_ENTRY_NUM_PER_BLOCK) { 506 | if (dir_buf[idx2].inode == 0) { 507 | flag = 0; 508 | break; 509 | } 510 | ++idx2; 511 | } 512 | ++idx1; 513 | } 514 | 515 | tar_node = dir_buf[idx2].inode = allocInode(); 516 | 517 | dir_buf[idx2].name_len = strlen(tar); 518 | dir_buf[idx2].file_type = static_cast(FileType::DIR); 519 | strcpy(dir_buf[idx2].name, tar); 520 | 521 | // 因为 idx1 多加了一次,所以在这里要减去 1 522 | updateDirDataBlock(inode_buf[0].i_block[idx1 - 1]); 523 | } 524 | else { 525 | // 需要分配新的数据块来存储目录项 526 | inode_buf[0].i_block[inode_buf[0].i_blocks] = allocDataBlock(); 527 | inode_buf[0].i_blocks++; 528 | loadDirDataBlock(inode_buf[0].i_block[inode_buf[0].i_blocks - 1]); 529 | 530 | tar_node = dir_buf[0].inode = allocInode(); 531 | dir_buf[0].name_len = strlen(tar); 532 | dir_buf[0].file_type = static_cast(FileType::DIR); 533 | strcpy(dir_buf[0].name, tar); 534 | 535 | for (int i = 1; i < DIR_ENTRY_NUM_PER_BLOCK; ++i) { 536 | dir_buf[i].inode = 0; 537 | } 538 | updateDirDataBlock(inode_buf[0].i_block[inode_buf[0].i_blocks - 1]); 539 | } 540 | 541 | inode_buf[0].i_size += DIR_ENTRY_SIZE; // the size of the new dir_entry 542 | 543 | updateInode(current_dir); 544 | 545 | preProcess(tar_node, strlen(tar), FileType::DIR); 546 | INFO("Dir Create Success!!!\n"); 547 | } 548 | else { 549 | WARN("Directory has alloady existed!\n"); 550 | } 551 | } 552 | 553 | // remove directory 554 | void Ext2::ext2_rmdir(char const tar[9]) { 555 | uint16_t tar_node, inode_idx, block_idx, dir_idx; 556 | 557 | if (!strcmp(tar, "..") || !strcmp(tar, ".")) { 558 | WARN(". and .. can not be deleted!\n"); 559 | return; 560 | } 561 | 562 | loadInode(current_dir); 563 | 564 | if (searchFile(tar, 2, inode_idx, block_idx, dir_idx)) { 565 | loadInode(inode_idx); 566 | // 如果该目录下只有 . 和 .. 567 | if (inode_buf[0].i_size == DIR_ENTRY_SIZE * 2) { 568 | inode_buf[0].i_size = 0; 569 | inode_buf[0].i_blocks = 0; 570 | 571 | freeDataBlock(inode_buf[0].i_block[0]); 572 | loadInode(current_dir); 573 | loadDirDataBlock(inode_buf[0].i_block[block_idx]); 574 | freeInode(dir_buf[dir_idx].inode); 575 | dir_buf[dir_idx].inode = 0; 576 | dir_buf[dir_idx].file_type = 0; 577 | dir_buf[dir_idx].name_len = 0; 578 | memset(&(dir_buf[dir_idx].name), 0, sizeof(dir_buf[dir_idx].name)); 579 | updateDirDataBlock(inode_buf[0].i_block[block_idx]); 580 | inode_buf[0].i_size -= DIR_ENTRY_SIZE; // free a dir_entry 581 | 582 | for (int m = 0; m < inode_buf[0].i_blocks; ++m) { 583 | loadDirDataBlock(inode_buf[0].i_block[m]); 584 | int empty_num = 0; 585 | for (int n = 0; n < DIR_ENTRY_NUM_PER_BLOCK; ++n) 586 | if (!dir_buf[n].inode && !dir_buf[n].name_len) 587 | ++empty_num; 588 | 589 | if (empty_num == DIR_ENTRY_NUM_PER_BLOCK) { 590 | freeDataBlock(inode_buf[0].i_block[m]); 591 | inode_buf[0].i_blocks--; 592 | for (int k = m; k < inode_buf[0].i_blocks - 1; ++k) { 593 | inode_buf[0].i_block[k] = inode_buf[0].i_block[k + 1]; 594 | } 595 | } 596 | } 597 | 598 | updateInode(current_dir); 599 | INFO("Remove Dir Success!!!\n"); 600 | return; 601 | } 602 | else { 603 | int tmp = current_dir; 604 | int i; 605 | i = (current_dir == 0) ? 2 : 0; 606 | for (; i < inode_buf[0].i_blocks; ++i) { 607 | loadDirDataBlock(inode_buf[0].i_block[i]); 608 | for (int m = 0; m < DIR_ENTRY_NUM_PER_BLOCK; ++m) { 609 | if (!strcmp(dir_buf[m].name, ".") || !strcmp(dir_buf[m].name, "..") || dir_buf[m].inode == 0) 610 | continue; 611 | if (dir_buf[m].file_type == 2) { 612 | strcpy(current_path, tar); 613 | current_dir = inode_idx; 614 | ext2_rmdir(dir_buf[m].name); 615 | } 616 | else if (dir_buf[m].file_type == 1) { 617 | current_dir = inode_idx; 618 | ext2_rm(dir_buf[m].name); 619 | } 620 | } 621 | if (inode_buf[0].i_size == DIR_ENTRY_SIZE * 2) { 622 | current_dir = tmp; 623 | ext2_rmdir(tar); 624 | } 625 | } 626 | current_dir = tmp; 627 | INFO("Remove Dir Success!!!\n"); 628 | return; 629 | } 630 | } 631 | else { 632 | WARN("Directory does not exsit!!!\n"); 633 | } 634 | } 635 | 636 | // 创建文件 637 | void Ext2::ext2_touch(char const tar[9], FileType type) { 638 | uint16_t inode_idx, block_idx, dir_idx; 639 | uint16_t tar_node; 640 | loadInode(current_dir); 641 | if (!searchFile(tar, static_cast(type), inode_idx, block_idx, 642 | dir_idx)) { 643 | if (inode_buf->i_size == 4096) { 644 | WARN("Current Directory has no free block to allocated!!!\n"); 645 | } 646 | int flag = 1; 647 | if (inode_buf[0].i_size != inode_buf[0].i_blocks * BLOCK_SIZE) { 648 | int i = 0; 649 | int j = 0; 650 | while (flag && i < inode_buf[0].i_blocks) { 651 | loadDirDataBlock(inode_buf[0].i_block[i]); 652 | j = 2; 653 | while (j < DIR_ENTRY_NUM_PER_BLOCK) { 654 | if (dir_buf[j].inode == 0) { 655 | flag = 0; 656 | break; 657 | } 658 | ++j; 659 | } 660 | ++i; 661 | } 662 | tar_node = dir_buf[j].inode = allocInode(); 663 | dir_buf[j].name_len = strlen(tar); 664 | dir_buf[j].file_type = static_cast(type); 665 | strcpy(dir_buf[j].name, tar); 666 | updateDirDataBlock(inode_buf[0].i_block[i - 1]); 667 | } 668 | else { 669 | inode_buf[0].i_block[inode_buf[0].i_blocks] = allocDataBlock(); 670 | inode_buf[0].i_blocks++; 671 | loadDirDataBlock(inode_buf[0].i_block[inode_buf[0].i_blocks - 1]); 672 | 673 | tar_node = dir_buf[0].inode = allocInode(); 674 | 675 | dir_buf[0].name_len = strlen(tar); 676 | dir_buf[0].file_type = static_cast(type); 677 | strcpy(dir_buf[0].name, tar); 678 | 679 | for (int i = 1; i < DIR_ENTRY_NUM_PER_BLOCK; ++i) 680 | dir_buf[flag].inode = 0; 681 | 682 | updateDirDataBlock(inode_buf[0].i_block[inode_buf[0].i_blocks - 1]); 683 | } 684 | inode_buf[0].i_size += DIR_ENTRY_SIZE; // a new dir_entry 685 | updateInode(current_dir); 686 | 687 | preProcess(tar_node, strlen(tar), type, tar); 688 | 689 | INFO("File Touch Success!!!\n"); 690 | } 691 | else { 692 | WARN("The file has already existed!!!\n"); 693 | } 694 | } 695 | 696 | // 删除文件 697 | // type: 默认为 1 698 | void Ext2::ext2_rm(char const tar[9], FileType type) { 699 | uint16_t inode_idx, block_idx, dir_idx; 700 | if (searchFile(tar, static_cast(type), inode_idx, block_idx, 701 | dir_idx)) { 702 | loadInode(inode_idx); 703 | 704 | if (searchInTable(inode_idx)) 705 | ext2_close(tar, type); 706 | 707 | for (int i = 0; i < inode_buf[0].i_blocks; ++i) 708 | freeDataBlock(inode_buf[0].i_block[i]); 709 | 710 | memset(&(inode_buf[0]), 0, sizeof(inode_buf[0])); 711 | freeInode(inode_idx); 712 | 713 | loadInode(current_dir); 714 | loadDirDataBlock(inode_buf[0].i_block[block_idx]); 715 | 716 | memset(&(dir_buf[dir_idx]), 0, sizeof(dir_buf[dir_idx])); 717 | updateDirDataBlock(inode_buf[0].i_block[block_idx]); 718 | 719 | inode_buf[0].i_size -= DIR_ENTRY_SIZE; 720 | 721 | for (int i = 1; i < inode_buf[0].i_blocks; ++i) { 722 | bool is_empty = false; 723 | int e_idx = 0; 724 | loadDirDataBlock(inode_buf[0].i_block[i]); 725 | for (int j = 0; j < DIR_ENTRY_NUM_PER_BLOCK; ++j) { 726 | if (dir_buf[j].inode) 727 | break; 728 | if (j == DIR_ENTRY_NUM_PER_BLOCK - 1) 729 | is_empty = true; 730 | } 731 | 732 | if (is_empty) { 733 | freeDataBlock(inode_buf[0].i_block[i]); 734 | for (int k = i; k < inode_buf[0].i_blocks - 1; ++k) { 735 | inode_buf[0].i_block[k] = inode_buf[0].i_block[k + 1]; 736 | } 737 | } 738 | } 739 | updateInode(current_dir); 740 | INFO("Remove File Success!!!\n"); 741 | } 742 | else { 743 | WARN("This file does not exsit!!!\n"); 744 | } 745 | } 746 | 747 | void Ext2::ext2_open(char const tar[9], FileType type) { 748 | uint16_t inode_idx, block_idx, dir_idx; 749 | 750 | if (searchFile(tar, static_cast(type), inode_idx, block_idx, 751 | dir_idx)) { 752 | if (searchInTable(inode_idx)) 753 | INFO("This file has been open!!!\n"); 754 | else { 755 | for (int i = 0; i < FOPEN_TABLE_MAX; ++i) { 756 | if (file_open_table[i] == 0) { 757 | file_open_table[i] = inode_idx; 758 | file_open_name_set.emplace(dir_buf[dir_idx].name); 759 | INFO("File Open Success!!!\n"); 760 | return; 761 | } 762 | } 763 | WARN("file_open_table has been full!!!\n"); 764 | } 765 | } 766 | else { 767 | WARN("This file does not exsit!!!\n"); 768 | } 769 | } 770 | 771 | void Ext2::ext2_close(char const tar[9], FileType type) { 772 | uint16_t inode_idx, block_idx, dir_idx; 773 | if (searchFile(tar, static_cast(type), inode_idx, block_idx, 774 | dir_idx)) { 775 | if (searchInTable(inode_idx)) 776 | for (int i = 0; i < FOPEN_TABLE_MAX; ++i) { 777 | if (file_open_table[i] == inode_idx) { 778 | file_open_table[i] = 0; 779 | file_open_name_set.erase( 780 | file_open_name_set.find(dir_buf[dir_idx].name)); 781 | INFO("File Close Success!!!\n"); 782 | return; 783 | } 784 | } 785 | else { 786 | WARN("File has not been open!!!\n"); 787 | } 788 | } 789 | else { 790 | WARN("This file does not exsit!!!\n"); 791 | } 792 | } 793 | 794 | void Ext2::ext2_read(char const tar[9]) { 795 | uint16_t node_idx, block_idx, dir_idx; 796 | if (!searchFile(tar, 1, node_idx, block_idx, dir_idx)) { 797 | WARN("This file doesn't exsit in curr directory!!!\n"); 798 | return; 799 | } 800 | if (!searchInTable(node_idx)) { 801 | WARN("This file has not been open, open first before read/write!!!\n"); 802 | return; 803 | } 804 | 805 | loadInode(node_idx); 806 | 807 | if (inode_buf[0].i_mode & IS_READABLE) { 808 | if (inode_buf[0].i_blocks == 0) { 809 | WARN("This file is empty!!!\n"); 810 | return; 811 | } 812 | 813 | bool is_level1_use = inode_buf[0].i_blocks >= 7; 814 | bool is_level2_use = inode_buf[0].i_blocks >= 8; 815 | 816 | if (is_level1_use) { 817 | // 0 ----- 5 (6 个直接索引的数据块) 818 | for (int i = 0; i < 6; ++i) { 819 | loadDataBlock(inode_buf[0].i_block[i]); 820 | for (int j = 0; j < BLOCK_SIZE; ++j) { 821 | if (data_buf[j] == '\0') 822 | break; 823 | printf("%c", data_buf[j]); 824 | } 825 | } 826 | // 6 ----> 一级间接索引的数据块 827 | loadIndexBlock_Level1(inode_buf[0].i_block[6]); 828 | for (int i = 0; i < 256; ++i) { 829 | loadDataBlock(level1_index_block_buf[i]); 830 | for (int j = 0; j < BLOCK_SIZE; ++j) { 831 | if (data_buf[j] == '\0') 832 | break; 833 | printf("%c", data_buf[j]); 834 | } 835 | } 836 | 837 | // 如果存在二级间接索引 838 | if (is_level2_use) { 839 | // 7 ----> 二级间接索引的数据块 840 | loadIndexBlock_Level2(inode_buf[0].i_block[7]); 841 | for (int i = 0; i < 256; ++i) { 842 | loadIndexBlock_Level1(level2_index_block_buf[i]); 843 | for (int j = 0; j < 256; ++j) { 844 | loadDataBlock(level1_index_block_buf[j]); 845 | for (int k = 0; k < BLOCK_SIZE; ++k) { 846 | if (data_buf[k] == '\0') 847 | break; 848 | printf("%c", data_buf[k]); 849 | } 850 | } 851 | } 852 | } 853 | else { 854 | printf("\n"); 855 | } 856 | } 857 | else { 858 | for (int i = 0; i < inode_buf[0].i_blocks; ++i) { 859 | loadDataBlock(inode_buf[0].i_block[i]); 860 | for (int j = 0; j < BLOCK_SIZE; ++j) { 861 | if (data_buf[j] == '\0') 862 | break; 863 | printf("%c", data_buf[j]); 864 | } 865 | } 866 | printf("\n"); 867 | } 868 | } 869 | else { 870 | WARN("Read this file is not allowed!!!\n"); 871 | } 872 | } 873 | 874 | // 覆盖写入 875 | void Ext2::ext2_write(char const tar[9]) { 876 | uint16_t node_idx, block_idx, dir_idx; 877 | if (!searchFile(tar, 1, node_idx, block_idx, dir_idx)) { 878 | WARN("This file doesn't exsit in curr directory!!!\n"); 879 | return; 880 | } 881 | if (!searchInTable(node_idx)) { 882 | WARN("This file has not been open, open first before read/write!!!\n"); 883 | return; 884 | } 885 | 886 | loadInode(node_idx); 887 | 888 | if (inode_buf[0].i_mode & IS_READABLE) { 889 | // input 890 | size_t tmp_idx = 0; 891 | std::string tmp; 892 | 893 | INFO("Input `$$` to end: \n\n"); 894 | 895 | char is_end[2]; 896 | 897 | while (1) { 898 | tmp.push_back(getchar()); 899 | is_end[tmp_idx % 2] = tmp[tmp_idx]; 900 | // 暂定为读到 `$$` 结束 901 | if (is_end[0] == '$' && is_end[1] == '$') { 902 | tmp.pop_back(); 903 | tmp.pop_back(); 904 | tmp.push_back('\0'); 905 | break; 906 | } 907 | if (tmp_idx >= MAX_FILE_CAPACITY - 1) { 908 | WARN("The Max file capacity is 4096!!!\n"); 909 | break; 910 | } 911 | ++tmp_idx; 912 | } 913 | 914 | std::cin.get(); 915 | 916 | int need_block_num = (tmp.length() % BLOCK_SIZE) ? (tmp.length() / BLOCK_SIZE + 1) : (tmp.length() / BLOCK_SIZE); 917 | 918 | // free first 919 | bool is_level1_use = inode_buf[0].i_blocks >= 7; 920 | bool is_level2_use = inode_buf[0].i_blocks >= 8; 921 | 922 | if (is_level1_use) { 923 | // free direct 924 | for (int i = 0; i < 6; ++i) 925 | freeDataBlock(inode_buf[0].i_block[i]); 926 | loadIndexBlock_Level1(inode_buf[0].i_block[6]); 927 | for (int i = 0; i < 256; ++i) 928 | freeDataBlock(level1_index_block_buf[i]); 929 | 930 | if (is_level2_use) { 931 | loadIndexBlock_Level2(inode_buf[0].i_block[7]); 932 | for (int i = 0; i < 256; ++i) { 933 | loadIndexBlock_Level1(level2_index_block_buf[i]); 934 | for (int j = 0; j < 256; ++j) 935 | freeDataBlock(level1_index_block_buf[j]); 936 | } 937 | } 938 | } 939 | else { 940 | for (int i = 0; i < inode_buf[0].i_blocks; ++i) 941 | freeDataBlock(inode_buf[0].i_block[i]); 942 | } 943 | 944 | inode_buf[0].i_blocks = need_block_num; 945 | 946 | bool is_level1_need = need_block_num >= (6 + 1); 947 | bool is_level2_need = need_block_num >= (38 + 1); 948 | 949 | if (is_level1_need) { 950 | memset(&level1_index_block_buf, 0, sizeof(level1_index_block_buf)); 951 | // alloc 952 | for (int i = 0; i < 7; ++i) 953 | inode_buf[0].i_block[i] = allocDataBlock(); 954 | need_block_num -= 6; 955 | int to_alloc_num = (is_level2_need) ? 256 : need_block_num; 956 | for (int i = 0; i < to_alloc_num; ++i) { 957 | level1_index_block_buf[i] = allocDataBlock(); 958 | } 959 | updateIndexBlock_Level1(inode_buf[0].i_block[6]); 960 | need_block_num -= to_alloc_num; 961 | 962 | if (is_level2_need) { 963 | memset(&level2_index_block_buf, 0, sizeof(level2_index_block_buf)); 964 | 965 | // alloc 966 | inode_buf[0].i_block[7] = allocDataBlock(); 967 | 968 | int to_alloc_level2_num = need_block_num / 256 + 1; 969 | 970 | for (int i = 0; i < to_alloc_level2_num; ++i) { 971 | level2_index_block_buf[i] = allocDataBlock(); 972 | int to_alloc_blk_num = (need_block_num <= 256) ? need_block_num : 256; 973 | loadIndexBlock_Level1(level2_index_block_buf[i]); 974 | for (int j = 0; j <= need_block_num; ++j) { 975 | level1_index_block_buf[j] = allocDataBlock(); 976 | need_block_num--; 977 | } 978 | updateIndexBlock_Level1(level2_index_block_buf[i]); 979 | } 980 | updateIndexBlock_Level2(inode_buf[0].i_block[7]); 981 | 982 | // write (需要一级间接和二级间接索引) 983 | 984 | // 直接和一级间接部分 985 | int glo_idx = 0; 986 | for (int i = 0; i < 6; ++i) { 987 | loadDataBlock(inode_buf[0].i_block[i]); 988 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, BLOCK_SIZE); 989 | updateDataBlock(inode_buf[0].i_block[i]); 990 | ++glo_idx; 991 | } 992 | loadIndexBlock_Level1(inode_buf[0].i_block[6]); 993 | for (int i = 0; i < 256; ++i) { 994 | loadDataBlock(level1_index_block_buf[i]); 995 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, BLOCK_SIZE); 996 | updateDataBlock(level1_index_block_buf[i]); 997 | ++glo_idx; 998 | } 999 | updateIndexBlock_Level1(inode_buf[0].i_block[6]); 1000 | 1001 | // 二级间接部分 1002 | loadIndexBlock_Level2(inode_buf[0].i_block[7]); 1003 | for (int i = 0; i < 256; ++i) { 1004 | if (!level2_index_block_buf[i]) { 1005 | loadIndexBlock_Level1(level2_index_block_buf[i]); 1006 | for (int j = 0; j < 256; ++j) { 1007 | if (!level1_index_block_buf[i]) { 1008 | if (j == 255 || !level1_index_block_buf[j + 1]) 1009 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, 1010 | tmp.length() - i * BLOCK_SIZE); 1011 | else 1012 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, 1013 | BLOCK_SIZE); 1014 | glo_idx++; 1015 | } 1016 | } 1017 | updateIndexBlock_Level1(level2_index_block_buf[i]); 1018 | } 1019 | } 1020 | updateIndexBlock_Level2(inode_buf[0].i_block[7]); 1021 | } 1022 | else { 1023 | // write (需要一级间接索引) 1024 | int glo_idx = 0; 1025 | for (int i = 0; i < 6; ++i) { 1026 | loadDataBlock(inode_buf[0].i_block[i]); 1027 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, BLOCK_SIZE); 1028 | updateDataBlock(inode_buf[0].i_block[i]); 1029 | ++glo_idx; 1030 | } 1031 | loadIndexBlock_Level1(inode_buf[0].i_block[6]); 1032 | for (int i = 0; i < 256; ++i) { 1033 | if (!level1_index_block_buf[i]) { 1034 | loadDataBlock(level1_index_block_buf[i]); 1035 | if (i == 255 || !level1_index_block_buf[i + 1]) { 1036 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, 1037 | tmp.length() - i * BLOCK_SIZE); 1038 | } 1039 | else { 1040 | memcpy(data_buf, tmp.data() + glo_idx * BLOCK_SIZE, BLOCK_SIZE); 1041 | } 1042 | updateDataBlock(level1_index_block_buf[i]); 1043 | ++glo_idx; 1044 | } 1045 | } 1046 | updateIndexBlock_Level1(inode_buf[0].i_block[6]); 1047 | } 1048 | } 1049 | else { 1050 | // alloc 1051 | inode_buf[0].i_blocks = need_block_num; 1052 | for (int i = 0; i < need_block_num; ++i) 1053 | inode_buf[0].i_block[i] = allocDataBlock(); 1054 | // write (不需要间接索引) 1055 | for (int i = 0; i < inode_buf[0].i_blocks; ++i) { 1056 | loadDataBlock(inode_buf[0].i_block[i]); 1057 | if (i == inode_buf[0].i_blocks - 1) 1058 | memcpy(data_buf, tmp.data() + i * BLOCK_SIZE, 1059 | tmp.length() - i * BLOCK_SIZE); 1060 | else 1061 | memcpy(data_buf, tmp.data() + i * BLOCK_SIZE, BLOCK_SIZE); 1062 | updateDataBlock(inode_buf[0].i_block[i]); 1063 | } 1064 | } 1065 | 1066 | updateInode(node_idx); 1067 | } 1068 | else { 1069 | WARN("Write to this file is not allowed!!!\n"); 1070 | } 1071 | } 1072 | 1073 | // TODO: 追加文件内容而不是重写 1074 | void Ext2::ext2_append(char const tar[9]) { 1075 | } 1076 | 1077 | std::string Ext2::type2Str(FileType type) { 1078 | switch (type) { 1079 | case FileType::UNKNOWN: 1080 | return ""; 1081 | case FileType::FILE: 1082 | return ""; 1083 | case FileType::DIR: 1084 | return ""; 1085 | default: 1086 | return "<>"; 1087 | } 1088 | } 1089 | 1090 | std::string Ext2::mode2Str(uint16_t mode) { 1091 | std::string res; 1092 | if (mode & IS_READABLE) 1093 | res.push_back('r'); 1094 | else 1095 | res.push_back('_'); 1096 | if (mode & IS_WRITEABLE) 1097 | res.push_back('w'); 1098 | else 1099 | res.push_back('_'); 1100 | if (mode & IS_EXEABLE) 1101 | res.push_back('x'); 1102 | else 1103 | res.push_back('_'); 1104 | return res; 1105 | } 1106 | 1107 | int Ext2::calcDirSize(uint16_t inode) { 1108 | int res = 0; 1109 | loadInode(inode); 1110 | int blocks = inode_buf[0].i_blocks; 1111 | 1112 | res += inode_buf[0].i_blocks * BLOCK_SIZE; 1113 | 1114 | for (int idx = 0; idx < blocks; ++idx) { 1115 | loadDirDataBlock(inode_buf[0].i_block[idx]); 1116 | for (int jdx = 2; jdx < DIR_ENTRY_NUM_PER_BLOCK; ++jdx) { 1117 | if (dir_buf[jdx].name_len) { 1118 | if (dir_buf[jdx].file_type == static_cast(FileType::DIR)) { 1119 | res += calcDirSize(dir_buf[jdx].inode); 1120 | } 1121 | else { 1122 | loadInode(dir_buf[jdx].inode); 1123 | res += inode_buf[0].i_blocks * BLOCK_SIZE; 1124 | } 1125 | } 1126 | } 1127 | } 1128 | return res; 1129 | } 1130 | 1131 | void Ext2::ext2_ll() { 1132 | uint16_t inode_idx, b_idx = 0, d_idx; 1133 | loadInode(current_dir); 1134 | int blocks = inode_buf[0].i_blocks; 1135 | while (b_idx < blocks) { 1136 | uint16_t tatget_dir = inode_buf[0].i_block[b_idx]; 1137 | loadDirDataBlock(tatget_dir); 1138 | d_idx = 0; 1139 | while (d_idx < DIR_ENTRY_NUM_PER_BLOCK) { 1140 | loadDirDataBlock(tatget_dir); 1141 | if (d_idx < 2 || dir_buf[d_idx].name_len) { 1142 | loadInode(dir_buf[d_idx].inode); 1143 | printf("\033[0m\033[1;32m%-9s \033[0m", dir_buf[d_idx].name); 1144 | printf("\033[0m\033[1;32m%-7s \033[0m", 1145 | type2Str(FileType(dir_buf[d_idx].file_type)).c_str()); 1146 | printf("\033[0m\033[1;32m%-5s \033[0m", 1147 | mode2Str(inode_buf[0].i_mode).c_str()); 1148 | if (dir_buf[d_idx].file_type == static_cast(FileType::DIR)) { 1149 | printf("\033[0m\033[1;32m%dB\n\033[0m", 1150 | calcDirSize(dir_buf[d_idx].inode)); 1151 | } 1152 | else { 1153 | printf("\033[0m\033[1;32m%dB\n\033[0m", 1154 | inode_buf[0].i_blocks * BLOCK_SIZE); 1155 | } 1156 | } 1157 | ++d_idx; 1158 | } 1159 | ++b_idx; 1160 | } 1161 | } 1162 | 1163 | void Ext2::ext2_ls() { 1164 | uint16_t inode_idx, b_idx = 0, d_idx; 1165 | loadInode(current_dir); 1166 | while (b_idx < inode_buf[0].i_blocks) { 1167 | loadDirDataBlock(inode_buf[0].i_block[b_idx]); 1168 | d_idx = 2; 1169 | // 32 : 512 Byte / 16 Byte (size of dir_entry) 1170 | while (d_idx < DIR_ENTRY_NUM_PER_BLOCK) { 1171 | if (dir_buf[d_idx].name_len) { 1172 | if (dir_buf[d_idx].file_type == 2) 1173 | INFO(dir_buf[d_idx].name); 1174 | else 1175 | printf("%s", dir_buf[d_idx].name); 1176 | printf(" "); 1177 | } 1178 | ++d_idx; 1179 | } 1180 | ++b_idx; 1181 | } 1182 | printf("\n"); 1183 | } 1184 | 1185 | void Ext2::ext2_l_open_file() { 1186 | for (const auto& n : file_open_name_set) { 1187 | INFO(n.c_str()); 1188 | INFO(" "); 1189 | } 1190 | INFO("\n"); 1191 | } 1192 | 1193 | void Ext2::ext2_chmod(char const tar[9]) { 1194 | INFO("Input the mode you want to change: such as r__, rwx, __x:\n"); 1195 | 1196 | std::string mode; 1197 | 1198 | std::cin >> mode; 1199 | 1200 | std::cin.get(); 1201 | 1202 | uint16_t output = 0b0000000100000000; 1203 | if (mode.length() > 3) 1204 | ERROR("Mode Input Error!!! Please check your input!!!\n"); 1205 | for (int i = 0; i < mode.length(); ++i) { 1206 | if (mode[i] == 'r') { 1207 | output = output | 0b0000000100000100; 1208 | } 1209 | else if (mode[i] == 'w') { 1210 | output = output | 0b0000000100000010; 1211 | } 1212 | else if (mode[i] == 'x') { 1213 | output = output | 0b0000000100000001; 1214 | } 1215 | else if (mode[i] == '_') { 1216 | // do nothing 1217 | } 1218 | else { 1219 | ERROR("Mode Input Error!!! Please check your input!!!\n"); 1220 | } 1221 | } 1222 | ext2_chmod_impl(tar, output); 1223 | } 1224 | 1225 | void Ext2::ext2_chmod_impl(char const tar[9], uint16_t mode) { 1226 | uint16_t inode_idx, block_idx, dir_idx; 1227 | 1228 | if (searchFile(tar, static_cast(FileType::FILE), inode_idx, 1229 | block_idx, dir_idx)) { 1230 | loadInode(inode_idx); 1231 | inode_buf[0].i_mode = mode; 1232 | updateInode(inode_idx); 1233 | INFO("Success!!!\n"); 1234 | } 1235 | else { 1236 | WARN("This file does not exsit!!!\n"); 1237 | } 1238 | } 1239 | 1240 | // *************************************************************************** 1241 | 1242 | void Ext2::showDiskInfo() { 1243 | loadGroupDesc(); 1244 | 1245 | printf("\033[0m\033[1;32mVolume Name : %s\n\033[0m", 1246 | group_desc_table[0].bg_volume_name); 1247 | printf("\033[0m\033[1;32mFree Block Count : %d\n\033[0m", 1248 | group_desc_table[0].bg_free_blocks_count); 1249 | printf("\033[0m\033[1;32mFree INode Count : %d\n\033[0m", 1250 | group_desc_table[0].bg_free_inodes_count); 1251 | } 1252 | 1253 | void Ext2::printCurrPath() { 1254 | printf("\033[0m\033[3;38m%s]\n\033[0m", Ext2::GetInstance().current_path); 1255 | INFO("> "); 1256 | } 1257 | -------------------------------------------------------------------------------- /lab3/FileSystem/src/Shell.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | void Shell::init() { 9 | Ext2::GetInstance().init(); 10 | constructMap(); 11 | } 12 | 13 | void Shell::constructMap() { 14 | is_init = true; 15 | 16 | input2command["cd"] = Command::CD; // cd xxx 17 | input2command["mkdir"] = Command::MKDIR; // mkdir xxx 18 | input2command["rmr"] = Command::RMDIR; // rm -r xxx 19 | input2command["rm"] = Command::RM; // rm xxx 20 | input2command["touch"] = Command::TOUCH; // touch xxx 21 | input2command["open"] = Command::OPEN; // open xxx 22 | input2command["close"] = Command::CLOSE; // close xxx 23 | input2command["read"] = Command::READ; // read xxx 24 | input2command["write"] = Command::WRITE; // write xxx 25 | input2command["writea"] = Command::APPEND; // write -a xxx 26 | input2command["ls"] = Command::LS; // ls 27 | input2command["ll"] = Command::LL; // ll 28 | input2command["llo"] = Command::LS_OPEN_FILE; // ll -o 29 | input2command["lld"] = Command::SHOW_DISK_INFO; // ll -d 30 | 31 | input2command["chmod"] = Command::CHMOD; // chmod xxx 32 | 33 | input2command["help"] = Command::HELP; // help 34 | input2command["clear"] = Command::CLEAR; // clear 35 | input2command["exit"] = Command::EXIT; // exit 36 | input2command["quit"] = Command::EXIT; // quit 37 | } 38 | 39 | Pack Shell::inputProcess(std::string input) { 40 | std::string space_delimiter = " "; 41 | std::vector inputs{}; 42 | 43 | size_t pos = 0; 44 | while ((pos = input.find(space_delimiter)) != std::string::npos) { 45 | inputs.push_back(input.substr(0, pos)); 46 | input.erase(0, pos + space_delimiter.length()); 47 | } 48 | inputs.push_back(input.substr(0, pos)); 49 | 50 | assert(inputs.size() <= 3); 51 | 52 | std::string process_input; 53 | if (inputs.size() == 3) 54 | process_input = inputs[0] + inputs[1].substr(1, 1); 55 | else if (inputs.size() == 2) 56 | if (inputs[1][0] == '-') 57 | process_input = inputs[0] + inputs[1].substr(1, 1); 58 | else 59 | process_input = inputs[0]; 60 | else if (inputs.size() == 1) 61 | process_input = inputs[0]; 62 | 63 | Pack res; 64 | 65 | if (input2command.find(process_input) != input2command.end()) { 66 | res.command = input2command[process_input]; 67 | res.is_valid = true; 68 | if (inputs.size() == 3) { 69 | if (inputs[2].length() <= 9) 70 | strncpy(&(res.target[0]), inputs[2].data(), inputs[2].length()); 71 | else { 72 | res.is_valid = false; 73 | ERROR("The max length of name of file/dir is 9!!!\n"); 74 | } 75 | } 76 | else if (inputs.size() == 2) 77 | if (inputs[1][0] != '-') { 78 | if (inputs[1].length() <= 9) 79 | strncpy(&(res.target[0]), inputs[1].data(), inputs[1].length()); 80 | else { 81 | res.is_valid = false; 82 | ERROR("The max length of name of file/dir is 9!!!\n"); 83 | } 84 | } 85 | } 86 | else { 87 | res.is_valid = false; 88 | } 89 | 90 | return res; 91 | } 92 | 93 | void Shell::help() { 94 | INFO("\n----------------- command --------------------\n"); 95 | INFO("cd [--] xxx : change current directory to xxx\n"); 96 | INFO("mkdir [--] xxx : make a new directory named xxx in current directory\n"); 97 | INFO("rm [-r] xxx : remove a file(without -r) // remove a directory(with -r)\n"); 98 | INFO("touch [--] xxx : create a new file named xxx in current directory\n"); 99 | INFO("open [--] xxx : add the file named xxx to file_open_table\n"); 100 | INFO("close [--] xxx : remove the file named xxx from file_open_table\n"); 101 | INFO("read [--] xxx : output the content of file in the terminal\n"); 102 | INFO("write [-a] xxx : delete original content then write(without -a) // Append write(with -a)\n"); 103 | INFO("ls [--] : list the contents in current didirectoryr\n"); 104 | INFO("ll [-od] : list details // show disk info(with -d) // list file open table(with -o)\n"); 105 | INFO("chmod [--] xxx : change the mode of the file\n"); 106 | INFO("clear [--] : clear\n"); 107 | INFO("exit [--] : exit\n"); 108 | INFO("----------------- command --------------------\n\n"); 109 | } 110 | 111 | void Shell::run() { 112 | assert(is_init && "Init first!!!"); 113 | 114 | while (1) { 115 | Ext2::GetInstance().printCurrPath(); 116 | 117 | std::cin.clear(); 118 | fflush(stdin); 119 | 120 | std::string input; 121 | std::getline(std::cin, input); 122 | 123 | Pack res = this->inputProcess(input); 124 | 125 | if (!res.is_valid) { 126 | ERROR("Input Error!!! Please check your input!!!\n"); 127 | continue; 128 | } 129 | 130 | switch (res.command) { 131 | case Command::CD: 132 | Ext2::GetInstance().ext2_cd(res.target); 133 | break; 134 | case Command::MKDIR: 135 | Ext2::GetInstance().ext2_mkdir(res.target); 136 | break; 137 | case Command::RMDIR: 138 | Ext2::GetInstance().ext2_rmdir(res.target); 139 | break; 140 | case Command::RM: 141 | Ext2::GetInstance().ext2_rm(res.target); 142 | break; 143 | case Command::TOUCH: 144 | Ext2::GetInstance().ext2_touch(res.target); 145 | break; 146 | case Command::OPEN: 147 | Ext2::GetInstance().ext2_open(res.target); 148 | break; 149 | case Command::CLOSE: 150 | Ext2::GetInstance().ext2_close(res.target); 151 | break; 152 | case Command::READ: 153 | Ext2::GetInstance().ext2_read(res.target); 154 | break; 155 | case Command::WRITE: 156 | Ext2::GetInstance().ext2_write(res.target); 157 | break; 158 | case Command::APPEND: 159 | Ext2::GetInstance().ext2_append(res.target); 160 | break; 161 | case Command::LS: 162 | Ext2::GetInstance().ext2_ls(); 163 | break; 164 | case Command::LL: 165 | Ext2::GetInstance().ext2_ll(); 166 | break; 167 | case Command::LS_OPEN_FILE: 168 | Ext2::GetInstance().ext2_l_open_file(); 169 | break; 170 | case Command::CHMOD: 171 | Ext2::GetInstance().ext2_chmod(res.target); 172 | break; 173 | case Command::SHOW_DISK_INFO: 174 | Ext2::GetInstance().showDiskInfo(); 175 | break; 176 | case Command::HELP: 177 | help(); 178 | break; 179 | case Command::CLEAR: 180 | system("clear"); 181 | break; 182 | case Command::EXIT: 183 | exit(0); 184 | break; 185 | default: 186 | break; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /lab3/FileSystem/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) { 6 | // ********************************************************** 7 | 8 | Shell::GetInstance().init(); 9 | 10 | Shell::GetInstance().run(); 11 | 12 | // ********************************************************** 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /lab3/README.md: -------------------------------------------------------------------------------- 1 | # OS_Lab3 2 | 3 | ## Part1 FileSystem_Ext2 4 | 5 | ### ***Intro*** 6 | 7 | Ext2的磁盘布局使用了组块的结构, 并且采用了多级索引使得单文件的大小得到了很大的提升. 8 | 9 | 10 | 11 | 在实现基于文件空间的类Ext2文件系统时,需要注意一下三个部分: 12 | 13 | 1. 使用单文件空间来模拟整个磁盘空间 14 | 2. 组织ext2系统所提供的各种功能以及其数据结构 15 | 3. 为用户提供shell和操作接口 16 | 17 | 18 | 19 |
20 | 21 | 解决方案如下: 22 | 23 | 1. 使用 `fseek` + `fwrite/fread` 模拟磁盘的读取和写入以及定位 24 | 2. 实现 `Ext2` 类来抽象 Ext2 文件系统 25 | 3. 实现 `Shell` 类并组合 `Ext2` 来向用户提供 Shell界面和接口操作 26 | 27 | 在此次实验中,为了简化,假定: 28 | 29 | 1. 只有一个组(Group), 即只有一个组描述符 30 | 2. 只有一个用户, 用户相关实现末节都可以忽略 31 | 3. 逻辑块大小与物理块大小均定义为 `512Byte` 32 | 33 | 简化后的文件系统布局如下: 34 | 35 | 36 | 37 |
38 | 39 | --- 40 | 41 | ### ***Analysis*** 42 | 43 | 简化后的文件系统结构很简单, 其中关键在于从文件名到实际数据块的映射, 大体上是这样一个顺序: 44 | 45 | ```shell 46 | File/Dir_Name ------> Inode ------> DataBlock(s) 47 | ``` 48 | 49 | 其中每个 Inode 可能是从一个文件映射而来, 也可能是从一个目录映射而来, 二者之间的区别在于: 50 | 51 | * 文件的 Inode 直接指向可以指向其所占有的所有数据块, 其中 i_blocks字段的前六位数据为直接索引, 即直接指向数据块; 第七位数据为一个一级间接索引, 第八位数据为一个二级间接索引; 数据块存放的就是文件的内容. 52 | * 目录的 Inode 也是指向数据块, 其与文件的不同之处在于, 数据块中存储的是很多个 `dir_entry`, 即目录项; 对于每个目录项, 如果 `file_type` 为 `FileType::DIR`, 则形成一个树形结构, 如果是文件则成为一个叶子结点, 指向其文件实际内容所在的数据块 53 | 54 | 55 | 56 | 57 | 58 | --- 59 | 60 | ### ***Impl*** 61 | 62 | `Ext2` 类的实现, 主要提供了一系列底层的操作给 `Shell` 63 | 64 | 65 | 66 | `Shell` 类主要只需要做两件事: 67 | ```shell 68 | UserInput ---> Params -----> ActualOp 69 | ``` 70 | 把用户操作转成 `op + params + target` 的形式, 然后调用 `Ext2` 的相关操作即可. 71 | 72 | 73 | 74 | --- 75 | 76 | ### ***Run*** 77 | 78 | 79 | 80 | --- 81 | 82 | ## Part2 Thread Pool Impl 83 | 84 | ### ***intro*** 85 | 86 | 使用 `std::thread` + `std::future` + `std::promise`等标准库以及模板元编程, 类型萃取等技术来实现一个**可复用**的线程池实现. 87 | 88 | ### ***run*** 89 | 90 | 工具类 `A` 91 | 92 | 93 | 94 | No_ThreadPool_Func 95 | 96 | 97 | 98 | With_ThreadPool_Func 99 | 100 | 101 | 102 | ***Result*** 103 | 104 | 105 | 106 | 可以看到并行版本的效率提升非常明显, 加速比达到了 107 | $$ 108 | 4.99468 / 0.82381 \approx 5.41 109 | $$ 110 | 111 | --- 112 | 113 | ## Part 3 遇到的问题 114 | 115 | 使用 `std::function` 时出现 116 | 117 | 118 | 119 | Search in StackOverflow, [capture-stdpromise-in-a-lambda-c14](https://stackoverflow.com/questions/33436336/capture-stdpromise-in-a-lambda-c14) 120 | 121 | 122 | 123 | 引入了 [Naios/function2](https://github.com/Naios/function2)来解决该问题 124 | 125 | --- 126 | 127 | ## Part 4 分析和思考 128 | 129 | 在写程序时要注意设计以及功能模块的划分,对于每一个功能要考虑各种情况,保证程序的健壮性. 130 | 131 | --- 132 | 133 | ## Part 5 自评分 134 | 135 | `Score: ` $30$ 136 | 137 | -------------------------------------------------------------------------------- /lab3/images/ctp/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/0.png -------------------------------------------------------------------------------- /lab3/images/ctp/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/1.png -------------------------------------------------------------------------------- /lab3/images/ctp/a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/a.png -------------------------------------------------------------------------------- /lab3/images/ctp/ans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/ans.png -------------------------------------------------------------------------------- /lab3/images/ctp/ans0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/ans0.png -------------------------------------------------------------------------------- /lab3/images/ctp/err.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/err.png -------------------------------------------------------------------------------- /lab3/images/ctp/res0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/res0.png -------------------------------------------------------------------------------- /lab3/images/ctp/res1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/res1.png -------------------------------------------------------------------------------- /lab3/images/ctp/xxx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/ctp/xxx.png -------------------------------------------------------------------------------- /lab3/images/fs/entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/entry.png -------------------------------------------------------------------------------- /lab3/images/fs/ext2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/ext2.png -------------------------------------------------------------------------------- /lab3/images/fs/impl0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/impl0.png -------------------------------------------------------------------------------- /lab3/images/fs/impl1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/impl1.png -------------------------------------------------------------------------------- /lab3/images/fs/inode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/inode.png -------------------------------------------------------------------------------- /lab3/images/fs/loc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/loc.png -------------------------------------------------------------------------------- /lab3/images/fs/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/run.png -------------------------------------------------------------------------------- /lab3/images/fs/str.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YichenWu11/OS_Lab/6d7322bb59542aa0c2b72f62dcc41bc53d288417/lab3/images/fs/str.png --------------------------------------------------------------------------------