NJUOS-11-操作系统上的进程

本文最后更新于:1 年前

进程结束啦,状态机专题也结束了。进入虚拟化的部分了,但是状态机用来理解进程也是有非常重要的意义的昂!!!

OS所有的一切都是状态机管理!

  • 本次课的主题:
    • 操作系统启动后到底做了什么
    • 操作系统如何管理程序(进程)

操作系统启动后到底做了什么?

image-20221222095030416

真正的操作系统做的事情就是加载系统里面的第一个程序,然后把所有控制权都交给这个程序。系统里面就有一个程序在执行,系统里面的进程都是组成一棵树状的结构。实际上树根那个程序,就是操作系统拉起来的。

  • can can need?

image-20221222095820651

可以看到,这里操作系统就是逐个去找可能存在的systemd的进程,就是我们说的第一个程序,也就是树的根。找到了就启动,找不到panic了,操作系统启动不了昂!!!这个根就提供了很多系统调用,比如:创建一个新的程序之类的昂!!!

1
2
3
4
5
6
7
alex ~  $ pstree
-+= 00001 root /sbin/launchd
|--= 00093 root /usr/libexec/logd
|--= 00094 root /usr/libexec/UserEventAgent (System)
|--= 00097 root /System/Library/PrivateFrameworks/Uninstall.framework/Resourc
|--= 00098 root /System/Library/Frameworks/CoreServices.framework/Versions/A/
|--= 00099 root /System/Library/PrivateFrameworks/MediaRemote.framework/Suppo

在mac上,其实也能看到结构的嗷,这个根,包括对应的进程所在的位置!

从系统启动到第一个进程

虚拟机(最小linux的启动与测试使用)

没有存储设备,只有包含两个文件的 “initramfs”

1
2
3
4
5
$ tree .
.
├── bin
│ └── busybox (可以在我们的Linux里直接执行)
└── init

加上 vmlinuz (内核镜像) 就可以在 QEMU 里启动了

image-20221222101312335

上面就是一个最小的Linux,可以不断往里面加文件,尝试去跑!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
alex ~/Desktop  $ cd linux-minimal
alex ~/Desktop/linux-minimal $ make
.
./init
./bin
./bin/busybox
5873 blocks
alex ~/Desktop/linux-minimal $ tree
.
├── Makefile
├── build
│   └── initramfs.cpio.gz
├── initramfs
│   ├── bin
│   │   └── busybox
│   └── init
└── vmlinuz

3 directories, 5 files

通过make指令可以成功编译,并且获得一个initramfs.cpio.gz镜像,挂载了就能跑的那种。

  • 直接跑起来:make run
1
2
3
alex ~/Desktop/linux-minimal  $ make run
/bin/sh: qemu-system-x86_64: command not found
make: *** [run] Error 127

因为我们没有下载qemu嘛,下载了就好昂!brew install qemu

  • 再次make run之后,我们其实就用虚拟机启动了一个最小的状态,通过info registers之类的指令,就可以看到系统当前的状态。

这里建议看看原视频昂!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
alex ~/Desktop/linux-minimal  $ make run
SeaBIOS (version rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org)


iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+07F91100+07EF1100 CA00



Booting from ROM..
sh: can't access tty; job control turned off
/ # /bin/busy box
sh: /bin/busy: not found
/ # /bin/busybox
BusyBox v1.31.1 (2020-03-22 13:22:47 UTC) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
or: busybox --list[-full]
or: busybox --show SCRIPT
or: busybox --install [-s] [DIR]
or: function [arguments]...

BusyBox is a multi-call binary that combines many common Unix
utilities into a single executable. Most people will create a
link to busybox for each function they wish to use and BusyBox
will act like whatever it was invoked as.

