[Zope-Checkins] SVN: Zope/trunk/ - Applied patch for
Sidnei da Silva
sidnei at awkly.org
Thu Mar 17 07:39:01 EST 2005
Log message for revision 29524:
- Applied patch for
http://www.zope.org/Collectors/Zope/1527. The patch
installs a windows 'control handler'. Ctrl+C/Break etc are
delivered asynchronously (notwithstanding the GIL) to a new
thread. This new thread triggers a shutdown, then tricks
asyncore into breaking out of its 'select' call.
Changed:
U Zope/trunk/doc/CHANGES.txt
U Zope/trunk/lib/python/Lifetime.py
U Zope/trunk/lib/python/ZEO/runzeo.py
-=-
Modified: Zope/trunk/doc/CHANGES.txt
===================================================================
--- Zope/trunk/doc/CHANGES.txt 2005-03-17 12:14:32 UTC (rev 29523)
+++ Zope/trunk/doc/CHANGES.txt 2005-03-17 12:39:01 UTC (rev 29524)
@@ -28,6 +28,13 @@
Features added
+ - Applied patch for
+ http://www.zope.org/Collectors/Zope/1527. The patch
+ installs a windows "control handler". Ctrl+C/Break etc are
+ delivered asynchronously (notwithstanding the GIL) to a new
+ thread. This new thread triggers a shutdown, then tricks
+ asyncore into breaking out of its 'select' call.
+
- The ZEO server now records its PID to a file like the ZEO
client. Defaults to $INSTANCE_HOME/var/ZEO.pid, and its
configurable in $INSTANCE_HOME/etc/zeo.conf.
Modified: Zope/trunk/lib/python/Lifetime.py
===================================================================
--- Zope/trunk/lib/python/Lifetime.py 2005-03-17 12:14:32 UTC (rev 29523)
+++ Zope/trunk/lib/python/Lifetime.py 2005-03-17 12:39:01 UTC (rev 29524)
@@ -38,6 +38,68 @@
# enough, but still clean.
_shutdown_timeout = 1.0
+def setup_windows_control_handler():
+ try:
+ from win32api import SetConsoleCtrlHandler, \
+ GenerateConsoleCtrlEvent
+ from win32con import CTRL_C_EVENT, CTRL_BREAK_EVENT, \
+ CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, \
+ CTRL_SHUTDOWN_EVENT
+ except ImportError:
+ pass
+ else:
+ def interrupt_select():
+ """Interrupt a sleeping acyncore 'select' call"""
+ # What is the right thing to do here?
+ # asyncore.close_all() works, but I fear that would
+ # prevent the poll based graceful cleanup code from working.
+ # This seems to work :)
+ for fd, obj in asyncore.socket_map.items():
+ if hasattr(obj, "pull_trigger"):
+ obj.pull_trigger()
+
+ def ctrl_handler(ctrlType):
+ """Called by Windows on a new thread whenever a
+ console control event is raised."""
+ result = 0
+ if ctrlType == CTRL_C_EVENT:
+ # user pressed Ctrl+C or someone did
+ # GenerateConsoleCtrlEvent
+ if _shutdown_phase == 0:
+ print "Shutting down Zope..."
+ shutdown(0)
+ interrupt_select()
+ elif _shutdown_timeout > 1.0:
+ print "Zope shutdown switching to 'fast'"
+ shutdown(0, 1)
+ else:
+ # Third time around - terminate via
+ # a CTRL_BREAK_EVENT
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)
+ result = 1
+ elif ctrlType == CTRL_BREAK_EVENT:
+ # Always let Ctrl+Break force it down.
+ # Default handler terminates process.
+ print "Terminating Zope (press Ctrl+C to shutdown cleanly)"
+ elif ctrlType == CTRL_CLOSE_EVENT:
+ # Console is about to die.
+ # CTRL_CLOSE_EVENT gives us 5 seconds before displaying
+ # the "End process" dialog - so switch directly to 'fast'
+ shutdown(0, 1)
+ interrupt_select()
+ result = 1
+ elif ctrlType in (CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT):
+ # MSDN says:
+ # "Note that this signal is received only by services.
+ # Interactive applications are terminated at logoff, so
+ # they are not present when the system sends this signal."
+ # We can therefore ignore it (our service framework
+ # manages shutdown in this case)
+ pass
+ return result
+ # Install our handler.
+ SetConsoleCtrlHandler(ctrl_handler)
+
def loop():
# Run the main loop until someone calls shutdown()
lifetime_loop()
@@ -46,6 +108,9 @@
graceful_shutdown_loop()
def lifetime_loop():
+ if sys.platform.startswith("win"):
+ setup_windows_control_handler()
+
# The main loop. Stay in here until we need to shutdown
map = asyncore.socket_map
timeout = 30.0
Modified: Zope/trunk/lib/python/ZEO/runzeo.py
===================================================================
--- Zope/trunk/lib/python/ZEO/runzeo.py 2005-03-17 12:14:32 UTC (rev 29523)
+++ Zope/trunk/lib/python/ZEO/runzeo.py 2005-03-17 12:39:01 UTC (rev 29524)
@@ -186,6 +186,8 @@
method is called without additional arguments.
"""
if os.name != "posix":
+ if os.name == "nt":
+ self.setup_win32_signals()
return
if hasattr(signal, 'SIGXFSZ'):
signal.signal(signal.SIGXFSZ, signal.SIG_IGN) # Special case
@@ -197,6 +199,48 @@
method()
signal.signal(sig, wrapper)
+ def setup_win32_signals(self):
+ try:
+ from win32api import SetConsoleCtrlHandler
+ import win32con # our handler uses this
+ except ImportError:
+ warn("no pywin32 extensions - can't install ctrl+c handler")
+ else:
+ SetConsoleCtrlHandler(self._win32_ctrl_handler)
+ # And borrow the Zope Signals module to get a log reopen handler.
+ from Signals.WinSignalHandler import SignalHandler
+ from Signals.Signals import logfileReopenHandler
+ SIGUSR2 = 12
+ SignalHandler.registerHandler(SIGUSR2, logfileReopenHandler)
+
+ def _win32_ctrl_handler(self, ctrlType):
+ """Called by Windows on a new thread whenever a
+ console control event is raised."""
+ from win32con import CTRL_C_EVENT, CTRL_BREAK_EVENT, \
+ CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, \
+ CTRL_SHUTDOWN_EVENT
+ import asyncore
+ result = 0
+ # Note we probably don't want to raise SystemExit from
+ # this thread - pywin32-203 at least calls PyErr_Print,
+ # which will still terminate us (but print a message
+ # about the callback failing)
+ if ctrlType == CTRL_C_EVENT:
+ # user pressed Ctrl+C or someone did
+ # GenerateConsoleCtrlEvent
+ info("terminated by CTRL_C_EVENT")
+ asyncore.close_all()
+ # Default will raise KeyboardInterrupt - we don't need that
+ elif ctrlType == CTRL_BREAK_EVENT:
+ info("terminated by CTRL_BREAK_EVENT")
+ asyncore.close_all()
+ # Default handler terminates process - result remains 0
+ elif ctrlType == CTRL_CLOSE_EVENT:
+ info("terminated by CTRL_CLOSE_EVENT")
+ asyncore.close_all()
+ result = 1
+ return result
+
def create_server(self):
from ZEO.StorageServer import StorageServer
self.server = StorageServer(
More information about the Zope-Checkins
mailing list