操作系统课内报告 内核编译、系统调用和进程同步通信 - 图文 联系客服

发布时间 : 星期五 文章操作系统课内报告 内核编译、系统调用和进程同步通信 - 图文更新完毕开始阅读22eedbe3d1f34693daef3e4c

操作系统课内实验报告

/*

child_tidptr, NULL, trace);

copy_process()函数申请PCB空间,并赋值 */

if (!IS_ERR(p)) {

根据该文件中别处定义的辅助函数,根据所提供的clone_flags参数的值为子孙进程建立祖先进程的数据结构中子孙进程部分的拷贝。如果clone_flags指明相关的部分应该是共享 而不是拷贝,这是辅助函数就简单地增加引用计数接着返回;否则,它就创建新进程所独有的新拷贝。 { } else {

wake_up_new_task(p, clone_flags); }

tracehook_report_clone_complete(trace, regs,clone_flags, nr, p);

if (clone_flags & CLONE_VFORK)

13

struct completion vfork; nr = task_pid_vnr(p);

if (clone_flags & CLONE_PARENT_SETTID)

put_user(nr, parent_tidptr);

if (clone_flags & CLONE_VFORK) { }

tracehook_report_clone(trace, regs, clone_flags, nr, p);

p->vfork_done = &vfork; init_completion(&vfork);

p->flags &= ~PF_STARTING;

if (unlikely(clone_flags & CLONE_STOPPED))

* We'll start up with an immediate SIGSTOP. sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); __set_task_state(p, TASK_STOPPED);

操作系统课内实验报告

{ } } else { } return nr; }

2.5.2 get_pid模块

PID 是使用get_pid函数生成的,该函数能够返回一个没有使用的PID。它从last_pid开始——这是最近分配的PID 。

内核中使用的get_pid的版本是内核复杂性和速度频繁折中的一个例子:这里速度更为重要一些。get_Pid经过了高度优化——它比直接向前的实现方法要复杂得多,但是速度也要快得多。最直接的实现方法将遍历执行整个任务列表——典型的情况可能有几十项,有时候也可能成百上千项——对每一个可能的PID 进程检测并找出适当的值。但是在人多数情况下都可以跳过。

如果我们所需要的只是要为每一个运行进程都快速计算一个各不相同的整数,那么这里已经有现实可用的方法:只要取在task 数组中进程的索引就可以了。这肯定要比现在的get_Pid 速度要快。毕竟,这无须遍历任务列表。但是,很多现存的应用程序都假定在一个PID 可以再重用之前都需要等待一段时间。这种假定在任何情况下都是不安全的,但是,如果为了这些程序的问题而将内核牵涉进去可能仍然是不好的。现存的PID 分配策略速度仍然很快,并且它偶尔还有可以暴露这些应用程序中的潜在的缺陷。 static int get_pid(unsigned long flags) {

static int next_safe = PID_MAX;//静态next_safe,初始时让它等于最大的pid值。 /*

next_safe 变量是一个为加快系统运行速度而设定的变量;它保持记录了可能保留的次最低的候选PID。当last_pid 递增并超过这个范围时,系统应该检测整个任务列表来保证这个候选PID是否仍在被保留若(原来保留这个PID 的进程现在可能已经运行完了)。由于遍历这个任务列表可能会很慢,所以、只要可能就应该避免执行这样的操作。因此,在执行这个

14

freezer_do_not_count(); wait_for_completion(&vfork); freezer_count();

tracehook_report_vfork_done(p, nr);

nr = PTR_ERR(p);

操作系统课内实验报告

遍历的过程中,get_Pid要重新计算next_safe ― 如果有些进程已经死掉了,这个数字可能现在更大了,因此get_pid可以避免一些将来对任务列表的遍历(next_safe是静态的,因此其值在下次get_Pid需要分配PID时就会保留下来)。如果新的进程要和其祖先共享PID ,就返回祖先进程的PID 。 */

struct task_struct *p; int pid;

if (flags & CLONE_PID) return current->pid; spin_lock(&lastpid_lock); /*

开始搜寻候选PID寻找未使用的值。位与运算只是通过测试低15位是否置位来简单测试last_pid的新值是否超过了32767(最大允许的PID) 。我怀疑这些内核开发者真的需要通过这样做来获得微小的速度优势,但是你永远也不会知道;至少在这段代码编写期间、gcc 还不够敏锐到足以注意到它们的等价性,并在生成的代码中选择稍微快速的形式。 */

if((++last_pid) & 0xffff8000) {

last_pid = 300; /* Skip daemons etc. */

goto inside;//显然,大于了8000,就不需要判断last_pid>=next_safe了。 }

if(last_pid >= next_safe) {//当准备分配的last_pid大于了next_safe,那么这个值就unsafe了。 inside:

next_safe = PID_MAX;//先把next_safe拉到最后,然后再一步一步的寻找最佳位置。 read_lock(&tasklist_lock); repeat:

for_each_task(p) { if(p->pid == last_pid || p->pgrp == last_pid || p->tgid == last_pid || p->session == last_pid) { if(++last_pid >= next_safe) {

if(last_pid & 0xffff8000)//next_safe值不总是PID_MAX

15

操作系统课内实验报告

last_pid = 300; next_safe = PID_MAX; }

goto repeat; }

if(p->pid > last_pid && next_safe > p->pid) next_safe = p->pid;

if(p->pgrp > last_pid && next_safe > p->pgrp) next_safe = p->pgrp;

if(p->session > last_pid && next_safe > p->session) next_safe = p->session;

//这是为了找到last_pid,到next_safe的最好空间。 }

read_unlock(&tasklist_lock); }

pid = last_pid;

spin_unlock(&lastpid_lock); return pid; }

2.5.3 do_execve模块 struct linux_binprm

初始化参数和环境 文件是否存在 N Y 填充bprm的argc和argv 出错! 用copy_strings把参数和环境变量拷贝到次进程 用search_binary_hander找到要执行的程序 图2.2 do_execve函数流程图

16