Currently defined functions:
[, [[, acpid, add-shell, addgroup, adduser, adjtimex, arch, arp,
arping, ash, awk, base64, basename, bc, beep, blkdiscard, blkid,
blockdev, bootchartd, brctl, bunzip2, bzcat, bzip2, cal, cat, chat,
chattr, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt,
cksum, clear, cmp, comm, conspy, cp, cpio, crond, crontab, cryptpw,
cttyhack, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod,
devmem, df, dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname,
dos2unix, dpkg, dpkg-deb, du, dumpkmap, dumpleases, echo, ed, egrep,
eject, env, envdir, envuidgid, ether-wake, expand, expr, factor,
fakeidentd, fallocate, false, fatattr, fbset, fbsplash, fdflush,
fdformat, fdisk, fgconsole, fgrep, find, findfs, flock, fold, free,
freeramdisk, fsck, fsck.minix, fsfreeze, fstrim, fsync, ftpd, ftpget,
ftpput, fuser, getopt, getty, grep, groups, gunzip, gzip, halt, hd,
hdparm, head, hexdump, hexedit, hostid, hostname, httpd, hush, hwclock,
i2cdetect, i2cdump, i2cget, i2cset, i2ctransfer, id, ifconfig, ifdown,
ifenslave, ifplugd, ifup, inetd, init, insmod, install, ionice, iostat,
ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, ipneigh, iproute, iprule,
iptunnel, kbd_mode, kill, killall, killall5, klogd, last, less, link,
linux32, linux64, linuxrc, ln, loadfont, loadkmap, logger, login,
logname, logread, losetup, lpd, lpq, lpr, ls, lsattr, lsmod, lsof,
lspci, lsscsi, lsusb, lzcat, lzma, lzop, makedevs, makemime, man,
md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mke2fs, mkfifo,
mkfs.ext2, mkfs.minix, mkfs.vfat, mknod, mkpasswd, mkswap, mktemp,
modinfo, modprobe, more, mount, mountpoint, mpstat, mt, mv, nameif,
nanddump, nandwrite, nbd-client, nc, netstat, nice, nl, nmeter, nohup,
nologin, nproc, nsenter, nslookup, ntpd, nuke, od, openvt, partprobe,
passwd, paste, patch, pgrep, pidof, ping, ping6, pipe_progress,
pivot_root, pkill, pmap, popmaildir, poweroff, powertop, printenv,
printf, ps, pscan, pstree, pwd, pwdx, raidautorun, rdate, rdev,
readahead, readlink, readprofile, realpath, reboot, reformime,
remove-shell, renice, reset, resize, resume, rev, rm, rmdir, rmmod,
route, rpm, rpm2cpio, rtcwake, run-init, run-parts, runlevel, runsv,
runsvdir, rx, script, scriptreplay, sed, sendmail, seq, setarch,
setconsole, setfattr, setfont, setkeycodes, setlogcons, setpriv,
setserial, setsid, setuidgid, sh, sha1sum, sha256sum, sha3sum,
sha512sum, showkey, shred, shuf, slattach, sleep, smemcap, softlimit,
sort, split, ssl_client, start-stop-daemon, stat, strings, stty, su,
sulogin, sum, sv, svc, svlogd, svok, swapoff, swapon, switch_root,
sync, sysctl, syslogd, tac, tail, tar, taskset, tc, tcpsvd, tee,
telnet, telnetd, test, tftp, tftpd, time, timeout, top, touch, tr,
traceroute, traceroute6, true, truncate, ts, tty, ttysize, tunctl,
ubiattach, ubidetach, ubimkvol, ubirename, ubirmvol, ubirsvol,
ubiupdatevol, udhcpc, udhcpc6, udhcpd, udpsvd, uevent, umount, uname,
unexpand, uniq, unix2dos, unlink, unlzma, unshare, unxz, unzip, uptime,
users, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, w,
wall, watch, watchdog, wc, wget, which, who, whoami, whois, xargs, xxd,
xz, xzcat, yes, zcat, zcip
/ # /bin/busybox ls
bin dev init root

image-20221222103332900

可以直接在linux运行busybox,其中包含了各种各样我们常用的命令行指令,虚拟机中直接执行命令是用不了的昂,要用里面的Busybox!


魔术来咯

上面的虚拟机里面,命令都用不了orz

BusyBox: The Swiss Army Knife of embedded Linux

img

1
2
3
4
5
6
7
8
9
c1="arch ash base64 cat chattr chgrp chmod chown conspy cp cpio cttyhack date dd df dmesg dnsdomainname dumpkmap echo ed egrep false fatattr fdflush fgrep fsync getopt grep gunzip gzip hostname hush ionice iostat ipcalc kbd_mode kill link linux32 linux64 ln login ls lsattr lzop makemime mkdir mknod mktemp more mount mountpoint mpstat mt mv netstat nice nuke pidof ping ping6 pipe_progress printenv ps pwd reformime resume rev rm rmdir rpm run-parts scriptreplay sed setarch setpriv setserial sh sleep stat stty su sync tar touch true umount uname usleep vi watch zcat"
c2="[ [[ awk basename bc beep blkdiscard bunzip2 bzcat bzip2 cal chpst chrt chvt cksum clear cmp comm crontab cryptpw cut dc deallocvt diff dirname dos2unix dpkg dpkg-deb du dumpleases eject env envdir envuidgid expand expr factor fallocate fgconsole find flock fold free ftpget ftpput fuser groups hd head hexdump hexedit hostid id install ipcrm ipcs killall last less logger logname lpq lpr lsof lspci lsscsi lsusb lzcat lzma man md5sum mesg microcom mkfifo mkpasswd nc nl nmeter nohup nproc nsenter nslookup od openvt passwd paste patch pgrep pkill pmap printf pscan"
c3="pstree pwdx readlink realpath renice reset resize rpm2cpio runsv runsvdir rx script seq setfattr setkeycodes setsid setuidgid sha1sum sha256sum sha3sum sha512sum showkey shred shuf smemcap softlimit sort split ssl_client strings sum sv svc svok tac tail taskset tcpsvd tee telnet test tftp time timeout top tr traceroute traceroute6 truncate ts tty ttysize udhcpc6 udpsvd unexpand uniq unix2dos unlink unlzma unshare unxz unzip uptime users uudecode uuencode vlock volname w wall wc wget which who whoami whois xargs xxd xz xzcat yes"
for cmd in $c1 $c2 $c3; do
/bin/busybox ln -s /bin/busybox /bin/$cmd
done
mkdir -p /proc && mount -t proc none /proc
mkdir -p /sys && mount -t sysfs none /sys
export PS1='(linux) '

在上面啥都用不了的虚拟机里面,把上述的指令拷贝进去。。。???可以直接在终端执行linux指令了!!!

本质上就是把busybox链接到/bin/目录下了,生成的链接文件的名字为ps, arch, ash, base64等linux常用命令的名字!

重启整个虚拟机的话:make && make run

image-20221222110452004

  • 试试 adb shell (toybox) -> 比busybox更简陋的一个命令行工具。一样的,符号链接,可以使用昂!!!

可以直接在文件系统中添加静态链接的二进制文件

手动放到linux-minimal/initramfs的code目录下,启动:

gcc -c minimal.S && ld minimal.o -> ./a.out

gcc logisim.c -o logisim -static

  • 静态链接的话,会有点大 -> 没关系。但是我们发现,我们在code目录下,mac编译好的这些输出的结果。在我们的qemu虚拟机,也就是在最小的linux环境下,一样是可以跑出来的!!!

我们最小的操作系统的dev,只有console昂!

image-20221222111320587

这里最小的linux里面,不也就是一个进程。然后在这个进程上面,运行别的程序吗?对不!!!

注意,init脚本里面有很多链接的过程被注释掉了,本质上就是我们上面手动执行的脚本,把注释掉的链接打开。直接make && make run,就能得到一个有体验的最小的linux系统昂!

  • 最小的Linux很好玩!!!
    • 足够真实,真的是一个Linux的环境!
    • 足够小,啥都没有哈哈哈哈,可以帮我们理解很多东西。

2021 年,CCF 以迅雷不及掩耳盗铃之势发布了 NOILinux 2.0

  • Ubuntu 20.04 Desktop (x86-64 only)
  • 真就不管那些 32-bit 的老爷机和老爷系统的死活了?

img和刚才的 “最小” 系统但本质一样

  • 有更多设备 (磁盘、网卡等)
  • initramfs 里挂载了磁盘
  • 磁盘里安装了最少的编译运行环境 (g++, …) 和一个 Web 服务
  • switch_root (pivot_root 系统调用) 完成 “启动”

和上面类似的!!!要真的模拟整个x64,x32根本顶不住啊。。。简单的呢?精简的文件系统,32-bit上跑64-bit,由于IO竞赛,只提供部分的外设(比如挂载磁盘,方便选手提交答案)还有运行环境,比如gcc之类的,不是就!!!很小的一个运行环境吗!!!

总结:

image-20221222113418246

syscall三大类:进程管理,内存管理,文件管理。有这三个调用,其实就能够构造出一个小小世界了!!!有这三个就可以写出一个小小的操作系统了昂!!!

进程

操作系统创建了第一个进程以后,操作系统只有一个进程。后面这些进程,该怎么产生呢?

  • 创建进程的API -> fork()

fork()

C 程序 = 状态机

  • 初始状态:main(argc, argv)
  • 程序可以直接在处理器上执行

虚拟化:操作系统在物理内存中保存多个状态机

  • 通过虚拟内存实现每次 “拿出来一个执行”
  • 中断后进入操作系统代码,“换一个执行”

状态机角度之Fork: 把进程这个状态机,复制了一份,复制出来的状态机和原来的状态机,完全一样的,而且相互独立的!!!内存的每个字节都一样,寄存器也都一样。除了返回值不一样(返回值在eax寄存器里面)

被创建出来的fork()返回值为0

  • 操作系统的模型就变了!!!从原来的一个程序,变成了多个进程。 -> 模型就变成了并发模型!!!

什么是操作系统?状态机的管理者

什么是虚拟化?操作系统里面可以管理好多个状态机,虽然容纳了很多状态机,但是每一次只能选一个状态机执行,这就是虚拟化!

  • 有个有意思的bomb:

image-20221222114528372

image-20221222114655072

image-20221222114620290

小的例子理解fork()

example 1

试着拿出一张纸,写出以下程序的输出结果

  • fork-demo.c
    • 你心里可能立即想,运行一下不就完了吗?
    • 记得用 “状态机” 去理解它
1
2
3
4
pid_t pid1 = fork();
pid_t pid2 = fork();
pid_t pid3 = fork();
printf("Hello World from (%d, %d, %d)\n", pid1, pid2, pid3);
  • Result:
1
2
3
4
5
6
7
8
9
alex ~/my_code/c++/CLionProject  $ ./a.out     
Hello World from (52270, 52271, 52273)
Hello World from (52270, 52271, 0)
Hello World from (52270, 0, 52274)
Hello World from (0, 52272, 52275)
Hello World from (52270, 0, 0)
Hello World from (0, 0, 52276)
Hello World from (0, 52272, 0)
Hello World from (0, 0, 0)

涉及到了并发,状态机开始复杂了…

main — (main -> pid1) — (main -> pid1 -> pid2) || (main -> pid1 && main -> pid2) — 再往下更乱呜呜呜!

image-20221222115336771

注意,fork的时候,是fork整个状态机昂!!!比如如果pid1执行了fork(),这个时候的fork(),是把pid1整个拷贝了一份(包括当前执行到的位置之类的)。pid1和main是并发执行的,所以从main()中fork()出来的进程,和pid1()中for()出来的,是不一样的昂!!!

example 2

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <unistd.h>

int main(int argc, char *argv[]) {
for(int i = 0 ; i < 2 ; i++) {
fork();
printf("Hello\n");
}

for(int i = 0 ; i < 2 ; i++) {
wait(NULL);
}
}

image-20221222123536007

预测:应该是六个

  • Result:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
alex ~/my_code/c++/CLionProject  $ ./a.out
Hello
Hello
Hello
Hello
Hello
Hello
alex ~/my_code/c++/CLionProject $ ./a.out | wc -l
8
alex ~/my_code/c++/CLionProject $ ./a.out | cat
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello

奇怪了,命令行输出是6行,但是统计输出的行数是八行???

计算机系统里没有魔法。机器永远是对的。

  • 本质上是printf有问题昂!

image-20221222124728497

image-20221222124804848

上面这里,就算有\n,但是管道到另外一个文件中./a.out | less,”Hello”也没有了…

我们的fork()是无情的拷贝机器,它会忠实地把所有的寄存器和所有的内存都赋值一遍,不管这些变量有什么含义。 -> 所以它会把那些库函数的内部状态,同样也复制一份。

fflush(stdout) -> 会执行一个系统调用,真正把字符输出到文件里面去(库函数,会执行一个底层的系统调用)。

buffer详解
  • buffer其实有两种
    • line buffer
    • full buffer

image-20221222125316805

  • tty(终端)是line buffer: 如果看到一个\n,就会把所有缓冲区的东西,用系统调用写出来。

  • pipe/file是full buffer: 写满4096B(一个页面)之后,才会丢给系统调用,把这个页面输出出来。

fflush本质上就是调用系统调用,把缓冲区内的内容打印出来。

tty的分析我们上面做过了,就是6个,对于pipe/file,我们应该怎么分析呢?

  • pipe/file中的full buffer的分析:

image-20221222151831917

所以最后线程结束的时候,把所有的Hello\n输出到pipe中去,总共就是8个Hello\n。什么叫“忠实“的复制?忠实就是把printf这种内部库的buffer,也复制了!!!它会把那些库函数的内部状态,全部也同样复制一份。

很有意思!!!

  • 能否改变这个行为?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <unistd.h>

int main(int argc, char *argv[]) {
setbuf(stdout, NULL);
for(int i = 0 ; i < 2 ; i++) {
fork();
printf("Hello\n");
}

for(int i = 0 ; i < 2 ; i++) {
wait(NULL);
}
}

设置为不缓冲!!!所有的printf都会被直接翻译为系统调用!!!

Results:

1
2
3
4
5
6
7
8
9
alex ~/my_code/c++/CLionProject  $ gcc main.cpp && ./a.out         
Hello
Hello
Hello
Hello
Hello
Hello
alex ~/my_code/c++/CLionProject $ gcc main.cpp && ./a.out | wc -l
6

连内部库的数组缓冲区都会被原样的复制!!!

example 3

多线程程序的某个线程执行 fork(),应该发生什么?

  • 这是个很有趣的问题:创造 fork 时创始人并没有考虑线程

我们可能作出以下设计:

  • 仅有执行 fork 的线程被复制,其他线程 “卡死”
  • 仅有执行 fork 的线程被复制,其他线程退出
  • 所有的线程都被复制并继续执行
    • 这三种设计分别会带来什么问题?

自己思考,后续会提到!

execve()

Fork: 程序是状态机,正在执行的程序是进程(正在运行的状态机),Fork是状态机的副本。

  • 光有 fork 还不够,怎么 “执行别的程序”?-> Execve()

image-20221222153015971

UNIX 的答案: execve

  • 将当前运行的状态机重置成成另一个程序的初始状态
1
int execve(const char *pathname, char * const argv, char * const envp);
  • 执行名为 pathname 的程序
  • 允许对新状态机设置参数argv(v) 和环境变量envp(e)
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <unistd.h>
#include <stdio.h>

int main() {
char * const argv[] = {
"/bin/bash", "-c", "env", NULL,
};
char * const envp[] = {
"HELLO=WORLD", NULL,
};
execve(argv[0], argv, envp);
printf("Hello, World!\n");
}

同一个进程,同一个进程号,所有的资源都在。但是,状态机被重置。

Results:

1
2
3
4
5
6
7
/Users/alex/my_code/c++/CLionProject/cmake-build-debug/CLionProject
HELLO=WORLD
PWD=/Users/alex/my_code/c++/CLionProject/cmake-build-debug
SHLVL=1
_=/usr/bin/env

Process finished with exit code 0

printf没有打印出来昂!!!因为重置了状态机,所以原来状态机,所有的状态都没有了昂!!!

环境变量

“应用程序执行的环境”

  • 使用env命令查看
    • PATH: 可执行文件搜索路径
    • PWD: 当前路径
    • HOME: home 目录
    • DISPLAY: 图形输出
    • PS1: shell 的提示符
  • export: 告诉 shell 在创建子进程时设置环境变量
    • 小技巧:export ARCH=x86_64-qemuexport ARCH=native
    • 上学期的 AM_HOME 终于破案了

可执行文件搜索路径

  • 还记得 gcc 的 strace 结果吗?
1
2
3
4
[pid 28369] execve("/usr/local/sbin/as", ["as", "--64", ...
[pid 28369] execve("/usr/local/bin/as", ["as", "--64", ...
[pid 28369] execve("/usr/sbin/as", ["as", "--64", ...
[pid 28369] execve("/usr/bin/as", ["as", "--64", ...
  • 这个搜索顺序恰好是 PATH 里指定的顺序

说白了,execve就会自动去我们的path里面去匹配,看看能不能找到,我们需要的东西!!!所以这里就和Windows里面一个道理,为啥需要配置Windows的环境变量(当下载软件的时候),这样软件才能找得到对应的软件的运行文件哇!!!

1
2
3
$ PATH="" /usr/bin/gcc a.c
gcc: error trying to exec 'as': execvp: No such file or directory
$ PATH="/usr/bin/" gcc a.c

计算机系统里没有魔法。机器永远是对的。

_exit()

有了 fork, execve 我们就能自由执行任何程序了,最后只缺一个销毁状态机的函数!

UNIX 的答案: _exit

  • 立即摧毁状态机
1
void _exit(int status)
  • 销毁当前状态机,并允许有一个返回值
  • 子进程终止会通知父进程 (后续课程解释)

这个简单……

  • 但问题来了:多线程程序怎么办?

exit 的几种写法 (它们是不同):

  • exit(0) - stdlib.h中声明的 libc 函数
    • 会调用 atexit
  • _exit(0) - glibc 的 syscall wrapper
    • 执行 “exit_group”系统调用终止整个进程 (所有线程)
      • 细心的同学已经在 strace 中发现了
    • 不会调用 atexit
  • syscall(SYS_exit, 0)
    • 执行 “exit” 系统调用终止当前线程
    • 不会调用 atexit

atexit会帮助我们做libc的clean up!!!atexit其实就是一个注册回掉函数的地方!!!

小例子

结束当前进程执行的四种方式

  • return, exit, _exit, syscall
  • exit-demo.c
    • 用 strace 观察程序的执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/syscall.h>

void func() {
printf("Goodbye, Cruel OS World!\n");
}

int main(int argc, char *argv[]) {
atexit(func);

// main函数return,会调用我们的atexit
if (argc < 2) return EXIT_FAILURE;

// libc函数exit,会调用我们的atexit
if (strcmp(argv[1], "exit") == 0)
exit(0);
// glibc函数_exit,不会调用我们的atexit
if (strcmp(argv[1], "_exit") == 0)
_exit(0);
// syscall(SYS_exit, 0),不会调用我们的atexit。
if (strcmp(argv[1], "__exit") == 0)
syscall(SYS_exit, 0);
}

image-20221222160103243

  • summary
    • main的返回和libc函数exit,不仅会执行atexit,还会做一些结尾处理。例如把printf的buffer的内容,给最终打印出来,给清空!
    • glibc函数_exit。操作系统是无情的状态机管理者,才不管我们的buffer有没有东西没打印,有没有atexit。操作系统调用来关闭的时候,直接摧毁整个状态机,进程和里面所有的线程,资源,全部结束掉。
    • syscall(SYS_exit, 0),执行的是老的操作系统的调用,关闭的是当前的这一个线程。而_exit则是删除所有的线程。
  • Linux默认执行的是删除退出是_exit,所有的线程才退出,这其实是一种比较安全的行为。

References

  1. qemu帮助手册:http://linux.51yip.com/search/qemu,上网查一下应该很多这个版本,虚拟机的启动,和进入虚拟机后的调试,都要使用到昂!

  2. tmux的使用:tmux select-window

  3. 视频链接:https://www.bilibili.com/video/BV1hL411w737/?spm_id_from=333.999.0.0&vd_source=ff957cd8fbaeb55d52afc75fbcc87dfd

  4. 课件链接:https://jyywiki.cn/OS/2022/slides/11.slides#/

  5. gcc exit-demo.c -static,静态编译之后,strace会简单一点昂!!!(因为会省去运行的时候,动态链接相关的系统调用,好看一点。)


NJUOS-11-操作系统上的进程
https://alexanderliu-creator.github.io/2022/12/22/njuos-11-cao-zuo-xi-tong-shang-de-jin-cheng/
作者
Alexander Liu
发布于
2022年12月22日
许可协议