While studying the internals of bash's job control mechanism under Linux I have came across a little problem of understanding. Let's assume the following scenario:

script is executed in background
user@linux:~# ./script.sh &

same script is executed in foreground at the same time
user@linux:~# ./script.sh

Now the first execution of the script is performed as a background job during the second execution of the script in the foreground. Bash now performs a blocking wait call with the PID of the foreground process until it terminates and then it gets the corresponding information. After the termination of the forground process bash controls the status of all background jobs and informs about every changes before returning to prompt. This is usually the default behavior called "+b".

But there is an other mode called "-b". In this mode bash informs immediately about every background job status change. In my understanding this is done by sending the signal SIGCHLD by the background process. But how could bash react to this signal of a terminated background process and print a message to the terminal although it executes a blocking wait call. Because in my opinion signals are only handled before returning to user mode.
Does bash call wait with the option WNOHANG within a loop until the current foreground terminates?

Furthermore, when operating in mode "-b" bash can write to the terminal although it doesn't belong to the foreground process group of the terminal. Even when I set the option "tostop" with stty, bash can write to the terminal without being part of the foreground process group. Does bash get any special permissions because it is part of the controlling process group of the terminal.

I hope, I could make clear where my problems of understanding are.


Yes, bash uses waitpid() with WNOHANG in a loop. You can see this in waitchld() in jobs.c:

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


      /* 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);

The notify_of_job_status() function simply writes to the bash process' standard error stream.

I can't unfortunately say much about whether setting tostop with stty should influence the shell that you do this in.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.