├── .gitmodules ├── README.md ├── docs ├── fs-rs.md ├── lab-1.md ├── lab-2.md ├── lab-3.md ├── pic │ └── mixed_index_fs.png └── pta.md ├── lab2 ├── Makefile └── pstree.c ├── lab3 ├── mq │ ├── _fifo │ │ ├── Makefile │ │ ├── init.h │ │ ├── receiver.c │ │ ├── sender1.c │ │ ├── sender2.c │ │ └── unlink.c │ ├── _thread │ │ ├── Makefile │ │ ├── init.h │ │ ├── mq.c │ │ └── unlink.c │ └── process_mq │ │ ├── Makefile │ │ ├── init.h │ │ ├── receiver.c │ │ ├── sender1.c │ │ ├── sender2.c │ │ └── unlink.c ├── pipe │ ├── Makefile │ ├── fifo.c │ ├── fifo_read.c │ ├── fifo_write.c │ ├── init.h │ ├── pipe.c │ └── size_of_pipe.c ├── shell │ ├── Makefile │ ├── cmd1.c │ ├── cmd2.c │ ├── cmd3.c │ ├── cmd4.c │ ├── shell-rs │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── Makefile │ │ └── src │ │ │ └── main.rs │ └── shell.c └── shm │ ├── Makefile │ ├── init.h │ ├── unlink.c │ ├── user1.c │ └── user2.c └── pta ├── 模拟进程调度.cpp ├── 模拟进程链表基本操作.cpp └── 模拟银行家算法.cpp /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "fs-rs"] 2 | path = fs-rs 3 | url = https://github.com/CelestialMelody/fs-rs.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HDU-OS-LAB 2 | 3 | Operating system experiment of HDU: including kernel compilation, system call, pstree kernel module, simulation shell, semaphore mechanism, pipeline communication, message queue communication, shared memory communication, simple file system(mix index file system), and simulation process list basic operation, process scheduling, banker algorithm. 4 | 5 | 杭州电子科技大学操作系统实验:内核编译、系统调用、pstree 内核模块、模拟 shell 、信号量机制、管道通信、消息队列通信、共享内存通信、简单文件系统(混合索引文件系统),以及模拟进程链表基本操作、进程调度、银行家算法。 6 | 7 | ### lab-1 kernel compilation and system call 8 | 9 | 实验一:内核编译和系统调用 10 | 11 | [实验过程](docs/lab-1.md) 12 | 13 | 14 | ### lab-2 pstree kernel module 15 | 16 | 实验二:pstree 内核模块 17 | 18 | [实验代码](lab2/) 19 | [实验说明](docs/lab-2.md) 20 | 21 | ### lab-3 IPC, sync and mutex 22 | 23 | 实验三:进程间通信和同步互斥 24 | 25 | - 模拟 shell 26 | - 信号量机制 27 | - 管道通信 28 | - 消息队列通信 29 | - 共享内存通信 30 | 31 | [实验代码](lab3/) 32 | [实验说明](docs/lab-3.md) 33 | 34 | 35 | ### PTA 题目 36 | 37 | [解题代码](pta/) 38 | [题目说明](docs/pta.md) 39 | ### lab-5 easy file system 40 | 41 | an easy mix index file system based on rcore easy-fs using rust 42 | 43 | 这是一个使用 rust 语言编写的,基于 rcore easy-fs 的简单混合索引文件系统,项目地址:[fs-rs](https://github.com/CelestialMelody/fs-rs.git) 44 | 45 | [项目介绍](docs/fs-rs.md) -------------------------------------------------------------------------------- /docs/fs-rs.md: -------------------------------------------------------------------------------- 1 | # fs-rs 2 | 3 | An easy mixed index file system based on eazy-fs of rcore. 4 | 5 | *see the latest in [here](https://github.com/CelestialMelody/fs-rs)* 6 | 7 | ### Usage 8 | 9 | if you don't have rust environment, you can download rust by: 10 | 11 | ```bash 12 | curl https://sh.rustup.rs -sSf | sh 13 | ``` 14 | 15 | then you can use the following commands to build and run: 16 | 17 | 18 | ```bash 19 | # for the first time 20 | make create 21 | 22 | # for the second time or later 23 | make open 24 | 25 | # to clean the build 26 | make clean 27 | ``` 28 | 29 | ### Features 30 | 31 | - read: read a file randomly. 32 | - write: write a file randomly. 33 | - cd: change directory simply. 34 | - ls: list files in current directory. 35 | - mkdir: create a directory. 36 | - touch: create a file. 37 | - rm: remove a file or a directory. 38 | - cat: print the content of a file. 39 | - fmt: format the file system. 40 | - chname: change the name of a file or a directory (a simple version of mv). 41 | - stat: get the size of a file or a directory.(a simple version of ls -l). 42 | - set: a test for file system (copy files form host to easy-fs). 43 | - get: a test for file system (copy files from easy-fs to host). 44 | 45 | *maybe more in future* 46 | 47 | - mv: move a file or a directory. 48 | - cp: copy a file or a directory. 49 | - pwd: print the current directory. 50 | - find: find a file or a directory. 51 | - ln: create a link. 52 | 53 | *If your shell is garbled, it is probably because of the font, and you can modify the icons in the code yourself, or download and use [Hack Nerd Font Mono](https://github.com/ryanoasis/nerd-fonts/blob/master/patched-fonts/Hack/Regular/complete/Hack%20Regular%20Nerd%20Font%20Complete%20Mono.ttf).* 54 | 55 | mixed_index_fs.png 61 | 62 |

image comes from: xiaolincoding

63 | -------------------------------------------------------------------------------- /docs/lab-1.md: -------------------------------------------------------------------------------- 1 | # 实验1 2 | 3 | ### 下载开发工具 4 | 5 | 首先你需要有一台 linux 虚拟机 或者 linux 服务器 6 | 7 | 根据你的 linux 发行版换源(Ubuntu apt \ CentOS yum \ Manjaro pacman) 8 | 9 | 下载相关工具(根据发行版), 这里以 Ubuntu 为例 10 | 11 | ``` 12 | sudo apt-get install git fakeroot make build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison libncurses-dev openssl libncurses5-dev 13 | ``` 14 | 15 | > 其他工具根据需求再添加即可 16 | > 17 | > 另外, *推荐* 安装源码阅读工具: vim + ctags + taglist (可参考课本教材) 18 | > 19 | > 执行: `sudo apt install vim ctags` 20 | > 21 | > [下载 taglist](https://github.com/yegappan/taglist) (请阅读 README 安装) 22 | > 23 | > 进入下载的源代码目录, 执行: `sudo ctags -R *` 24 | 25 | > *编辑环境推荐 - 远程连接虚拟机* 26 | > 27 | > [vscode + Vmware tcp端口转发](https://blog.csdn.net/yylxiaobai/article/details/120024829) 或者 [vscode + ssh](https://zhuanlan.zhihu.com/p/81749330) 28 | 29 | 30 | 31 | ### 下载源代码 32 | 33 | 下载源码到本地 (linux-xxx.tar.xz) 34 | 35 | 官网链接:https://www.kernel.org/ 36 | 37 | 镜像站:https://mirrors.edge.kernel.org/pub/linux/kernel/ 38 | 39 | 解压:tar -xvf linux-xxx.tar.xz 40 | 41 | 42 | 43 | ### 修改Linux内核标签 44 | 45 | 想法是寻找 main.c 或者与初始化相关的函数 46 | 47 | 1. 打开 init/main.c 48 | 2. 查找 `start_kernel` 函数 49 | 3. 写入 pr_notice("学号 姓名"); 50 | > 尽量靠前, 否则可能不会输出(据说写的太靠后可能不会输出) 51 | > 52 | > 另外, 可能有同学可能以为可以在 include/linux/uts.h 中通过修改 UTS_SYSNAME 来修改内核标签 53 | > 54 | > ```c 55 | > #define UTS_SYSNAME "Linux" 56 | > ``` 57 | > 58 | > 虽然似乎可以做到, 但并不推荐这样做. 59 | > 60 | > 如果你是使用 vscode 远程连接虚拟机来编辑代码, 这很有可能导致你无法进行远程连接 61 | > 62 | > 原因在于 vscode 的 远程资源管理器 仅识别 Linux / Mac / Windows, 当你修改了 UTS_NAME, 这将导致你无法再远程连接虚拟机, 因为 vscode 无法识别该操作系统. 63 | > 64 | > 但是这并不是 ssh 的问题, 即你仍然可以在 powershell 中通过 ssh 远程连接虚拟机. 65 | > 66 | > PS: 本人一开始就是这么做到, 遇见了无法连接虚拟机的问题, 然后仔细查看控制台输出发现问题的原因 67 | > 68 | > 详细可以参考 [这个链接](https://stackoverflow.com/questions/64298741/vs-code-ssh-remote-connection-issues/#:~:text=Add%20a%20comment-,1,okkk%2C%20I%20solve%20the%20problem.,-Share) 69 | 70 | 71 | 72 | ### 内核编译 73 | 74 | > 以下所有的 make 都可以带上参数 -j 来加速 75 | > 76 | > 根据你的 cpu 核心数确定 -j 后的数字, 或者直接 `make -j$(nproc)` 77 | 78 | ```shell 79 | # 精减不需要的模块 (加速内核编译) 80 | make localmodconfig 81 | 82 | # 手动配置内核是一项相当困难的任务, 因此复制现有配置并自定义它是更明智的做法 83 | # 之后编译可能会遇见报错, 详情看后文 84 | cp /boot/config-$(uname -r) .config 85 | 86 | # 检查一下是否有自己需要的模块没有选上 87 | # 在这一步的 General setup 中, 可以修改 uname -r 的输出 88 | # 注意 uname -r 只是为了获取内核版本, 这里修改为其他字符串并不意味着修改了主机名 89 | # 另外, 不要在此处使用空格, 否则, 之后编译可能会遇见报错, 详情看后文 90 | make menuconfig 91 | 92 | # 编译 93 | make 94 | 95 | # 安装模块 96 | make modules_install 97 | 98 | # 安装内核 99 | make install 100 | 101 | # 配置 grub 引导程序 102 | sudo update-grub2 103 | 104 | # 立即重启并以新的内核启动 105 | reboot -n 106 | ``` 107 | 108 | 最后, 在开机进度条界面长按 Shift, 进入 grub 进行内核切换 109 | 110 | > 你可能会遇见的报错 111 | > 112 | > [.config 文件](https://blog.csdn.net/qq_36393978/article/details/118157426) 113 | > 114 | > [manuconfig 在 General Setup local version 填入空格](https://blog.csdn.net/gylltq/article/details/45485583) 115 | 116 | 117 | 118 | ### 添加系统调用 119 | 120 | #### 分配系统调用号,修改系统调用表 121 | 122 | 查看系统调用表, 在表中为系统调用添加一个系统调用号 123 | 124 | ``` 125 | vim ./arch/x86/entry/syscalls/syscall_64.tbl 126 | ``` 127 | 128 | 每个系统调用在表中占一个表项,其格式为 129 | 130 | `<系统调用号> <系统调用名> <服务例程入口地址>` 131 | 132 | ``` 133 | #kernal_lab_add_sys_call 134 | 135 | 360 common simple_info sys_simple_info 136 | 361 common set_nice sys_set_nice 137 | 362 common set_host_name sys_set_host_name 138 | ``` 139 | 140 | > 有的同学可能看到课本教材上提到: 141 | > 142 | > > 注意, Linux 4.18 及以后的版本的服务例程地址格式必须以 "\_\_64\_" 开头 143 | > 144 | > 本人内核版本为 5.18.19, 按照上面的方法, 反而因此失败. 145 | > 146 | > 实际上, Linux 5.18.19 编译时会通过宏自动添加, 不需要管这句话. 147 | 148 | 149 | 150 | #### 申明系统调用服务例程原型 151 | 152 | Linux 系统调用服务例程的原型声明在文件 include/linux/syscalls.h 中, 可在文件末尾添加类似`asmlinkage long sys_xxx_syscall(void);`的系统调用代码. 153 | 154 | ```c 155 | // 在 include/linux/syscall.h 最后 156 | 157 | // kernel_lab 158 | // 基本上可以抄前面的 newumane 方法 159 | asmlinkage long sys_simple_info(struct new_utsname __user * name); 160 | 161 | // 事实上, 如果改变 nice value, prio value 也会被修改, 所以只需要改 nice 即可 162 | asmlinkage long sys_set_nice(pid_t pid, int flag, int nicevalue, void __user *prio, void __user *nice); 163 | 164 | // 基本上可以抄前面的 sethostname 方法 165 | asmlinkage long sys_set_host_name(char __user *name, int len); 166 | ``` 167 | 168 | 169 | 170 | #### 实现系统调用服务例程 171 | 172 | 新调用编写服务例程通常添加在 kernel/sys.c 文件中. 173 | 174 | 系统调用函数的定义`SYSCALL_DEFINEX` 类型函数的格式: 175 | 176 | SYSCALL_DEFINEX(函数名,参数变量类型1,参数变量名1, …, 参数变量类型N,参数变量名n) 177 | 178 | SYSCALL_DEFINEX 最后的 `X` 为参数的数目(最大为6) 179 | 180 | ```c 181 | // include/linux/syscall.h 182 | 183 | #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) 184 | #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) 185 | #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) 186 | #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) 187 | #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) 188 | #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) 189 | 190 | #define SYSCALL_DEFINE_MAXARGS 6 191 | ``` 192 | 193 | 194 | 195 | `simple_info` 196 | 197 | ```c 198 | // kernel/sys.c 199 | 200 | // ps: c 语言并不会检测形参类型 struct __user * 来自哪里, 也就是说, 我们在用户态写的结构体类型与内核的结构体成员类型一致就可以使用. 201 | SYSCALL_DEFINE1(simple_info, struct new_utsname __user *, name) 202 | { 203 | struct new_utsname tmp; 204 | 205 | // 函数 down_read() 是读者用来得到读写信号量 sem 时调用的, 206 | // 如果该信号量在被写者所持有,则对该函数的调用会导致调用者的睡眠。 207 | // 通过该操作,多个读者可以获得读写信号量。 208 | down_read(&uts_sem); 209 | memcpy(&tmp, utsname(), sizeof(tmp)); 210 | // 函数up_read()是读者释放读写信号量sem时调用的。 211 | // 它一般与down_read()函数和down_read_trylock()配对使用, 212 | // 但是如果down_read_trylock()返回0,则表示读者未获得信号量,也就不需要调用up_read()来释放。 213 | up_read(&uts_sem); 214 | if (copy_to_user(name, &tmp, sizeof(tmp))) 215 | return -EFAULT; 216 | 217 | if (override_release(name->release, sizeof(name->release))) 218 | return -EFAULT; 219 | if (override_architecture(name)) 220 | return -EFAULT; 221 | 222 | printk(KERN_NOTICE "Clstilmldy\nkernel version: %s\nkernel relese: %s\nkernel sysname: %s\nkernel nodemane: %s\n", 223 | utsname()->version, 224 | utsname()->release, 225 | utsname()->sysname, 226 | utsname()->nodename); 227 | 228 | return 0; 229 | } 230 | ``` 231 | 232 | 233 | 234 | `set_nice` 235 | 236 | ```c 237 | SYSCALL_DEFINE5(set_nice, pid_t, pid, int, flag, int, nicevalue, void __user *, prio, void __user *, nice) 238 | { 239 | int cur_prio, cur_nice; 240 | struct pid *ppid; 241 | struct task_struct *pcb; 242 | 243 | ppid = find_get_pid(pid); 244 | pcb = pid_task(ppid, PIDTYPE_PID); 245 | cur_prio = task_prio(pcb); 246 | cur_nice = task_nice(pcb); 247 | 248 | if(flag == 1) { 249 | pr_notice("old_prio: %d, old_nice: %d\n", cur_prio, cur_nice); 250 | // when nice changed, prio value will be changed too 251 | set_user_nice(pcb, nicevalue); 252 | cur_nice = task_nice(pcb); 253 | cur_prio = task_prio(pcb); 254 | pr_notice("new_prio: %d, new_nice: %d\n", cur_prio, cur_nice); 255 | // copy to user space 256 | if (copy_to_user(prio, &cur_prio, sizeof(cur_prio))) 257 | return -EFAULT; 258 | if (copy_to_user(nice, &cur_nice, sizeof(cur_nice))) 259 | return -EFAULT; 260 | return 0; 261 | } 262 | else if(flag == 0) { 263 | if (copy_to_user(prio, &cur_prio, sizeof(cur_prio))) 264 | return -EFAULT; 265 | if (copy_to_user(nice, &cur_nice, sizeof(cur_nice))) 266 | return -EFAULT; 267 | pr_notice("cur_prio: %d, cur_nice: %d\n", cur_prio, cur_nice); 268 | return 0; 269 | } 270 | return -EFAULT; 271 | } 272 | ``` 273 | 274 | 275 | 276 | `sethostname` 277 | 278 | > 可以用 `uname -n `命令来查看主机名称 279 | 280 | ```c 281 | // just like sethostname 282 | SYSCALL_DEFINE2(set_host_name, char __user *, name, int, len) 283 | { 284 | int errno; 285 | char tmp[__NEW_UTS_LEN]; // __NEW_UTS_LEN=64 286 | 287 | // check whether the current process has a CAP_SYS_ADMIN authorization 288 | // 注释掉 防止没有 CAP_SYS_ADMIN 289 | // if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) 290 | // return -EPERM; 291 | 292 | if (len < 0 || len > __NEW_UTS_LEN) 293 | return -EINVAL; 294 | errno = -EFAULT; 295 | 296 | // copy_form_user 297 | // copies the string pointed to by name from the user space to the kernel space. 298 | // If it fails, the number of bytes not copied is returned. 299 | // If it succeeds, 0 is returned. 300 | if (!copy_from_user(tmp, name, len)) { 301 | struct new_utsname *u; 302 | 303 | // down_write 得到读写信号量 sem,它会导致调用者睡眠,只能在进程上下文使用,用于获取Linux内核读写信号量中的写锁 304 | down_write(&uts_sem); 305 | // 获取当前内核名称和其它信息,成功执行时,返回0。失败返回-1,errno被设为EFAULT,表示buf无效。 306 | u = utsname(); 307 | 308 | pr_notice("old host name: %s\n", u->nodename); 309 | 310 | // 从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中 311 | memcpy(u->nodename, tmp, len); 312 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); 313 | errno = 0; 314 | // 使用UTS namespace隔离hostname 315 | uts_proc_notify(UTS_PROC_HOSTNAME); 316 | // 释放写锁 317 | up_write(&uts_sem); 318 | 319 | pr_notice("new host name: %s\n", u->nodename); 320 | } 321 | return errno; 322 | } 323 | ``` 324 | 325 | > 虽然无论是 pr_notice 还是 printk 都会默认打印出换行符, 但还是建议在最后加上换行符, 以免出现 dmesg 信息滞后(最后一条没显示, 但实际会打印, 不过没显示, 只有下次使用 printk 时, 再 dmesg 会显示); 不过目前来看, 可能还是有这个问题(不过只是小bug) 326 | > 327 | > 还有一个小问题是: 对于 set_host_name, 可以使用 uname -n (或者对于 bash 可以直观看出); 但是, 可能会遇见 dmseg 阻塞问题 328 | 329 | 330 | #### 编译内核 331 | 332 | 如何编译见前文. (如果前面已经编译过, 再次编译会更快些) 333 | 334 | 335 | 336 | #### 编写用户态程序测试系统调用 337 | 338 | simple_info.c 339 | 340 | ```c 341 | #include 342 | #include 343 | #include 344 | #include 345 | #include 346 | 347 | #define __NEW_UTS_LEN 64 348 | 349 | struct old_utsname { 350 | char sysname[65]; 351 | char nodename[65]; 352 | char release[65]; 353 | char version[65]; 354 | char machine[65]; 355 | }; 356 | 357 | // c 语言并不会检测形参类型 struct __user * 来自哪里, 也就是说, 我们在用户态写的结构体类型与内核的结构体成员类型一致就可以使用. 358 | // 该类型实际在内核 include/linux/utsname.h 中 359 | struct new_utsname { 360 | char sysname[__NEW_UTS_LEN + 1]; 361 | char nodename[__NEW_UTS_LEN + 1]; 362 | char release[__NEW_UTS_LEN + 1]; 363 | char version[__NEW_UTS_LEN + 1]; 364 | char machine[__NEW_UTS_LEN + 1]; 365 | char domainname[__NEW_UTS_LEN + 1]; 366 | }; 367 | 368 | 369 | int main() { 370 | struct new_utsname name; 371 | if (syscall(360, &name)) { 372 | perror("simple info"); 373 | return -1; 374 | } 375 | printf("\033[1;36mClstilmldyOS\n"); 376 | printf("\033[0mkernel version: %s\nkernel relese: %s\nkernel sysname: %s\nkernel nodemane: %s\n", 377 | name.version, name.release, name.sysname, name.nodename); 378 | return 0; 379 | } 380 | ``` 381 | 382 | 383 | 384 | set_nice_prio.c 385 | 386 | ```c 387 | #include 388 | #include 389 | #include 390 | #include 391 | 392 | int main() { 393 | int pid; 394 | int nicevalue = 6; 395 | int *prio; 396 | int *nice; 397 | int n, p; 398 | char temp_flag; 399 | prio = &p; 400 | nice = &n; 401 | 402 | printf("please input pid:\n"); 403 | scanf("%d", &pid); 404 | 405 | if (syscall(361, pid, 0, 0, prio, nice)) { 406 | perror("simple info"); 407 | return -1; 408 | } 409 | 410 | printf("cur nice: %d, cur prio: %d\n", *nice, *prio); 411 | 412 | printf("if change nice? [y or else]\n"); 413 | scanf("\n%c", &temp_flag); 414 | if (temp_flag == 'y') { 415 | printf("please input new nice value:\n"); 416 | scanf("%d", &nicevalue); 417 | if (syscall(361, pid, 1, nicevalue, prio, nice)) { 418 | perror("simple info"); 419 | return -1; 420 | } 421 | printf("cur nice: %d, cur prio: %d\n", *nice, *prio); 422 | } 423 | return 0; 424 | } 425 | ``` 426 | 427 | 428 | 429 | set_host_name.c 430 | 431 | ```c 432 | #include 433 | #include 434 | #include 435 | #include 436 | #include 437 | 438 | int main() { 439 | char hostname[20] = {'\0'}; 440 | 441 | printf("please input new host name:\n"); 442 | scanf("%s", hostname); 443 | int len = strlen(hostname); 444 | 445 | if (syscall(362, hostname, len)) { 446 | perror("set host name"); 447 | return -1; 448 | } 449 | printf("new host name is: %s\n", hostname); 450 | return 0; 451 | } 452 | ``` 453 | 454 | Makefile 455 | 456 | ```makefile 457 | SRC := $(wildcard *.c) 458 | # 移除后缀名 459 | TARGET := $(patsubst %.c, %, $(SRC)) 460 | 461 | all: $(TARGET) 462 | 463 | # 依次编译(静态模式) 464 | $(TARGET): %: %.c 465 | gcc -o $@ $< 466 | 467 | clean: 468 | rm -f $(TARGET) 469 | ``` 470 | 471 | ### 其他 472 | 473 | 474 | > *参考命令* 475 | > 476 | > 查看当前内核版本: `uname -r` 477 | > 478 | > 显示在网络上的主机名称: `uname -n` 479 | > 480 | > 读取内核开机日志(开机信息)最后 100 条: `sudo dmesg | tail -100` 481 | 482 | 483 | 484 | > *其他参考链接* 485 | > 486 | > [Makefile 教程](https://www.ruanyifeng.com/blog/2015/02/make.html) (ps: 进阶一点需要结合 [shell 编程](https://wangdoc.com/bash/)) 487 | > 488 | > [删除不需要的内核](https://blog.csdn.net/u014386899/article/details/89372099) 489 | > 490 | > [printk 用法](https://blog.csdn.net/u014470361/article/details/81302002) (ps: 可以尝试使用 [pr_notice](https://blog.csdn.net/weixin_38227420/article/details/79335835) 等等简化的 printk) 491 | > 492 | > [manuconfig 详解](https://blog.csdn.net/HowieXue/article/details/76696631) [详解2](https://www.cnblogs.com/chorm590/p/13977818.html) 493 | > 494 | > [syscall 原理](http://gityuan.com/2016/05/21/syscall/) 495 | > 496 | > [make localmodconfig 加速编译](https://www.cnblogs.com/fly-fish/archive/2011/08/16/2140595.html) 497 | > 498 | > [EN 内核编译](https://www.pcsuggest.com/compile-linux-kernel/) 499 | > 500 | > *实验细节* 501 | > 502 | > 学长学姐的博客: [One](https://zhuanlan.zhihu.com/p/363014797) [Two](https://blog.psyqlk.space/2022/11/14/linux-complier-practice/#%E6%B8%85%E9%99%A4%E6%AE%8B%E7%95%99%E7%9A%84-config%E5%92%8C-o%E6%96%87%E4%BB%B6) -------------------------------------------------------------------------------- /docs/lab-2.md: -------------------------------------------------------------------------------- 1 | # 实验2 2 | 3 | 简单体验 4 | 5 | ```shell 6 | # 编译 7 | make 8 | 9 | # 安装模块 默认 pid =1 10 | make insmod 11 | 12 | # 指定 pid 13 | make insmod pid=1 14 | 15 | # 清理并卸载模块 16 | make clean 17 | ``` 18 | 19 |
效果展开查看 20 |

 21 | [ 3946.079878] current process
 22 |                pid: 1, name: systemd, state: 1
 23 | [ 3946.079882] swapper/0(pid: 0)
 24 | [ 3946.079883]     ├─systemd(pid: 1)
 25 | [ 3946.079884]     │   ├─systemd-journal(pid: 428)
 26 | [ 3946.079885]     │   ├─vmware-vmblock-(pid: 460)
 27 | [ 3946.079886]     │   ├─systemd-udevd(pid: 483)
 28 | [ 3946.079886]     │   ├─systemd-oomd(pid: 689)
 29 | [ 3946.079888]     │   ├─systemd-resolve(pid: 691)
 30 | [ 3946.079888]     │   ├─systemd-timesyn(pid: 699)
 31 | [ 3946.079889]     │   ├─auditd(pid: 705)
 32 | [ 3946.079890]     │   ├─VGAuthService(pid: 793)
 33 | [ 3946.079891]     │   ├─vmtoolsd(pid: 799)
 34 | [ 3946.079891]     │   ├─accounts-daemon(pid: 873)
 35 | [ 3946.079892]     │   ├─acpid(pid: 875)
 36 | [ 3946.079893]     │   ├─avahi-daemon(pid: 880)
 37 | [ 3946.079894]     │   │   └─avahi-daemon(pid: 937)
 38 | [ 3946.079894]     │   ├─cron(pid: 881)
 39 | [ 3946.079895]     │   ├─dbus-daemon(pid: 882)
 40 | [ 3946.079896]     │   ├─NetworkManager(pid: 883)
 41 | [ 3946.079897]     │   ├─irqbalance(pid: 891)
 42 | [ 3946.079898]     │   ├─networkd-dispat(pid: 905)
 43 | [ 3946.079898]     │   ├─polkitd(pid: 906)
 44 | [ 3946.079899]     │   ├─power-profiles-(pid: 910)
 45 | [ 3946.079899]     │   ├─rsyslogd(pid: 915)
 46 | [ 3946.079900]     │   ├─snapd(pid: 916)
 47 | [ 3946.079901]     │   ├─switcheroo-cont(pid: 917)
 48 | [ 3946.079901]     │   ├─systemd-logind(pid: 918)
 49 | [ 3946.079902]     │   ├─udisksd(pid: 920)
 50 | [ 3946.079903]     │   ├─wpa_supplicant(pid: 922)
 51 | [ 3946.079903]     │   ├─ModemManager(pid: 955)
 52 | [ 3946.079904]     │   ├─cupsd(pid: 973)
 53 | [ 3946.079905]     │   ├─unattended-upgr(pid: 982)
 54 | [ 3946.079905]     │   ├─sshd(pid: 990)
 55 | [ 3946.079906]     │   │   ├─sshd(pid: 1751)
 56 | [ 3946.079907]     │   │   │   └─sshd(pid: 1909)
 57 | [ 3946.079908]     │   │   │       └─bash(pid: 1910)
 58 | [ 3946.079909]     │   │   │           ├─sh(pid: 1965)
 59 | [ 3946.079910]     │   │   │           │   └─node(pid: 1975)
 60 | [ 3946.079911]     │   │   │           │       ├─node(pid: 2139)
 61 | [ 3946.079912]     │   │   │           │       │   ├─zsh(pid: 3048)
 62 | [ 3946.079912]     │   │   │           │       │   │   └─sudo(pid: 5702)
 63 | [ 3946.079913]     │   │   │           │       │   │       └─sudo(pid: 5721)
 64 | [ 3946.079914]     │   │   │           │       │   │           └─insmod(pid: 5722)
 65 | [ 3946.079915]     │   │   │           │       │   └─zsh(pid: 3499)
 66 | [ 3946.079916]     │   │   │           │       ├─node(pid: 2954)
 67 | [ 3946.079917]     │   │   │           │       │   ├─node(pid: 3005)
 68 | [ 3946.080384]     │   │   │           │       │   └─cpptools(pid: 3144)
 69 | [ 3946.080386]     │   │   │           │       └─node(pid: 2965)
 70 | [ 3946.080387]     │   │   │           └─sleep(pid: 5144)
 71 | [ 3946.080388]     │   │   ├─sshd(pid: 2843)
 72 | [ 3946.080389]     │   │   │   └─sshd(pid: 2881)
 73 | [ 3946.080390]     │   │   │       └─bash(pid: 2882)
 74 | [ 3946.080390]     │   │   │           └─sleep(pid: 5146)
 75 | [ 3946.080391]     │   │   ├─sshd(pid: 3626)
 76 | [ 3946.080392]     │   │   │   └─sshd(pid: 3705)
 77 | [ 3946.080393]     │   │   │       └─bash(pid: 3706)
 78 | [ 3946.080393]     │   │   │           └─sleep(pid: 5145)
 79 | [ 3946.080394]     │   │   ├─sshd(pid: 4655)
 80 | [ 3946.080395]     │   │   │   └─sshd(pid: 4779)
 81 | [ 3946.080396]     │   │   │       └─bash(pid: 4780)
 82 | [ 3946.080397]     │   │   │           └─sleep(pid: 5142)
 83 | [ 3946.080397]     │   │   └─sshd(pid: 4852)
 84 | [ 3946.080398]     │   │       └─sshd(pid: 4890)
 85 | [ 3946.080399]     │   │           └─bash(pid: 4891)
 86 | [ 3946.080400]     │   │               └─sleep(pid: 5143)
 87 | [ 3946.080400]     │   ├─gdm3(pid: 1008)
 88 | [ 3946.080401]     │   │   └─gdm-session-wor(pid: 1100)
 89 | [ 3946.080402]     │   │       └─gdm-wayland-ses(pid: 1133)
 90 | [ 3946.080403]     │   │           └─gnome-session-b(pid: 1145)
 91 | [ 3946.080404]     │   ├─clash-core-serv(pid: 1028)
 92 | [ 3946.080404]     │   ├─cups-browsed(pid: 1031)
 93 | [ 3946.080405]     │   ├─kerneloops(pid: 1064)
 94 | [ 3946.080406]     │   ├─kerneloops(pid: 1067)
 95 | [ 3946.080406]     │   ├─systemd(pid: 1106)
 96 | [ 3946.080407]     │   │   ├─(sd-pam)(pid: 1107)
 97 | [ 3946.080408]     │   │   ├─pipewire(pid: 1118)
 98 | [ 3946.080408]     │   │   ├─pipewire-media-(pid: 1119)
 99 | [ 3946.080409]     │   │   ├─pulseaudio(pid: 1120)
