标签:
一.复习上周内容
上周主要学习了Linux中的系统调用的过程,如图所示就是系统调用的大致过程:
一.关于进程调度的一些基本概念
fork():进程是处于执行期的程序以及相关资源的总称,进程在创建它的时候开始存活,在Linux系统中。这通常是调用fork()系统的结果,该系统调用通过复制一个现有进程来创建一个全新的进程,调用fork()的进程成为父进程,新产生的进程称之为子进程,在调用结束时,在返回点这个相同位置上,父进程恢复执行,子进程开始执行,fork()系统从内核返回两次:一次返回到父进程,另一次回到新的子进程。其中fork()实际上是由clone()系统调用实现的。
exec():创建新的进城之后会立即执行新的进程,接着调用exec()这组函数就可以创建新的地址空间,并把新的地址空间载入其中。
进程描述符:内核把进程的列表存放在叫做任务队列的双向循环列表中,链表中的类型都是task_struct、成为进程描述符的结构,进程描述符包含一个具体进程的所有信息,能完整的描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其它的更多信息。
thread_info:每个进程的task_struct存放在内核栈的尾端,
进程状态转换:
- TASK_RUNNING具体是就绪还是执行,要看系统当前的资源分配情况;
- TASK_ZOMBIE也叫僵尸进程
三.实验过程
1.更新menu内核,然后删除test_fork.c以及test.c(以减少对之后实验的影响)
2.编译内核,可以看到fork命令
3.启动gdb调试,并对主要的函数设置断点
4.在MenuOS中执行fork,就会发现fork函数停在了父进程中
5.继续执行之后,停在了do_fork的位置。然后n单步执行,依次进入copy_process、dup_task_struct。按s进入该函数,可以看到dst = src(也就是复制父进程的struct)
6.在copy_thread中,可以看到把task_pg_regs(p)也就是内核堆栈特定的地址找到并初始化
7.到了159、160行的代码就是把压入的代码再放到子进程中:
*children = *current_pt_regs(); childregs->ax = 0;
8.164行,是确定返回地址
p->thread.ip = (unsigned long) ret_from_fork;
实验感想:
只是我第一次这么早就完成博客,在这次实验的过程中我了解了进程间调度的基本方法,还自己实践了gdb对内核代码的调试,很有意义。
标签:
原文地址:http://www.cnblogs.com/20135124freedom/p/5336851.html