os复习
    
    2019-06-21
    
    
    
  
    
- 1题基本概念
- 2题进程和虚存
- 1题文件系统
- 1题并发编程
编译 链接
gcc -o的系统调用
elf文件格式
终端 shell
为什么按键能显示在屏幕上?按下回车命令就会执行?
I/O设备模型
- I/O设备:可以与计算机(?)进行数据传输的硬件(?)
- 发送命令
- 读取状态
- 传输数据
 
- 设备驱动程序:进程(operating system?)与设备控制器(?)之间的通信程序
| $ psPID TTY          TIME CMD
 6577 pts/3    00:00:00 zsh
 9178 pts/3    00:00:00 ps
 
 $ ps -l
 F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
 0 S  1000  6577  1883  0  80   0 -  7676 sigsus pts/3    00:00:00 zsh
 4 R  1000  9265  6577  0  80   0 -  7531 -      pts/3    00:00:00 ps
 
 | 
- polling
- interupt
- hybrid
- DMA(直接存储器访问):允许外设可以独立地直接读写系统的存储器(?),而不需要cpu介入处理
./hello如何被执行
- 先调用fork
- 子进程调用execve->hello
- 父进程wait
- execve不会改变进程文件的状态,只会把进程替换成另一个程序
| $ sudo echo "a" > shitzsh: 权限不够: shit
 
 $ sudo bash -c 'echo "a" > shit'
 
 | 
加载器(文件如何变成进程?)
第一条指令在哪里?
main函数执行之前,系统发生了什么?
| gdb shit
 (gdb) starti
 Program stopped.
 0x00007ffff7fd4090 in _start () from /lib64/ld-linux-x86-64.so.2
 
 
 (gdb) info inferior
 * 1    process 6569      /shit
 
 $ pmap 6569
 6569:   /shit
 0000555555554000      4K r---- shit
 0000555555555000      4K r-x-- shit
 0000555555556000      4K r---- shit
 0000555555557000      8K rw--- shit
 00007ffff7fce000     12K r----   [ anon ]
 00007ffff7fd1000      8K r-x--   [ anon ]
 00007ffff7fd3000      4K r---- ld-2.28.so
 00007ffff7fd4000    128K r-x-- ld-2.28.so
 00007ffff7ff4000     32K r---- ld-2.28.so
 00007ffff7ffc000      8K rw--- ld-2.28.so
 00007ffff7ffe000      4K rw---   [ anon ]
 00007ffffffde000    132K rw---   [ stack ]
 ffffffffff600000      4K r-x--   [ anon ]
 total              352K
 
 (gdb) b _start
 Breakpoint 1 at 0x555555555060
 
 (gdb) c
 Breakpoint 1, 0x0000555555555060 in _start ()
 
 $ pmap 6569
 6569:   /shit
 0000555555554000      4K r---- shit
 0000555555555000      4K r-x-- shit
 0000555555556000      4K r---- shit
 0000555555557000      4K r---- shit
 0000555555558000      4K rw--- shit
 00007ffff7dc3000    136K r---- libc-2.28.so
 00007ffff7de5000   1476K r-x-- libc-2.28.so
 00007ffff7f56000    304K r---- libc-2.28.so
 00007ffff7fa2000      4K ----- libc-2.28.so
 00007ffff7fa3000     16K r---- libc-2.28.so
 00007ffff7fa7000      8K rw--- libc-2.28.so
 00007ffff7fa9000     24K rw---   [ anon ]
 00007ffff7fce000     12K r----   [ anon ]
 00007ffff7fd1000      8K r-x--   [ anon ]
 00007ffff7fd3000      4K r---- ld-2.28.so
 00007ffff7fd4000    128K r-x-- ld-2.28.so
 00007ffff7ff4000     32K r---- ld-2.28.so
 00007ffff7ffc000      4K r---- ld-2.28.so
 00007ffff7ffd000      4K rw--- ld-2.28.so
 00007ffff7ffe000      4K rw---   [ anon ]
 00007ffffffde000    132K rw---   [ stack ]
 ffffffffff600000      4K r-x--   [ anon ]
 total             2320K
 
 ...
 Breakpoint 1, 0x0000555555555149 in main ()
 
 $ pmap 6569
 
 
 | 
