2018-2019-1 20189221 《Linux内核原理与分析》第六周作业

实验五

实验过程

将Fork函数移植到Linux的MenuOS

fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程。在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。通过fork返回的值来判断当前进程是子进程还是父进程。

启动MenuOS:

在test.c中添加代码如下:


int Fork(int argc, char *argv[])
{ pid_t fpid;
int count = 0;
fpid = fork();
if (fpid < 0)
printf("error in fork!");
else if (fpid == 0) {
printf("i am the child process, my process id is %d\n",getpid());
count++;
}
else {
printf("i am the parent process, my process id is %d\n",getpid());
count++;
}
printf("count: %d\n",count);
return 0;
} int main()
{
PrintMenuOS();
SetPrompt("MenuOS>>");
MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
MenuConfig("quit","Quit from MenuOS",Quit);
MenuConfig("fork","fork a child process",Fork); ExecuteMenu();

运行结果:

sys_call过程分析

gdb调试:

由于实验楼多次卡顿,十分浪费时间

调试代码:

$ gdb
(gdb) file linux-3.18.6/vmlinux
(gdb) target remote:1234
(gdb) continue

在sys_fork设置断点,在qemu中输入fork-asm命令,可以看到停在了sys_fork()函数中。

然后s单步执行,finish返回do_fork函数,返回值$2=866,即分配了pid=866的子进程。继续单步,到了schedule()中,此时发生了进程调度。finish后schedule返回。

再次单步执行,出现Cannot find bounds of current function。此时gdb已无法跟踪。

gdb中输入c继续执行,看到qemu中输出fid = 866,即子进程的pid为866。

system_call的代码:

ENTRY(system_call)
RING0_INT_FRAME
ASM_CLAC
pushl_cfi %eax //保存系统调用号;
SAVE_ALL //可以用到的所有CPU寄存器保存到栈中
GET_THREAD_INFO(%ebp) //ebp用于存放当前进程thread_info结构的地址
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax //检查系统调用号(系统调用号应小于NR_syscalls),
jae syscall_badsys //不合法,跳入到异常处理
syscall_call:
call *sys_call_table(,%eax,4) //合法,对照系统调用号在系统调用表中寻找相应服务例程
movl %eax,PT_EAX(%esp) //保存返回值到栈中
syscall_exit:
testl $_TIF_ALLWORK_MASK, %ecx //检查是否需要处理信号
jne syscall_exit_work //需要,进入 syscall_exit_work
restore_all:
TRACE_IRQS_IRET //不需要,执行restore_all恢复,返回用户态
irq_return:
INTERRUPT_RETURN //相当于iret

system_call流程:

实验总结

系统调用是特殊的中断函数,是多种中断处理过程的集合

系统调用的过程其实是另一种上下文切换的实现:

首先SAVE ALL保存上下文

根据IDT调用内核函数

执行RESTORE_ALL并返回用户模式

系统调用与中断的共同之处

  • 保存现场

    在系统调用时,用SAVE_ALL来保存系统调用时的上下文。

    中断处理的第一步也是要保存中断程序现场。

    中断处理完之后,可以返回到原来被中断的地方,在原有的运行环境下继续正确的执行下去。

  • 确定中断信息

    在系统调用中,需要将系统调用号通过eax传入,通过sys_call_table查询到调用的系统调用,然后跳转到相应的程序进行处理。

    中断处理时系统也需要有一个中断号,通过检索中断向量表,了解中断的类型和设备。

  • 处理中断

    跳转到相应的中断处理程序后,对中断进行处理。

  • 返回

    系统调用时最后要restore_all恢复系统调用时的现场,并用iret返回用户态。

    同样,执行完中断处理程序,内核也要执行特定指令序列,恢复中断时现场,并使得进程回到用户态。

系统调用与一般函数的不同之处

  • 不是通过“CALL”指令而是通过“INT”指令发起调用;

  • 不是通过“RET”指令,而是通过“IRET”指令完成调用返回;

  • 当到达内核态后,操作系统需要严格检查系统调用传递的参数,确保不破坏整个系统的安全性;

  • 执行系统调用可导致进程等待某事件发生,从而可引起进程切换;

最新文章

  1. 站在风口,你或许就是那年薪20w+的程序猿
  2. teeChart 修改注册表实现无试用到期提示
  3. SecureCRT中文乱码解决已设置UTF-8
  4. [AngularJS] 使用AngularAMD动态加载Service
  5. 【 D3.js 入门系列 --- 2.1 】 关于如何选择,插入,删除元素
  6. Hibernate缓存原理与策略 Hibernate缓存原理:
  7. mysql使用基础 sql语句(一)
  8. 12-1 上午mysql 基本语句
  9. PC端 $_SERVER 说明
  10. Android_Toast
  11. Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces
  12. [置顶] vi、akw和sed总结
  13. 浅谈SpringMVC(一)
  14. 解决ionic &lt;ion-nav&gt; rootParams获取不到参数
  15. Vue中的计算属性与$watch
  16. 【CH6802】车的放置
  17. 史上最简单的SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config)
  18. java多线程快速入门(十二)
  19. AndroidのInputFillter之按字符过滤长度,一个中文当两个字符
  20. JavaBasic_01

热门文章

  1. ssh 管理 linux登录远程服务器
  2. zgrep用法
  3. 电子产品使用感受之--Windows 10 小米笔记本Air HDMI转VGA无信号问题
  4. ASP.NET Core 实现用户登录验证的最低配置
  5. Django:环境搭建
  6. C和C指针小记(五)-指针类型
  7. 转:JAVA中解决Filter过滤掉css,js,图片文件等问题
  8. LeetCode 589 N-ary Tree Preorder Traversal 解题报告
  9. 洛谷P4358密钥破解 [CQOI2016] 数论
  10. 【pyqtgraph绘图】在pyqtgraph中绘图