文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>linux 1.0 内核注解 linux/kernel/exit.c

linux 1.0 内核注解 linux/kernel/exit.c

时间:2009-03-08  来源:taozhijiangscu

/********************************************
 *Created By: 陶治江
 *Date:       2009-3-7
 ********************************************/
#define DEBUG_PROC_TREE #include <linux/wait.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/resource.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/malloc.h>
#include <asm/segment.h>
extern void shm_exit (void);
extern void sem_exit (void);
int getrusage(struct task_struct *, int, struct rusage *); //如果实际上信号被设置了就返回1,否则返回0,这个函数
//是被send_sig调用的
static int generate(unsigned long sig, struct task_struct * p)
{
 //这一这种信号码同信号位图的转换方式
 unsigned long mask = 1 << (sig-1);
 
 //指向任务结构中的处理sigaction结构指针
 struct sigaction * sa = sig + p->sigaction - 1;
 //如果任务结构中PF_PTRACED位被设置,就设置信号
 if (p->flags & PF_PTRACED) {
  p->signal |= mask;
  return 1;
 }
 
 //如果该信号sigaction结构中指明该信号处理方法是被忽略,就
 //不设置该信号,但是SIGCHLD信号除外
 if (sa->sa_handler == SIG_IGN && sig != SIGCHLD)
  return 0;
  
 //有的信号被设置为默认的处理方法,这些信号也不被设置,
 //另外的一个特殊的是信号SIGCONT已经被处理过了,也不用设置了
 //但是呢,不知道SIGCONT信号如果有非默认的处理方式怎么办?
 //在先前的send_sig中的处理是否合法?silly question哈
 if ((sa->sa_handler == SIG_DFL) &&
     (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH))
  return 0;
 
 p->signal |= mask; //设置信号
 return 1;
}
//向指定的任务发送信号
int send_sig(unsigned long sig,struct task_struct * p,int priv)
{
 if (!p || sig > 32)
  return -EINVAL;
  
 //信号SIGCONT使得因为SIGSTOP而停止的进程继续进行
 if (!priv
  && ((sig != SIGCONT) || (current->session != p->session))  //是不是只有在同一个会话组中才能发送信号啊?
  && (current->euid != p->euid)
  && (current->uid != p->uid)
  && !suser())
  return -EPERM;
  
 if (!sig) 
  return 0;
  
 if ((sig == SIGKILL) || (sig == SIGCONT)) {
  if (p->state == TASK_STOPPED)
    p->state = TASK_RUNNING;
  p->exit_code = 0;
  //这些信号虽然很古怪,也很多,但是都是要由SIGCONT
  //来唤醒的,另外发现即使发送SIGKILL也先复位这些信号
  p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
    (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
 }
 
 //如果是SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU就复位SIGCONT,从上面
 //和这里可知,这些信号同SIGCONT是互斥的
 if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
  p->signal &= ~(1<<(SIGCONT-1));
  
 //虽然SIGCONT等信号这里被处理了,但是
 //其他的信号的产生还要经过这个函数的
 generate(sig,p);
 
 return 0;
}
/*如果当前任务的父进程是任务1,说明这个进程将退出了
 *就发送SIGCHLD信号来善后,否则就向等待的父进程发送
 *信号,唤醒等待的父进程*/
void notify_parent(struct task_struct * tsk)
{
 //在进程创建(fork)的时候,p->exit_signal = clone_flags & CSIGNAL;
 //当创建的父进程比子进程先死亡的时候,子进程的父进程就是init进程了
 //这里猜测init和真正的父进程收到的子进程发送的信号是不一样的~~
 if (tsk->p_pptr == task[1])
  tsk->exit_signal = SIGCHLD;
 send_sig(tsk->exit_signal, tsk->p_pptr, 1);
 wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
}
/*释放指定任务结构的任务槽,内存页面和页目录项等
 *但是任务不能释放任务本身哦*/
void release(struct task_struct * p)
{
 int i;
 if (!p)
  return;
 if (p == current) {
  printk("task releasing itself\n");
  return;
 }
 for (i=1 ; i<NR_TASKS ; i++)
  if (task[i] == p) {
   task[i] = NULL;
   REMOVE_LINKS(p);  //在链表中撤除
   free_page(p->kernel_stack_page);
   free_page((long) p);
   return;
  }
 panic("trying to release non-existent task");
}
#ifdef DEBUG_PROC_TREE //检查指定的任务结构指针是否存在,如果存在返回0,否则1就不存在
int bad_task_ptr(struct task_struct *p)
{
 int  i;
 if (!p)
  return 0;
 for (i=0 ; i<NR_TASKS ; i++)
  if (task[i] == p)
   return 0;
 return 1;
}
void audit_ptree(void)
{
 int i;
 for (i=1 ; i<NR_TASKS ; i++) {
  if (!task[i])
   continue;
  if (bad_task_ptr(task[i]->p_pptr))
   printk("Warning, pid %d's parent link is bad\n",
    task[i]->pid);
  if (bad_task_ptr(task[i]->p_cptr))
   printk("Warning, pid %d's child link is bad\n",
    task[i]->pid);
  if (bad_task_ptr(task[i]->p_ysptr))
   printk("Warning, pid %d's ys link is bad\n",
    task[i]->pid);
  if (bad_task_ptr(task[i]->p_osptr))
   printk("Warning, pid %d's os link is bad\n",
    task[i]->pid);
  if (task[i]->p_pptr == task[i])
   printk("Warning, pid %d parent link points to self\n",
    task[i]->pid);
  if (task[i]->p_cptr == task[i])
   printk("Warning, pid %d child link points to self\n",
    task[i]->pid);
  if (task[i]->p_ysptr == task[i])
   printk("Warning, pid %d ys link points to self\n",
    task[i]->pid);
  if (task[i]->p_osptr == task[i])
   printk("Warning, pid %d os link points to self\n",
    task[i]->pid);
  if (task[i]->p_osptr) {
   if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
    printk(
   "Warning, pid %d older sibling %d parent is %d\n",
    task[i]->pid, task[i]->p_osptr->pid,
    task[i]->p_osptr->p_pptr->pid);
   if (task[i]->p_osptr->p_ysptr != task[i])
    printk(
  "Warning, pid %d older sibling %d has mismatched ys link\n",
    task[i]->pid, task[i]->p_osptr->pid);
  }
  if (task[i]->p_ysptr) {
   if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
    printk(
   "Warning, pid %d younger sibling %d parent is %d\n",
    task[i]->pid, task[i]->p_osptr->pid,
    task[i]->p_osptr->p_pptr->pid);
   if (task[i]->p_ysptr->p_osptr != task[i])
    printk(
  "Warning, pid %d younger sibling %d has mismatched os link\n",
    task[i]->pid, task[i]->p_ysptr->pid);
  }
  if (task[i]->p_cptr) {
   if (task[i]->p_cptr->p_pptr != task[i])
    printk(
   "Warning, pid %d youngest child %d has mismatched parent link\n",
    task[i]->pid, task[i]->p_cptr->pid);
   if (task[i]->p_cptr->p_ysptr)
    printk(
   "Warning, pid %d youngest child %d has non-NULL ys link\n",
    task[i]->pid, task[i]->p_cptr->pid);
  }
 }
}
#endif /* DEBUG_PROC_TREE */
/*返回进程组的会话号,如果进程的pid号同
 *指定的参数pgrp一样,也返回这单个进程的会话号*/
//这里关于会话、进程组、进程的关系是:
//每一个进程都属于一个进程组,而每一个进程组又属于一个会话
//一般当一个用户在一个终端登陆的时候即创建了一个会话
//进程组由组中的领头进程进行标识
//一个会话组中只能有一个前台进程组,其他的进程组都是后台进程组
//leader用来标识进程是否是进程组中的领头进程
int session_of_pgrp(int pgrp)
{
 struct task_struct *p;
 int fallback;
 fallback = -1;
 for_each_task(p) {
   if (p->session <= 0)
    continue;
    
  if (p->pgrp == pgrp)
   return p->session; //会话号
   
  if (p->pid == pgrp)  //进程是领头进程,so?
   fallback = p->session;
 }
 return fallback;
}
//向进程组发送信号,成功返回0,否则返回错误号,这些
//常常在终端中使用^C, ^Z等来发送
int kill_pg(int pgrp, int sig, int priv)
{
 struct task_struct *p;
 int err,retval = -ESRCH;
 int found = 0;
 if (sig<0 || sig>32 || pgrp<=0)
  return -EINVAL;
 for_each_task(p) {
  if (p->pgrp == pgrp) {
   if ((err = send_sig(sig,p,priv)) != 0)  //注意的是send_sig是返回0表示成功的,
              //而generate()是用0和1看是否设置了,注意区分
    retval = err;
   else
    found++;
  }
 }
 return(found ? 0 : retval);
}
//向会话首领发送信号,常常是发送SIGHUP信号给
//拥有终端的进程组的组长(我是这样理解的)
int kill_sl(int sess, int sig, int priv)
{
 struct task_struct *p;
 int err,retval = -ESRCH;
 int found = 0;
 if (sig<0 || sig>32 || sess<=0)
  return -EINVAL;
 for_each_task(p) {
  if (p->session == sess && p->leader) {
   if ((err = send_sig(sig,p,priv)) != 0)
    retval = err;
   else
    found++;
  }
 }
 return(found ? 0 : retval);
}
//针对于pid>0的用来指定某个特定进程的操作
//这个函数将会被sys_kill调用
int kill_proc(int pid, int sig, int priv)
{
  struct task_struct *p;
 if (sig<0 || sig>32)
  return -EINVAL;
 for_each_task(p) {
  if (p && p->pid == pid)
   return send_sig(sig,p,priv); //0
 }
 return(-ESRCH);
}
//向制定进程发送指定信号(POSIX制定-1参数没有定义,这里有出入哦)
asmlinkage int sys_kill(int pid,int sig)
{
 int err, retval = 0, count = 0;
 if (!pid)    //如果pid==0,就向同组的所有进程发送信号
  return(kill_pg(current->pgrp,sig,0));
  
 if (pid == -1) {  //向所有的进程发送信号,进程1除外
  struct task_struct * p;
  for_each_task(p) { 
   if (p->pid > 1 && p != current) {  //这个把current剔除了,but why?
    ++count;
    if ((err = send_sig(sig,p,0)) != -EPERM)
     retval = err;
   }
  }
  return(count ? retval : -ESRCH); //count>0,证明发送过了,是局部的返回值
           // 0 is the best
 }
 
 if (pid < 0)    //向指定的进程组发送信号
  return(kill_pg(-pid,sig,0));
  
       //pid>0,向指定的pid发送信号
 return(kill_proc(pid,sig,0));
}
//是否是孤儿进程“组”,如果不是返回0,是返回1
//呃,可能的理解是:由于一个会话可以有多个进程组,而每个进程
//也可以同时存在于多个进程组当中。所以如果一个会话中的一个进程组
//同外界的维系只是因为一个父进程和一个子进程之间的关系,那么
//父进程或者子进程的对出将产生孤儿进程组了
//而POSIX给予的处理方式就是先向进程组发送SIGHUP信号,这将导致
//进程组中的信号被挂起,其后再发送SIGCONT信号,让没有被SIGHUP
//挂起的信号继续运行
int is_orphaned_pgrp(int pgrp)
{
 struct task_struct *p;
 for_each_task(p) {
  if ((p->pgrp != pgrp) ||
      (p->state == TASK_ZOMBIE) ||
      (p->p_pptr->pid == 1))
   continue;
   
   //this indicate p->pgrp==pgrp
   //下面表示父进程和子进程不再同一个进程组,那么就不是孤儿进程组了
  if ((p->p_pptr->pgrp != pgrp) &&
      (p->p_pptr->session == p->session))
   return 0;
 }
 return(1); /* (sighing) "Often!" */
}
//检查进程组中是否有TASK_STOPPED标记的进程
//如果有返回1,否则返回
static int has_stopped_jobs(int pgrp)
{
 struct task_struct * p;
 for_each_task(p) {
  if (p->pgrp != pgrp)
   continue;
  if (p->state == TASK_STOPPED)
   return(1);
 }
 return(0);
}
/*这个进程要所有的子进程忘记自己是他们原来的"老子" :-)
 *一般是将他们的父进程设置为任务1,不知道什么使用用
 *到任务0了 :-(
 *可能这个函数是当父进程要死的时候,由init进程收养
 *孤儿进程的*/
static void forget_original_parent(struct task_struct * father)
{
 struct task_struct * p;
 for_each_task(p) {
  if (p->p_opptr == father)
   if (task[1])
    p->p_opptr = task[1];
   else
    p->p_opptr = task[0];
 }
}

NORET_TYPE void do_exit(long code) //这里的NORET_TYPE实际就是__volatile__ :-)
{
 struct task_struct *p;
 int i;
fake_volatile:
 if (current->semun)
  sem_exit();
 if (current->shm)
  shm_exit();
  
 free_page_tables(current);
 
 for (i=0 ; i<NR_OPEN ; i++)
  if (current->filp[i])
   sys_close(i);
   
 forget_original_parent(current); //当前进程的所有的子进程被init收养
 
 /*放回各个节点*/
 iput(current->pwd);
 current->pwd = NULL;
 iput(current->root);
 current->root = NULL;
 iput(current->executable);
 current->executable = NULL;
 
 
 {
  struct vm_area_struct * mpnt, *mpnt1;
  mpnt = current->mmap;
  current->mmap = NULL;
  while (mpnt) {
   mpnt1 = mpnt->vm_next;
   if (mpnt->vm_ops && mpnt->vm_ops->close)
    mpnt->vm_ops->close(mpnt);
   kfree(mpnt);
   mpnt = mpnt1;
  }
 }
 if (current->ldt) {
  vfree(current->ldt);
  current->ldt = NULL;
  for (i=1 ; i<NR_TASKS ; i++) {
   if (task[i] == current) {
    set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, &default_ldt, 1);  //清空
    load_ldt(i);
   }
  }
 }
 current->state = TASK_ZOMBIE;  //僵死进程了
 current->exit_code = code;
 current->rss = 0;
 
  //这里说明了current进程所在的进程组只有通过current
  //和父进程的关系维系着同外界进程组的联系,那么current的
  //退出将导致current进程组为孤儿进程组,那么就用POSIX的处理方式处理
 if ((current->p_pptr->pgrp != current->pgrp) &&
     (current->p_pptr->session == current->session) &&
     is_orphaned_pgrp(current->pgrp) &&
     has_stopped_jobs(current->pgrp))
 {
  kill_pg(current->pgrp,SIGHUP,1);
  kill_pg(current->pgrp,SIGCONT,1);
 }
 
 //通知自己的父进程
 notify_parent(current);
 
 /*
  * This loop does two things:
  *
    * A.  Make init inherit all the child processes
  * B.  Check to see if any process groups have become orphaned
  * as a result of our exiting, and if they have any stopped
  * jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
  */
 while ((p = current->p_cptr) != NULL) {
  current->p_cptr = p->p_osptr;  //p是current的子进程!
  p->p_ysptr = NULL;
  
  //让init进程收养current进程的所有的子进程
  p->flags &= ~(PF_PTRACED|PF_TRACESYS);
  if (task[1] && task[1] != current)
   p->p_pptr = task[1];
  else
   p->p_pptr = task[0];
   
  p->p_osptr = p->p_pptr->p_cptr;
  p->p_osptr->p_ysptr = p;
  p->p_pptr->p_cptr = p;
  
  if (p->state == TASK_ZOMBIE)  //也是僵死进程了
   notify_parent(p);
   
  //当current进程退出的时候,它们的子进程所在的进程组
  //也有可能成为孤儿进程组的,同前面一样再操作一次!
  if ((p->pgrp != current->pgrp) &&
      (p->session == current->session) &&
      is_orphaned_pgrp(p->pgrp) &&
      has_stopped_jobs(p->pgrp)) {
   kill_pg(p->pgrp,SIGHUP,1);
   kill_pg(p->pgrp,SIGCONT,1);
  }
 }
 
 if (current->leader)  //进程组首领
  disassociate_ctty(1); //如果有会话终端,就释放终端资源
 
 if (last_task_used_math == current)
  last_task_used_math = NULL;  //呃,反正进程要结束了,不用保存协处理器信息了
  
#ifdef DEBUG_PROC_TREE
 audit_ptree();
#endif
 schedule();
 
 goto fake_volatile;
}
asmlinkage int sys_exit(int error_code)
{
 do_exit((error_code&0xff)<<8);
}
//    The wait4 function suspends execution of the current  process  until  a
//       child as specified by the pid argument has exited, or until a signal is
//       delivered whose action is to terminate the current process or to call a
//       signal  handling  function.  If a child as requested by pid has already
//       exited by the time of the call  (a  so-called  "zombie"  process),  the
//       function  returns  immediately.  Any system resources used by the child
//       are freed.
asmlinkage int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
{
 int flag, retval;
 struct wait_queue wait = { current, NULL };
 struct task_struct *p;
 if (stat_addr) {   //用来保存终止进程的状态
  flag = verify_area(VERIFY_WRITE, stat_addr, 4);
  if (flag)
   return flag;
 }
 add_wait_queue(&current->wait_chldexit,&wait);
repeat:
 flag=0;
  for (p = current->p_cptr ; p ; p = p->p_osptr) {
  if (pid>0) {   //指定进程
   if (p->pid != pid)
    continue;
  } else if (!pid) {  //当前进程组
   if (p->pgrp != current->pgrp)
    continue;
  } else if (pid != -1) { //指定进程组
   if (p->pgrp != -pid)
    continue;
  }
  //else 全部的子进程
  
  
  /* wait for cloned processes iff the __WCLONE flag is set */
  if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
   continue;
   
  flag = 1;
  switch (p->state) {
   case TASK_STOPPED:  //进程被挂起,因为被追踪或者收到了停止类的信号
    if (!p->exit_code) //收到了停止类的信号而不是被追踪
     continue;
    if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED)) //不被追踪
     continue;
    if (stat_addr)  //拷贝信息
     put_fs_long((p->exit_code << 8) | 0x7f,
      stat_addr);
    p->exit_code = 0; //清楚退出代码
    if (ru != NULL)
     getrusage(p, RUSAGE_BOTH, ru); //获得资源的利用信息
    retval = p->pid;
    goto end_wait4;  //处理完毕,退出
    
   case TASK_ZOMBIE:  //呃,时间统计并加入到当前进程中
    current->cutime += p->utime + p->cutime;
    current->cstime += p->stime + p->cstime;
    current->cmin_flt += p->min_flt + p->cmin_flt;
    current->cmaj_flt += p->maj_flt + p->cmaj_flt;
    if (ru != NULL)
     getrusage(p, RUSAGE_BOTH, ru);
    flag = p->pid;
    if (stat_addr)
     put_fs_long(p->exit_code, stat_addr);  //注意这里的退出代码同上面的不同!
    if (p->p_opptr != p->p_pptr) { 
        //如果进程的原始父进程同现在的父进程不同就不能释放资源
        //此时将进程从队列中断开,然后设置为原始的父进程,再插入
        //到链中,并通知父进程发送 SIGCHLD信号
     REMOVE_LINKS(p);
     p->p_pptr = p->p_opptr;
     SET_LINKS(p);
     notify_parent(p); //通知父进程
    } else
     release(p);   //释放资源
#ifdef DEBUG_PROC_TREE
    audit_ptree();
#endif
    retval = flag;
    goto end_wait4;
   default:
    continue;
  }
 }
 
 //呃,这里说明有满足条件的进程,但是进程的状态不是停止或者僵死的状态
 if (flag) {
  retval = 0;
  if (options & WNOHANG) //这个标志表示如果没有子进程处于退出或者停止
        //状态就立即返回
   goto end_wait4;
   
  current->state=TASK_INTERRUPTIBLE;
  schedule();
  current->signal &= ~(1<<(SIGCHLD-1));
  retval = -ERESTARTSYS;
  if (current->signal & ~current->blocked)
   goto end_wait4;
   
   //如果该进程再次运行,说明是被别的信号唤醒了,这时候重新扫描
  goto repeat;
 }
 retval = -ECHILD;
end_wait4:
 remove_wait_queue(&current->wait_chldexit,&wait);
 return retval;
}
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
 return sys_wait4(pid, stat_addr, options, NULL);
}
  文档地址:http://blogimg.chinaunix.net/blog/upfile2/090308130013.pdf
相关阅读 更多 +
排行榜 更多 +
几何飞行内购修改版

几何飞行内购修改版

飞行射击 下载
别踩白块内购修改版

别踩白块内购修改版

休闲益智 下载
乐涂数字填色游戏

乐涂数字填色游戏

休闲益智 下载