进程管理之进程创建和删除(一)

我们先来介绍内核进程创建函数kernel_thread()

pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
 struct pt_regs regs;//定义系统寄存器

 memset(&regs, 0, sizeof(regs));//把这些寄存器清零

 regs.ARM_r1 = (unsigned long)arg;//我们把传递给可执行函数的参数先付给r1。
 regs.ARM_r2 = (unsigned long)fn;//我们把可执行函数指针传递给r2。
 regs.ARM_r3 = (unsigned long)do_exit;//我们把函数推出函数传递给r3。
 regs.ARM_pc = (unsigned long)kernel_thread_helper;//最后我们把kernel_thread_helper()函数指针传递给pc。这样我们就会直接处理这个函数了,这个函数只是一个过渡的过程,首先他会把r1传递给r0,将r3传递给lr,最后把r2传递给pc。所以执行完这个过渡函数后,我们就会执行可执行函数了。
 regs.ARM_cpsr = SVC_MODE;//我们设置当前寄存器cpsr中的超级用户模式。

 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);//这个函数很重要,就是进程创建函数,我们这里要注意的只是flags部分,这里就规定了这个子进程与父进程之间的关系。CLONE_VM 表示父子进程共享虚拟地址,CLONE_UNTRACED 表示不可以调试子程序。
}

接下来我们看下创建用户进程函数sys_fork(),这个是fork()函数系统调用的内核实现函数。

asmlinkage int sys_fork(struct pt_regs regs)
{
 return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);//又可以发现这里也是调用do_fork()函数去创建一个进程,这里只是设置了SIGCHLD
}
我们接下来看下创建用户进程,父子进程共享现行地址空间的函数sys_vfork(),这个是vfork()函数系统调用的内核实现函数。

asmlinkage int sys_vfork(struct pt_regs regs)
{
 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);//这里我们没有看过的标志是CLONE_VFORK,它表示可以调用vfork()父进程可以睡眠标志。
}
接下来要介绍的是克隆用户进程函数sys_clone(),这个是clone()函数系统调用的内核实现函数。

asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)//这个函数的参数除了我们上面一直强调的系统寄存器外,还多出了clone_flags克隆进程控制标志字,还有就是新的栈指针newsp
{
 if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID))//如果clone_flags设置了设置父进程TID标志,或是清楚子进程TID标志
  return -EINVAL;//返回无效,由于clone()系统调用就是克隆出轻量级进程,也就是线程,与父进程共享同样的PID号,他们形成线程组,线程组的领头线程的TID号就是他们的PID号。

 if (!newsp)//如果新的堆栈为空
  newsp = regs->ARM_sp;//将传进来的堆栈寄存器的值作为新的栈指针。

 return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
}

我们下来要讨论的函数就是这个创建进程函数do_fork()

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)
{
 struct task_struct *p;
 int trace = 0;
 long pid = alloc_pidmap();//申请一个空闲PID号

 if (pid < 0)//如果发现pid无效的话
  return -EAGAIN;
 if (unlikely(current->ptrace)) {//如果当前进程的跟踪标志不等于0,说明要继续调试
  trace = fork_traceflag (clone_flags);//这个函数是根据clone_flags和current->ptrace两者的值来设置trace
  if (trace)//如果trace不为0的话
   clone_flags |= CLONE_PTRACE;//控制标志或上CLONE_PTREACE,表示这个进程是跟踪调试子进程
 }

 p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);//根据clone_flags的设置来创建进程p的各种数据结构并做相关初始化。
 if (!IS_ERR(p)) {//如果上面的操作无误
  struct completion vfork;//声明完成量结构vfork

  if (clone_flags & CLONE_VFORK) {//如果执行的是vfork()系统调用
   p->vfork_done = &vfork;//将上面声明的变量地址传给p->vfork_done
   init_completion(&vfork);//初始化完成结构变量的成员
  }

  if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {//如果要调试进程p,或者要求将进程p的起始状态设置为暂停状态
   sigaddset(&p->pending.signal, SIGSTOP);//p->pending->signal[0]=SIGSTOP其中pending表示进程p的私有挂起信号。
   set_tsk_thread_flag(p, TIF_SIGPENDING);//p->thread_info->flags=TIF_SIGPENDING表示进程有挂起型号。
  }

  if (!(clone_flags & CLONE_STOPPED))//进一步确定是否要求进程p的起始状态设置为暂停状态。
   wake_up_new_task(p, clone_flags);//如果不是的话,我们唤醒进程p,但是不进行切换。
  else
   p->state = TASK_STOPPED;//如果是的话,我们把进程的state设置为TASK_STOPPED表示进程现在是暂停状态。
  ++total_forks;//这个是个全局变量,统计系统执行do_fork()函数次数的计数器。

  if (unlikely (trace)) {如果确实要调试进程p
   current->ptrace_message = pid;//我们使当前进程的ptrace_message=pid,将进程p的pid号作为父进程的调试信息。
   ptrace_notify ((trace << 8) | SIGTRAP);
  }

  if (clone_flags & CLONE_VFORK) {//如果执行的是vfork()系统调用的话
   wait_for_completion(&vfork);//在此等待vfork的完成
   if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))//如果要调试vfork
    ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
  }
 } else {
  free_pidmap(pid);
  pid = PTR_ERR(p);//把p的错误号直接返回给pid
 }
 return pid;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值