printf
printf代码位于何处?
| static void __attribute__ ((constructor)) fuck(){
 printf("hello\n");
 }
 
 | 
实现线程安全的printf?(20分的并发编程题)
- P操作P(S):将信号量S减去1,若结果小于0,则把调用P(S)的进程置成等待信号量S的状态,即为请求资源
- V操作V(S):将信号量S加上1,若结果不大于0,则释放一个等待信号量S的进程,即为释放资源
| void producer() {
 while (1) {
 mutex_lock(&mutex);
 
 if (count == n) wait(¬full, &mutex);
 produce();
 count ++;
 signal(¬empty);
 
 mutex_unlock(&mutex);
 }
 }
 
 void consumer()
 {
 while (1) {
 mutex_lock(&mutex);
 
 if (count == 0) wait(¬empty, &mutex);
 consume();
 count --;
 signal(¬full);
 
 mutex_unlock(&mutex);
 }
 }
 
 | 
| void producer(){
 while (1) {
 P(&space);
 mutex_lock(&mutex);
 
 produce();
 
 mutex_unlock(&mutex);
 V(&items);
 }
 }
 
 void consumer()
 {
 while (1) {
 P(&items);
 mutex_lock(&mutex);
 
 consume();
 
 mutex_unlock(&mutex);
 V(&space);
 }
 }
 
 | 
printf末尾换行
异常退出
| int main(){
 FILE *fp = fopen("del", "w");
 setbuf(fp, NULL);
 fputs("fuck", fp);
 assert(0);
 return 0;
 }
 
 | 
| $ gcc hello.c -o shit
 $ ./shit
 shit: hello.c:11: main: Assertion `0' failed.
 
 $ cat del
 fuck%
 
 | 
fork
| int main(){
 for (int i = 0; i < n; i ++) {
 fork();
 printf("hello\n");
 }
 return 0;
 }
 
 | 
| n | ./hello │ wc -l | ./hello | 
| 1 | 2 | 2 | 
| 2 | 8 | 6 | 
| int main(){
 setbuf(stdout, NULL);
 for (int i = 0; i < n; i ++) {
 fork();
 printf("hello\n");
 }
 return 0;
 }
 
 | 
| n | ./hello │ wc -l | ./hello | 
| 1 | 2 | 2 | 
| 2 | 6 | 6 | 
printf的系统调用
- ltrace命令
- libc缓冲区
- write系统调用
write
write写到哪里?
- 文件描述符对应的文件,例如一个设备(/dev/ttyx),或是文件系统中的一个文件
文件系统如何实现?
FAT(文件分配表)
FAT32文件系统快速入门,CSDN
长文件名
ext2(inode)
鸟哥的Linux私房菜:Linux的ext2档案系统
- 最大单一文件大小
- 12直接,1间接,1双间接,1三间接,设块大小为x(kb),1个block号4byte
- x*12 + x*(x*1024/4) + x*(x*1024/4)^2 + x*(x*1024/4)^3(byte)
 
- 资料存放区:inode table,data block
- metadata:- superblock,- block bitmap,- inode bitmap
如何保护我们的数据不受损害?
RAID
鸟哥的Linux私房菜:Software RAID
| RAID | 容量 | 容错 | 顺序度 | 随机读 | 顺序写 | 随机写 | 
| 0 | $n$ | 0 | $n$ | $n$ | $n$ | $n$ | 
| 1 | $n/2$ |  | $> n/2$ | $n$ | $n/2$ | $n/2$ | 
| 4 | $n-1$ | 1 | $n-1$ | $n-1$ | $n-1$ | $1/2$ | 
| 5 | $n-1$ | 1 | $n-1$ | $n$ | $n-1$ | $n/4$ | 
fsck
扫描inodes里的所有数据块,检查bitmap的一致性
日志
鸟哥的Linux私房菜:Linux的ext2档案系统
在磁盘上保存所有对数据结构的操作,每次启动时重做这些操作,在内存里重新建立文件系统
优化
- 批处理
- Metadata journaling
- 只对inode和bitmap做journaling,数据可以随意写入