[code.view]

[top] / python / PyMOTW / signal / index.rst

     ============================================================
     signal -- Receive notification of asynchronous system events
     ============================================================
     
     .. module:: signal
         :synopsis: Receive notification of asynchronous system events
     
     :Purpose: Receive notification of asynchronous system events
     :Python Version: 1.4 and later
     
     .. note::
     
         Programming with Unix signal handlers is a non-trivial endeavor. This is an introduction,
         and does not include all of the details you may need to use signals successfully on every
         platform. There is some degree of standardization across versions of Unix, but there is
         also some variation, so consult documentation for your OS if you run into trouble.
     
     Signals are an operating system feature that provide a means of
     notifying your program of an event, and having it handled
     asynchronously.  They can be generated by the system itself, or sent
     from one process to another.  Since signals interrupt the regular flow
     of your program, it is possible that some operations (especially I/O)
     may produce error if a signal is received in the middle.
     
     Signals are identified by integers and are defined in the operating
     system C headers.  Python exposes the signals appropriate for the
     platform as symbols in the :mod:`signal` module.  For the examples
     below, I will use ``SIGINT`` and ``SIGUSR1``.  Both are typically
     defined for all Unix and Unix-like systems.
     
     Receiving Signals
     =================
     
     As with other forms of event-based programming, signals are received
     by establishing a callback function, called a *signal handler*, that
     is invoked when the signal occurs.  The arguments to your signal
     handler are the signal number and the stack frame from the point in
     your program that was interrupted by the signal.
     
     .. include:: signal_signal.py
         :literal:
         :start-after: #end_pymotw_header
     
     This relatively simple example script loops indefinitely, pausing for
     a few seconds each time.  When a signal comes in, the sleep call is
     interrupted and the signal handler ``receive_signal()`` prints the
     signal number.  When the signal handler returns, the loop continues.
     
     To send signals to the running program, I use the command line program
     kill.  To produce the output below, I ran ``signal_signal.py`` in one
     window, then ``kill -USR1 $pid``, ``kill -USR2 $pid``, and ``kill -INT
     $pid`` in another.
     
     ::
     
         $ python signal_signal.py 
         My PID is: 71387
         Waiting...
         Waiting...
         Waiting...
         Received: 30
         Waiting...
         Waiting...
         Received: 31
         Waiting...
         Waiting...
         Traceback (most recent call last):
           File "signal_signal.py", line 25, in <module>
             time.sleep(3)
         KeyboardInterrupt
     
     
     getsignal()
     ===========
     
     To see what signal handlers are registered for a signal, use
     :func:`getsignal()`.  Pass the signal number as argument.  The return
     value is the registered handler, or one of the special values
     ``signal.SIG_IGN`` (if the signal is being ignored),
     ``signal.SIG_DFL`` (if the default behavior is being used), or
     ``None`` (if the existing signal handler was registered from C, rather
     than Python).
     
     .. include:: signal_getsignal.py
         :literal:
         :start-after: #end_pymotw_header
     
     Again, since each OS may have different signals defined, the output
     you see from running this on other systems may vary.  This is from OS
     X:
     
     ::
     
         $ python signal_getsignal.py
         SIGHUP     ( 1): SIG_DFL
         SIGINT     ( 2): <built-in function default_int_handler>
         SIGQUIT    ( 3): SIG_DFL
         SIGILL     ( 4): SIG_DFL
         SIGTRAP    ( 5): SIG_DFL
         SIGIOT     ( 6): SIG_DFL
         SIGEMT     ( 7): SIG_DFL
         SIGFPE     ( 8): SIG_DFL
         SIGKILL    ( 9): None
         SIGBUS     (10): SIG_DFL
         SIGSEGV    (11): SIG_DFL
         SIGSYS     (12): SIG_DFL
         SIGPIPE    (13): SIG_IGN
         SIGALRM    (14): <function alarm_received at 0x7c3f0>
         SIGTERM    (15): SIG_DFL
         SIGURG     (16): SIG_DFL
         SIGSTOP    (17): None
         SIGTSTP    (18): SIG_DFL
         SIGCONT    (19): SIG_DFL
         SIGCHLD    (20): SIG_DFL
         SIGTTIN    (21): SIG_DFL
         SIGTTOU    (22): SIG_DFL
         SIGIO      (23): SIG_DFL
         SIGXCPU    (24): SIG_DFL
         SIGXFSZ    (25): SIG_IGN
         SIGVTALRM  (26): SIG_DFL
         SIGPROF    (27): SIG_DFL
         SIGWINCH   (28): SIG_DFL
         SIGINFO    (29): SIG_DFL
         SIGUSR1    (30): SIG_DFL
         SIGUSR2    (31): SIG_DFL
     
     
     Sending Signals
     ===============
     
     The function for sending signals is ``os.kill()``.  Its use is covered
     in the section on the :mod:`os` module,
     :ref:`creating-processes-with-os-fork`.
     
     Alarms
     ======
     
     Alarms are a special sort of signal, where your program asks the OS to
     notify it after some period of time has elapsed.  As `the standard
     module documentation for os
     <http://docs.python.org/lib/node545.html>`_ points out, this is useful
     for avoiding blocking indefinitely on an I/O operation or other system
     call.
     
     .. include:: signal_alarm.py
         :literal:
         :start-after: #end_pymotw_header
     
     In this example, the call to :func:`sleep()` does not last the full 4
     seconds.
     
     ::
     
         $ python signal_alarm.py
         Before: Sun Aug 17 10:51:09 2008
         Alarm : Sun Aug 17 10:51:11 2008
         After : Sun Aug 17 10:51:11 2008
     
     
     Ignoring Signals
     ================
     
     To ignore a signal, register ``SIG_IGN`` as the handler.  This script
     replaces the default handler for ``SIGINT`` with ``SIG_IGN``, and
     registers a handler for ``SIGUSR1``.  Then it uses
     :func:`signal.pause()` to wait for a signal to be received.
     
     .. include:: signal_ignore.py
         :literal:
         :start-after: #end_pymotw_header
     
     Normally ``SIGINT`` (the signal sent by the shell to your program when
     you hit Ctrl-C) raises a :ref:`KeyboardInterrupt
     <exceptions-KeyboardInterrupt>`.  In this example, we ignore ``SIGINT``
     and raise :ref:`SystemExit <exceptions-SystemExit>` when we see
     ``SIGUSR1``.  Each ``^C`` represents an attempt to use Ctrl-C to kill
     the script from the terminal.  Using ``kill -USR1 72598`` from another
     terminal eventually causes the script to exit.
     
     ::
     
         $ python signal_ignore.py 
         My PID: 72598
         ^C^C^C^CExiting
     
     
     Signals and Threads
     ===================
     
     Signals and threads don't generally mix well because only the main
     thread of a process will receive signals.  The following example sets
     up a signal handler, waits for the signal in one thread, and sends the
     signal from another.
     
     .. include:: signal_threads.py
         :literal:
         :start-after: #end_pymotw_header
     
     Notice that the signal handlers were all registered in the main
     thread.  This is a requirement of the signal module implementation for
     Python, regardless of underlying platform support for mixing threads
     and signals.  Although the receiver thread calls
     :func:`signal.pause()`, it does not receive the signal.  The
     ``signal.alarm(2)`` call near the end of the example prevents an
     infinite block, since the receiver thread will never exit.
     
     ::
     
         $ python signal_threads.py 
         Waiting for signal in <Thread(receiver, started)>
         Sending signal in <Thread(sender, started)>
         Received signal 30 in <_MainThread(MainThread, started)>
         Waiting for <Thread(receiver, started)>
         Alarm clock
     
     Although alarms can be set in threads, they are also received by the
     main thread.
     
     .. include:: signal_threads_alarm.py
         :literal:
         :start-after: #end_pymotw_header
     
     Notice that the alarm does not abort the :func:`sleep()` call in
     :func:`use_alarm()`.
     
     ::
     
         $ python signal_threads_alarm.py
         Sun Aug 17 12:06:00 2008 Setting alarm in <Thread(alarm_thread, started)>
         Sun Aug 17 12:06:00 2008 Sleeping in <Thread(alarm_thread, started)>
         Sun Aug 17 12:06:00 2008 Waiting for <Thread(alarm_thread, started)>;
         Sun Aug 17 12:06:03 2008 Done with sleep
         Sun Aug 17 12:06:03 2008 Alarm in <_MainThread(MainThread, started)>
         Sun Aug 17 12:06:03 2008 Exiting normally
     
     .. seealso::
     
         `signal <http://docs.python.org/lib/module-signal.html>`_
             Standard library documentation for this module.
     
         :ref:`creating-processes-with-os-fork`
             The :func:`kill()` function can be used to send signals
             between processes.
     

[top] / python / PyMOTW / signal / index.rst

contact | logmethods.com