.. _EventsSignals:

.. raw:: html

   <script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "EventsSignals";ODSA.SETTINGS.MODULE_LONG_NAME = "Events and Signals";ODSA.SETTINGS.MODULE_CHAPTER = "Processes and OS Basics"; ODSA.SETTINGS.BUILD_DATE = "2021-06-14 17:15:25"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script>


.. |--| unicode:: U+2013   .. en dash
.. |---| unicode:: U+2014  .. em dash, trimming surrounding whitespace
   :trim:


.. This file is part of the OpenCSF eTextbook project. It was
.. auto-generated by scripts from the OpenDSA eTextbook project.
.. See https://OpenCSF.org for more details. OpenCSF is distributed
.. under a Creative Commons Attribution-NonCommercial 4.0 International
.. License (see http://creativecommons.org/licenses/by-nc/4.0/),
.. Copyright (c) 2019-2021 by Michael S. Kirkpatrick. OpenDSA is
.. distributed under an MIT open source license, Copyright (c) 2012-2021
.. by the OpenDSA Project Contributors.

.. avmetadata::
   :author: Michael S. Kirkpatrick
   :requires:
   :satisfies: Events and Signals
   :topic: Events, Signals, Signal Handlers

Events and Signals
==================

In between the creation and destruction of the process, a number of other events can occur that may
or may not be expected. For instance, the program may require user input from the keyboard, or it
may try to read data from a file. When these requests are made, the process may be put into a
:term:`blocked state` until the requested input data is available. When that input data is provided,
the process will then resume. Similarly, an external user or the kernel itself might force the
process to enter a :term:`suspended state` for an indefinite time period. For instance, maybe the
machine is overloaded and slow, so a system administrator intervenes to pause some processes temporarily.

Blocking, suspending, and resuming processes all correspond to the abstract notion of a process life
cycle event. Other events can occur that do not necessarily cause a change in the process state
(e.g., the process can ignore the event and continue running). Here, we'll look at code for creating
processes and handling these events using :term:`signals <signal>`.


Sending Process Signals
-----------------------

If you have been working with the command line for a while, there is a good chance that you have
used signals without realizing it. When a process gets stuck (e.g., in an infinite loop), you might
have hit ``Ctrl-c`` to kill the process. Or if you knew the PID, you may have executed ``kill -9``
on the PID or even ``killall`` with the name of the program. In all of these cases, bash sent a
signal to the killed process that caused the process to terminate.

Signals can be identified by either their name or their number. From the command line, you can send
a signal using the ``kill`` utility with either the signal name or the associated number. For
instance, the following command would send ``SIGKILL`` to process number 12345:

.. codeinclude:: Processes/KillKill.txt

This command is identical to calling ``kill -9 12345``, because ``SIGKILL`` is signal 9 in POSIX
systems. One thing to note about using the ``kill`` utility is that the ``"SIG"`` part of the name
is omitted. You can observe this in the previous example, where we used the ``-KILL`` argument to
specify the ``SIGKILL`` signal. `Table 2.4 <#tbl2-4>`_ describes some common signals.

.. _tbl2-4:

.. raw:: html

   <center>
     <div class="col-10">
       <table class="table table-bordered">
         <thead class="jmu-dark-purple-bg text-light">
           <tr>
             <th class="py-0 center">Name</th>
             <th class="py-0 center">Number</th>
             <th class="py-0 center">Description</th>
           </tr>
         </thead>
         <tbody>
           <tr>
             <td class="py-0 center"><code>SIGINT</code></td>
             <td class="py-0 center">2</td>
             <td class="py-0">Interrupts the process, generally killing it. Typically sent with <code>Ctrl-c</code>.</td>
           </tr>
           <tr>
             <td class="py-0 center"><code>SIGKILL</code></td>
             <td class="py-0 center">9</td>
             <td class="py-0">Kills the process. Cannot be ignored or overwritten.</td>
           </tr>
           <tr>
             <td class="py-0 center"><code>SIGSEGV</code></td>
             <td class="py-0 center">11</td>
             <td class="py-0">Sent to a process when it experiences a segmentation fault.</td>
           </tr>
           <tr>
             <td class="py-0 center"><code>SIGCHLD</code></td>
             <td class="py-0 center">18</td>
             <td class="py-0">Sent to a parent when a child process finishes. Used by <code>wait()</code>.</td>
           </tr>
           <tr>
             <td class="py-0 center"><code>SIGSTOP</code></td>
             <td class="py-0 center">23</td>
             <td class="py-0">Suspends the process. Cannot be ignored or overwritten.</td>
           </tr>
           <tr>
             <td class="py-0 center"><code>SIGTSTP</code></td>
             <td class="py-0 center">24</td>
             <td class="py-0">Suspends the process. Typically sent with <code>Ctrl-z</code>.</td>
           </tr>
           <tr>
             <td class="py-0 center"><code>SIGCONT</code></td>
             <td class="py-0 center">25</td>
             <td class="py-0">Resumes a suspended process.</td>
           </tr>
         </tbody>
       </table>
       <p>Table 2.4: Common POSIX signals, their numbers, and their effects</p>
     </div>
   </center>

As described in the table, ``SIGINT`` and ``SIGKILL`` serve essentially the same purpose, as do
``SIGSTOP`` and ``SIGTSTP``. The difference is that programs can implement custom handlers for
``SIGINT`` and ``SIGTSTP``, possibly even ignoring them. The reason for this is that the application
may be in the middle of some critical task that cannot wait. For example, the process may be
half-way completed with writing data to a file; a custom signal handler may allow the process to
finish writing the file before exiting. ``SIGKILL`` and ``SIGSTOP`` cannot be overwritten, and these
signals will kill or suspend the process immediately.

The ``SIGCONT`` signal can be used to resume a process that has been suspended with either
``SIGSTOP`` or ``SIGTSTP``. For instance, you may start a program on the command line, then wish to
make it run in the background. You could use ``Ctrl-z`` to send ``SIGTSTP``, suspending the process;
then, use the ``bg`` command to send ``SIGCONT``, resuming the process in the background. Similarly,
``fg`` would send ``SIGCONT``, but resume the process in the foreground.

The default behavior for C programs is to respond to ``SIGSEGV`` by printing a message that a
segmentation fault occurred and then exit. A program can include a custom signal handler to respond
to segmentation faults differently. As an example, this is how debuggers (e.g., ``gdb``) detect
segmentation faults. Instead of killing the process, the debugger pauses it, allowing the user to
run the ``backtrace`` utility to determine what line of code caused the fault.

.. topic:: C library functions – <signal.h>

   .. figure:: Images/CSF-Images-Library.png
      :align: left
      :width: 100%
      :alt: Decorative C library image

   ``int kill(pid_t pid, int sig);``
     Send a signal to another process.


The ``SIGCHLD`` signal gets sent to a process whenever any of its children terminate. The
``waitpid()`` library function includes a custom signal handler that checks if the terminated
process matches the one that the parent was waiting on. If not, the parent would suspend itself
again. Similarly, ``wait()`` includes a signal handler to determine if all of the process's children
have completed.

`Code Listing 2.18 <#cl2-18>`_ shows how to use ``kill()`` to send a signal from inside a program. Since
``fork()`` returns 0 to the child process, only the child will enter the infinite loop on line 15.
The parent process would skip over this and execute the call to ``kill()`` on line 20. Note that the
timing of the two processes does not matter here. Without the ``sleep()`` on line 18, the parent
would kill the child before it had a chance to run; adding the ``sleep()`` gives both a chance to
print the message on line 7. Since the child is killed while running on line 15, only the parent
will print the message on line 21.

.. _cl2-18:

.. codeinclude:: Processes/CodeListing-2.18.c
   :linenos: true

Custom Signal Handlers
----------------------

To overwrite a signal handler, you start by defining a function with the desired new behavior. In
the simplest form, this function must take exactly one ``int`` parameter and have a ``void`` return
type. The parameter received by this function will be the specific signal that was passed. As such,
it is possible to define one signal handling function and use it to respond to multiple signals.

.. topic:: C library functions – <signal.h>

   .. figure:: Images/CSF-Images-Library.png
      :align: left
      :width: 100%
      :alt: Decorative C library image

   ``int sigaction(int sig, const struct sigaction *restrict act,  struct sigaction *restrict oact);``
     Use a custom function to respond to a standard signal.

`Code Listing 2.19 <#cl2-19>`_ shows how to use ``sigaction()`` to overwrite a signal handler. Lines 6 – 21
define the behavior of the signal handler. On line 29, this function name (i.e., the address of the
function) is copied into the ``sa_handler`` field of a ``struct sigaction``. Line 32 successfully
overwrites the ``SIGINT`` handler, so using ``Ctrl-C`` on the command line will invoke the custom
``sigint_handler()`` function. Line 36 will fail to overwrite the ``SIGKILL`` handler, as this
action is not permitted. When this program is run, it can still be killed with the ``kill -9`` command.

.. _cl2-19:

.. codeinclude:: Processes/CodeListing-2.19.c
   :linenos: true

The call to ``exit()`` on line 20 is important for this example. Without this call, using ``Ctrl-c``
would no longer terminate the program. Each time that the ``SIGINT`` would be raised, the signal
handler would print the message and the function would return back to what it was doing before. That
is, the function would return back to the infinite loop on line 41. **This is very dangerous and
should not be done in regular practice**. We can do so here only because our infinite loop is doing nothing.

In more realistic code, the signal might interfere with the executing code. For instance, the
interrupted code might have just set a number of registers to prepare for a function call. The
signal handler might then change these values, leading to errors when the normal execution resumes.
If the application must be able to return to normal execution after processing a signal, the
solution is to create a non-local goto with ``sigsetjmp()`` and ``siglongjmp()``.

.. topic:: C library functions – <sig/setjmp.h>

   .. figure:: Images/CSF-Images-Library.png
      :align: left
      :width: 100%
      :alt: Decorative C library image

   ``int sigsetjmp(sigjmp_buf env, int savemask);``
     Set jump point for a non-local goto.

   ``void siglongjmp(sigjmp_buf env, int val);``
     Non-local goto with signal handling.

`Code Listing 2.20 <#cl2-20>`_ illustrates the basic structure of non-local gotos. Assuming the signal handler is
set up properly (as indicated by the comment on line 17), the call to ``sigsetjmp()`` on line 18
creates a safe place to resume execution after handling the signal. When this function is called
directly, the return value will be 0 (i.e., false); as such, the body of the if-statement will not
be executed when the process first runs. The process will enter the infinite loop at line 21. Then,
when the signal occurs, the ``sig_handler()`` will run. The call to ``siglongjmp()`` on line 11
causes the flow of execution to return to line 18, where the target of the goto was set. However,
critically, this call also changes the return value from ``sigsetjmp()`` to become the second value
passed to ``siglongjmp()``! As such, after the signal handler runs, the process will resume normal
execution as if ``sigsetjmp()`` had returned 1 (true) and printing the message on line 19. At that
point, the process would return to the infinite loop. Note that both ``sigsetjmp()`` and
``siglongjmp()`` require the same global ``sigjmp_buf`` variable to be connected.

.. _cl2-20:

.. codeinclude:: Processes/CodeListing-2.20.c
   :linenos: true

The existing code has a problem, however. When a signal occurs, a bit gets set in the *signal
mask* to indicate that this signal has been raised. If the signal occurs again, **the signal handler
will not get invoked again**. Rather, signal handlers will only run when the bit in the signal mask
first gets set. Consequently, if `Code Listing 2.20 <#cl2-20>`_ was used to overwrite ``SIGINT``, only the first
``Ctrl-c`` would invoke the signal handler. All additional ``SIGINT``\ s would be ignored. The
``sigprocmask()`` function can fix this problem by lowering the bit in the signal mask.

.. topic:: C library functions – <setjmp.h>

   .. figure:: Images/CSF-Images-Library.png
      :align: left
      :width: 100%
      :alt: Decorative C library image

   ``int sigaddset(sigset_t *set, int signo);``
     Add a signal to a signal set.

   ``int sigemptyset(sigset_t *set);``
     Initialize an empty signal set.

   ``int sigprocmask(int how, const sigset_t *set, sigset_t *oset);``
     Examine and change blocked signals.

`Code Listing 2.21 <#cl2-21>`_ fixes the signal handler from `Code Listing 2.20 <#cl2-20>`_ by resetting the signal
mask. Line 12 will clear the bit (``SIG_UNBLOCK``) in the signal mask for each signal in the set. Since lines 9
– 11 create a set that contains only the signal that was being processed (i.e., because the current
signal number gets passed as the ``signum`` argument), only the current signal will get reset. [#f16]_
Consequently, when the normal execution would resume, the signal could be repeatedly raised.

.. _cl2-21:

.. codeinclude:: Processes/CodeListing-2.21.c
   :linenos: true

.. topic:: Bug Warning

   .. figure:: Images/CSF-Images-BugWarning.png
      :align: left
      :width: 90%
      :alt: Decorative bug warning

   The number of functions that can be safely called from within a signal handler is very limited. For
   instance, you should never call ``printf()`` from within a signal handler. The problem is that most
   C functions in the standard library are not guaranteed to have well-defined behavior in an
   asynchronous context. To avoid bugs that arise from undefined execution timing, you should only
   call functions that are asynchronous-safe. The list of functions and more information can be found
   in CERT Secure Coding Rule SIG30-C.

There are other variations that can be used for custom signal handlers beyond what is shown here.
For further information, consult the POSIX documentation for ``sigaction()``. Also, note that there
is an older ``signal()`` function that can also be used for overwriting signals. However, use of
``signal()`` is discouraged in the POSIX specification, and newer applications should use
``sigaction()`` instead.

.. [#f16] Note that other signals could be added to this set; if those other signals were currently
   waiting to be handled, the call to ``sigprocmask()`` would clear them and their handlers would not be invoked.

.. avembed:: Exercises/Processes/ProcSigSumm.html ka
   :module: EventsSignals
   :points: 1.0
   :required: True
   :exer_opts: JXOP-debug=true&amp;JOP-lang=en&amp;JXOP-code=java
   :long_name: Signals questions
   :threshold: 3

