chvnetcom 2019-11-07
类别 | 原因 | 异步/同步 | 返回行为 |
---|---|---|---|
中断 | 来自I/O设备的信号 | 异步 | 总是返回到下一条指令 |
陷阱 | 有意的异常 | 同步 | 总是返回到下一条指令 |
故障 | 潜在可恢复错误号 | 同步 | 可能返回到当前指令 |
终止 | 不可恢复错误 | 同步 | 不返回 |
syscall n
指令来满足用户向内核请求服务n,syscall
指令会导致一个到异常处理程序的陷阱,处理程序调用适当的内核程序。普通函数运行在用户模式,而系统调用运行在内核模式。abort
例程,abort
终止应用程序。/proc
文件系统,包含内核数据结构的内容的可读形式,运行用户模式进程访问。man syscalls
查看全部系统调用的列表。系统级函数遇到错误时,通常返回-1,并设置全局变量errno
。strace
命令可以打印程序和它的子进程调用的每个系统调用的轨迹进程有三种状态:
①运行:进程在CPU上执行,或等待被执行(会被调度)。
②停止:进程被挂起(不会被调度)。收到SIGSTOP
、SIGTSTP
、SIDTTIN
、SIGTTOU
信号,进程停止,收到 SIGCONT 信号,进程再次开始运行。
③终止:进程永远停止。原因可能是:收到终止进程的信号,从主程序返回,调用exit
函数。
fork
函数。新创建的子进程和父进程几乎相同,它获得父进程用户级虚拟地址空间和文件描述符的副本,主要区别是它们的PID不同。 fork 函数调用一次,返回两次;父子进程是并发运行的,不能假设它们的执行顺序;两个进程的初始地址空间相同,但是是相互独立的;它们还共享打开的文件。fork
三次,就会有八个进程。wait
和waitpid
等函数。execve
加载filename
后,调用启动代码,启动代码准备栈,将控制传给新程序的主函数int main(int argc, char *argv[], char *envp[])
。用户栈的典型组织:
main
函数只有两个参数,一般环境数组使用全局变量environ
传递。getenv
函数族。#include <stdlib.h> /** 在环境数组中搜索字符串"name=value" * @return 返回指向value的指针,若无返回NULL */ char *getenv(const char *name); /** 以"name=value"格式取字符串,添加到数组 * @return 返回0,出错返回-1 */ int putenv(char *string); /** 若name不存在,将"name=value"添加到数组;如存在且overwrite非0,用value覆盖原值 * @return 返回0,出错返回-1 */ int setenv(const char *name, const char *value, int overwrite); /** 删除环境变量name * @return 返回0,出错返回-1 */ int unsetenv(const char *name);
name
为环境变量名。ps
命令可以查看系统中当前的进程。top
命令会打印当前进程资源使用的信息。Linux系统中的信号:
kill
函数,显示要求内核发送信号给目的进程。进程可以给自己发送信号。发出而没有被接收的信号称为待处理信号。一种类型最多有一个待处理信号,重复的信号被丢弃。进程可以阻塞某种信号,这时仍可被发送,但不会被接收。一个待处理信号最多只能被接收一次。
shell
为每个作业创建一个独立的进程组,进程组ID一般为作业中父进程中的一个。SIGINT
信号到shell
,shell
捕获信号发送给前台进程组的每个进程,默认终止前台作业。^Z
发送SIGTSTP
信号到shell
,shell
捕获信号发送给前台进程组的每个进程,默认挂起前台作业。kill
命令向其他进程发送任意信号,给定的PID为负值时,表示发送信号给进程组ID为PID绝对值的所有进程。kill
函数发送信号给任意进程(包括自己)。sigprocmask
函数检测和更改当前信号屏蔽字。signal
函数修改和信号关联的默认行为(除 SIGSTOP 和 SIGKILL 外):#include <signal.h> typedef void (*sighandler_t)(int); /** 改变和信号signum关联的行为 * @return 返回前次处理程序的指针,出错返回SIG_ERR */ sighandler_t signal(int signum, sighandler_t handler);
参数说明:
①signum 信号编号。
②handler 指向用户定义函数,也就是信号处理程序的指针。或者为:
③SIG_IGN :忽略 signum
信号。
④SIG_DFL :恢复 signum
信号默认行为。
signal
函数会将signum
参数传递给信号处理程序handler
的参数,这样handler
可以捕捉不同类型的信号。signal
的语义和实现有关,最好使用sigaction
函数代替它。
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <signal.h> #include <unistd.h> void w_error(const char *msg) { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } void handler(int sig) { printf("caught SIGINT\n"); /* exit(0); */ } int main() { if (signal(SIGINT, handler) == SIG_ERR) w_error("signal error"); pause(); printf("come back\n"); exit(0); }
errno
设为EINTR
。sigaction
函数,使在Posix兼容的系统上可以设置信号处理语义。#include <setjmp.h> /** 在env缓冲区中保存当前栈的内容,供longjmp使用,返回0 * @return setjmp返回0,longjmp返回非0 */ int setjmp(jmp_buf env); int sigsetjmp(sigjmp_buf env, int savesigs); /** 从env缓冲区中恢复栈的内容,触发一个从最近一次初始化env的setjmp调用的返回,setjmp返回非0的给定val值 */ void longjmp(jmp_buf env, int val); void siglongjmp(sigjmp_buf env, int val);
sigsetjmp
和siglongjmp
。如果savesigs
非0,则sigsetjmp
在env
中保存进程的当前信号屏蔽字,调用siglongjmp
时从env
恢复保存的信号屏蔽字。同时,应该使用一个volatile sig_atomic_t
类型的变量来确保env
未设置时不被中断。#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> static sigjmp_buf buf; static volatile sig_atomic_t canjmp; void handler(int sig) { if (canjmp == 0) return; /* ... */ canjmp = 0; siglongjmp(buf, 1); } int main() { signal(SIGINT, handler); if (!sigsetjmp(buf, 1)) printf("starting\n"); else printf("restarting\n"); canjmp = 1; while (1) { sleep(1); printf("processing ...\n"); } exit(0); }
本周教材学习内容较多,与操作系统课程内容有交集,也学习到了全新的内容,对计算机程序运行有了更加深刻直观的理解。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 1/1 | 20/20 | |
第二周 | 300/500 | 1/1 | 10/15 | |
第三周 | 200/500 | 1/1 | 10/12 | |
第四周 | 500/500 | 1/1 | 12/12 | |
第五周 | 200/500 | 1/1 | 8/12 | |
第六周 | 300/500 | 1/1 | 12/12 | |
第七周 | 300/500 | 1/1 | 15/15 |
计划学习时间:15小时
实际学习时间:15小时