CPS 445 Lecture notes: Command shells



Coverage: [USP] Chapter 11


Basic shell setup


    (regenerated from [ATT])

    see [USP] §§11.1-11.3 for more details


Signal handling in the foreground

  • a <ctrl-c> should not cause the shell to exit; shell should ignore SIGINT and SIGQUIT and block them
  • since child should be able to be terminated, child must set the handlers for SIGINT and SIGQUIT back to the default before execing
  • ush3.c; signalsetup.c
  • improvement in ush4.c; shell should not just ignore SIGINT; it should deal with it;
  • furthermore, shell should only block SIGINT and SIGQUIT when absolutely necessary
  • if shell (parent) receives a SIGINT, parent clears the input line and returns to prompt through siglongjump
  • child (command) should not do this
  • child should take the default action, which is to exit
    • parent blocks the signal before the fork
    • child restores the default action prior to unblocking; done by default with execvp
    • child cannot wait for this feature in execvp; a signal may come in between unblocking the signal and the call to execvp
  • William Kimball asks `why not just remove the if statement entirely from the child?'
  • why is wait now at the top of the loop?


Back to signal handling in the foreground

  • William Kimball asks `why not just remove the if statement entirely from the child?' because the exec will not unblock by default
  • why is wait now at the top of the loop?
  • how to integrate with pipelines and background processes?


Process groups, sessions, and controlling terminals: context

  • pipes need process groups
  • background processes need sessions and controlling terminals


Process groups

  • a process group is a collection of processes; established so a group of processes can receive a signal as a unit
  • process group id: associated with each process
  • use negative sign with kill
  • the process id of process group leader is equal in value to the id of the process group
  • group persists as long as some process is in it; thus, a group may be without a leader
  • child processes inherit the group id of their parent
  • setpgid: allows a process to change its group
    • id of calling process assumed if passed a 0 for pid
    • the process with pid becomes the leader if passed a 0 for gpid
    • parent can use this function to change the group of its child before a call to exec
    • a child can establish a new group for itself by calling this function with pgid set to the value of its pid
  • getpgrp returns the process group id of the caller


Sessions

  • a session is a collection of process groups
    • established for purposes of job control
    • creator is called the session leader; the shell is a session leader
    • session identified by the process id of its leader
  • every process belongs to a session, inherited from its parent
  • getsid: returns the group id of the session leader of the process specified by pid
  • setsid: creates a new session and makes the caller its leader
    • also creates a new group with id equal to the value of the caller's process id
    • results in one session of one group of one process, with no controlling terminal
  • Example 11.24:
    (all background process groups)
    ls -l | sort -n + 4 | grep testfile > testfile.out &
    grep process | sort > process.out &
    du . > du.out &
    cat /etc/passwd | grep users | sort | head > users.out &
    
    • all processes will have the same session id (the process id and session id of the shell)
    • one process (i.e., the leader) in each group will have the same id as the group


Controlling terminals

  • a session may have a controlling terminal associated with it
  • shell uses the controlling terminal to interact with user
  • a controlling terminal is associated with only one session
  • while session may contain multiple groups, only one at a time can perform I/O through the controlling terminal
    • called the foreground process group or foreground job
    • others are called the background process groups or background jobs; processes in this group are not affected by keyboard input from the terminal controlling the session to which it belongs
  • main purpose of job control is to shift processes between these two groups
  • ctermid: used to obtain the name of the caller's controlling terminal
  • Example 11.22: <ctrl-c> during execution of ls -l | sort -n +4 | more; all 4 processes belong to the foreground process group
  • Example 11.23: <ctrl-c> during execution of ls -l | sort -n +4 | more &


See nice summary on p. 391


Background processes

  • shell does not wait for a background process
  • background process is not killed by a SIGINT from the keyboard
  • rusers & is a long running command which is good for purposes of testing background processes
  • ush5.c handles background processes
    • must determine if an & is present on the command line before forking; because both parent and child need this information
    • parent does not wait
    • child calls setpgid to detach itself from the foreground process group of its session
  • demonstration of zombies
  • ush6.c address the problem of zombie processes
    • fork twice thus creating a child and grandchild
    • child exits immediately
    • this leaves the grandchild as an orphan adopted by init
    • now have parent wait for all children, even background processes
    • graphical depiction


  • new problem: shell must be able to detect of background process was stopped due to a SIGSTOP
    • waitpid has an option for detecting children stopped by signals
    • however, due to the extra fork, the command is run as a grandchild of the shell, not a child
    • solution: do not use extra call to fork; call waitpid with WNOHANG
      • more direct solution approach
      • implemented in ush7.c


References

    [ATT] UNIX System Calls and Libraries -- Part 1, Version 2.1.1, AT&T, 1990.
    [USP] K.A. Robbins and S. Robbins. UNIX Systems Programming: Concurrency, Communication, and Threads. Prentice Hall, Upper Saddle River, NJ, Second edition, 2003.

Return Home