您的位置:首页 > 运维架构 > Linux

深入理解linux内核读书笔记(第三章)

2015-06-17 16:14 435 查看
1. 进程是程序执行时的一个实例。

2. 从内核的角度看,进程是系统进行资源分配的实体。

3. linux 通过轻量级进程来支持多线程应用,每一个轻量级进程对应一个线程。

线程之间共享地址空间,打开的文件等资源,内核对每一个轻量级进程进行单独调度。

4. 一个线程组包含了一组线程用来实现多线程应用,对于getpid,kill, _exit等系统调用,线程组作为一个整体。

5. 内核通过task_struct 结构体来保存进程的信息。

6. 进程的状态 task_struct->state

(1) TASK_RUNNING, 正在cpu上执行或者等待被执行。

(2) TASK_INTERRUPTTBLE,进程正在被挂起直到满足一定条件后被唤醒。唤醒条件包括中断,发送信号,或者等待的条件得到满足。

(3) TASK_UNINTERRUPTTBLE, 和(2)类似,但是不能被信号唤醒。

(4) TASK_STOPPED, 进程执行暂停。

(5) TASK_TRACED, 进程被调试器暂停

7. 进程的退出状态 task_struct->exit_state

(1) EXIT_ZOMBIE, 进程执行已经结束,但是父进程还没有调用wait4或者waitpid之类的系统调用来获取该进程的信息。

(2)EXIT_DEAD, 进程的最后状态,进程正在被系统移除,将进程退出状态从EXIT_ZOMBIE改为EXIT_DEAD可以防止其他的进程对该进程调用wait系列的函数。

8. 内核提供了set_task_state 和set_current_state宏来对进程的状态进行赋值,并且保证赋值的操作被正确执行(不会与其他操作乱序)。

9. 每个可以被单独调度的执行实体都有task_struct 结构体,大部分对进程的引用都是通过task_struct 的指针来完成。

10. 线程组共有的id是第一个线程的pid,保存在tgid中,getpid返回tgid而不是pid。

11. 进程的thread_info 和 内核栈共同占有两个页面,也可以配置占有一个页面,其中,thread_info位于低地址处,内核栈底位于地址顶端。

12. 两个list增加的操作:

(1) list_add(n, p), 将n节点添加到p节点之后。

(2) list_add_tail(n, p), 将n节点添加到p节点之前。

13. 当只有一个孩子进程时,children.prev 和 children.next都指向那个孩子进程; 第一个孩子的sibling.prev指向parent,最后一个孩子的sibling.next也指向parent。

14. 进程状态为TASK_STOPPED, TASK_ZOMBIE和TASK_DEAD的进程没有用链表连接,因为这些进程只能通过pid或者特定的父进程来访问;

进程状态为TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程根据等待事件细分为好多种,因此引入了等待队列。

15. __wait_queue结构体中,flags为1的话,表示是独占进程,内核有选择地唤醒进程; 为0的话是非独占进程,内核无条件唤醒。

16. 所有非独占进程位于等待队列的前面,而独占进程位于等待队列的后面,每次特定条件满足后,唤醒所有的非独占进程和一个独占进程。

17. 每个进程的资源配额保存在signal_struct 的rlim数组中,包括当前的使用量和最大使用量。子进程继承父进程的配额。

18. 在进程恢复执行之前必须要载入cpu寄存器的数据被称为硬件上下文,他是进程上下文的一个子集。

19. linux中,一部分硬件上下文保存在task_struct中,剩下的保存在内核栈中。

20. linux 2.6使用软件来进行进程切换,和x86提供的硬件切换相比,速度差不多,但是有更多的优化空间。

21. 进程切换发生在内核空间。当发生切换时,用户态的寄存器内容已经被保存在内核栈中,包括esp,和ss。

22. 尽管linux不使用硬件来切换进程,但是还是要求为每个cpu设置一个TSS段来保存硬件上下文。

23. 当进程从用户态切换到内核态时,从TSS中取得内核栈的地址。另外,当用户进程访问IO端口时,需要去检查TSS中的IO位图。通过tr寄存器来访问tss。

24. task_struct 中的thread_struct 保存了除通用寄存器的大部分寄存器,通用寄存器保存在内核栈中。

25. 每个进程切换包含两步:

(1)切换pgd,装入新的进程地址空间。

(2) 切换内核栈和硬件上下文。

26. 进程切换的第2步主要是由switch_to 宏来完成。switch_to的第三个last参数是一个输出参数,用来指向切换前的进程描述符。

27. thread_struct 中的esp0用来指向内核栈底(内核栈空), esp指向进程切换时的内核栈地址。(详见copy_thread)

28. linux 中,传统的fork 系统调用是通过 clone来实现的,flags(低字节)只包含SIGCHLD。

29. vfork中,包含的flags有SIGCHLD,CLONE_VM和CLONE_VFORK,child_stack和父进程相同。

30. clone, fork 和 vfork系统调用都是经过do_fork来处理。

31. 内核线程只运行在内核态,只使用大于PAGE_OFFSET的地址空间。

32. kernel_thread用来新建一个内核线程, 相当于调用do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL)。

33. 0进程(又叫idle进程, swapper进程), 是在内核初始化过程中创建的内核线程。进程描述符保存在init_task中。

34. start_kernel函数会创建另外一个内核线程,1进程,又叫init进程。该内核线程会调用init_post去执行用户的init进程。

35. release_task用来释放zombie进程的最后一个数据结构。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: