问题: strace 输入中的 execve(...)到底是什么?
过程实践状态切换
过程生命周期
Linux过程基本概念
- 过程是 Linux 工作的执行单元,也是 Linux 系统资源的调配单位
- 每个 Linux 利用程序运行后由一个或多个过程
- 一个 Linux 过程能够执行一个或多个程序
- Linux 过程有多种不同状态(即:Linux 过程有不同的活法)
Linux 过程状态分析
- 就绪 / 运行 状态 (R) : TASK_RUNNING
阻塞状态:
- 可中断 (S) : TASK_INTERRUPTIBLE (可被内核信号唤醒)
- 不可中断 (D) : TASK_UNINTERRUPTIBLE (对实时性要求高时应用)
- 进行状态 (T) : TASK_STOP
退出状态 : TASK_DEAD
- 僵尸 (X) : EXIT_ZIMBIE (过程生命期完结,但内核中还保留着与过程相干的数据信息)
- 死亡 (Z) : EXIT_DEAD
tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/0 4826 pts/0 Ss 0:00 /bin/bash 5328 pts/0 R+ 0:00 ps ax 5329 pts/0 S+ 0:00 grep --color=auto pts/0
tiansong@tiansong:~/Desktop/linux$ sleep 120^C 【CTRL + C】
tiansong@tiansong:~/Desktop/linux$ sleep 120 &[1] 5423tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/0 4826 pts/0 Ss 0:00 /bin/bash 5423 pts/0 S 0:00 sleep 120 5453 pts/0 R+ 0:00 ps ax 5454 pts/0 S+ 0:00 grep --color=auto pts/0tiansong@tiansong:~/Desktop/linux$ kill 5423[1]+ Terminated sleep 120tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/0 4826 pts/0 Ss 0:00 /bin/bash 5501 pts/0 R+ 0:00 ps ax 5502 pts/0 R+ 0:00 grep --color=auto pts/0
loop.c
int main(){ while(1); return 0;}
tiansong@tiansong:~/Desktop/linux$ gcc ./loop.c -o loop.outtiansong@tiansong:~/Desktop/linux$ ./loop.out &[1] 6510tiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/3 6021 pts/3 Ss 0:00 /bin/bash 6510 pts/3 R 0:04 ./loop.out 6522 pts/3 R+ 0:00 ps ax 6523 pts/3 S+ 0:00 grep --color=auto pts/3tiansong@tiansong:~/Desktop/linux$ kill 6510[1]+ Terminated ./loop.outtiansong@tiansong:~/Desktop/linux$ ps ax | grep pts/3 6021 pts/3 Ss 0:00 /bin/bash 6543 pts/3 R+ 0:00 ps ax 6544 pts/3 S+ 0:00 grep --color=auto pts/3
Linux 过程树简介
Linux 过程必知必会
- 每个过程都有一个惟一的标识符(PID)
- 每个过程都是由一个过程创立而来(即:父过程)
#include <sys/types.h>#include <unistd.h>pid_t getpid(); // 以后过程 id pid_t getppid(); // 以后过程父过程 id
一些乏味的问题
- 问题一:第 1 个过程时什么?
- 问题二:如何创立过程
Linux 过程树
- 整个 Linux 零碎的所有过程形成一个树结构
- 树根由内核主动创立,即:
IDLE (PID → 0)
零碎中的第一个过程是 init / systemd (PID → 1)
- 0 号过程创立 1 号过程,1 号过程负责实现内核局部初始化工作
- 1 号过程加载执行初始化程序,演变为用户态 1 号过程
tiansong@tiansong:~/Desktop/linux$ pstreesystemd-+-ModemManager---2*[{ModemManager}] |-NetworkManager---2*[{NetworkManager}] |-VGAuthService |-accounts-daemon---2*[{accounts-daemon}] |-acpid |-avahi-daemon---avahi-daemon |-bluetoothd |-colord---2*[{colord}] |-cron |-cups-browsed---2*[{cups-browsed}] |-cupsd---dbus |-dbus-daemon |-fwupd---4*[{fwupd}] |-gdm3-+-gdm-session-wor-+-gdm-x-session-+-Xorg---{Xorg} | | | |-gnome-session-b-+-ssh-agent | | | | `-2*[{gnome-session-b}] | | | `-2*[{gdm-x-session}] | | `-2*[{gdm-session-wor}] | `-2*[{gdm3}] |-gnome-keyring-d---3*[{gnome-keyring-d}] |-irqbalance---{irqbalance} |-2*[kerneloops] |-networkd-dispat |-nmbd |-polkitd---2*[{polkitd}] |-rsyslogd---3*[{rsyslogd}] |-rtkit-daemon---2*[{rtkit-daemon}] |-sh---node-+-node-+-bash | | `-11*[{node}] | |-node---11*[{node}] | |-node---12*[{node}] | `-10*[{node}] |-smbd-+-cleanupd | |-samba-bgqd | `-smbd-notifyd |-snapd---17*[{snapd}] |-sshd---sshd---sshd---bash---sleep |-switcheroo-cont---2*[{switcheroo-cont}] |-systemd-+-(sd-pam) | |-at-spi-bus-laun-+-dbus-daemon | | `-3*[{at-spi-bus-laun}] | |-at-spi2-registr---2*[{at-spi2-registr}] | |-dbus-daemon | |-dconf-service---2*[{dconf-service}] | |-evolution-addre---5*[{evolution-addre}] | |-evolution-calen---8*[{evolution-calen}] | |-evolution-sourc---3*[{evolution-sourc}] | |-gjs---10*[{gjs}] | |-gnome-session-b-+-evolution-alarm---5*[{evolution-alarm}] | | |-gsd-disk-utilit---2*[{gsd-disk-utilit}] | | |-update-notifier---3*[{update-notifier}] | | `-3*[{gnome-session-b}] | |-gnome-session-c---{gnome-session-c} | |-gnome-shell-+-ibus-daemon-+-ibus-dconf---3*[{ibus-dconf}] | | | |-ibus-engine-sim---2*[{ibus-engine-sim}] | | | |-ibus-extension----3*[{ibus-extension-}] | | | `-2*[{ibus-daemon}] | | `-11*[{gnome-shell}] | |-gnome-shell-cal---5*[{gnome-shell-cal}] | |-gnome-terminal--+-bash---pstree | | `-4*[{gnome-terminal-}] | |-goa-daemon---3*[{goa-daemon}] | |-goa-identity-se---2*[{goa-identity-se}] | |-gsd-a11y-settin---3*[{gsd-a11y-settin}] | |-gsd-color---3*[{gsd-color}] | |-gsd-datetime---3*[{gsd-datetime}] | |-gsd-housekeepin---3*[{gsd-housekeepin}] | |-gsd-keyboard---3*[{gsd-keyboard}] | |-gsd-media-keys---3*[{gsd-media-keys}] | |-gsd-power---3*[{gsd-power}] | |-gsd-print-notif---2*[{gsd-print-notif}] | |-gsd-printer---2*[{gsd-printer}] | |-gsd-rfkill---2*[{gsd-rfkill}] | |-gsd-screensaver---2*[{gsd-screensaver}] | |-gsd-sharing---3*[{gsd-sharing}] | |-gsd-smartcard---4*[{gsd-smartcard}] | |-gsd-sound---3*[{gsd-sound}] | |-gsd-usb-protect---3*[{gsd-usb-protect}] | |-gsd-wacom---2*[{gsd-wacom}] | |-gsd-wwan---3*[{gsd-wwan}] | |-gsd-xsettings---3*[{gsd-xsettings}] | |-gvfs-afc-volume---3*[{gvfs-afc-volume}] | |-gvfs-goa-volume---2*[{gvfs-goa-volume}] | |-gvfs-gphoto2-vo---2*[{gvfs-gphoto2-vo}] | |-gvfs-mtp-volume---2*[{gvfs-mtp-volume}] | |-gvfs-udisks2-vo---3*[{gvfs-udisks2-vo}] | |-gvfsd-+-gvfsd-trash---2*[{gvfsd-trash}] | | `-2*[{gvfsd}] | |-gvfsd-fuse---5*[{gvfsd-fuse}] | |-gvfsd-metadata---2*[{gvfsd-metadata}] | |-ibus-portal---2*[{ibus-portal}] | |-ibus-x11---2*[{ibus-x11}] | |-pulseaudio---3*[{pulseaudio}] | |-tracker-miner-f---4*[{tracker-miner-f}] | `-xdg-permission----2*[{xdg-permission-}] |-systemd-journal |-systemd-logind |-systemd-resolve |-systemd-timesyn---{systemd-timesyn} |-systemd-udevd |-udisksd---4*[{udisksd}] |-unattended-upgr---{unattended-upgr} |-upowerd---2*[{upowerd}] |-vmtoolsd---3*[{vmtoolsd}] |-whoopsie---2*[{whoopsie}] `-wpa_supplicant
// 打印以后过程 PIDtiansong@tiansong:~/Desktop/linux$ echo $$6021
// 打印从树根到以后过程的门路,systemd(1091) 再次被加载实现更多初始化工作tiansong@tiansong:~/Desktop/linux$ pstree -A -p -s $$systemd(1)---systemd(1091)---gnome-terminal-(6837)---bash(6845)---pstree(7046)
tiansong@tiansong:~/Desktop/linux$ ./loop.out &[1] 7214tiansong@tiansong:~/Desktop/linux$ ./loop.out &[2] 7217tiansong@tiansong:~/Desktop/linux$ ./loop.out &[3] 7220tiansong@tiansong:~/Desktop/linux$ ./loop.out &[4] 7223tiansong@tiansong:~/Desktop/linux$ pstree -A -p -s $$systemd(1)---systemd(1091)---gnome-terminal-(6837)---bash(6845)-+-loop.out(7254) |-loop.out(7255) |-loop.out(7256) |-loop.out(7257) `-pstree(7259)
Linux 过程创立实战
Linux 过程创立
pid_t fork(void);
- (零碎调用)通过以后过程创立新过程,以后过程为父过程,新过程为子过程
int execve(const char *pathname, char *const argv[], char *const envp[]);
- (零碎调用)在以后过程中执行 pathname 指定的程序代码
fork() 的工作形式
- 为子过程申请内存空间,并将父过程数据齐全复制到子过程空间
- 两个过程中的程序执行地位完全一致(
fork()函数调用地位
) 不同之处:
- 父过程: fork() 返回紫禁城 PID
- 子过程: fork() 返回 0
通过 fork() 返回值判断父子过程,执行不同代码
上面程序输入什么? 为什么?
main.c
#include <stdio.h>#include <unistd.h>#include <sys/types.h>static int g_global = 0;int main(){ int pid = 0; printf("Hello Word!\n"); printf("current = %d\n", getpid()); if ((pid = fork()) > 0) { g_global = 1; usleep(100); printf("child = %d\n", pid); printf("%d g_global = %d\n", getpid(), g_global); } else { g_global = 10; printf("parent = %d\n", getppid()); printf("%d g_global = %d\n", getpid(), g_global); } return 0;}
tiansong@tiansong:~/Desktop/linux$ ./main.out Hello Word!current = 8010child = 8011parent = 80108011 g_global = 108010 g_global = 1
fork 与 execve 利用
思考: 如何了解 “每个 Linux 过程能够执行一个或多个程序”?
1、 过程是一个存在于内存的实体2、 过程由程序加载而来3、 过程能够加载多个程序的代码
execve (...) 的工作形式
- 依据参数门路加载可程序程序(程序加载到以后过程中)
- 通过可执行程序信息构建过程数据,并写入以后过程空间
- 将程序执行地位重置到入口地址处(即:main())
execve(...)
将重置以后过程空间(代码 & 数据)而不会创立新过程
上面的程序输入什么?为什么?
test.c
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#define EXE "helloword.out"int main(){ char *args[] = {EXE, NULL}; printf("begin\n"); printf("pid = %d\n", getpid()); execve(EXE, args, NULL); printf("end\n"); return 0;}
helloword.c
#include <stdio.h>#include <unistd.h>#include <sys/types.h>int main(){ printf("exec = %d, %s\n", getpid(), "Hello World!"); return 0;}
tiansong@tiansong:~/Desktop/linux$ gcc test.c -o test.outtiansong@tiansong:~/Desktop/linux$ gcc helloword.c -o helloword.outtiansong@tiansong:~/Desktop/linux$ ./test.out beginpid = 8518exec = 8518, Hello World!
留神:end 没有输入
test.c
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#define EXE "helloword.out"int create_process(const char *path, char *args[]){ int ret = fork(); if (ret == 0) { execve(path, args, NULL); } return ret;}int main(){ char *args[] = {EXE, NULL}; printf("begin\n"); printf("pid = %d\n", getpid()); printf("child = %d\n", create_process(EXE, args)); printf("end\n"); return 0;}
tiansong@tiansong:~/Desktop/linux$ ./test.out beginpid = 8833child = 8834endexec = 8834, Hello World!