100 | [ 3946.080410]     │   │   ├─snapd-desktop-i(pid: 1122)
101 | [ 3946.080411]     │   │   ├─dbus-daemon(pid: 1134)
102 | [ 3946.080411]     │   │   ├─gvfsd(pid: 1147)
103 | [ 3946.080412]     │   │   │   └─gvfsd-trash(pid: 1508)
104 | [ 3946.080413]     │   │   ├─gvfsd-fuse(pid: 1174)
105 | [ 3946.080414]     │   │   ├─gnome-session-c(pid: 1207)
106 | [ 3946.080415]     │   │   ├─gnome-session-b(pid: 1216)
107 | [ 3946.080416]     │   │   │   ├─at-spi-bus-laun(pid: 1241)
108 | [ 3946.080416]     │   │   │   │   └─dbus-daemon(pid: 1253)
109 | [ 3946.080417]     │   │   │   ├─evolution-alarm(pid: 1592)
110 | [ 3946.080418]     │   │   │   ├─fcitx5(pid: 1618)
111 | [ 3946.080418]     │   │   │   ├─gsd-disk-utilit(pid: 1635)
112 | [ 3946.080419]     │   │   │   └─update-notifier(pid: 2811)
113 | [ 3946.080420]     │   │   ├─gnome-shell(pid: 1242)
114 | [ 3946.080421]     │   │   │   └─Xwayland(pid: 1692)
115 | [ 3946.080606]     │   │   ├─xdg-document-po(pid: 1300)
116 | [ 3946.080618]     │   │   ├─xdg-permission-(pid: 1303)
117 | [ 3946.080619]     │   │   ├─evolution-sourc(pid: 1411)
118 | [ 3946.080620]     │   │   ├─dconf-service(pid: 1425)
119 | [ 3946.080621]     │   │   ├─gvfs-udisks2-vo(pid: 1432)
120 | [ 3946.080622]     │   │   ├─xdg-desktop-por(pid: 1434)
121 | [ 3946.080622]     │   │   ├─gnome-shell-cal(pid: 1404)
122 | [ 3946.080623]     │   │   ├─evolution-calen(pid: 1440)
123 | [ 3946.080624]     │   │   ├─xdg-desktop-por(pid: 1444)
124 | [ 3946.080624]     │   │   ├─gvfs-mtp-volume(pid: 1448)
125 | [ 3946.080625]     │   │   ├─gvfs-afc-volume(pid: 1453)
126 | [ 3946.080626]     │   │   ├─gvfs-gphoto2-vo(pid: 1458)
127 | [ 3946.080627]     │   │   ├─gvfs-goa-volume(pid: 1466)
128 | [ 3946.080627]     │   │   ├─evolution-addre(pid: 1483)
129 | [ 3946.080628]     │   │   ├─goa-daemon(pid: 1424)
130 | [ 3946.080628]     │   │   ├─goa-identity-se(pid: 1482)
131 | [ 3946.080629]     │   │   ├─at-spi2-registr(pid: 1519)
132 | [ 3946.080630]     │   │   ├─gsd-a11y-settin(pid: 1541)
133 | [ 3946.080631]     │   │   ├─gsd-color(pid: 1545)
134 | [ 3946.080632]     │   │   ├─gsd-datetime(pid: 1547)
135 | [ 3946.080632]     │   │   ├─gsd-housekeepin(pid: 1549)
136 | [ 3946.080643]     │   │   ├─gsd-keyboard(pid: 1551)
137 | [ 3946.080644]     │   │   ├─gsd-media-keys(pid: 1557)
138 | [ 3946.080644]     │   │   ├─gsd-power(pid: 1560)
139 | [ 3946.080645]     │   │   ├─gsd-print-notif(pid: 1563)
140 | [ 3946.080646]     │   │   ├─gsd-rfkill(pid: 1575)
141 | [ 3946.080647]     │   │   ├─gsd-screensaver(pid: 1577)
142 | [ 3946.080647]     │   │   ├─gsd-sharing(pid: 1580)
143 | [ 3946.080648]     │   │   ├─gsd-smartcard(pid: 1585)
144 | [ 3946.080648]     │   │   ├─gjs(pid: 1518)
145 | [ 3946.080649]     │   │   ├─gsd-sound(pid: 1606)
146 | [ 3946.080650]     │   │   ├─gsd-wacom(pid: 1614)
147 | [ 3946.080650]     │   │   ├─vmtoolsd(pid: 1640)
148 | [ 3946.080651]     │   │   ├─gsd-printer(pid: 1668)
149 | [ 3946.080652]     │   │   ├─snap-store(pid: 1686)
150 | [ 3946.080652]     │   │   ├─xdg-desktop-por(pid: 1929)
151 | [ 3946.080653]     │   │   ├─gjs(pid: 1954)
152 | [ 3946.080654]     │   │   ├─tracker-miner-f(pid: 2131)
153 | [ 3946.080655]     │   │   ├─gsd-xsettings(pid: 2195)
154 | [ 3946.080655]     │   │   ├─gvfsd-metadata(pid: 2270)
155 | [ 3946.080656]     │   │   ├─gnome-terminal(pid: 2300)
156 | [ 3946.080657]     │   │   │   └─gnome-terminal.(pid: 2305)
157 | [ 3946.080658]     │   │   ├─gnome-terminal-(pid: 2316)
158 | [ 3946.080658]     │   │   │   └─zsh(pid: 2347)
159 | [ 3946.080659]     │   │   ├─zsh(pid: 2363)
160 | [ 3946.080660]     │   │   │   └─gitstatusd-linu(pid: 2408)
161 | [ 3946.080670]     │   │   ├─zsh(pid: 2405)
162 | [ 3946.080670]     │   │   └─zsh(pid: 2407)
163 | [ 3946.080671]     │   ├─rtkit-daemon(pid: 1124)
164 | [ 3946.080672]     │   ├─gnome-keyring-d(pid: 1126)
165 | [ 3946.080673]     │   ├─upowerd(pid: 1413)
166 | [ 3946.080673]     │   ├─packagekitd(pid: 1497)
167 | [ 3946.080674]     │   ├─colord(pid: 1747)
168 | [ 3946.080675]     │   ├─fwupd(pid: 2304)
169 | [ 3946.080675]     │   ├─zsh(pid: 3117)
170 | [ 3946.080676]     │   ├─zsh(pid: 3119)
171 | [ 3946.080676]     │   ├─zsh(pid: 3121)
172 | [ 3946.080677]     │   │   └─gitstatusd-linu(pid: 3126)
173 | [ 3946.080678]     │   ├─zsh(pid: 3504)
174 | [ 3946.080679]     │   │   └─gitstatusd-linu(pid: 3543)
175 | [ 3946.080679]     │   ├─zsh(pid: 3540)
176 | [ 3946.080680]     │   └─zsh(pid: 3541)
177 | [ 3946.080681]     └─kthreadd(pid: 2)
178 | [ 3946.080681]         ├─rcu_gp(pid: 3)
179 | [ 3946.080682]         ├─rcu_par_gp(pid: 4)
180 | [ 3946.080683]         ├─netns(pid: 5)
181 | [ 3946.080683]         ├─kworker/0:0H(pid: 7)
182 | [ 3946.080684]         ├─kworker/0:1H(pid: 9)
183 | [ 3946.080684]         ├─mm_percpu_wq(pid: 10)
184 | [ 3946.080685]         ├─rcu_tasks_kthre(pid: 11)
185 | [ 3946.080686]         ├─rcu_tasks_rude_(pid: 12)
186 | [ 3946.080686]         ├─rcu_tasks_trace(pid: 13)
187 | [ 3946.080687]         ├─ksoftirqd/0(pid: 14)
188 | [ 3946.080687]         ├─rcu_preempt(pid: 15)
189 | [ 3946.080688]         ├─migration/0(pid: 16)
190 | [ 3946.080688]         ├─idle_inject/0(pid: 17)
191 | [ 3946.080689]         ├─kworker/0:1(pid: 18)
192 | [ 3946.080690]         ├─cpuhp/0(pid: 19)
193 | [ 3946.080690]         ├─cpuhp/1(pid: 20)
194 | [ 3946.080691]         ├─idle_inject/1(pid: 21)
195 | [ 3946.080691]         ├─migration/1(pid: 22)
196 | [ 3946.080692]         ├─ksoftirqd/1(pid: 23)
197 | [ 3946.080693]         ├─kworker/1:0H(pid: 25)
198 | [ 3946.080693]         ├─cpuhp/2(pid: 26)
199 | [ 3946.080694]         ├─idle_inject/2(pid: 27)
200 | [ 3946.080695]         ├─migration/2(pid: 28)
201 | [ 3946.080695]         ├─ksoftirqd/2(pid: 29)
202 | [ 3946.080696]         ├─kworker/2:0H(pid: 31)
203 | [ 3946.080696]         ├─cpuhp/3(pid: 32)
204 | [ 3946.080697]         ├─idle_inject/3(pid: 33)
205 | [ 3946.080698]         ├─migration/3(pid: 34)
206 | [ 3946.080698]         ├─ksoftirqd/3(pid: 35)
207 | [ 3946.080699]         ├─kworker/3:0(pid: 36)
208 | [ 3946.080708]         ├─kworker/3:0H(pid: 37)
209 | [ 3946.080709]         ├─cpuhp/4(pid: 38)
210 | [ 3946.080710]         ├─idle_inject/4(pid: 39)
211 | [ 3946.080710]         ├─migration/4(pid: 40)
212 | [ 3946.080711]         ├─ksoftirqd/4(pid: 41)
213 | [ 3946.080711]         ├─kworker/4:0H(pid: 43)
214 | [ 3946.080712]         ├─cpuhp/5(pid: 44)
215 | [ 3946.080713]         ├─idle_inject/5(pid: 45)
216 | [ 3946.080713]         ├─migration/5(pid: 46)
217 | [ 3946.080722]         ├─ksoftirqd/5(pid: 47)
218 | [ 3946.080723]         ├─kworker/5:0H(pid: 49)
219 | [ 3946.080723]         ├─cpuhp/6(pid: 50)
220 | [ 3946.080724]         ├─idle_inject/6(pid: 51)
221 | [ 3946.080724]         ├─migration/6(pid: 52)
222 | [ 3946.080725]         ├─ksoftirqd/6(pid: 53)
223 | [ 3946.080726]         ├─kworker/6:0H(pid: 55)
224 | [ 3946.080726]         ├─cpuhp/7(pid: 56)
225 | [ 3946.080727]         ├─idle_inject/7(pid: 57)
226 | [ 3946.080727]         ├─migration/7(pid: 58)
227 | [ 3946.080728]         ├─ksoftirqd/7(pid: 59)
228 | [ 3946.080729]         ├─kworker/7:0H(pid: 61)
229 | [ 3946.080729]         ├─kdevtmpfs(pid: 62)
230 | [ 3946.080730]         ├─inet_frag_wq(pid: 63)
231 | [ 3946.080730]         ├─kauditd(pid: 64)
232 | [ 3946.080731]         ├─kworker/1:1(pid: 66)
233 | [ 3946.080732]         ├─khungtaskd(pid: 68)
234 | [ 3946.080732]         ├─oom_reaper(pid: 69)
235 | [ 3946.080733]         ├─writeback(pid: 70)
236 | [ 3946.080733]         ├─kcompactd0(pid: 71)
237 | [ 3946.080734]         ├─ksmd(pid: 72)
238 | [ 3946.080735]         ├─khugepaged(pid: 73)
239 | [ 3946.080735]         ├─kintegrityd(pid: 74)
240 | [ 3946.080736]         ├─kblockd(pid: 75)
241 | [ 3946.080736]         ├─blkcg_punt_bio(pid: 76)
242 | [ 3946.080737]         ├─tpm_dev_wq(pid: 79)
243 | [ 3946.080737]         ├─ata_sff(pid: 80)
244 | [ 3946.080738]         ├─md(pid: 81)
245 | [ 3946.080739]         ├─edac-poller(pid: 82)
246 | [ 3946.080739]         ├─devfreq_wq(pid: 83)
247 | [ 3946.080740]         ├─watchdogd(pid: 84)
248 | [ 3946.080740]         ├─kworker/1:1H(pid: 85)
249 | [ 3946.080741]         ├─kswapd0(pid: 86)
250 | [ 3946.080742]         ├─ecryptfs-kthrea(pid: 87)
251 | [ 3946.080742]         ├─kthrotld(pid: 94)
252 | [ 3946.080743]         ├─kworker/5:1(pid: 97)
253 | [ 3946.080743]         ├─kworker/5:2(pid: 98)
254 | [ 3946.080753]         ├─irq/24-pciehp(pid: 102)
255 | [ 3946.080753]         ├─irq/25-pciehp(pid: 103)
256 | [ 3946.080754]         ├─irq/26-pciehp(pid: 104)
257 | [ 3946.080754]         ├─irq/27-pciehp(pid: 105)
258 | [ 3946.080755]         ├─irq/28-pciehp(pid: 106)
259 | [ 3946.080756]         ├─irq/29-pciehp(pid: 107)
260 | [ 3946.080756]         ├─irq/30-pciehp(pid: 108)
261 | [ 3946.080757]         ├─irq/31-pciehp(pid: 109)
262 | [ 3946.080758]         ├─irq/32-pciehp(pid: 110)
263 | [ 3946.080758]         ├─irq/33-pciehp(pid: 111)
264 | [ 3946.080759]         ├─irq/34-pciehp(pid: 112)
265 | [ 3946.080759]         ├─irq/35-pciehp(pid: 113)
266 | [ 3946.080760]         ├─irq/36-pciehp(pid: 114)
267 | [ 3946.080760]         ├─irq/37-pciehp(pid: 115)
268 | [ 3946.080761]         ├─irq/38-pciehp(pid: 116)
269 | [ 3946.080761]         ├─irq/39-pciehp(pid: 117)
270 | [ 3946.080762]         ├─irq/40-pciehp(pid: 118)
271 | [ 3946.080763]         ├─irq/41-pciehp(pid: 119)
272 | [ 3946.080764]         ├─irq/42-pciehp(pid: 120)
273 | [ 3946.080764]         ├─irq/43-pciehp(pid: 121)
274 | [ 3946.080765]         ├─irq/44-pciehp(pid: 122)
275 | [ 3946.080765]         ├─irq/45-pciehp(pid: 123)
276 | [ 3946.080766]         ├─irq/46-pciehp(pid: 124)
277 | [ 3946.080766]         ├─irq/47-pciehp(pid: 125)
278 | [ 3946.080767]         ├─irq/48-pciehp(pid: 126)
279 | [ 3946.080768]         ├─irq/49-pciehp(pid: 128)
280 | [ 3946.080768]         ├─irq/50-pciehp(pid: 129)
281 | [ 3946.080769]         ├─irq/51-pciehp(pid: 130)
282 | [ 3946.080769]         ├─irq/52-pciehp(pid: 131)
283 | [ 3946.080770]         ├─irq/53-pciehp(pid: 132)
284 | [ 3946.080771]         ├─irq/54-pciehp(pid: 133)
285 | [ 3946.080771]         ├─irq/55-pciehp(pid: 134)
286 | [ 3946.080780]         ├─kworker/4:1(pid: 135)
287 | [ 3946.080781]         ├─acpi_thermal_pm(pid: 136)
288 | [ 3946.080782]         ├─scsi_eh_0(pid: 139)
289 | [ 3946.080782]         ├─scsi_tmf_0(pid: 140)
290 | [ 3946.080783]         ├─scsi_eh_1(pid: 141)
291 | [ 3946.080784]         ├─scsi_tmf_1(pid: 142)
292 | [ 3946.080784]         ├─vfio-irqfd-clea(pid: 143)
293 | [ 3946.080785]         ├─kworker/6:1H(pid: 144)
294 | [ 3946.080785]         ├─kworker/7:1H(pid: 145)
295 | [ 3946.080786]         ├─mld(pid: 147)
296 | [ 3946.080787]         ├─kworker/3:1H(pid: 148)
297 | [ 3946.080788]         ├─ipv6_addrconf(pid: 149)
298 | [ 3946.080788]         ├─kstrp(pid: 154)
299 | [ 3946.080789]         ├─kworker/5:1H(pid: 160)
300 | [ 3946.080789]         ├─zswap-shrink(pid: 161)
301 | [ 3946.080799]         ├─kworker/u257:0(pid: 162)
302 | [ 3946.080799]         ├─charger_manager(pid: 208)
303 | [ 3946.080808]         ├─mpt_poll_0(pid: 259)
304 | [ 3946.080809]         ├─mpt/0(pid: 260)
305 | [ 3946.080810]         ├─kworker/4:1H(pid: 262)
306 | [ 3946.080811]         ├─scsi_eh_2(pid: 265)
307 | [ 3946.080811]         ├─scsi_tmf_2(pid: 266)
308 | [ 3946.080812]         ├─scsi_eh_3(pid: 267)
309 | [ 3946.080813]         ├─scsi_tmf_3(pid: 268)
310 | [ 3946.080813]         ├─scsi_eh_4(pid: 269)
311 | [ 3946.080814]         ├─scsi_tmf_4(pid: 270)
312 | [ 3946.080815]         ├─scsi_eh_5(pid: 271)
313 | [ 3946.080815]         ├─scsi_tmf_5(pid: 272)
314 | [ 3946.080816]         ├─scsi_eh_6(pid: 273)
315 | [ 3946.080817]         ├─scsi_tmf_6(pid: 274)
316 | [ 3946.080817]         ├─scsi_eh_7(pid: 275)
317 | [ 3946.080818]         ├─scsi_tmf_7(pid: 276)
318 | [ 3946.080819]         ├─scsi_eh_8(pid: 277)
319 | [ 3946.080819]         ├─scsi_tmf_8(pid: 278)
320 | [ 3946.080820]         ├─scsi_eh_9(pid: 279)
321 | [ 3946.080820]         ├─scsi_tmf_9(pid: 280)
322 | [ 3946.080821]         ├─scsi_eh_10(pid: 281)
323 | [ 3946.080821]         ├─scsi_tmf_10(pid: 282)
324 | [ 3946.080822]         ├─scsi_eh_11(pid: 283)
325 | [ 3946.080823]         ├─scsi_tmf_11(pid: 284)
326 | [ 3946.080823]         ├─scsi_eh_12(pid: 285)
327 | [ 3946.080824]         ├─scsi_tmf_12(pid: 286)
328 | [ 3946.080824]         ├─scsi_eh_13(pid: 287)
329 | [ 3946.080825]         ├─scsi_tmf_13(pid: 288)
330 | [ 3946.080826]         ├─scsi_eh_14(pid: 289)
331 | [ 3946.080827]         ├─scsi_tmf_14(pid: 290)
332 | [ 3946.080827]         ├─scsi_eh_15(pid: 291)
333 | [ 3946.080828]         ├─scsi_tmf_15(pid: 292)
334 | [ 3946.080828]         ├─scsi_eh_16(pid: 293)
335 | [ 3946.080829]         ├─scsi_tmf_16(pid: 294)
336 | [ 3946.080830]         ├─scsi_eh_17(pid: 295)
337 | [ 3946.080830]         ├─scsi_tmf_17(pid: 296)
338 | [ 3946.080831]         ├─scsi_eh_18(pid: 297)
339 | [ 3946.080832]         ├─scsi_tmf_18(pid: 298)
340 | [ 3946.080832]         ├─scsi_eh_19(pid: 299)
341 | [ 3946.080833]         ├─scsi_tmf_19(pid: 300)
342 | [ 3946.080834]         ├─scsi_eh_20(pid: 301)
343 | [ 3946.080834]         ├─scsi_tmf_20(pid: 302)
344 | [ 3946.080835]         ├─scsi_eh_21(pid: 303)
345 | [ 3946.080835]         ├─scsi_tmf_21(pid: 304)
346 | [ 3946.080836]         ├─scsi_eh_22(pid: 305)
347 | [ 3946.080837]         ├─scsi_tmf_22(pid: 306)
348 | [ 3946.080853]         ├─scsi_eh_23(pid: 307)
349 | [ 3946.080854]         ├─scsi_tmf_23(pid: 308)
350 | [ 3946.080855]         ├─scsi_eh_24(pid: 309)
351 | [ 3946.080855]         ├─scsi_tmf_24(pid: 310)
352 | [ 3946.080856]         ├─scsi_eh_25(pid: 311)
353 | [ 3946.080856]         ├─scsi_tmf_25(pid: 312)
354 | [ 3946.080857]         ├─scsi_eh_26(pid: 313)
355 | [ 3946.080858]         ├─scsi_tmf_26(pid: 314)
356 | [ 3946.080858]         ├─scsi_eh_27(pid: 315)
357 | [ 3946.080859]         ├─scsi_tmf_27(pid: 316)
358 | [ 3946.080859]         ├─scsi_eh_28(pid: 317)
359 | [ 3946.080860]         ├─scsi_tmf_28(pid: 318)
360 | [ 3946.080861]         ├─scsi_eh_29(pid: 319)
361 | [ 3946.080861]         ├─scsi_tmf_29(pid: 320)
362 | [ 3946.080862]         ├─scsi_eh_30(pid: 321)
363 | [ 3946.080862]         ├─scsi_tmf_30(pid: 322)
364 | [ 3946.080863]         ├─scsi_eh_31(pid: 323)
365 | [ 3946.080863]         ├─scsi_tmf_31(pid: 324)
366 | [ 3946.080864]         ├─kworker/u256:24(pid: 345)
367 | [ 3946.080865]         ├─kworker/2:2(pid: 353)
368 | [ 3946.080865]         ├─scsi_eh_32(pid: 354)
369 | [ 3946.080866]         ├─scsi_tmf_32(pid: 355)
370 | [ 3946.080866]         ├─kworker/2:1H(pid: 364)
371 | [ 3946.080867]         ├─jbd2/sda3-8(pid: 386)
372 | [ 3946.080868]         ├─ext4-rsv-conver(pid: 387)
373 | [ 3946.080868]         ├─irq/16-vmwgfx(pid: 522)
374 | [ 3946.080869]         ├─card0-crtc0(pid: 523)
375 | [ 3946.080870]         ├─card0-crtc1(pid: 524)
376 | [ 3946.080870]         ├─card0-crtc2(pid: 525)
377 | [ 3946.080871]         ├─card0-crtc3(pid: 526)
378 | [ 3946.080871]         ├─card0-crtc4(pid: 527)
379 | [ 3946.080872]         ├─card0-crtc5(pid: 528)
380 | [ 3946.080872]         ├─card0-crtc6(pid: 529)
381 | [ 3946.080873]         ├─card0-crtc7(pid: 530)
382 | [ 3946.080874]         ├─cryptd(pid: 563)
383 | [ 3946.080874]         ├─kworker/6:4(pid: 2298)
384 | [ 3946.080875]         ├─kworker/0:0(pid: 3603)
385 | [ 3946.080875]         ├─kworker/1:0(pid: 3604)
386 | [ 3946.080876]         ├─kworker/6:1(pid: 3611)
387 | [ 3946.080877]         ├─kworker/3:2(pid: 3789)
388 | [ 3946.080877]         ├─kworker/2:1(pid: 3856)
389 | [ 3946.080887]         ├─kworker/7:2(pid: 4966)
390 | [ 3946.080887]         ├─kworker/7:3(pid: 4967)
391 | [ 3946.080888]         ├─kworker/4:0(pid: 4972)
392 | [ 3946.080889]         ├─kworker/u256:2(pid: 5082)
393 | [ 3946.080889]         └─kworker/u256:0(pid: 5095)
394 | 
-------------------------------------------------------------------------------- /docs/lab-3.md: -------------------------------------------------------------------------------- 1 | # 实验3 2 | 3 | ### 实现一个模拟的shell 4 | 5 | [查看代码](../lab3/shell) 6 | 7 | (ps: 另外提供了一个 rust 实现的 shell, 这是 [fs-rs 提供的 shell](https://github.com/CelestialMelody/fs-rs/blob/main/src/main.rs) 的参考实现) 8 | 9 | **实验思路** 10 | 11 | 可以使用现有的C语言函数来实现shell命令 12 | 13 | > 参考: [exec族函数 system函数 popen函数 PATH](https://blog.csdn.net/FHNCSDN/article/details/118328231) 14 | 15 | 16 | 17 | 18 | 19 | ### 实现一个管道通信程序 20 | 21 | [查看代码](../lab3/pipe) 22 | 23 | **无名管道** 24 | 25 | 需要指定两个文件描述符, 通过 `pipe` 函数创建一个管道文件使其一端读文件一端写 26 | 27 | 对管道文件的读写和普通文件一样, 直接用 `read` 和 `write` 函数 28 | 29 | 读写之前要调用 `close` 关闭不需要的写读描述符 30 | 31 | ```c 32 | int fd[2]; 33 | pipe(fd); // fd[0]读文件, fd[1]写文件 34 | ``` 35 | 36 | 利用信号量机制, 让子进程先发送消息, 最后父进程接受信息 37 | 38 | [查看代码](../lab3/pipe/pipe.c) 39 | 40 | 41 | 42 | **有名管道** 43 | 44 | 有名管道使用的是 `fifo` 函数, 一个进程写数据, 一个进程读数据 45 | 46 | 对管道文件的读写和普通文件一样, 直接用 open, write, 和 read 函数 47 | 48 | ```c 49 | int mkfifo(const char * pathname, mode_t mode); // pathname为管道文件所在地址,mode为管道文件权限 50 | ``` 51 | 52 | 1. 可以使用 fork 实现(三个子进程与一个父进程) [查看代码](../lab3/pipe/fifopipe.c) 53 | 54 | 2. 分出读写有名管道(一个进程读, 一个进程写) [读进程](../lab3/pipe/fifo_read.c) [写进程](../lab3/pipe/fifo_write.c) 55 | 56 | 分别启动两个进程, 一方发送, 一方接收, 直达发送放发送 "exit" 57 | 58 | > 使用前, 如果之前的有名管道存在, 先清理有名管道 (rm fifoname) 59 | > 60 | > 如果使用 Ctrl + c/z/d 强制退出, 记得先清理有名管道 (rm fifoname) 61 | > 62 | > 另外, 最后需要的效果看情况调整, 实现包括: 63 | > 64 | > - 一直读取数据直到输入 quit 或者 exit 65 | > - 读取指定的字节数 直到管道为空 66 | 67 | 68 | 69 | **统计无名管道大小** 70 | 71 | 让一个线程不断往无名管道中写入数据, 直至管道写满后阻塞 72 | 73 | 另一个线程等待若干时间后(此时管道已写满), 输出管道写入数据大小 74 | 75 | [查看代码](../lab3/pipe/size_of_pipe.c) 76 | 77 | 78 | 79 | ### 利用Linux的消息队列通信机制实现两个线程间的通信 80 | 81 | 包括多进程(线程)同步、互斥通信 82 | 83 | sender1, sender2 给 reciver 发消息; 当 sender 发送 "exit" 时自己退出; 当 reciver 收到 sender1, sender2 两者的 "exit" 时退出 84 | 85 | > 代码分别有三个文件夹 86 | > 87 | > _thread: 使用线程实现, 实际效果不好(仅供参考) 88 | > 89 | > _fifo: 借助 fifo 实现(参考学长代码修改版, 虽然代码确实是使用了消息队列, 但仍然借助了有名管道实现) 90 | > 91 | > procee_mq: 使用消息队列机制实现 92 | 93 | [查看代码](../lab3/mq) [推荐使用](../lab3/mq/process_mq) 94 | 95 | 96 | 97 | ### 利用Linux的共享内存通信机制实现两个进程间的通信 98 | 99 | 实现双向通信 100 | 101 | 当前实现中使用 3 个信号量: send, recv1, recv2 102 | 103 | 假设 user1 获取 send, 当 user1 发送完成后, signal(recv2), 通知 user2 可以发送与接收; 104 | 105 | 当 user2 获取到 recv2, 读取后内容后, signal(send), 于是 user1 与 user2 可以任意一方获取 send 发送; 106 | 107 | 直到一方发送 "over" 108 | 109 | [查看代码](../lab3/shm) 110 | 111 | 112 | 113 | 114 | 115 | **🍡说明** 116 | 117 | *本实验主要参考了学长代码 [github](https://github.com/plussone/HDU-operation-system-course-design-code) 我进行了参考, 学习, 修改* 118 | 119 | *另外, 学长也基本对整个操作系统实验进行了详细的分享 [地址](https://blog.csdn.net/qq_34851605/category_10779696.html)* 120 | 121 | *本章内容也是参考了学长的分享 非常感谢学长的分享❤️* 122 | 123 | 124 | 125 | 126 | 127 | *其他参考资料* 128 | 129 | > [exec 族](https://book.itheima.net/course/223/1277519158031949826/1277528003525484545) 130 | > 131 | > *进程间通信* 132 | > 133 | > - [匿名管道](https://book.itheima.net/course/223/1277519158031949826/1277528240394608641) 134 | > - [有名管道](https://book.itheima.net/course/223/1277519158031949826/1277528240402997249) 135 | > 136 | > - [消息队列](https://book.itheima.net/course/223/1277519158031949826/1277528201857343489) 137 | > - [共享内存](https://book.itheima.net/course/223/1277519158031949826/1277528201861537793) 138 | > 139 | > *线程同步* 140 | > 141 | > - [信号量](https://book.itheima.net/course/223/1277519158031949826/1277528625427521540) -------------------------------------------------------------------------------- /docs/pic/mixed_index_fs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CelestialMelody/HDU-OS-LAB/843d0a73cda7063c156a50c5d8120796d8b303ff/docs/pic/mixed_index_fs.png -------------------------------------------------------------------------------- /docs/pta.md: -------------------------------------------------------------------------------- 1 | # PAT题目 2 | 3 | ### 模拟进程链表基本操作 4 | 5 | 请用C语言编写一个进程信息管理程序,以链表的方式管理进程信息。 6 | 7 | 输入n(n>=5)个进程的信息,程序中统一按优先级进行对进程pid排序,如果优先级相同再按pid进行次序。编程实现对进程信息节点的查找find、排序sort、添加append、修改modify、删除delete和插入insert等功能。 8 | 9 | **输入样例** 10 | 11 |
12 | 展开查看 13 |

 14 | 1、在这里给出一组sort操作的输入数据。例如:
 15 | 
 16 | ```in
 17 | 170210 mkdir 20 3
 18 | 170209 pwd 22 6
 19 | 170208 ps 18 5 
 20 | 170207 who 18 7 
 21 | 170206 whoami 19 8 
 22 | 170205 ifconfig 21 2 
 23 | 170204 gcc 19 1 
 24 | 170203 find 18 4
 25 | 170202 grep 21 9 
 26 | 170201 more 22 10
 27 | sort
 28 | ```
 29 | 
 30 | 2、在这里给出一组append操作的输入数据。例如:
 31 | 
 32 | ```in
 33 | 170210 mkdir 20 3
 34 | 170209 pwd 22 6
 35 | 170208 ps 18 5 
 36 | 170207 who 18 7 
 37 | 170206 whoami 19 8 
 38 | 170205 ifconfig 21 2 
 39 | 170204 gcc 19 1 
 40 | 170203 find 18 4
 41 | 170202 grep 21 9 
 42 | 170201 more 22 10
 43 | append 170211 vim 21 15
 44 | ```
 45 | 
 46 | 3、在这里给出一组modify操作的输入数据。例如:
 47 | 
 48 | ```in
 49 | 170210 mkdir 20 3
 50 | 170209 pwd 22 6
 51 | 170208 ps 18 5
 52 | 170207 who 18 7
 53 | 170206 whoami 19 8
 54 | 170205 ifconfig 21 2
 55 | 170204 gcc 19 1
 56 | 170203 find 18 4
 57 | 170202 grep 21 9
 58 | 170201 more 22 10
 59 | modify 170203 5
 60 | ```
 61 | 
 62 | 4、在这里给出一组delete操作的输入数据。例如:
 63 | 
 64 | ```in
 65 | 170210 mkdir 20 3
 66 | 170209 pwd 22 6
 67 | 170208 ps 18 5 
 68 | 170207 who 18 7 
 69 | 170206 whoami 19 8 
 70 | 170205 ifconfig 21 2 
 71 | 170204 gcc 19 1 
 72 | 170203 find 18 4
 73 | 170202 grep 21 9 
 74 | 170201 more 22 10
 75 | delete 170208
 76 | ```
 77 | 
 78 | 5、在这里给出一组insert操作的输入数据。例如:
 79 | 
 80 | ```in
 81 | 170210 mkdir 20 3
 82 | 170209 pwd 22 6
 83 | 170208 ps 18 5 
 84 | 170207 who 18 7 
 85 | 170206 whoami 19 8 
 86 | 170205 ifconfig 21 2 
 87 | 170204 gcc 19 1 
 88 | 170203 find 18 4
 89 | 170202 grep 21 9 
 90 | 170201 more 22 10
 91 | insert 170209 170211 vim 21 15
 92 | ```
 93 | 
 94 | 6、在这里给出一组find操作的输入数据。例如:
 95 | 
 96 | ```in
 97 | 170210 mkdir 20 3
 98 | 170209 pwd 22 6
 99 | 170208 ps 18 5 
100 | 170207 who 18 7 
101 | 170206 whoami 19 8 
102 | 170205 ifconfig 21 2 
103 | 170204 gcc 19 1 
104 | 170203 find 18 4
105 | 170202 grep 21 9 
106 | 170201 more 22 10
107 | find 170203
108 | ```
109 | 
110 |
111 | 112 | **输出样例** 113 | 114 |
115 | 展开查看 116 |

