[Zope-Checkins] CVS: Zope/lib/python/Signals - SignalHandler.py:1.1.30.1 Signals.py:1.1.30.1 __init__.py:1.1.30.1

Chris McDonough chrism@zope.com
Mon, 25 Nov 2002 22:10:39 -0500


Update of /cvs-repository/Zope/lib/python/Signals
In directory cvs.zope.org:/tmp/cvs-serv25870

Added Files:
      Tag: chrism-install-branch
	SignalHandler.py Signals.py __init__.py 
Log Message:
Recommit signals to chrism-install-branch.,


=== Added File Zope/lib/python/Signals/SignalHandler.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################

"""Signal handling dispatcher."""

__version__='$Revision: 1.1.30.1 $'[11:-2]

import sys, os
import signal, zLOG

class SignalHandler:

    def __init__(self):
        self.registry = {}

    def registerHandler(self, signum, handler):
        """Register a handler function that will be called when the process
           recieves the signal signum. The signum argument must be a signal
           constant such as SIGTERM. The handler argument must be a function
           or method that takes no arguments. Note that handlers will not
           be called on non-posix platforms."""
        if os.name != 'posix':
            return
        items = self.registry.get(signum)
        if items is None:
            items = self.registry[signum] = []
            signal.signal(signum, self.signalHandler)
            signame = get_signal_name(signum)
            zLOG.LOG('Z2', zLOG.BLATHER, "Installed sighandler for %s" % (
                      signame
                      ))
        items.insert(0, handler)

    def getRegisteredSignals(self):
        """Return a list of the signals that have handlers registered. This
           is used to pass the signals through to the ZDaemon code."""
        return self.registry.keys()

    def signalHandler(self, signum, frame):
        """Meta signal handler that dispatches to registered handlers."""
        signame = get_signal_name(signum)
        zLOG.LOG('Z2', zLOG.INFO , "Caught signal %s" % signame)

        for handler in self.registry.get(signum, []):
            # Never let a bad handler prevent the standard signal
            # handlers from running.
            try: handler()
            except SystemExit:
                # if we trap SystemExit, we can't restart
                raise
            except:
                zLOG.LOG('Z2', zLOG.WARNING,
                         'A handler for %s failed!' % signame,
                         error=sys.exc_info())

_signals = None

def get_signal_name(n):
    """Return the symbolic name for signal n.

    Returns 'unknown' if there is no SIG name bound to n in the signal
    module.
    """
    global _signals
    if _signals is None:
        _signals = {}
        for k, v in signal.__dict__.items():
            startswith = getattr(k, 'startswith', None)
            if startswith is None:
                continue
            if startswith('SIG') and not startswith('SIG_'):
                _signals[v] = k
    return _signals.get(n, 'unknown')

# The SignalHandler is actually a singleton.
SignalHandler = SignalHandler()


=== Added File Zope/lib/python/Signals/Signals.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""
Zope signal handlers for clean shutdown, restart and log rotation.

$Id: Signals.py,v 1.1.30.1 2002/11/26 03:10:38 chrism Exp $
"""
__version__='$Revision: 1.1.30.1 $'[11:-2]

from SignalHandler import SignalHandler
import zLOG
import sys
import Lifetime

def shutdownFastHandler():
    """Shutdown cleanly on SIGTERM. This is registered first,
       so it should be called after all other handlers."""
    zLOG.LOG('Z2', zLOG.INFO , "Shutting down fast")
    Lifetime.shutdown(0,fast=1)


def shutdownHandler():
    """Shutdown cleanly on SIGINT. This is registered first,
       so it should be called after all other handlers."""
    zLOG.LOG('Z2', zLOG.INFO , "Shutting down")
    sys.exit(0)

def restartHandler():
    """Restart cleanly on SIGHUP. This is registered first, so it
       should be called after all other SIGHUP handlers."""
    zLOG.LOG('Z2', zLOG.INFO , "Restarting")
    Lifetime.shutdown(1)

def logfileReopenHandler():
    """Reopen log files on SIGUSR2. This is registered first, so it
       should be called after all other SIGUSR2 handlers."""
    zLOG.LOG('Z2', zLOG.INFO , "Reopening log files")
    reopen = getattr(getattr(sys, '__lg', None), 'reopen', None)
    if reopen is not None:
        reopen()
        zLOG.LOG('Z2', zLOG.BLATHER, "Reopened access log")
    reopen = getattr(getattr(sys, '__detailedlog', None), 'reopen', None)
    if reopen is not None:
        reopen()
        zLOG.LOG('Z2', zLOG.BLATHER,"Reopened detailed request log")
    zLOG.initialize()
    zLOG.LOG('Z2', zLOG.BLATHER, "Reopened event log")
    zLOG.LOG('Z2', zLOG.INFO, "Log files reopened successfully")

def packHandler():
    """ Packs the main database.  Not safe to call under a signal
    handler, because it blocks the main thread """
    zLOG.LOG('Z2', zLOG.INFO, 'Packing main ZODB database')
    import Globals
    try:
        db = Globals.opened[0]
        db.pack()
        zLOG.LOG('Z2', zLOG.INFO,
                'Database packing launched or completed successfully')
    except:
        zLOG.LOG('Z2', zLOG.INFO,
                 'Call to pack failed!', error=sys.exc_info())
        

def registerZopeSignals():
    import signal
    SignalHandler.registerHandler(signal.SIGTERM, shutdownFastHandler)
    SignalHandler.registerHandler(signal.SIGINT, shutdownHandler)
    SignalHandler.registerHandler(signal.SIGHUP, restartHandler)
    SignalHandler.registerHandler(signal.SIGUSR2, logfileReopenHandler)
    # SIGUSR1 is nominally reserved for pack, but we dont have an
    # implementation that is stable yet because if the signal handler
    # fires it will be caught in the main thread and all network operations
    # will cease until it's finished.
    #SignalHandler.registerHandler(signal.SIGUSR1, packHandler)


=== Added File Zope/lib/python/Signals/__init__.py ===
"""
Signals package __init__.py
"""