中科大软院linux实验

  • 格式:pdf
  • 大小:101.04 KB
  • 文档页数:8

下载文档原格式

  / 8
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

printf("I am child process,my pid is %d,返回值 is %d\n",getpid(),id); else printf("I am parent process,my pid is %d,返回值 is %d\n",getpid(),id); } } return 0; }
if (!(clone_flags & CLONE_STOPPED)) wake_up_new_task(p, clone_flags); else __set_task_state(p, TASK_STOPPED); 上述代码表示:如果没有设置 CLONE_STOPPED 标志,就立刻唤醒新进程,否则就设置该进 程的运行状态为 TASK_STOPPED。
运行结果如下:其中,fork 返回值分别是:0(子进程),1933(父进程)
ustc@ubuntu:~$ ./fok I am child process,my process id is 1933 The return number is 0 I am parent process,my process id is 1829 The return number is 1933 b)编写另外一个程序:连续 3 次调用 fork,然后让子进程和父进程分别输出 fork 的返回值 和各自的 pid,说明一共创建了几个进程?画出进程之间的创建关系。(进程使用 pid 来标 识) #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<sys/types.h> int main() { int id,i; for(i=1;i<4;i++) { id=fork(); wait(); if(id==-1) printf("Failed!"); else { if(id==0)
if (unlikely (trace)) { current->ptrace_message = nr; ptrace_notify ((trace << 8) | SIGTRAP); }
1.从用户态体验进程的创建
程序如下:
a)使用 c 语言编写一段用户程序:调用 fork 创建一个子进程,然后子进程和父进程分别输出 fork 的返回值。 #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<sys/types.h> int main() { int pid; pid=fork(); wait(); if(pid==-1) printf("Failed!"); else if(pid==0) {printf("I am child process,my process id is %d\n",getpid()); printf("The return number is %d\n",pid); exit(0); } else{ printf("I am parent process,my process id is %d\n",getppid()); printf("The return number is %d\n",pid); } }
long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) 其中 clone_flags 是一个标志集合,用来指定控制复制过程的一些属性。stack_start 是用户状态 下栈的起始地址。regs 是一个指向寄存器集合的指针。stack_size 是用户状态下栈的大小。 parent_tidptr 和 child_tidptr 是指向用户空间中地址的两个指针,分别指向父子进程的 TID。 do_fork 函数主要部分分为:copy_process,确定 PID,wake_up_new_task,设置 clone_vfork。 部分代码分析: if (unlikely(current->ptrace)) { trace = fork_traceflag (clone_flags); if (trace) clone_flags |= CLONE_PTRACE; } 以上代码的作用是:判断当前进程是否处于被跟踪状态。如果当前进程处于被跟踪调试状态,调 用 fork_tracflag 获得 clone_flags 所要求的跟踪方式编码,如果这个编码不为 0 说明父进程在跟踪 当前进程的情况下还想继续跟踪当前进程创建的子进程。然后更新 clone_flags,为下一步标志子进 程也要被跟踪做准备。 p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL); copy_process 是 do_fork 的主要部分(后面再详细分析 copy_process)。它返回新创建的 进程的 task_struct 结构体指针 p,新创建的 task_struct 是父进程的一份拷贝。 if (!IS_ERR(p)) { struct completion vfork; nr = task_pid_vnr(p); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); } 如果 copy_process 函数返回的地址落在合法的地址里面,通过调用 task_pid_vnr(p)获得它 的局部 pid 并且更新新创建的子进程的 pid 命名空间。再通过 put_user 函数将子进程的 pid 写入到 父进程的局部变量中,这样父进程就可以找到新创建的子进程了。再判断,如果执行的是 vfork(), 那么就设置 p 的 vfork_done 指向刚刚分配的 vfork 结构(CLONE_VFORK 的含义是把子进程插 入等待队列,并挂起父进程,直到子进程执行结束或执行新的程序才唤醒父进程)。然后初始化 vfork 结构的各个成员。执行下列代码: if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); } 如果进程 p 处于被跟踪状态,或者要求将进程 p 的起始状态设置为暂停状态,在新建进程处理链 表中添加信号 SIGSTOP,并设置进程的信号处理标记 TIF_SIGPENDING,这样在进程获得处理 器时会立即处理信号 SIGSTOP,此时进程会立即放弃处理器进入睡眠状态。
接着,如果进程处于被监视状态,那么把子进程的 pid 放入当前进程的 ptrace_message,这 样跟踪进程就可以通过这个字段对新的子进程进行访问了。
if (clone_flags & CLONE_VFORK) { freezer_do_not_count(); wait_for_completion(&vfork); freezer_count(); if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) { current->ptrace_message = nr; ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); } }
运行结果如下:
ustc@ubuntu:~$ ./fk I am child process,my pid is 3376,返回值 is 0 I am child process,my pid is 3377,返回值 is 0 I am child process,my pid is 3378,返回值 is 0 I am parent process,my pid is 3377,返回值 is 3378 I am parent process,my pid is 3376,返回值 is 3377 I am child process,my pid is 3379,返回值 is 0 I am parent process,my pid is 3376,返回值 is 3379 I am parent process,my pid is 3375,返回值 is 3376 I am child process,my pid is 3380,返回值 is 0 I am child process,my piห้องสมุดไป่ตู้ is 3381,返回值 is 0 I am parent process,my pid is 3380,返回值 is 3381 I am parent process,my pid is 3375,返回值 is 3380 I am child process,my pid is 3382,返回值 is 0 I am parent process,my pid is 3375,返回值 is 3382
分析可知总共创建了八个进程。进程之间的创建关系如下图所示。
3375
3376
3375
3380
3376
3377
3375
3382
3380 3381
3376
3379
3377
3378
2.对 linux 中进程的创建进行分析,提交分析报告。
Linux 提供了几个系统调用 fork,vfork,clone 用来创建新进程,其中,clone 创建轻量级进程, 必须指定要共享的资源,exec 系统调用执行一个新程序,exit 系统调用终止进程。 在 arch\x86\kernel\process_32.c 文件中,我们可以看到 fork,vfork,clone 的定义,如下所 示。 asmlinkage int sys_fork(struct pt_regs regs) { return do_fork(SIGCHLD, regs.sp, &regs, 0, NULL, NULL); } asmlinkage int sys_clone(struct pt_regs regs) { unsigned long clone_flags; unsigned long newsp; int __user *parent_tidptr, *child_tidptr; clone_flags = regs.bx; newsp = regs.cx; parent_tidptr = (int __user *)regs.dx; child_tidptr = (int __user *)regs.di; if (!newsp) newsp = regs.sp; return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr); } asmlinkage int sys_vfork(struct pt_regs regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, &regs, 0, NULL, NULL); } 不论是 fork,vfork 还是 clone,在内核中最终都调用了 do_fork。可以看到 do_fork 是进程创 建的基础。在.\linux\kernel\fork.c 内找到 do_fork 函数,并进行分析。

相关主题