117 | 1、在这里给出sort操作的相应输出。例如:
118 | 
119 | ```out
120 | 170204
121 | 170205
122 | 170210
123 | 170203
124 | 170208
125 | 170209
126 | 170207
127 | 170206
128 | 170202
129 | 170201
130 | ```
131 | 
132 | 2、在这里给出append操作的相应输出。例如:
133 | 
134 | ```out
135 | 170210
136 | 170209
137 | 170208
138 | 170207
139 | 170206
140 | 170205
141 | 170204
142 | 170203
143 | 170202
144 | 170201
145 | 170211
146 | ```
147 | 
148 | 3、在这里给出modify操作的相应输出。例如:
149 | 
150 | ```out
151 | 170203
152 | 5
153 | ```
154 | 
155 | 4、在这里给出delete操作的相应输出。例如:
156 | 
157 | ```out
158 | 170210
159 | 170209
160 | 170207
161 | 170206
162 | 170205
163 | 170204
164 | 170203
165 | 170202
166 | 170201
167 | ```
168 | 
169 | 5、在这里给出insert操作的相应输出。例如:
170 | 
171 | ```out
172 | 170210
173 | 170209
174 | 170211
175 | 170208
176 | 170207
177 | 170206
178 | 170205
179 | 170204
180 | 170203
181 | 170202
182 | 170201
183 | ```
184 | 
185 | 6、在这里给出find操作的相应输出。例如:
186 | 
187 | ```out
188 | 170203
189 | 4
190 | ```
191 | 
192 |
193 | 194 | 195 | 196 | ### 模拟进程调度 197 | 198 | 请你编写一个C语言程序,模拟若干进程调度执行的情况。假设进程的状态分为执行和就绪两种。每个进程以其PCB为代表即可,无需创建真正的进程。以链表的方式组织PCB,分为二个队列:readyQueue就绪队列和runningQueue执行队列。 199 | 200 | 程序开始运行时,用户输入进程调度方式:先来先服务(FCFS)或短进程优先(SPF),进程数量n,以及每个进程需要运行的时间t0/t1/…/tn,先创建进程PCB,然后插入到readyQueue队列中。程序先从就绪队列中按FCFS或SPF选择一个进程投入运行(注:需要将该PCB中的状态变量赋值为“运行”)。相应的修改其所在队列,再将原来处于运行态的进程需要转变为“就绪”态,插入readyQueue队列。 201 | 202 | 假设时间片是2,进程每次调度运行后,其还需运行的时间应该减少2,直至为0,即表示该进程执行完毕。 203 | 204 | **输入样例** 205 |
206 | 展开查看 207 |

