bash 的作业控制如何处理停止或终止的后台作业?

bash 的作业控制如何处理停止或终止的后台作业?

在研究 Linux 下 bash 作业控制机制的内部结构时,我遇到了一个理解上的小问题。让我们假设以下场景:

脚本在后台执行
user@linux:~# ./script.sh &

相同的脚本同时在前台执行
user@linux:~# ./script.sh

现在,在前台第二次执行脚本期间,脚本的第一次执行将作为后台作业执行。 Bash 现在使用前台进程的 PID 执行阻塞等待调用,直到它终止,然后获取相应的信息。前台进程终止后,bash 控制所有后台作业的状态,并在返回提示符之前通知每个更改。这通常是称为“+b”的默认行为。

但还有另一种模式称为“-b”。在此模式下,bash 会立即通知每个后台作业状态更改。据我了解,这是通过后台进程发送信号 SIGCHLD 来完成的。但是 bash 如何对终止后台进程的信号做出反应,并将消息打印到终端,尽管它执行了阻塞等待调用。因为在我看来,信号仅在返回用户模式之前进行处理。
bash 调用是否会在循环中使用选项 WNOHANG 等待,直到当前前台终止?

此外,当在“-b”模式下运行时,bash 可以写入终端,尽管它不属于终端的前台进程组。即使当我使用 stty 设置选项“tostop”时,bash 也可以写入终端,而无需成为前台进程组的一部分。 bash 是否获得任何特殊权限,因为它是终端控制进程组的一部分。

我希望,我能弄清楚我的理解问题在哪里。

答案1

是的,在循环中bash使用waitpid()with 。WNOHANG你可以看到这个waitchld()jobs.c:

static int
waitchld (wpid, block)
     pid_t wpid;
     int block;
{

...

  do
    {
      /* We don't want to be notified about jobs stopping if job control
         is not active.  XXX - was interactive_shell instead of job_control */
      waitpid_flags = (job_control && subshell_environment == 0)
                        ? (WUNTRACED|wcontinued)
                        : 0;
      if (sigchld || block == 0)
        waitpid_flags |= WNOHANG;

...

  if (block == 1 && queue_sigchld == 0 && (waitpid_flags & WNOHANG) == 0)
    {
      internal_warning (_("waitchld: turning on WNOHANG to avoid indefinite block"));
      waitpid_flags |= WNOHANG;
    }

  pid = WAITPID (-1, &status, waitpid_flags);

...

  /* We have successfully recorded the useful information about this process
     that has just changed state.  If we notify asynchronously, and the job
     that this process belongs to is no longer running, then notify the user
     of that fact now. */
  if (asynchronous_notification && interactive)
    notify_of_job_status ();

  return (children_exited);
}

功能notify_of_job_status()只是写入bash进程的标准错误流。

不幸的是,我不能说太多关于是否tostop设置stty 应该影响您执行此操作的 shell。

相关内容