20135302魏静静——linux课程第六周实验及总结
linux课程第六周实验及总结
实验及学习总结
1.进程描述符task_struct数据结构
- 进程的作用:
将信号、进程间通信、内存管理和文件系统联系起来
- 操作系统的三大功能:
进程管理、内存管理、文件系统
-
内核通过唯一的进程标识PID来区别每个进程
- Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_info和进程的内核堆栈
-
task_struct结构的大体框架:
- 进程描述符中的state域描述了进程的当前状态:
- task_running
- task_interruprtion
- task_uninterruption
- task_traced
- task_stopped
2.进程的创建
fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建
1号进程是所有用户态进程的祖先,0号进程是所有内核线程的祖先
-
进程的创建大致步骤:
- 调用dup_task_struct()为新进程分配内核栈,task_struct等,其中的内容与父进程相同。
- check新进程(进程数目是否超出上限等)
- 清理新进程的信息(比如PID置0等),使之与父进程区别开。
- 新进程状态置为 TASK_UNINTERRUPTIBLE
- 更新task_struct的flags成员。
- 调用alloc_pid()为新进程分配一个有效的PID
- 根据clone()的参数标志,拷贝或共享相应的信息
- 做一些扫尾工作并返回新进程指针
-
从堆栈来看:
-
那么上图中的schedule_tuil做了什么呢?我们可以从实验中看到:
-
创建一个新进程在内核中的执行过程
- 复制一个PCB——task_struct,见copy_process内部
-
err = arch_dup_task_struct(tsk, orig);
-
给新进程分配一个新的内核堆栈
-
ti = alloc_thread_info_node(tsk, node);
-
tsk->stack = ti;
-
setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈。
-
-
从用户态的代码看fork():函数返回了两次,即在父子进程中各返回一次
- *childregs = *current_pt_regs(); //复制内核堆
- childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
- p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
- p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址