208 | 1、在这里给出一组输入。例如:
209 | 
210 | ```in
211 | fcfs 3
212 | 12 6 8
213 | ```
214 | 
215 | 2、在这里给出一组输入。例如:
216 | 
217 | ```in
218 | FCFS 5
219 | 10 2 5 8 6
220 | ```
221 | 
222 | 3、在这里给出一组输入。例如:
223 | 
224 | ```in
225 | spf 8
226 | 8 4 7 3 1 6 4 5
227 | ```
228 | 
229 |
230 | 231 | **输出样例** 232 | 233 |
234 | 展开查看 235 |

236 | 1、在这里给出相应的输出。例如:
237 | 
238 | ```out
239 | fcfs
240 | P00
241 | P01
242 | P02
243 | P00
244 | P01
245 | P02
246 | P00
247 | P01
248 | P02
249 | P00
250 | P02
251 | P00
252 | P00
253 | ```
254 | 
255 | 2、在这里给出相应的输出。例如:
256 | 
257 | ```out
258 | FCFS
259 | P00
260 | P01
261 | P02
262 | P03
263 | P04
264 | P00
265 | P02
266 | P03
267 | P04
268 | P00
269 | P02
270 | P03
271 | P04
272 | P00
273 | P03
274 | P00
275 | ```
276 | 
277 | 3、在这里给出相应的输出。例如:
278 | 
279 | ```out
280 | spf
281 | P04
282 | P03
283 | P01
284 | P03
285 | P01
286 | P06
287 | P07
288 | P06
289 | P07
290 | P05
291 | P07
292 | P05
293 | P02
294 | P05
295 | P02
296 | P00
297 | P02
298 | P00
299 | P02
300 | P00
301 | P00
302 | ```
303 | 
304 |
305 | 306 | ### 模拟银行家算法 307 | 308 | 请你编写一个实现银行家算法的程序,输入进程需要的最大资源需求,进程已经拥有的系统资源和还预留的系统资源,再输入T0时刻Pi申请的系统资源数,请用银行家算法进行安全性检查,如果系统安全,则输出进程运行的安全序列,如果系统不安全,输入unsafe。 309 | 310 | 要求:按资源需求量最小优先的原则选取进程的运行顺序。 311 | 312 | > 输入信息: 313 | > 314 | > 2 5 // 资源总数为2 进程总数为5 315 | > 316 | > // 每个进程需要最大资源数 317 | > 318 | > 2 4 // 这行指: 对于第一个进程(进程0),需要第一类资源 2 个单位, 需要第二类资源 4 个单位 319 | > 320 | > 10 2 321 | > 322 | > 5 4 323 | > 324 | > 3 1 325 | > 326 | > 4 2 327 | > 328 | > // 进程已拥有的资源数 329 | > 330 | > 2 0 331 | > 332 | > 3 2 // 这行指: 对于第二个进程(进程1),已分配的第一类资源 3 个单位, 已分配的第二类资源 2 个单位 333 | > 334 | > 1 4 335 | > 336 | > 2 1 337 | > 338 | > 0 0 339 | > 340 | > // 系统预留的资源数 341 | > 342 | > 2 7 // 这行指: 系统剩余的第一类资源为 2 个单位, 第二类资源 7 个单位 343 | > 344 | > 0 0 4 // 进程编号, 申请数, 进程 0 申请(第一类资源数 0, 第二类资源数 4) 345 | 346 | 347 | 348 | **输入样例** 349 | 350 |
351 | 展开查看 352 |

353 | 1、在这里给出一组输入。例如:
354 | 
355 | ```in
356 | 2 5
357 | 2 4
358 | 10 2
359 | 5 4
360 | 3 1
361 | 4 2
362 | 2 0
363 | 3 2
364 | 1 4
365 | 2 1
366 | 0 0
367 | 2 7
368 | 0 0 4
369 | ```
370 | 
371 | 2、在这里给出一组输入。例如:
372 | 
373 | ```in
374 | 2 5
375 | 2 4
376 | 10 2
377 | 5 4
378 | 3 1
379 | 4 2
380 | 2 0
381 | 3 2
382 | 1 4
383 | 2 1
384 | 0 0
385 | 2 7
386 | 1 2 0
387 | ```
388 | 
389 | 3、在这里给出一组输入。例如:
390 | 
391 | ```in
392 | 3 5
393 | 7 5 3
394 | 3 2 2
395 | 9 0 2
396 | 2 2 2
397 | 4 3 3
398 | 0 1 0
399 | 2 0 0
400 | 3 0 2
401 | 2 1 1
402 | 0 0 2
403 | 3 3 2
404 | 0 3 3 0
405 | ```
406 | 
407 |
408 | 409 | **输出样例** 410 | 411 |
412 | 展开查看 413 |

