Chinaunix首页 | 论坛 | 博客
  • 博客访问: 40195
  • 博文数量: 10
  • 博客积分: 226
  • 博客等级: 二等列兵
  • 技术积分: 115
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-02 22:51
文章分类

全部博文(10)

文章存档

2015年(2)

2012年(8)

我的朋友

分类: LINUX

2015-12-28 01:43:39

#!/bin/bash
while true
do     
    ping 127.0.0.1
done

ping.sh

$> ping.sh
^c

bash script can't stop

首先要明确的是:

前台进程组受到sigint 后,一般情况下会立即退出。 因为用户键入^+c的本意是终止前台进程组。 
但是, ping在受到 sigint后, 立即capture 该信号, 也就是不执行默认动作。而是 通过 exit 正常退出, 发出sigchld 信号给父进程(bash脚本), 父进程认为该自进程正常结束, 循环继续。

源代码分析:
bash 4.3.3
jobs.c




当用户键入ctrl+c后, bash脚本和其子进程 都看见sigint信号,(他们是前台进程组成员)。 bash脚本作为父进程处于waitpid blocking状态, 收到sigint 后waitpid 立即返回 -1, 设置errorno为  EINTR。同时 bash要求child 立即死亡(也就是sigint的默认动作 terminate)。最后设置  child_caught_sigint = 1, bash 随后会根据该flag 退出;  
如果child capture signal,设置   child_caught_sigint = 0;   bash 根据该flag 不退出, 因为子进程capture sigint后, 并立即退出。 其信号处理函数需要做特定处理, 然后通过exit退出, 父进程会受到 sigchld 信号,父进程会认为子进程正常退出, 循环继续。

      /* If waitpid returns -1/EINTR and the shell saw a SIGINT, then we
     assume the child has blocked or handled SIGINT.  In that case, we
     require the child to actually die due to SIGINT to act on the
     SIGINT we received; otherwise we assume the child handled it and
     let it go. */
      if (pid < 0 && errno == EINTR && wait_sigint_received)
    child_caught_sigint = 1;

      if (pid <= 0)
    continue;    /* jumps right to the test */

      /* If the child process did die due to SIGINT, forget our assumption
     that it caught or otherwise handled it. */
      if (WIFSIGNALED (status) && WTERMSIG (status) == SIGINT)
        child_caught_sigint = 0;

bash 能够判断子进程是否因为 sigint 而自然terminate

      /* If the child process did die due to SIGINT, forget our assumption
     that it caught or otherwise handled it. */
      if (WIFSIGNALED (status) && WTERMSIG (status) == SIGINT)
        child_caught_sigint = 0;



如果child capture sigint 则调用 trap handler,
  if (JOBSTATE (job) == JDEAD)
    {
      /* If we're running a shell script and we get a SIGINT with a
     SIGINT trap handler, but the foreground job handles it and
     does not exit due to SIGINT, run the trap handler but do not
     otherwise act as if we got the interrupt. */
      if (wait_sigint_received && interactive_shell == 0 &&
      child_caught_sigint && IS_FOREGROUND (job) &&
      signal_is_trapped (SIGINT))
    {
      int old_frozen;
      wait_sigint_received = 0;
      last_command_exit_value = process_exit_status (child->status);

      old_frozen = jobs_list_frozen;
      jobs_list_frozen = 1;
      tstatus = maybe_call_trap_handler (SIGINT);
      jobs_list_frozen = old_frozen;
    }

至于更多的细节请补充
阅读(2015) | 评论(0) | 转发(0) |
0

上一篇:链接器,符号解析与重定位-概念

下一篇:没有了

给主人留下些什么吧!~~