414 | 1、在这里给出相应的输出。例如:
415 | 
416 | ```out
417 | safe
418 | P00
419 | P03
420 | P02
421 | P04
422 | P01
423 | ```
424 | 
425 | 2、在这里给出相应的输出。例如:
426 | 
427 | ```out
428 | safe
429 | P00
430 | P03
431 | P02
432 | P01
433 | P04
434 | ```
435 | 
436 | 3、在这里给出相应的输出。例如:
437 | 
438 | ```out
439 | unsafe
440 | ```
441 | 
442 |
-------------------------------------------------------------------------------- /lab2/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := pstree.o 2 | 3 | TARGET := $(obj-m:.o=) 4 | MOD := $(obj-m:.o=).ko 5 | pid ?= 1 6 | LEN ?= 1000 7 | 8 | KDIR := /lib/modules/$(shell uname -r)/build 9 | PWD := $(shell pwd) 10 | 11 | default: 12 | make -C $(KDIR) M=$(PWD) modules 13 | 14 | insmod: default 15 | sudo insmod $(MOD) pid=$(pid) 16 | sudo dmesg | tail -$(LEN) 17 | 18 | # 如果通过 lsmod 查看模块,发现模块没有被卸载,可以使用 rmmod 命令卸载模块 19 | clean: 20 | make -C $(KDIR) M=$(PWD) clean 21 | if [ $(shell lsmod | grep $(TARGET) | wc -l) -eq 1 ]; then \ 22 | sudo rmmod $(TARGET); \ 23 | fi 24 | 25 | .PHONY: default insmod clean -------------------------------------------------------------------------------- /lab2/pstree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static pid_t pid = 1; 8 | module_param(pid, int, 0644); 9 | 10 | // 树的先序遍历 11 | // root: 当前进程 12 | // is_last: 当前进程是否是父进程的最后一个孩子(是 true, 不是 false) 13 | // hs_is_last: 当前进程有 兄弟 的同时,是否是父进程的最后一个孩子(是 true, 不是 false) 14 | // prev_msg: 当前进程的前缀(并不是完整的前缀,还缺乏当前进程的信息) 15 | static void print_children(struct task_struct *root, bool is_last, bool has_sibling, char prev_msg[100]) 16 | { 17 | struct task_struct *p_children; 18 | struct task_struct *p_last_children; 19 | struct list_head *p_list; 20 | 21 | // 进程是否有多个孩子(有 true, 没有 false) 22 | bool has_many_children = false; 23 | 24 | // 为孩子构建前缀 25 | char msg[100]; 26 | memset(msg, 0, sizeof(msg)); 27 | // 为了防止对prev_msg直接修改,先复制一份 28 | strcpy(msg, prev_msg); 29 | 30 | // 根据当前进程的位置,构建当前进程完整的前缀 31 | if (is_last) 32 | { 33 | printk("%s└─%s(pid: %d)\n", prev_msg, root->comm, root->pid); 34 | } 35 | else 36 | { 37 | printk("%s├─%s(pid: %d)\n", prev_msg, root->comm, root->pid); 38 | } 39 | 40 | p_list = &root->children; 41 | // 如果没有孩子则返回 42 | if (p_list->next == p_list) 43 | { 44 | return; 45 | } 46 | 47 | p_last_children = list_entry(p_list->prev, struct task_struct, sibling); 48 | 49 | p_list = &root->children; 50 | // 判断孩子有没有兄弟 51 | if (p_list->next->next != p_list) 52 | { 53 | has_many_children = true; 54 | } 55 | else 56 | { 57 | has_many_children = false; 58 | } 59 | 60 | // 为孩子构建前缀 61 | if (has_sibling) 62 | { // 进程有兄弟 63 | if (is_last) 64 | // 进程是父进程的最后一个孩子 65 | strcat(msg, " "); 66 | else 67 | strcat(msg, "│ "); 68 | } 69 | else 70 | { 71 | strcat(msg, " "); 72 | } 73 | 74 | list_for_each(p_list, &root->children) 75 | { 76 | p_children = list_entry(p_list, struct task_struct, sibling); 77 | // 打印最后一个孩子 78 | if (p_children == p_last_children) 79 | { 80 | print_children(p_last_children, true, has_many_children, msg); 81 | } 82 | // 打印其他孩子 83 | else 84 | { 85 | print_children(p_children, false, has_many_children, msg); 86 | } 87 | } 88 | return; 89 | } 90 | 91 | static int pstree_init(void) 92 | { 93 | struct task_struct *pcb; 94 | struct task_struct *p_sibling; 95 | struct task_struct *p_last_sibling; 96 | struct list_head *p_list; 97 | 98 | // 进程是否有兄弟(有 true, 没有 false) 99 | bool has_sibling = false; 100 | 101 | // 为孩子构建前缀 102 | char prev_msg[100]; 103 | 104 | // find_vpid(pid) 通过 pid 查找进程 105 | pcb = pid_task(find_vpid(pid), PIDTYPE_PID); 106 | pr_notice("current process\npid: %d, name: %s, state: %d", pcb->pid, pcb->comm, pcb->__state); 107 | 108 | // 判断有没有父进程 109 | if (pcb->parent == NULL) 110 | { // 没有父进程 111 | sprintf(prev_msg, "none parent"); 112 | pr_notice("%s", prev_msg); 113 | } 114 | else 115 | { // 有父进程,打印父进程信息 116 | sprintf(prev_msg, "%s(pid: %d)", pcb->parent->comm, pcb->parent->pid); 117 | pr_notice("%s", prev_msg); 118 | } 119 | 120 | p_list = &pcb->parent->children; 121 | // 判断有没有兄弟 122 | if (p_list->next->next != p_list) 123 | { // 有兄弟 124 | has_sibling = true; 125 | } 126 | else 127 | { 128 | has_sibling = false; 129 | } 130 | 131 | // 获取最后一个孩子 132 | p_last_sibling = list_entry(p_list->prev, struct task_struct, sibling); 133 | 134 | // 重新构造 prev_msg 135 | // 为孩子构建前缀 136 | sprintf(prev_msg, " "); 137 | 138 | // 遍历所有兄弟 139 | list_for_each(p_list, &pcb->parent->children) 140 | { 141 | // 打印所有兄弟的孩子 142 | // 获取兄弟 143 | p_sibling = list_entry(p_list, struct task_struct, sibling); 144 | // 打印最后一个孩子 145 | if (p_sibling == p_last_sibling) 146 | { 147 | print_children(p_last_sibling, true, has_sibling, prev_msg); 148 | } 149 | // 打印其他孩子 150 | else 151 | { 152 | print_children(p_sibling, false, has_sibling, prev_msg); 153 | } 154 | } 155 | return 0; 156 | } 157 | 158 | static void pstree_exit(void) 159 | { 160 | printk(KERN_ALERT "pstree end\n"); 161 | return; 162 | } 163 | 164 | module_init(pstree_init); 165 | module_exit(pstree_exit); 166 | MODULE_LICENSE("GPL"); -------------------------------------------------------------------------------- /lab3/mq/_fifo/Makefile: -------------------------------------------------------------------------------- 1 | all: sender1 sender2 receiver unlink 2 | 3 | unlink: unlink.c 4 | gcc unlink.c -o unlink 5 | 6 | sender1: sender1.c 7 | gcc sender1.c -pthread -o sender1 8 | 9 | sender2: sender2.c 10 | gcc sender2.c -pthread -o sender2 11 | 12 | receiver: receiver.c 13 | gcc receiver.c -pthread -o receiver 14 | 15 | clean: 16 | # 执行 unlink 后 再执行删除 17 | ./unlink 18 | rm sender1 sender2 receiver unlink -------------------------------------------------------------------------------- /lab3/mq/_fifo/init.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #define FIFO1 "fifo1" 19 | #define FIFO2 "fifo2" 20 | 21 | #define fifofile1 "fifomy1" 22 | #define fifofile2 "fifomy2" 23 | 24 | int fd1, fd2; //消息队列标识符 25 | 26 | sem_t *sem_send; 27 | sem_t *sem_receive; 28 | sem_t *sem_over1; 29 | sem_t *sem_over2; 30 | 31 | //缓冲区mymsg 32 | struct Msgbuf 33 | { 34 | long msg_type; //消息类型1为发送者的消息,2为接收的消息。 35 | int id; // 1为发送者1,2为发送者2。 36 | char text[100]; 37 | }; 38 | 39 | void init() 40 | { 41 | //初始化信号量 42 | sem_send = sem_open("send", O_CREAT, 0666, 1); 43 | sem_receive = sem_open("receive", O_CREAT, 0666, 0); 44 | sem_over1 = sem_open("over1", O_CREAT, 0666, 0); 45 | sem_over2 = sem_open("over2", O_CREAT, 0666, 0); 46 | } -------------------------------------------------------------------------------- /lab3/mq/_fifo/receiver.c: -------------------------------------------------------------------------------- 1 | // receiver.c 2 | #include "init.h" 3 | 4 | int main() 5 | { 6 | int msgid; 7 | int flag_over1 = 0; 8 | int flag_over2 = 0; 9 | struct Msgbuf r_msg; //消息接受区 10 | struct Msgbuf s_msg; 11 | 12 | msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); 13 | 14 | init(); 15 | 16 | mkfifo(fifofile1, 0666); 17 | mkfifo(fifofile2, 0666); 18 | 19 | fd1 = open(fifofile1, O_WRONLY); 20 | fd2 = open(fifofile2, O_WRONLY); 21 | write(fd1, &msgid, sizeof(int)); 22 | sem_post(sem_over1); 23 | write(fd2, &msgid, sizeof(int)); 24 | sem_post(sem_over2); 25 | 26 | // id = (unsigned int)pthread_self(); 27 | s_msg.msg_type = 2; 28 | s_msg.id = 3; 29 | 30 | printf("tid:%u 进程(线程)3:\n", (unsigned int)pthread_self()); 31 | 32 | while (1) 33 | { 34 | sem_wait(sem_receive); 35 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 36 | printf("收到线程%u的消息: %s\n", r_msg.id, r_msg.text); 37 | 38 | if (r_msg.id == 1) 39 | { 40 | if (strcmp(r_msg.text, "end1") == 0) 41 | { 42 | printf("发送给线程1:over1\n"); 43 | strcpy(s_msg.text, "over1"); 44 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 45 | 46 | sem_post(sem_over1); 47 | flag_over1 = 1; 48 | } 49 | else 50 | { 51 | sem_post(sem_send); 52 | } 53 | } 54 | else if (r_msg.id == 2) 55 | { 56 | if (strcmp(r_msg.text, "end2") == 0) 57 | { 58 | printf("发送给线程2:over2\n"); 59 | strcpy(s_msg.text, "over2"); 60 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 61 | 62 | sem_post(sem_over2); 63 | flag_over2 = 1; 64 | } 65 | else 66 | { 67 | sem_post(sem_send); 68 | } 69 | } 70 | 71 | if (flag_over1 && flag_over2) 72 | break; 73 | } 74 | 75 | sem_unlink("send"); 76 | sem_unlink("receive"); 77 | sem_unlink("over1"); 78 | sem_unlink("over2"); 79 | 80 | return 0; 81 | } -------------------------------------------------------------------------------- /lab3/mq/_fifo/sender1.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | int main() 4 | { 5 | char str[100]; 6 | int msgid; 7 | struct Msgbuf r_msg; //消息接受区 8 | struct Msgbuf s_msg; 9 | 10 | init(); 11 | 12 | fd1 = open(fifofile1, O_RDONLY); 13 | sem_wait(sem_over1); 14 | read(fd1, &msgid, sizeof(int)); 15 | 16 | s_msg.msg_type = 1; 17 | s_msg.id = 1; 18 | 19 | printf("tid:%u 进程(线程)1: \n", (unsigned int)pthread_self()); 20 | 21 | while (1) 22 | { 23 | printf("发送:"); 24 | scanf("%[^\n]%*c", str); 25 | 26 | if (strcmp(str, "end1") == 0) 27 | { 28 | printf("退出请发送:exit\n"); 29 | continue; 30 | } 31 | 32 | sem_wait(sem_send); 33 | 34 | if (strcmp(str, "exit") == 0) 35 | { 36 | strcpy(s_msg.text, "end1"); 37 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 38 | sem_post(sem_receive); 39 | break; 40 | } 41 | 42 | strcpy(s_msg.text, str); 43 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 44 | sem_post(sem_receive); 45 | } 46 | sem_wait(sem_over1); 47 | 48 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 49 | printf("收到线程%u的消息: %s\n", r_msg.id, r_msg.text); 50 | 51 | sem_post(sem_send); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /lab3/mq/_fifo/sender2.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | int main() 4 | { 5 | char str[100]; 6 | int msgid; 7 | struct Msgbuf r_msg; //消息接受区 8 | struct Msgbuf s_msg; 9 | 10 | init(); 11 | 12 | fd2 = open(fifofile2, O_RDONLY); 13 | sem_wait(sem_over2); 14 | read(fd2, &msgid, sizeof(int)); 15 | 16 | s_msg.msg_type = 1; 17 | s_msg.id = 2; 18 | 19 | printf("tid:%u 进程(线程)2:\n", (unsigned int)pthread_self()); 20 | 21 | while (1) 22 | { 23 | printf("发送:"); 24 | scanf("%[^\n]%*c", str); 25 | 26 | if (strcmp(str, "end2") == 0) 27 | { 28 | printf("退出请发送:exit\n"); 29 | continue; 30 | } 31 | 32 | sem_wait(sem_send); 33 | 34 | if (strcmp(str, "exit") == 0) 35 | { 36 | strcpy(s_msg.text, "end2"); 37 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 38 | sem_post(sem_receive); 39 | break; 40 | } 41 | 42 | strcpy(s_msg.text, str); 43 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 44 | sem_post(sem_receive); 45 | } 46 | 47 | sem_wait(sem_over2); 48 | 49 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 50 | printf("收到线程%u的消息: %s\n", r_msg.id, r_msg.text); 51 | 52 | sem_post(sem_send); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /lab3/mq/_fifo/unlink.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | int main() 3 | { 4 | sem_unlink("send"); 5 | sem_unlink("receive"); 6 | sem_unlink("over1"); 7 | sem_unlink("over2"); 8 | 9 | unlink(fifofile1); 10 | unlink(fifofile2); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /lab3/mq/_thread/Makefile: -------------------------------------------------------------------------------- 1 | all: mq unlink 2 | 3 | mq: mq.c 4 | $(CC) mq.c -o mq -pthread -g 5 | 6 | unlink: unlink.c 7 | gcc unlink.c -pthread -o unlink 8 | 9 | clean: 10 | rm mq unlink -------------------------------------------------------------------------------- /lab3/mq/_thread/init.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #define SEND 1 19 | #define RECEIVE 2 20 | 21 | int fd1, fd2; //消息队列标识符 22 | 23 | sem_t *sem_send; 24 | sem_t *sem_receive; 25 | sem_t *sem_over1; 26 | sem_t *sem_over2; 27 | 28 | //缓冲区mymsg 29 | struct Msgbuf 30 | { 31 | long msg_type; 32 | int id; // 1为发送者1,2为发送者2。 33 | int tid; //发送者的线程id 34 | char text[100]; 35 | }; 36 | 37 | void init() 38 | { 39 | //初始化信号量 40 | sem_send = sem_open("send", O_CREAT, 0666, 1); 41 | sem_receive = sem_open("receive", O_CREAT, 0666, 0); 42 | sem_over1 = sem_open("over1", O_CREAT, 0666, 0); 43 | sem_over2 = sem_open("over2", O_CREAT, 0666, 0); 44 | } -------------------------------------------------------------------------------- /lab3/mq/_thread/mq.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | void *sender1(void *arg); 4 | void *sender2(void *arg); 5 | void *receiver(void *arg); 6 | 7 | int main() 8 | { 9 | int res = -1; 10 | pthread_t p_t_send1; 11 | pthread_t p_t_send2; 12 | pthread_t p_t_receive; 13 | void *thread_result = NULL; 14 | 15 | //初始化信号量 16 | init(); 17 | 18 | // 创建线程 19 | res = pthread_create(&p_t_send1, NULL, sender1, NULL); 20 | res = pthread_create(&p_t_send2, NULL, sender2, NULL); 21 | res = pthread_create(&p_t_receive, NULL, receiver, NULL); 22 | if (res != 0) 23 | { 24 | perror("pthread_create"); 25 | exit(-1); 26 | } 27 | 28 | // 等待线程结束 29 | res = pthread_join(p_t_receive, &thread_result); // receiver线程结束前提是sender1和sender2线程都结束 30 | if (res != 0) 31 | { 32 | perror("pthread_join"); 33 | exit(-1); 34 | } 35 | 36 | // 销毁信号量 37 | sem_close(sem_send); 38 | sem_close(sem_over1); 39 | sem_close(sem_over2); 40 | sem_close(sem_receive); 41 | 42 | sem_unlink("send"); 43 | sem_unlink("over1"); 44 | sem_unlink("over2"); 45 | sem_unlink("receive"); 46 | 47 | return 0; 48 | } 49 | 50 | void *sender1(void *arg) 51 | { 52 | char str[100]; 53 | int msgid; 54 | struct Msgbuf r_msg; 55 | struct Msgbuf s_msg; 56 | 57 | s_msg.msg_type = SEND; 58 | s_msg.tid = (unsigned int)pthread_self(); 59 | s_msg.id = 1; 60 | 61 | sem_wait(sem_over1); 62 | msgid = msgget((key_t)1000, 0664 | IPC_CREAT); 63 | if (msgid == -1) 64 | { 65 | perror("msgget"); 66 | exit(1); 67 | } 68 | printf("process(id:%d) tid: %u\n", s_msg.id, (unsigned int)pthread_self()); 69 | 70 | while (1) 71 | { 72 | printf("input:\n"); 73 | scanf("%[^\n]%*c", str); 74 | 75 | if (strcmp(str, "end1") == 0) 76 | { 77 | printf("please send \"exit\"\n"); 78 | continue; 79 | } 80 | 81 | sem_wait(sem_send); 82 | 83 | if (strcmp(str, "exit") == 0) 84 | { 85 | strcpy(s_msg.text, "end1"); 86 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 87 | sem_post(sem_receive); 88 | break; 89 | } 90 | 91 | strcpy(s_msg.text, str); 92 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 93 | sem_post(sem_receive); 94 | } 95 | 96 | sem_wait(sem_over1); 97 | 98 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 99 | printf("receive message from %u:\n%s\n", r_msg.id, r_msg.text); 100 | 101 | sem_post(sem_send); 102 | return NULL; 103 | } 104 | 105 | void *sender2(void *arg) 106 | { 107 | char str[100]; 108 | int msgid; 109 | struct Msgbuf r_msg; 110 | struct Msgbuf s_msg; 111 | 112 | s_msg.msg_type = SEND; 113 | s_msg.tid = (unsigned int)pthread_self(); 114 | s_msg.id = 2; 115 | 116 | sem_wait(sem_over2); 117 | msgid = msgget((key_t)1000, 0664 | IPC_CREAT); 118 | if (msgid == -1) 119 | { 120 | perror("msgget"); 121 | exit(1); 122 | } 123 | printf("process(id:%d) tid: %u\n", s_msg.id, (unsigned int)pthread_self()); 124 | 125 | while (1) 126 | { 127 | printf("input:\n"); 128 | scanf("%[^\n]%*c", str); 129 | 130 | if (strcmp(str, "end2") == 0) 131 | { 132 | printf("please send \"exit\"\n"); 133 | continue; 134 | } 135 | 136 | sem_wait(sem_send); 137 | 138 | if (strcmp(str, "exit") == 0) 139 | { 140 | strcpy(s_msg.text, "end2"); 141 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 142 | sem_post(sem_receive); 143 | break; 144 | } 145 | 146 | strcpy(s_msg.text, str); 147 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 148 | sem_post(sem_receive); 149 | } 150 | 151 | sem_wait(sem_over2); 152 | 153 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 154 | printf("receive message from %u:\n%s\n", r_msg.id, r_msg.text); 155 | 156 | sem_post(sem_send); 157 | return NULL; 158 | } 159 | 160 | void *receiver(void *arg) 161 | { 162 | int msgid; 163 | struct Msgbuf r_msg; 164 | struct Msgbuf s_msg; 165 | int flag_over1 = 0; 166 | int flag_over2 = 0; 167 | 168 | msgid = msgget((key_t)1000, 0664 | IPC_CREAT); 169 | if (msgid == -1) 170 | { 171 | perror("msgget"); 172 | exit(1); 173 | } 174 | 175 | sem_post(sem_over1); 176 | sem_post(sem_over2); 177 | 178 | s_msg.msg_type = RECEIVE; 179 | s_msg.tid = (unsigned int)pthread_self(); 180 | s_msg.id = 3; 181 | printf("process(id:%d) tid: %u\n", s_msg.id, (unsigned int)pthread_self()); 182 | 183 | while (1) 184 | { 185 | sem_wait(sem_receive); 186 | 187 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), SEND, 0); 188 | printf("receive: message form sender(id:%d, tid:%u): %s\n", r_msg.id, r_msg.tid, r_msg.text); 189 | 190 | if (r_msg.id == 1) 191 | { 192 | if (strcmp(r_msg.text, "end1") == 0) 193 | { 194 | printf("send message to sender(id:%d, thread %u): over\n", r_msg.id, r_msg.tid); 195 | strcpy(s_msg.text, "over"); 196 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 197 | 198 | sem_post(sem_over1); 199 | flag_over1 = 1; 200 | } 201 | else 202 | { 203 | sem_post(sem_send); 204 | } 205 | } 206 | else if (r_msg.id == 2) 207 | { 208 | if (strcmp(r_msg.text, "end2") == 0) 209 | { 210 | printf("send message to sender(id:%d, thread %u): over\n", r_msg.id, r_msg.tid); 211 | strcpy(s_msg.text, "over"); 212 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 213 | 214 | sem_post(sem_over2); 215 | flag_over2 = 1; 216 | } 217 | else 218 | { 219 | sem_post(sem_send); 220 | } 221 | } 222 | 223 | if (flag_over1 == 1 && flag_over2 == 1) 224 | { 225 | break; 226 | } 227 | } 228 | } -------------------------------------------------------------------------------- /lab3/mq/_thread/unlink.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | int main() 3 | { 4 | sem_unlink("send"); 5 | sem_unlink("receive"); 6 | sem_unlink("over1"); 7 | sem_unlink("over2"); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /lab3/mq/process_mq/Makefile: -------------------------------------------------------------------------------- 1 | all: sender1 sender2 receiver unlink 2 | ./unlink 3 | sender1: sender1.c 4 | gcc sender1.c -pthread -o sender1 5 | sender2: sender2.c 6 | gcc sender2.c -pthread -o sender2 7 | receiver: receiver.c 8 | gcc receiver.c -pthread -o receiver 9 | unlink: 10 | gcc unlink.c -o unlink 11 | clean: 12 | rm sender1 sender2 receiver unlink -------------------------------------------------------------------------------- /lab3/mq/process_mq/init.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | sem_t *sem_send; 19 | sem_t *sem_receive; 20 | sem_t *sem_over1; 21 | sem_t *sem_over2; 22 | 23 | // 缓冲区mymsg 24 | struct Msgbuf 25 | { 26 | long msg_type; // 消息类型1为发送者的消息,2为接收的消息。 27 | int id; // 1为发送者1,2为发送者2, 3为接收者 28 | char text[100]; 29 | }; 30 | 31 | void init() 32 | { 33 | // 初始化信号量 34 | sem_send = sem_open("send", O_CREAT, 0666, 1); 35 | sem_receive = sem_open("receive", O_CREAT, 0666, 0); 36 | sem_over1 = sem_open("over1", O_CREAT, 0666, 0); 37 | sem_over2 = sem_open("over2", O_CREAT, 0666, 0); 38 | } -------------------------------------------------------------------------------- /lab3/mq/process_mq/receiver.c: -------------------------------------------------------------------------------- 1 | // receiver.c 2 | #include "init.h" 3 | 4 | int main() 5 | { 6 | int msgid; 7 | int flag_over1 = 0; 8 | int flag_over2 = 0; 9 | struct Msgbuf r_msg; //消息接受区 10 | struct Msgbuf s_msg; 11 | 12 | msgid = msgget((key_t)1000, 0666 | IPC_CREAT); 13 | 14 | init(); 15 | 16 | sem_post(sem_over1); 17 | sem_post(sem_over2); 18 | 19 | s_msg.msg_type = 2; 20 | s_msg.id = 3; 21 | 22 | printf("process tid: %u\n", (unsigned int)pthread_self()); 23 | 24 | while (1) 25 | { 26 | sem_wait(sem_receive); 27 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 28 | printf("receive message from %u:\n%s\n", r_msg.id, r_msg.text); 29 | 30 | if (r_msg.id == 1) 31 | { 32 | if (strcmp(r_msg.text, "end1") == 0) 33 | { 34 | printf("sending message to process 1: over\n"); 35 | strcpy(s_msg.text, "over1"); 36 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 37 | 38 | sem_post(sem_over1); 39 | flag_over1 = 1; 40 | } 41 | else 42 | { 43 | sem_post(sem_send); 44 | } 45 | } 46 | else if (r_msg.id == 2) 47 | { 48 | if (strcmp(r_msg.text, "end2") == 0) 49 | { 50 | printf("sending message to process 2: over\n"); 51 | strcpy(s_msg.text, "over2"); 52 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 53 | 54 | sem_post(sem_over2); 55 | flag_over2 = 1; 56 | } 57 | else 58 | { 59 | sem_post(sem_send); 60 | } 61 | } 62 | 63 | if (flag_over1 && flag_over2) 64 | break; 65 | } 66 | 67 | sem_unlink("send"); 68 | sem_unlink("receive"); 69 | sem_unlink("over1"); 70 | sem_unlink("over2"); 71 | 72 | return 0; 73 | } -------------------------------------------------------------------------------- /lab3/mq/process_mq/sender1.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | int main() 4 | { 5 | // char str[100]; // bug 6 | int msgid; 7 | struct Msgbuf r_msg; // 消息接受区 8 | struct Msgbuf s_msg; 9 | 10 | init(); 11 | s_msg.msg_type = 1; 12 | s_msg.id = 1; 13 | 14 | sem_wait(sem_over1); // 确保receiver先初始化完成 15 | // 创建消息队列 see https://book.itheima.net/course/223/1277519158031949826/1277528201857343489 16 | msgid = msgget((key_t)1000, 0664 | IPC_CREAT); 17 | if (msgid == -1) 18 | { 19 | perror("msgget"); 20 | exit(1); 21 | } 22 | printf("process tid: %u\n", (unsigned int)pthread_self()); 23 | 24 | while (1) 25 | { 26 | char str[100] = {0}; // fix bug 27 | printf("input:\n"); 28 | 29 | // used 30 | // see https://stackoverflow.com/questions/30065675/what-does-scanf-nc-mean 31 | // scanf("%[^\n]%*c", str); 32 | 33 | fgets(str, 100, stdin); // 会读取空格与换行符 34 | 35 | // used 36 | // if (strcmp(str, "end1") == 0) 37 | if (strncmp(str, "end1", 4) == 0) 38 | { 39 | printf("please send \"exit\"\n"); 40 | continue; 41 | } 42 | 43 | sem_wait(sem_send); 44 | 45 | // used 46 | // if (strcmp(str, "exit") == 0) 47 | 48 | if (strncmp(str, "exit", 4) == 0) 49 | { 50 | strcpy(s_msg.text, "end1"); 51 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 52 | sem_post(sem_receive); 53 | break; 54 | } 55 | 56 | // used 57 | // strcpy(s_msg.text, str); 58 | 59 | // str 丢弃换行符后再发送 60 | str[strlen(str) - 1] = '\0'; // fix bug 61 | // strncpy(s_msg.text, str, strlen(str) - 1); // bug 不会清空s_msg.text 62 | strcpy(s_msg.text, str); 63 | 64 | // test 65 | printf("sender1 str len: %ld\n", strlen(str)); 66 | printf("s_msg.text len: %ld\n", strlen(s_msg.text)); // 发现没有清空 67 | 68 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 69 | sem_post(sem_receive); 70 | } 71 | sem_wait(sem_over1); 72 | 73 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 74 | printf("receive message from %u:\n%s\n", r_msg.id, r_msg.text); 75 | 76 | sem_post(sem_send); 77 | return 0; 78 | } -------------------------------------------------------------------------------- /lab3/mq/process_mq/sender2.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | int main() 4 | { 5 | // char str[100]; // bug 6 | int msgid; 7 | struct Msgbuf r_msg; // 消息接受区 8 | struct Msgbuf s_msg; 9 | 10 | init(); 11 | s_msg.msg_type = 1; 12 | s_msg.id = 2; 13 | 14 | sem_wait(sem_over2); // 确保receiver先初始化完成 15 | msgid = msgget((key_t)1000, 0664 | IPC_CREAT); // 创建消息队列 16 | if (msgid == -1) 17 | { 18 | perror("msgget"); 19 | exit(1); 20 | } 21 | printf("process tid: %u\n", (unsigned int)pthread_self()); 22 | 23 | while (1) 24 | { 25 | char str[100] = {0}; // fix bug 26 | printf("input:\n"); 27 | // used 28 | // scanf("%[^\n]%*c", str); // see https://stackoverflow.com/questions/30065675/what-does-scanf-nc-mean 29 | // 但是没法读取空格 30 | 31 | fgets(str, 100, stdin); // 会读取空格与换行符 32 | 33 | // used 34 | // if (strcmp(str, "end2") == 0) 35 | 36 | if (strncmp(str, "end2", 4) == 0) 37 | { 38 | printf("please send \"exit\"\n"); 39 | continue; 40 | } 41 | 42 | sem_wait(sem_send); 43 | 44 | // used 45 | // if (strcmp(str, "exit") == 0) 46 | 47 | if (strncmp(str, "exit", 4) == 0) 48 | { 49 | strcpy(s_msg.text, "end2"); 50 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 51 | sem_post(sem_receive); 52 | break; 53 | } 54 | 55 | // used 56 | // strcpy(s_msg.text, str); 57 | 58 | // str 丢弃换行符后再发送 59 | str[strlen(str) - 1] = '\0'; // fix bug 60 | // strncpy(s_msg.text, str, strlen(str) - 1); // bug 不会清空s_msg.text 61 | strcpy(s_msg.text, str); 62 | 63 | // test 64 | printf("sender2 str len: %ld\n", strlen(str)); 65 | printf("s_msg.text len: %ld\n", strlen(s_msg.text)); 66 | 67 | msgsnd(msgid, &s_msg, sizeof(struct Msgbuf), 0); 68 | sem_post(sem_receive); 69 | } 70 | sem_wait(sem_over2); 71 | 72 | msgrcv(msgid, &r_msg, sizeof(struct Msgbuf), 0, 0); 73 | printf("receive message from %u:\n%s\n", r_msg.id, r_msg.text); 74 | 75 | sem_post(sem_send); 76 | return 0; 77 | } -------------------------------------------------------------------------------- /lab3/mq/process_mq/unlink.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | int main() 3 | { 4 | sem_unlink("send"); 5 | sem_unlink("receive"); 6 | sem_unlink("over1"); 7 | sem_unlink("over2"); 8 | 9 | return 0; 10 | } -------------------------------------------------------------------------------- /lab3/pipe/Makefile: -------------------------------------------------------------------------------- 1 | SRC := $(wildcard ./*.c) 2 | APP = $(patsubst %.c, %, $(SRC)) 3 | 4 | all: pipe fifo_read fifo_write size_of_pipe fifo 5 | 6 | pipe : 7 | gcc pipe.c -o pipe -pthread 8 | 9 | fifo : 10 | gcc fifo.c -o fifo -pthread 11 | 12 | fifo_read : 13 | gcc fifo_read.c -o fifo_read -pthread 14 | 15 | fifo_write : 16 | gcc fifo_write.c -o fifo_write -pthread 17 | 18 | size_of_pipe : 19 | gcc size_of_pipe.c -o size_of_pipe -pthread 20 | 21 | clean: 22 | # 如果文件存在,就删除 23 | for i in $(APP); do \ 24 | if [ -f $$i ]; then \ 25 | rm $$i; \ 26 | fi; \ 27 | done -------------------------------------------------------------------------------- /lab3/pipe/fifo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | char buf[1024]; 16 | char temp[256]; 17 | int id; 18 | int fd; 19 | int ret; 20 | sem_t *mutex; 21 | sem_t *receive1; 22 | sem_t *receive2; 23 | sem_t *receive3; 24 | pid_t pid; 25 | 26 | if (argc < 2) 27 | { // 判断是否输入了文件名 28 | printf("miss fifoname\n"); 29 | exit(1); 30 | } 31 | ret = access(argv[1], F_OK); // 判断文件是否存在 32 | if (-1 == ret) 33 | { 34 | int ret = mkfifo(argv[1], 0664); // 创建FIFO文件 35 | if (-1 == ret) 36 | { 37 | perror("mkfifo error"); 38 | exit(1); 39 | } 40 | // else if (0 == ret) 41 | // { 42 | // printf("mkfifo success"); 43 | // } 44 | } 45 | 46 | memset(buf, 0, sizeof(buf)); // initialize buffer 47 | memset(temp, 0, sizeof(temp)); 48 | sem_unlink("mutex"); // unlink semaphore if it exists 49 | sem_unlink("send1"); 50 | sem_unlink("receive1"); 51 | 52 | mutex = sem_open("mutex", O_CREAT, 0644, 1); // sem_open(name, flag, mode, value); 53 | receive1 = sem_open("receive1", O_CREAT, 0644, 0); 54 | receive2 = sem_open("receive2", O_CREAT, 0644, 0); 55 | receive3 = sem_open("receive3", O_CREAT, 0644, 0); 56 | 57 | for (id = 0; id < 3; id++) 58 | { // create 3 child processes 59 | pid = fork(); 60 | if (0 == pid) // child process 61 | { 62 | break; 63 | } 64 | if (0 > pid) 65 | { 66 | sem_close(mutex); 67 | sem_close(receive1); 68 | sem_close(receive2); 69 | sem_close(receive3); 70 | 71 | sem_unlink("mutex"); 72 | sem_unlink("receive1"); 73 | sem_unlink("receive2"); 74 | sem_unlink("receive3"); 75 | 76 | perror("fork"); 77 | exit(1); 78 | } 79 | } 80 | 81 | if (3 == id) 82 | { // parent process 83 | fd = open(argv[1], O_RDONLY); // 需要同时获取 84 | sem_wait(receive1); // wait for signal from child 85 | sem_wait(receive2); 86 | sem_wait(receive3); 87 | sem_wait(mutex); // lock 88 | 89 | read(fd, buf, sizeof(buf)); // read from pipe 90 | printf("parent read: %s\n", buf); 91 | 92 | // int size = 0; 93 | // ret = ioctl(fd, FIONREAD, &size); 94 | // if (-1 == ret) 95 | // { 96 | // perror("ioctl"); 97 | // exit(1); 98 | // } 99 | // printf("fifo size is %d\n", size); 100 | 101 | // int count = 0; 102 | // while (1) 103 | // { 104 | // memset(buf, 0, sizeof(buf)); 105 | // printf("please input the counts of chars you want to read:\n"); 106 | // if (!scanf("%d", &count)) 107 | // { 108 | // sem_post(mutex); // unlock 109 | // close(fd); 110 | 111 | // sem_close(mutex); 112 | // sem_close(receive1); 113 | // sem_close(receive2); 114 | // sem_close(receive3); 115 | 116 | // sem_unlink("mutex"); 117 | // sem_unlink("receive1"); 118 | // sem_unlink("receive2"); 119 | // sem_unlink("receive3"); 120 | // unlink(argv[1]); 121 | 122 | // perror("scanf"); 123 | // exit(1); 124 | // } 125 | // read(fd, buf, count); // read from pipe 126 | // printf("Parent (pid:%d) receive: %s\n", getpid(), buf); 127 | 128 | // ret = ioctl(fd, FIONREAD, &size); 129 | // if (-1 == ret) 130 | // { 131 | // perror("ioctl"); 132 | // exit(1); 133 | // } 134 | // printf("fifo size = %d\n", size); 135 | 136 | // printf("length of buf is %d\n", strlen(buf)); 137 | // } 138 | 139 | sem_post(mutex); // unlock 140 | close(fd); 141 | 142 | sem_close(mutex); 143 | sem_close(receive1); 144 | sem_close(receive2); 145 | sem_close(receive3); 146 | 147 | sem_unlink("mutex"); 148 | sem_unlink("receive1"); 149 | sem_unlink("receive2"); 150 | sem_unlink("receive3"); 151 | unlink(argv[1]); 152 | } 153 | else if (0 == id) 154 | { // child process 1 155 | sem_wait(mutex); // lock 156 | fd = open(argv[1], O_WRONLY); 157 | printf("Child %d (pid:%d) send: ", id, getpid()); 158 | // fgets(buf, sizeof(buf), stdin); 159 | memset(temp, 0, sizeof(temp)); 160 | scanf("%[^\n]%*c", temp); 161 | sprintf(buf, "%s ", temp); 162 | write(fd, buf, strlen(buf)); // write to pipe 163 | close(fd); 164 | sem_post(mutex); // unlock 165 | sem_post(receive1); // send signal to parent 166 | } 167 | else if (1 == id) 168 | { // child process 2 169 | sem_wait(mutex); 170 | fd = open(argv[1], O_WRONLY); 171 | printf("Child %d (pid:%d) send: ", id, getpid()); 172 | scanf("%[^\n]%*c", temp); 173 | sprintf(buf, "%s ", temp); 174 | write(fd, buf, strlen(buf)); 175 | close(fd); 176 | sem_post(mutex); 177 | sem_post(receive2); 178 | } 179 | else if (2 == id) 180 | { // child process 3 181 | sem_wait(mutex); 182 | fd = open(argv[1], O_WRONLY); 183 | printf("Child %d (pid:%d) send: ", id, getpid()); 184 | scanf("%[^\n]%*c", temp); 185 | sprintf(buf, "%s ", temp); 186 | write(fd, buf, strlen(buf)); 187 | close(fd); 188 | sem_post(mutex); 189 | sem_post(receive3); 190 | } 191 | 192 | sem_close(mutex); 193 | sem_close(receive1); 194 | sem_close(receive2); 195 | sem_close(receive3); 196 | 197 | sem_unlink("mutex"); 198 | sem_unlink("send"); 199 | sem_unlink("receive"); 200 | 201 | return 0; 202 | } -------------------------------------------------------------------------------- /lab3/pipe/fifo_read.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | // 读取 fifoname 6 | if (2 > argc) 7 | { 8 | printf("miss fifoname\n"); 9 | exit(1); 10 | } 11 | 12 | // 借助信号量 13 | init(); // 可以不借助信号量 14 | 15 | // access: 判断文件是否存在 16 | // F_OK: 判断文件是否存在 17 | // 返回值: 0: 存在, -1: 不存在 18 | int ret = access(argv[1], F_OK); 19 | if (-1 == ret) 20 | { 21 | int ret = mkfifo(argv[1], 0664); 22 | if (-1 == ret) 23 | { 24 | perror("mkfifo"); 25 | exit(1); 26 | } 27 | else 28 | printf("mkfifo success\n"); 29 | } 30 | 31 | int fd = open(argv[1], O_RDONLY); 32 | if (-1 == fd) 33 | { 34 | perror("open"); 35 | exit(1); 36 | } 37 | 38 | // bug: 没有新建一个 buf 会导致 buf 之前的读取长度大于 quit 或者 exit 的长度时 读取的内容不仅仅是 quit 或者 exit 39 | char buf[1024] = {0}; 40 | int fifo_size = 0; 41 | 42 | // 方式一: 43 | // 一直读取数据直到输入 quit 或者 exit 44 | while (1) 45 | { 46 | // 读取数据 47 | char buf[1024] = {0}; // fix bug 48 | 49 | sem_wait(sem_receive); 50 | sem_wait(mutex); 51 | read(fd, buf, sizeof(buf)); 52 | sem_post(mutex); 53 | sem_post(sem_send); 54 | 55 | // read(fd, buf, sizeof(buf)); // 可以不借助信号量 56 | 57 | // bug: buf 之前的读取长度大于 quit 或者 exit 的长度时 读取的内容不仅仅是 quit 或者 exit 58 | if (0 == strcmp(buf, "quit") || 0 == strcmp(buf, "exit")) 59 | { 60 | close(fd); 61 | unlink(argv[1]); 62 | exit(0); 63 | } 64 | printf("read: %s\n", buf); 65 | } 66 | 67 | // 方式二: 68 | // 读取指定的字节数 直到管道为空 69 | // while (1) 70 | // { 71 | // printf("please input the counts of chars you want to read:\n"); 72 | // int count = 0; 73 | // if (!scanf("%d", &count)) 74 | // { 75 | // close(fd); 76 | // unlink(argv[1]); 77 | 78 | // perror("scanf"); 79 | // exit(1); 80 | // } 81 | 82 | // memset(buf, 0, sizeof(buf)); 83 | 84 | // read(fd, buf, count); 85 | // // 设置读取的字节数 86 | // printf("read: %s\n", buf); 87 | 88 | // // count the fifo size 89 | // ret = ioctl(fd, FIONREAD, &fifo_size); // FIONREAD: get the number of bytes in the FIFO 90 | // if (-1 == ret) 91 | // { 92 | // close(fd); 93 | // unlink(argv[1]); 94 | 95 | // perror("ioctl"); 96 | // exit(1); 97 | // } 98 | // printf("fifo size = %d\n", fifo_size); 99 | 100 | // // 当 buf 为空 或者 fifo_size 为 0 时,退出循环 101 | // if (!strlen(buf) || fifo_size == 0) 102 | // { 103 | // break; 104 | // } 105 | // } 106 | 107 | close(fd); 108 | unlink(argv[1]); 109 | 110 | // 删除信号量 111 | // _unlink(); // 可以不借助信号量 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /lab3/pipe/fifo_write.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | if (argc < 2) 6 | { // 判断是否输入了文件名 7 | printf("miss fifoname\n"); 8 | exit(1); 9 | } 10 | int ret = access(argv[1], F_OK); // 判断文件是否存在 11 | if (-1 == ret) 12 | { 13 | int ret = mkfifo(argv[1], 0664); // 创建FIFO文件 14 | if (-1 == ret) 15 | { 16 | perror("mkfifo error"); 17 | exit(1); 18 | } 19 | else if (0 == ret) 20 | { 21 | printf("mkfifo success\n"); 22 | } 23 | } 24 | 25 | // 借助信号量 26 | init(); // 可以不借助信号量 27 | 28 | int fd = open(argv[1], O_WRONLY); // 打开FIFO文件 O_RDONLY O_WRONLY O_RDWR 29 | 30 | while (1) 31 | { 32 | char buf[1024] = {0}; 33 | // if (!scanf("%s", buf)) // scanf 忽略空格 换行 34 | if (!fgets(buf, sizeof(buf), stdin)) // fgets 读取换行符 35 | { 36 | close(fd); 37 | unlink(argv[1]); 38 | perror("scanf error"); 39 | exit(1); 40 | } 41 | 42 | sem_wait(sem_send); 43 | sem_wait(mutex); 44 | write(fd, buf, strlen(buf) - 1); // -1 去掉换行符 45 | sem_post(mutex); 46 | sem_post(sem_receive); 47 | 48 | // 可以不借助信号量 49 | // write(fd, buf, strlen(buf) - 1); 50 | 51 | // if (0 == strcmp(buf, "quit") || 0 == strcmp(buf, "exit")) // 使用 scanf 52 | if (0 == strncmp(buf, "quit", 4) || 0 == strncmp(buf, "exit", 4)) // 使用 fgets 53 | { 54 | close(fd); 55 | unlink(argv[1]); 56 | exit(0); 57 | } 58 | } 59 | 60 | close(fd); 61 | _unlink(); // 可以不借助信号量 62 | return 0; 63 | } -------------------------------------------------------------------------------- /lab3/pipe/init.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | sem_t *sem_send; 20 | sem_t *sem_receive; 21 | sem_t *mutex; 22 | 23 | void init() 24 | { 25 | // 初始化信号量 26 | sem_send = sem_open("send", O_CREAT, 0666, 1); 27 | sem_receive = sem_open("receive", O_CREAT, 0666, 0); 28 | mutex = sem_open("mutex", O_CREAT, 0666, 1); 29 | } 30 | 31 | void _unlink() 32 | { 33 | sem_unlink("send"); 34 | sem_unlink("receive"); 35 | sem_unlink("mutex"); 36 | } -------------------------------------------------------------------------------- /lab3/pipe/pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() 12 | { 13 | int fd[2]; // file descriptor 14 | int ret; 15 | char buf[1024]; 16 | int id; 17 | sem_t *mutex; 18 | sem_t *receive1; 19 | sem_t *receive2; 20 | sem_t *receive3; 21 | pid_t pid; 22 | 23 | memset(buf, 0, sizeof(buf)); // initialize buffer 24 | sem_unlink("mutex"); // unlink semaphore if it exists 25 | sem_unlink("receive1"); 26 | sem_unlink("receive2"); 27 | sem_unlink("receive3"); 28 | 29 | mutex = sem_open("mutex", O_CREAT, 0644, 1); // sem_open(name, flag, mode, value); 30 | receive1 = sem_open("receive1", O_CREAT, 0644, 0); 31 | receive2 = sem_open("receive2", O_CREAT, 0644, 0); 32 | receive3 = sem_open("receive3", O_CREAT, 0644, 0); 33 | 34 | ret = pipe(fd); // create pipe; fd[0] = read end, fd[1] = write end 35 | if (ret == -1) 36 | { 37 | perror("pipe"); 38 | exit(1); 39 | } 40 | 41 | for (id = 0; id < 3; id++) 42 | { // create 3 child processes 43 | pid = fork(); 44 | if (0 == pid) // child process 45 | { 46 | // 使用这种方式创建 3 个子进程 47 | // 并且可以有效区分父子进程 48 | // id = 0, 1, 2 为子进程 49 | // id = 3 为父进程 50 | break; 51 | } 52 | if (0 > pid) 53 | { 54 | sem_close(mutex); 55 | sem_close(receive1); 56 | sem_close(receive2); 57 | sem_close(receive3); 58 | 59 | sem_unlink("mutex"); 60 | sem_unlink("receive1"); 61 | sem_unlink("receive2"); 62 | sem_unlink("receive3"); 63 | 64 | perror("fork"); 65 | exit(1); 66 | } 67 | } 68 | 69 | if (3 == id) 70 | { // parent process 71 | close(fd[1]); // close write end 72 | sem_wait(receive1); // wait for signal from child 73 | sem_wait(receive2); 74 | sem_wait(receive3); 75 | sem_wait(mutex); // lock 76 | 77 | // 打印管道大小 78 | int pipe_size = 0; 79 | ioctl(fd[0], FIONREAD, &pipe_size); 80 | printf("pipe size: %d bytes\n", pipe_size); 81 | while (pipe_size) 82 | { 83 | printf("please input the counts of chars you want to read:\n"); 84 | int count = 0; 85 | 86 | if (!scanf("%d", &count)) 87 | { 88 | perror("scanf"); 89 | exit(1); 90 | } 91 | 92 | read(fd[0], buf, count); // read from pipe 93 | printf("Parent (pid:%d) receive: %s\n", getpid(), buf); 94 | 95 | // 打印管道大小 96 | ioctl(fd[0], FIONREAD, &pipe_size); 97 | printf("pipe size: %d bytes\n", pipe_size); 98 | } 99 | 100 | sem_post(mutex); // unlock 101 | 102 | sem_close(mutex); 103 | sem_close(receive1); 104 | sem_close(receive2); 105 | sem_close(receive3); 106 | 107 | sem_unlink("mutex"); 108 | sem_unlink("send"); 109 | sem_unlink("receive"); 110 | } 111 | else if (0 == id) 112 | { // child process 1 113 | close(fd[0]); // close read end 114 | sem_wait(mutex); // lock 115 | printf("Child %d (pid:%d) send: ", id, getpid()); 116 | 117 | // scanf("%[^\n]%*c", buf); // read from stdin, %[^\n]%*c : read until newline 118 | // write(fd[1], buf, strlen(buf)); 119 | 120 | fgets(buf, 1024, stdin); 121 | write(fd[1], buf, strlen(buf) - 1); // -1 to remove newline 122 | sem_post(mutex); // unlock 123 | sem_post(receive1); // send signal to parent 124 | } 125 | else if (1 == id) 126 | { // child process 2 127 | close(fd[0]); 128 | sem_wait(mutex); 129 | printf("Child %d (pid:%d) send: ", id, getpid()); 130 | 131 | // scanf("%[^\n]%*c", buf); 132 | // write(fd[1], buf, strlen(buf)); 133 | 134 | fgets(buf, 1024, stdin); 135 | write(fd[1], buf, strlen(buf) - 1); // -1 to remove newline 136 | sem_post(mutex); 137 | sem_post(receive2); 138 | } 139 | else if (2 == id) 140 | { // child process 3 141 | close(fd[0]); 142 | sem_wait(mutex); 143 | printf("Child %d (pid:%d) send: ", id, getpid()); 144 | 145 | // scanf("%[^\n]%*c", buf); 146 | // write(fd[1], buf, strlen(buf)); 147 | 148 | fgets(buf, 1024, stdin); 149 | write(fd[1], buf, strlen(buf) - 1); // -1 to remove newline 150 | sem_post(mutex); 151 | sem_post(receive3); 152 | } 153 | 154 | return 0; 155 | } -------------------------------------------------------------------------------- /lab3/pipe/size_of_pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // C语言中多线程之间共享全局变量data段数据 13 | int i = 0; 14 | 15 | void *continue_write() 16 | { 17 | int fd[2] = {0}; 18 | 19 | int ret = pipe(fd); 20 | if (ret == -1) 21 | { 22 | perror("pipe"); 23 | exit(1); 24 | } 25 | for (i = 0; i < (int)1e6; i++) 26 | { // 阻塞时, i不再增加 27 | write(fd[1], "c", 1); // write 1 byte to pipe 28 | } 29 | close(fd[0]); // close read end 30 | close(fd[1]); // close write end 31 | } 32 | 33 | int main() 34 | { 35 | pthread_t tid; 36 | int lastnum = -1; 37 | pthread_create(&tid, NULL, continue_write, NULL); // create a thread to write to pipe 38 | while (1) 39 | { 40 | if (i != lastnum) 41 | { // 未阻塞 42 | lastnum = i; 43 | usleep(1000); 44 | } 45 | else 46 | { // 阻塞时,i == lastnum 47 | printf("pipe size is %d bytes\n", lastnum); 48 | break; 49 | } 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /lab3/shell/Makefile: -------------------------------------------------------------------------------- 1 | SRC := $(wildcard ./*.c) 2 | APP = $(patsubst %.c, %, $(SRC)) 3 | SHELL_RS := $(shell pwd)/shell-rs 4 | 5 | all: cmd1 cmd2 cmd3 cmd4 shell 6 | 7 | shell_rs: all 8 | make -C $(SHELL_RS) run 9 | 10 | cmd1: 11 | gcc cmd1.c -o cmd1 12 | 13 | cmd2: 14 | gcc cmd2.c -o cmd2 15 | 16 | cmd3: 17 | gcc cmd3.c -o cmd3 18 | 19 | cmd4: 20 | gcc cmd4.c -o cmd4 21 | 22 | shell: 23 | gcc shell.c -o shell 24 | 25 | clean: 26 | rm $(APP) 27 | make -C $(SHELL_RS) clean -------------------------------------------------------------------------------- /lab3/shell/cmd1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | execl("/bin/ls", "ls", "-l", NULL); 9 | perror("execl"); 10 | exit(1); 11 | } -------------------------------------------------------------------------------- /lab3/shell/cmd2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | execl("/bin/pwd", "pwd", NULL); 9 | perror("execl"); 10 | exit(1); 11 | } -------------------------------------------------------------------------------- /lab3/shell/cmd3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | execl("/bin/df", "df", NULL); 9 | perror("execl"); 10 | exit(1); 11 | } -------------------------------------------------------------------------------- /lab3/shell/cmd4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | char* args[20] = {"grep", "-i", "cmd", "shell.c", NULL, NULL}; 9 | execv("/bin/grep", args); 10 | perror("execv"); 11 | exit(1); 12 | } -------------------------------------------------------------------------------- /lab3/shell/shell-rs/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "lazy_static" 7 | version = "1.4.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 10 | 11 | [[package]] 12 | name = "shell" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "lazy_static", 16 | ] 17 | -------------------------------------------------------------------------------- /lab3/shell/shell-rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shell" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | lazy_static = "1.4.0" 10 | -------------------------------------------------------------------------------- /lab3/shell/shell-rs/Makefile: -------------------------------------------------------------------------------- 1 | APP: 2 | cargo build 3 | 4 | run: 5 | cargo run 6 | 7 | clean: 8 | cargo clean 9 | -------------------------------------------------------------------------------- /lab3/shell/shell-rs/src/main.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::*; 2 | use std::cell::{Ref, RefCell, RefMut}; 3 | use std::env; 4 | use std::io::{stdin, stdout, Write}; 5 | use std::path::Path; 6 | use std::process::Command; 7 | use std::str::SplitWhitespace; 8 | 9 | pub struct UnSafeCell { 10 | /// inner data 11 | inner: RefCell, 12 | } 13 | 14 | unsafe impl Sync for UnSafeCell {} 15 | 16 | impl UnSafeCell { 17 | /// User is responsible to guarantee that inner struct is only used in uniprocessor. 18 | pub unsafe fn new(value: T) -> Self { 19 | Self { 20 | inner: RefCell::new(value), 21 | } 22 | } 23 | /// Panic if the data has been borrowed. 24 | pub fn borrow_mut(&self) -> RefMut<'_, T> { 25 | self.inner.borrow_mut() 26 | } 27 | 28 | pub fn borrow(&self) -> Ref<'_, T> { 29 | self.inner.borrow() 30 | } 31 | } 32 | 33 | const USER: &str = "Clstilmldy"; 34 | 35 | lazy_static! { 36 | static ref PATH: UnSafeCell = unsafe { 37 | UnSafeCell::new(format!("❂ {}  {}\n╰─❯ ", USER, { 38 | let dir = env::current_dir().unwrap(); 39 | dir.display().to_string() 40 | })) 41 | }; 42 | } 43 | 44 | fn main() { 45 | loop { 46 | // Prompt and flush stdout in preparation for stdin 47 | print!("{}", PATH.borrow()); 48 | stdout().flush().expect("Failed to flush stdout :("); 49 | 50 | // Take in user input 51 | let mut input = String::new(); 52 | stdin() 53 | .read_line(&mut input) 54 | .expect("Failed to read input :("); 55 | 56 | // Split input into command and args 57 | let mut input = input.trim().split_whitespace(); // Shadows String with SplitWhitespace Iterator 58 | let cmd = input.next().unwrap(); 59 | match cmd { 60 | "cd" => cd(input), 61 | "exit" => break, 62 | cmd => run_cmd(cmd, input), 63 | } 64 | } 65 | } 66 | 67 | fn cd(mut args: SplitWhitespace) { 68 | // The next arg should be the path, if it does not exist then use "/" in it's place 69 | let target = args.next().unwrap_or("/"); 70 | // Convert &str to Path and then set the current directory to that path (and check for errors) 71 | let path = Path::new(target); 72 | if let Err(error) = env::set_current_dir(path) { 73 | eprintln!("{}", error); 74 | } 75 | 76 | PATH.borrow_mut().clear(); 77 | PATH.borrow_mut() 78 | .push_str(&format!("❂ {}  {}\n╰─❯ ", USER, { 79 | let dir = env::current_dir().unwrap(); 80 | dir.display().to_string() 81 | })); 82 | } 83 | 84 | fn run_cmd(cmd: &str, args: SplitWhitespace) { 85 | // Spawn command as child-process of the shell 86 | let child = Command::new(cmd).args(args).spawn(); 87 | // Error checking for child 88 | match child { 89 | Ok(mut child) => { 90 | if let Err(error) = child.wait() { 91 | eprintln!("{}", error); 92 | } 93 | } 94 | Err(error) => eprintln!("{}", error), 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lab3/shell/shell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | char cmd[100]; 12 | char *cmds[20] = {NULL}; 13 | int child_proc_status; 14 | pid_t pid; 15 | 16 | while (1) 17 | { 18 | printf("shell:"); 19 | fgets(cmd, 100, stdin); 20 | char cmd_copy[100]; 21 | strcpy(cmd_copy, cmd); 22 | 23 | int cnt = 0; 24 | // split the command into tokens 25 | // strtok 用法:https://www.runoob.com/cprogramming/c-function-strtok.html 26 | cmds[cnt] = strtok(cmd_copy, " \n"); 27 | while (cmds[cnt]) 28 | { 29 | cmds[++cnt] = strtok(NULL, " \n"); 30 | } 31 | cmds[cnt] = NULL; 32 | 33 | child_proc_status = -1; 34 | if (!strcmp(cmds[0], "cmd1") || !strcmp(cmds[0], "cmd2") || !strcmp(cmds[0], "cmd3")) 35 | { 36 | // fork 子进程中返回 0 值, 而父进程中返回子进程ID 37 | pid = fork(); 38 | if (pid < 0) 39 | { 40 | printf("fork error\n"); 41 | } 42 | else if (pid > 0) 43 | { // parent proc 44 | wait(&child_proc_status); // wait child proc end 45 | } 46 | else 47 | { 48 | char cmdf[102]; 49 | sprintf(cmdf, "./%s", cmds[0]); 50 | system(cmdf); 51 | exit(0); 52 | } 53 | } 54 | else if (!strcmp(cmds[0], "exit")) 55 | { 56 | printf("shell exit\n"); 57 | break; 58 | } 59 | else if (!strcmp(cmds[0], "find")) 60 | { 61 | system(cmd); 62 | } 63 | else if (!strcmp(cmds[0], "grep")) 64 | { 65 | system(cmd); 66 | } 67 | else if (!strcmp(cmds[0], "clear")) 68 | { 69 | system(cmd); 70 | } 71 | else 72 | { 73 | printf("Command not found\n"); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /lab3/shm/Makefile: -------------------------------------------------------------------------------- 1 | all: user1 user2 2 | 3 | user1: user1.c 4 | gcc user1.c -o user1 -pthread -g 5 | 6 | user2: user2.c 7 | gcc user2.c -o user2 -pthread -g 8 | 9 | clean: 10 | rm -f user1 user2 -------------------------------------------------------------------------------- /lab3/shm/init.h: -------------------------------------------------------------------------------- 1 | /** 2 | * shm1 与 shm2 通过共享内存通信 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include //信号量头文件 21 | #include 22 | 23 | #define MEM_MIN_SIZE 1024 24 | 25 | sem_t *sem_sender; 26 | sem_t *sem_receiver1; 27 | sem_t *sem_receiver2; 28 | 29 | key_t key; 30 | int shm_id; 31 | void *shm_p; 32 | 33 | void init() 34 | { 35 | //初始化信号量 36 | sem_sender = sem_open("sender", O_CREAT, 0666, 1); 37 | sem_receiver1 = sem_open("receiver1", O_CREAT, 0666, 0); 38 | sem_receiver2 = sem_open("receiver2", O_CREAT, 0666, 0); 39 | 40 | key = ftok("/home/melody/lab/3lab/", 0); 41 | if (key == -1) 42 | { 43 | perror("ftok error"); 44 | exit(-1); 45 | } 46 | printf("key = %d\n", key); 47 | 48 | //创建共享内存,成功则返回id (一个与key相关的标识符) 49 | shm_id = shmget(key, MEM_MIN_SIZE, 0666 | IPC_CREAT); 50 | if (shm_id < 0) 51 | { 52 | perror("shmget"); 53 | exit(-1); 54 | } 55 | printf("shm_id = %d\n", shm_id); 56 | 57 | //指定共享内存映射到新虚拟地址空间,返回起始地址 58 | shm_p = shmat(shm_id, NULL, 0); // 0表示可读可写 59 | if (shm_p == (void *)-1) 60 | { 61 | perror("shmat"); 62 | exit(-1); 63 | } 64 | return; 65 | } -------------------------------------------------------------------------------- /lab3/shm/unlink.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | int main() 3 | { 4 | sem_unlink("sender"); 5 | sem_unlink("receiver1"); 6 | sem_unlink("receiver2"); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /lab3/shm/user1.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | // 用于 4 | pthread_t r_thread, s_thread; 5 | 6 | void *send(void *arg) 7 | { 8 | char msg[MEM_MIN_SIZE]; // msg -> fmt string 9 | // char s_str[100]; // input string; bug 10 | while (1) 11 | { 12 | char s_str[100] = {0}; // fix bug 13 | printf("Process %d input:\n", *((pid_t *)arg)); 14 | fflush(stdout); 15 | 16 | // see https://stackoverflow.com/questions/30065675/what-does-scanf-nc-mean 17 | // scanf("%[^\n]%*c", s_str); // cant read line with space 18 | 19 | fgets(s_str, 100, stdin); // can read line with space 20 | s_str[strlen(s_str) - 1] = '\0'; // remove '\n' 21 | 22 | // Wait for the receiver to be ready. 23 | sem_wait(sem_sender); 24 | 25 | sprintf(msg, "%d:%s", *((pid_t *)arg), s_str); 26 | strcpy((char *)shm_p, msg); 27 | 28 | // Tell the receiver(user2) that the message is ready. 29 | sem_post(sem_receiver2); 30 | 31 | // send "over" to exit. 32 | if (!strcmp(s_str, "over")) 33 | { 34 | pthread_cancel(r_thread); // Cancel the receiver thread. 35 | shmdt(shm_p); 36 | break; 37 | } 38 | } 39 | } 40 | 41 | void *receive(void *arg) 42 | { 43 | char r_str[100]; 44 | char *p; 45 | while (1) 46 | { 47 | // Wait to receive a message from the sender(user2). 48 | sem_wait(sem_receiver1); 49 | 50 | strcpy(r_str, (char *)shm_p); 51 | 52 | // Find the first ':' in the string. 53 | p = strchr(r_str, ':'); 54 | *(p++) = '\0'; 55 | printf("Received message from process %s:\n%s\n", r_str, p); 56 | 57 | // if user1 send "over" to exit. 58 | // see https://book.itheima.net/course/223/1277519158031949826/1277528201861537793 59 | if (strcmp(p, "over") == 0) 60 | { 61 | pthread_cancel(s_thread); // Cancel the sender thread. 62 | shmdt(shm_p); // Detach the shared memory. 63 | shmctl(shm_id, IPC_RMID, NULL); // Remove the shared memory. 64 | sem_unlink("sender"); // Remove the semaphore. 65 | sem_unlink("receiver1"); 66 | sem_unlink("receiver2"); 67 | break; 68 | } 69 | 70 | printf("Process %d input:\n", *((pid_t *)arg)); 71 | fflush(stdout); 72 | sem_post(sem_sender); 73 | } 74 | } 75 | 76 | int main() 77 | { 78 | pid_t pid = getpid(); 79 | int res1 = 0, res2 = 0; 80 | 81 | init(); 82 | 83 | printf("Process %d Start...\n\n", pid); 84 | // pthread_create() see https://book.itheima.net/course/223/1277519158031949826/1277528575729213444 85 | res1 = pthread_create(&s_thread, NULL, send, &pid); 86 | res2 = pthread_create(&r_thread, NULL, receive, &pid); 87 | 88 | if (res1 || res2) 89 | { 90 | printf("create pthread failed\n"); 91 | return 1; 92 | } 93 | 94 | pthread_join(s_thread, NULL); 95 | pthread_join(r_thread, NULL); 96 | printf("Process %d Exit...\n", pid); 97 | } -------------------------------------------------------------------------------- /lab3/shm/user2.c: -------------------------------------------------------------------------------- 1 | #include "init.h" 2 | 3 | pthread_t r_thread, s_thread; 4 | 5 | void *send(void *arg) 6 | { 7 | char msg[MEM_MIN_SIZE]; // msg -> fmt string 8 | // char s_str[100]; // input string; bug 9 | while (1) 10 | { 11 | char s_str[100] = {0}; // fix bug 12 | printf("Process %d input:\n", *((pid_t *)arg)); 13 | fflush(stdout); // fflush(stdout) is to flush the output buffer. 14 | 15 | // scanf("%[^\n]%*c", s_str); // cant read line with space 16 | 17 | fgets(s_str, 100, stdin); // can read line with space 18 | s_str[strlen(s_str) - 1] = '\0'; // remove '\n' 19 | 20 | // Wait for the receiver to be ready. 21 | sem_wait(sem_sender); 22 | 23 | sprintf(msg, "%d:%s", *((pid_t *)arg), s_str); 24 | strcpy((char *)shm_p, msg); 25 | 26 | // Tell the receiver(user1) that the message is ready. 27 | sem_post(sem_receiver1); 28 | 29 | // send "over" to exit. 30 | if (!strcmp(s_str, "over")) 31 | { 32 | pthread_cancel(r_thread); // Cancel the receiver thread. 33 | shmdt(shm_p); 34 | break; 35 | } 36 | } 37 | } 38 | 39 | void *receive(void *arg) 40 | { 41 | char r_str[100]; 42 | char *p; 43 | while (1) 44 | { 45 | // Wait to receive a message from the sender(user1). 46 | sem_wait(sem_receiver2); 47 | 48 | strcpy(r_str, (char *)shm_p); 49 | 50 | // Find the first ':' in the string. 51 | p = strchr(r_str, ':'); 52 | *(p++) = '\0'; 53 | printf("Received message from process %s:\n%s\n", r_str, p); 54 | 55 | // if user1 send "over" to exit. 56 | if (strcmp(p, "over") == 0) 57 | { 58 | pthread_cancel(s_thread); // Cancel the sender thread. 59 | shmdt(shm_p); // Detach the shared memory. 60 | shmctl(shm_id, IPC_RMID, NULL); // Remove the shared memory. 61 | sem_unlink("sender"); // Remove the semaphore. 62 | sem_unlink("receiver1"); 63 | sem_unlink("receiver2"); 64 | break; 65 | } 66 | 67 | printf("Process %d input:\n", *((pid_t *)arg)); 68 | fflush(stdout); 69 | sem_post(sem_sender); 70 | } 71 | } 72 | 73 | int main() 74 | { 75 | pid_t pid = getpid(); 76 | int res1 = 0, res2 = 0; 77 | 78 | init(); 79 | 80 | printf("Process %d Start...\n\n", pid); 81 | res1 = pthread_create(&s_thread, NULL, send, &pid); 82 | res2 = pthread_create(&r_thread, NULL, receive, &pid); 83 | 84 | if (res1 || res2) 85 | { 86 | printf("create pthread failed\n"); 87 | return 1; 88 | } 89 | 90 | pthread_join(s_thread, NULL); 91 | pthread_join(r_thread, NULL); 92 | printf("Process %d Exit...\n", pid); 93 | } -------------------------------------------------------------------------------- /pta/模拟进程调度.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NEW 0x00 6 | #define READY 0x01 7 | #define RUNNING 0x02 8 | #define TERMINATED 0x03 9 | 10 | #define TIMESLICE 0x02 11 | 12 | using namespace std; 13 | 14 | static string FCFS_UPPER = "FCFS"; 15 | static string SPF_UPPER = "SPF"; 16 | static string FCFS_LOWER = "fcfs"; 17 | static string SPF_LOWER = "spf"; 18 | 19 | struct PCB 20 | { 21 | int time; 22 | string name; 23 | int state; 24 | 25 | PCB() 26 | { 27 | time = 0; 28 | name = " "; 29 | state = NEW; 30 | } 31 | 32 | PCB(int _t, string _name) : time(_t), name(_name) 33 | { 34 | state = NEW; 35 | } 36 | }; 37 | 38 | struct Compare 39 | { 40 | bool operator()(PCB a, PCB b) 41 | { 42 | if (a.time == b.time) 43 | return a.name > b.name; 44 | else 45 | return a.time > b.time; 46 | } 47 | }; 48 | 49 | queue pcb_queue; 50 | queue pcb_terminated; 51 | priority_queue, Compare> pcb_pri_queue; 52 | 53 | void build_fcfs(const int &, const vector &); 54 | void build_spf(const int &, const vector &); 55 | void set_name(const int &, vector &); 56 | void work_fcfs(); 57 | void work_spf(); 58 | void _print(); 59 | 60 | void set_name(const int &n, vector &pcb_name) 61 | { 62 | string _prefix = "P"; 63 | string _prefix_0 = "P0"; 64 | for (int i = 0; i < n; i++) 65 | { 66 | if (i < 10) 67 | { 68 | string name = _prefix_0 + to_string(i); 69 | pcb_name.push_back(name); 70 | continue; 71 | } 72 | string name = _prefix + to_string(i); 73 | pcb_name.push_back(name); 74 | } 75 | } 76 | 77 | void build_fcfs(const int &n, const vector &name) 78 | { 79 | int time = 0; 80 | for (int i = 0; i < n; i++) 81 | { 82 | cin >> time; 83 | pcb_queue.push(PCB(time, name[i])); 84 | } 85 | } 86 | 87 | void build_spf(const int &n, const vector &name) 88 | { 89 | int time = 0; 90 | for (int i = 0; i < n; i++) 91 | { 92 | cin >> time; 93 | pcb_pri_queue.push(PCB(time, name[i])); 94 | } 95 | } 96 | 97 | void work_fcfs() 98 | { 99 | while (!pcb_queue.empty()) 100 | { 101 | auto &&front = pcb_queue.front(); 102 | front.state = RUNNING; 103 | cout << endl 104 | << front.name; 105 | front.time -= TIMESLICE; 106 | if (front.time <= 0) 107 | { 108 | front.state = TERMINATED; 109 | pcb_queue.pop(); 110 | pcb_terminated.push(front); 111 | continue; 112 | } 113 | front.state = READY; 114 | pcb_queue.pop(); 115 | pcb_queue.push(front); 116 | } 117 | } 118 | 119 | void work_spf() 120 | { 121 | PCB top = pcb_pri_queue.top(); 122 | PCB prev = top; 123 | while (!pcb_pri_queue.empty()) 124 | { 125 | top = pcb_pri_queue.top(); 126 | pcb_pri_queue.pop(); 127 | if (prev.name != top.name && prev.state != TERMINATED) 128 | { 129 | pcb_pri_queue.push(prev); 130 | } 131 | cout << endl 132 | << top.name; 133 | top.state = RUNNING; 134 | top.time -= TIMESLICE; 135 | if (top.time <= 0) 136 | { 137 | top.state = TERMINATED; 138 | prev = top; 139 | pcb_terminated.push(top); 140 | continue; 141 | } 142 | top.state = READY; 143 | prev = top; 144 | } 145 | if (prev.state != TERMINATED) 146 | { 147 | prev.state = RUNNING; 148 | while (prev.time > 0) 149 | { 150 | cout << endl 151 | << prev.name; 152 | prev.time -= TIMESLICE; 153 | if (prev.time <= 0) 154 | { 155 | prev.state = TERMINATED; 156 | pcb_terminated.push(prev); 157 | } 158 | } 159 | } 160 | } 161 | 162 | void _print() 163 | { 164 | while (!pcb_queue.empty()) 165 | { 166 | cout << pcb_queue.front().name << " " << pcb_queue.front().time << endl; 167 | pcb_queue.pop(); 168 | } 169 | while (!pcb_pri_queue.empty()) 170 | { 171 | cout << pcb_pri_queue.top().name << " " << pcb_pri_queue.top().time << endl; 172 | pcb_pri_queue.pop(); 173 | } 174 | } 175 | 176 | int main() 177 | { 178 | std::ios::sync_with_stdio(false); 179 | std::cin.tie(0); 180 | vector pcb_name; 181 | string schecdule_mode; 182 | int pcb_cnt; 183 | cin >> schecdule_mode >> pcb_cnt; 184 | set_name(pcb_cnt, pcb_name); 185 | 186 | if (schecdule_mode == FCFS_LOWER || schecdule_mode == FCFS_UPPER) 187 | { 188 | cout << schecdule_mode; 189 | build_fcfs(pcb_cnt, pcb_name); 190 | work_fcfs(); 191 | return 0; 192 | } 193 | if (schecdule_mode == SPF_LOWER || schecdule_mode == SPF_UPPER) 194 | { 195 | cout << schecdule_mode; 196 | build_spf(pcb_cnt, pcb_name); 197 | work_spf(); 198 | return 0; 199 | } 200 | } -------------------------------------------------------------------------------- /pta/模拟进程链表基本操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct PCB 7 | { 8 | long pid; 9 | string name; 10 | int strategy; // 控制策略 11 | int priority; // 优先级 12 | PCB *next; 13 | 14 | PCB() 15 | { 16 | pid = -1; 17 | name = "nil"; 18 | strategy = -1; 19 | priority = -1; 20 | next = nullptr; 21 | } 22 | PCB(long id, string nm, int stra, int pri) : pid(id), name(nm), strategy(stra), priority(pri) 23 | { 24 | next = nullptr; 25 | } 26 | }; 27 | 28 | class Process 29 | { 30 | public: 31 | PCB *head; 32 | void print_pcb(); 33 | void print_pid(); 34 | ~Process() 35 | { 36 | PCB *p = head; 37 | while (p != nullptr) 38 | { 39 | PCB *del = p; 40 | p = p->next; 41 | // cout << endl 42 | // << "delete " << del->pid; 43 | delete del; 44 | } 45 | } 46 | void command_choose(vector &command); 47 | void append_pcb(vector &command); 48 | void modify_pcb(vector &command); 49 | void delete_pcb(vector &command); 50 | void insert_pcb(vector &command); 51 | void find_pcb(vector &command); 52 | void sort_pcb(); // merge sort 53 | friend PCB *merge_pcb(PCB *h1, PCB *h2); 54 | }; 55 | 56 | static char SEP = ' '; 57 | 58 | void print_command(const vector &msgs) 59 | { 60 | for (int i = 0; i < msgs.size(); i++) 61 | { 62 | cout << msgs[i] << " "; 63 | } 64 | cout << endl; 65 | } 66 | 67 | bool is_number(const string &s) 68 | { 69 | auto it = s.begin(); 70 | while (it != s.end() && std::isdigit(*it)) 71 | ++it; 72 | return !s.empty() && it == s.end(); 73 | } 74 | 75 | void Process::print_pcb() 76 | { 77 | PCB *p = head; 78 | while (p) 79 | { 80 | cout << p->pid << " " << p->name << " " 81 | << p->strategy << " " << p->priority << endl; 82 | p = p->next; 83 | } 84 | } 85 | 86 | void Process::print_pid() 87 | { 88 | PCB *p = head; 89 | while (p->next) 90 | { 91 | cout << p->pid << endl; 92 | p = p->next; 93 | } 94 | cout << p->pid; 95 | } 96 | 97 | void Process::command_choose(vector &command) 98 | { 99 | string cmd = command[0]; 100 | if (cmd == "sort") 101 | { 102 | sort_pcb(); 103 | print_pid(); 104 | return; 105 | } 106 | if (cmd == "append") 107 | { 108 | append_pcb(command); 109 | print_pid(); 110 | return; 111 | } 112 | if (cmd == "modify") 113 | { 114 | modify_pcb(command); 115 | return; 116 | } 117 | if (cmd == "delete") 118 | { 119 | delete_pcb(command); 120 | print_pid(); 121 | return; 122 | } 123 | if (cmd == "insert") 124 | { 125 | insert_pcb(command); 126 | print_pid(); 127 | return; 128 | } 129 | if (cmd == "find") 130 | { 131 | find_pcb(command); 132 | return; 133 | } 134 | } 135 | 136 | void Process::find_pcb(vector &command) 137 | { 138 | long id = stol(command[1]); 139 | 140 | PCB *dummy_node = new PCB(); 141 | dummy_node->next = head; 142 | PCB *p = dummy_node; 143 | while (p->next && p->next->pid != id) 144 | { 145 | p = p->next; 146 | } 147 | if (p->next) 148 | { 149 | cout << p->next->pid << endl 150 | << p->next->priority; 151 | } 152 | delete dummy_node; // see delete_pcb explain 153 | } 154 | 155 | void Process::insert_pcb(vector &command) 156 | { 157 | long prev_pid = stol(command[1]); 158 | long insert_pid = stol(command[2]); 159 | string nm = command[3]; 160 | int stra = stoi(command[4]); 161 | int pri = stoi(command[5]); 162 | 163 | PCB *prev = head; // do not need dummy_node 164 | while (prev && prev->pid != prev_pid) 165 | { 166 | prev = prev->next; 167 | } 168 | if (prev) 169 | { 170 | PCB *insert_node = new PCB(insert_pid, nm, stra, pri); 171 | insert_node->next = prev->next; 172 | prev->next = insert_node; 173 | } 174 | } 175 | 176 | void Process::delete_pcb(vector &command) 177 | { 178 | long id = stol(command[1]); 179 | 180 | PCB *dummy_node = new PCB(); 181 | dummy_node->next = head; 182 | PCB *prev = dummy_node; 183 | while (prev->next && prev->next->pid != id) 184 | { 185 | prev = prev->next; 186 | } 187 | if (prev->next) 188 | { 189 | PCB *del = prev->next; 190 | prev->next = del->next; // wether del->next is nullptr 191 | delete del; 192 | } 193 | // dummy_node->next = nullptr; // no need; see ~Process(), dummy is not related to class Process 194 | delete dummy_node; 195 | } 196 | 197 | void Process::append_pcb(vector &command) 198 | { 199 | long id = stol(command[1]); 200 | string nm = command[2]; 201 | int stra = stoi(command[3]); 202 | int pri = stoi(command[3]); 203 | PCB *p = head; 204 | while (p->next) 205 | { 206 | p = p->next; 207 | } 208 | p->next = new PCB(id, nm, stra, pri); 209 | } 210 | 211 | void Process::modify_pcb(vector &command) 212 | { 213 | long id = stol(command[1]); 214 | int pri = stoi(command[2]); 215 | 216 | PCB *p = head; 217 | 218 | if (p->pid == id) 219 | { 220 | p->priority = pri; 221 | cout << p->pid << endl 222 | << p->priority; 223 | return; 224 | } 225 | 226 | while (p->next && p->pid != id) 227 | { 228 | p = p->next; 229 | } 230 | 231 | if (p) 232 | { 233 | p->priority = pri; 234 | cout << p->pid << endl 235 | << p->priority; 236 | } 237 | return; 238 | } 239 | 240 | PCB *merge_pcb(PCB *h1, PCB *h2) 241 | { 242 | PCB *dummy_node = new PCB(); 243 | PCB *p = dummy_node; 244 | while (h1 && h2) 245 | { 246 | if (h1->priority <= h2->priority) 247 | { 248 | p->next = h1; 249 | h1 = h1->next; 250 | } 251 | else 252 | { 253 | p->next = h2; 254 | h2 = h2->next; 255 | } 256 | p = p->next; 257 | } 258 | if (h1) 259 | { 260 | p->next = h1; 261 | } 262 | if (h2) 263 | { 264 | p->next = h2; 265 | } 266 | PCB *head = dummy_node->next; 267 | delete dummy_node; 268 | return head; 269 | } 270 | 271 | void Process::sort_pcb() 272 | { 273 | if (head == nullptr) 274 | return; 275 | 276 | // get length 277 | int length = 0; 278 | PCB *p = head; 279 | while (p) 280 | { 281 | length++; 282 | p = p->next; 283 | } 284 | 285 | PCB *dummy_node = new PCB(); 286 | dummy_node->next = head; 287 | 288 | for (int sub_len = 1; sub_len < length; sub_len <<= 1) 289 | { 290 | PCB *prev = dummy_node; 291 | PCB *curr = dummy_node->next; 292 | while (curr) 293 | { 294 | PCB *h1 = curr; 295 | for (int i = 1; i < sub_len && curr->next; i++) 296 | { 297 | curr = curr->next; 298 | } 299 | 300 | PCB *h2 = curr->next; 301 | curr->next = nullptr; 302 | curr = h2; 303 | for (int i = 1; i < sub_len && curr && curr->next; i++) 304 | { // 可能为奇数 curr is nullptr 305 | curr = curr->next; 306 | } 307 | PCB *nxt = nullptr; 308 | if (curr) 309 | { 310 | nxt = curr->next; 311 | curr->next = nullptr; 312 | } 313 | PCB *merged = merge_pcb(h1, h2); 314 | prev->next = merged; 315 | while (prev->next) 316 | { 317 | prev = prev->next; 318 | } 319 | curr = nxt; 320 | } 321 | } 322 | head = dummy_node->next; 323 | delete dummy_node; 324 | } 325 | 326 | int main() 327 | { 328 | std::ios::sync_with_stdio(false); 329 | std::cin.tie(0); 330 | string msg; 331 | Process process; 332 | PCB *dummy_node = new PCB(); 333 | PCB *p = dummy_node; 334 | vector command; 335 | 336 | while (getline(cin, msg)) 337 | { 338 | // prase input 339 | string str; 340 | vector msgs; 341 | 342 | for (auto &ref_char : msg) 343 | { 344 | if (ref_char == SEP) 345 | { 346 | msgs.push_back(str); 347 | str.clear(); 348 | } 349 | else 350 | { 351 | str.push_back(ref_char); 352 | } 353 | } 354 | 355 | if (!str.empty()) 356 | { 357 | msgs.push_back(str); 358 | str.clear(); 359 | } 360 | 361 | // record 362 | long id; 363 | int stra, pri; 364 | string nm; 365 | 366 | if (is_number(msgs[0])) 367 | { 368 | id = stol(msgs[0]); // may be methed 369 | nm = msgs[1]; 370 | stra = stoi(msgs[2]); 371 | pri = stoi(msgs[3]); 372 | p->next = new PCB(id, nm, stra, pri); 373 | p = p->next; 374 | } 375 | else 376 | { 377 | move(msgs.begin(), msgs.end(), back_inserter(command)); 378 | // print_command(command); 379 | } 380 | } 381 | 382 | process.head = dummy_node->next; 383 | // process.print_pcb(); 384 | 385 | process.command_choose(command); 386 | } -------------------------------------------------------------------------------- /pta/模拟银行家算法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | struct Process 9 | { 10 | string name; 11 | vector resource_need; // 还需分配 12 | vector resource_allocated; // 已分配 13 | }; 14 | 15 | vector resource_free; // 空闲资源 16 | vector pcb; 17 | vector pcb_name; 18 | int resource_cnt, pcb_cnt; 19 | 20 | void set_name(const int &, vector &); 21 | void work(); 22 | bool deal_with(vector &); 23 | void choose_to_deal(vector &, vector &); 24 | 25 | void set_name(const int &n, vector &pcb_name) 26 | { 27 | string _prefix = "P"; 28 | string _prefix_0 = "P0"; 29 | for (int i = 0; i < n; i++) 30 | { 31 | if (i < 10) 32 | { 33 | string name = _prefix_0 + to_string(i); 34 | pcb_name.push_back(name); 35 | continue; 36 | } 37 | string name = _prefix + to_string(i); 38 | pcb_name.push_back(name); 39 | } 40 | } 41 | 42 | void _print() 43 | { 44 | for (int i = 0; i < pcb_cnt; i++) 45 | { 46 | cout << pcb[i].name << " "; 47 | for (int j = 0; j < resource_cnt; j++) 48 | { 49 | cout << "need: " << pcb[i].resource_need[j] << " allocated: " << pcb[i].resource_allocated[j] << " "; 50 | } 51 | cout << endl; 52 | } 53 | cout << "free: "; 54 | for (int j = 0; j < resource_cnt; j++) 55 | { 56 | cout << resource_free[j] << " "; 57 | } 58 | cout << endl; 59 | } 60 | 61 | void work() 62 | { 63 | int pid = 0; 64 | bool flag = true; 65 | Process apply; 66 | vector pcb_list; 67 | apply.resource_need.resize(resource_cnt); 68 | 69 | cin >> pid; 70 | apply.name = pcb_name[pid]; 71 | 72 | // deal with 73 | auto it = find_if(pcb.begin(), pcb.end(), [&apply](Process p) 74 | { return p.name == apply.name; }); 75 | for (int i = 0; i < resource_cnt; i++) 76 | { 77 | cin >> apply.resource_need[i]; 78 | if (apply.resource_need[i] > it->resource_need[i] || apply.resource_need[i] > resource_free[i]) 79 | { 80 | cout << "unsafe"; 81 | return; 82 | } 83 | else 84 | { 85 | it->resource_need[i] -= apply.resource_need[i]; 86 | if (it->resource_need[i] > 0) 87 | { 88 | flag = false; 89 | } 90 | it->resource_allocated[i] += apply.resource_need[i]; 91 | resource_free[i] -= apply.resource_need[i]; 92 | } 93 | } 94 | 95 | if (flag == true) 96 | { 97 | for (int i = 0; i < resource_cnt; i++) 98 | { 99 | resource_free[i] += it->resource_allocated[i]; 100 | } 101 | pcb_list.push_back(it->name); 102 | pcb.erase(it); 103 | } 104 | 105 | if (deal_with(pcb_list)) 106 | { 107 | cout << "safe"; 108 | for (int i = 0; i < pcb_list.size(); i++) 109 | { 110 | cout << endl; 111 | cout << pcb_list[i]; 112 | } 113 | } 114 | } 115 | 116 | bool deal_with(vector &pcb_list) 117 | { 118 | bool accept = false; 119 | int i = 0; 120 | vector can_deal; 121 | while (!pcb.empty()) 122 | { 123 | if (i >= pcb.size()) 124 | { 125 | if (can_deal.empty()) 126 | { 127 | cout << "unsafe"; 128 | return false; 129 | } 130 | choose_to_deal(can_deal, pcb_list); 131 | can_deal.clear(); 132 | i = 0; 133 | } 134 | accept = true; 135 | for (int j = 0; j < resource_cnt; j++) 136 | { 137 | if (pcb[i].resource_need[j] > resource_free[j]) 138 | { 139 | accept = false; 140 | break; 141 | } 142 | } 143 | if (accept == true) 144 | { 145 | can_deal.push_back(pcb[i]); 146 | } 147 | i++; 148 | } 149 | return true; 150 | } 151 | 152 | void choose_to_deal(vector &can_deal, vector &pcb_list) 153 | { 154 | // 用自定义函数对象排序 155 | struct Compare 156 | { 157 | bool operator()(Process a, Process b) const 158 | { 159 | int sum_a = 0; 160 | int sum_b = 0; 161 | for (int i = 0; i < resource_cnt; i++) 162 | { 163 | sum_a += a.resource_need[i]; 164 | sum_b += b.resource_need[i]; 165 | } 166 | return sum_a < sum_b; 167 | } 168 | }; 169 | Compare cmp; 170 | sort(can_deal.begin(), can_deal.end(), cmp); 171 | auto it = find_if(pcb.begin(), pcb.end(), [&can_deal](Process p) 172 | { return p.name == can_deal[0].name; }); 173 | // free 174 | pcb_list.push_back(it->name); 175 | for (int j = 0; j < resource_cnt; j++) 176 | { 177 | resource_free[j] += it->resource_allocated[j]; 178 | } 179 | pcb.erase(it); 180 | } 181 | 182 | int main() 183 | { 184 | std::ios::sync_with_stdio(false); 185 | std::cin.tie(0); 186 | 187 | cin >> resource_cnt >> pcb_cnt; 188 | set_name(pcb_cnt, pcb_name); 189 | resource_free.resize(resource_cnt); 190 | Process p; 191 | p.resource_allocated.resize(resource_cnt); 192 | p.resource_need.resize(resource_cnt); 193 | for (int i = 0; i < pcb_cnt; i++) 194 | { 195 | p.name = pcb_name[i]; 196 | for (int j = 0; j < resource_cnt; j++) 197 | { 198 | cin >> p.resource_need[j]; 199 | } 200 | pcb.push_back(p); 201 | } 202 | for (int i = 0; i < pcb_cnt; i++) 203 | { 204 | for (int j = 0; j < resource_cnt; j++) 205 | { 206 | cin >> pcb[i].resource_allocated[j]; 207 | pcb[i].resource_need[j] -= pcb[i].resource_allocated[j]; 208 | } 209 | } 210 | 211 | for (int i = 0; i < resource_cnt; i++) 212 | { 213 | cin >> resource_free[i]; 214 | } 215 | 216 | // _print(); 217 | 218 | work(); 219 | } --------------------------------------------------------------------------------