[Zodb-checkins] CVS: Zope/lib/python/zdaemon - SignalPasser.py:1.1.2.1 Daemon.py:1.2.2.1
Chris McDonough
chrism@zope.com
Fri, 15 Mar 2002 14:36:04 -0500
Update of /cvs-repository/Zope/lib/python/zdaemon
In directory cvs.zope.org:/tmp/cvs-serv19763/lib/python/zdaemon
Modified Files:
Tag: chrism_logrotate_branch
Daemon.py
Added Files:
Tag: chrism_logrotate_branch
SignalPasser.py
Log Message:
Patched up z2.py and some of asyncore to be able to deal with signals.
In this branch, Zope will:
- open and close all of its logfiles upon receving a USR2 signal
- restart "cleanly" upon receiving a HUP signal
- shutdown "cleanly" upon receiving a TERM or INT signal.
=== Added File Zope/lib/python/zdaemon/SignalPasser.py ===
class SignalPasser:
def __init__(self, pid):
self.pid = pid
def __call__(self, signum, frame):
import os, sys, signal
os.kill(self.pid, signum)
if signum in [signal.SIGTERM, signal.SIGINT]:
sys.exit(0)
def pass_signals_to_process(pid, signals):
import signal
for s in signals:
signal.signal(s, SignalPasser(pid))
=== Zope/lib/python/zdaemon/Daemon.py 1.2 => 1.2.2.1 ===
##############################################################################
-import os, sys, time, signal, posix
+import os, sys, time, posix, signal
+ALL_SIGNALS = ['SIGABRT', 'SIGALRM', 'SIGBUS', 'SIGCHLD', 'SIGCLD', 'SIGCONT', 'SIGFPE', 'SIGHUP', 'SIGILL', 'SIGINT', 'SIGIO', 'SIGIOT', 'SIGKILL', 'SIGPIPE', 'SIGPOLL', 'SIGPROF', 'SIGPWR', 'SIGQUIT', 'SIGSEGV', 'SIGSTOP', 'SIGSYS', 'SIGTERM', 'SIGTRAP', 'SIGTSTP', 'SIGTTIN', 'SIGTTOU', 'SIGURG', 'SIGUSR1', 'SIGUSR2', 'SIGVTALRM', 'SIGWINCH', 'SIGXCPU', 'SIGXFSZ']
+
from ZDaemonLogging import pstamp
import Heartbeat
@@ -43,7 +45,9 @@
pstamp('Houston, we have forked', zLOG.INFO)
return pid
-def run(argv, pidfile=''):
+import signal
+
+def run(argv, pidfile='', signals=[]):
if os.environ.has_key('ZDAEMON_MANAGED'):
# We're the child at this point.
return
@@ -66,7 +70,18 @@
raise ForkError
elif pid:
- # Parent
+ # the process we're daemoning for can signify that it
+ # wants us to notify it when we get specific signals
+ #
+ #
+ # we always register TERM and INT so we can reap our child.
+ signals = signals + [signal.SIGTERM, signal.SIGINT]
+ # TERM happens on normal kill
+ # INT happens on Ctrl-C (debug mode)
+ import SignalPasser
+ SignalPasser.pass_signals_to_process(pid, signals)
+
+ # Parent
pstamp(('Hi, I just forked off a kid: %s' % pid), zLOG.INFO)
# here we want the pid of the parent
if pidfile:
@@ -74,24 +89,44 @@
pf.write(("%s" % os.getpid()))
pf.close()
- while 1:
- if not Heartbeat.BEAT_DELAY:
- p,s = os.waitpid(pid, 0)
- else:
- p,s = os.waitpid(pid, os.WNOHANG)
- if not p:
- time.sleep(Heartbeat.BEAT_DELAY)
- Heartbeat.heartbeat()
- continue
- if s:
- pstamp(('Aiieee! %s exited with error code: %s'
- % (p, s)), zLOG.ERROR)
- else:
- pstamp(('The kid, %s, died on me.' % pid),
- zLOG.WARNING)
- raise ForkError
-
- raise KidDiedOnMeError
+ while 1:
+ try:
+ if not Heartbeat.BEAT_DELAY:
+ try:
+ p,s = os.waitpid(pid, 0)
+ except OSError:
+ # catch EINTR, it's raised as a result of
+ # interrupting waitpid with a signal
+ # and we don't care about it.
+ continue
+ else:
+ try:
+ p,s = os.waitpid(pid, os.WNOHANG)
+ except OSError:
+ # catch EINTR, it's raised as a result of
+ # interrupting waitpid with a signal
+ # and we don't care about it.
+ p, s = None, None
+ if not p:
+ time.sleep(Heartbeat.BEAT_DELAY)
+ Heartbeat.heartbeat()
+ continue
+ if s:
+ pstamp(('Aiieee! %s exited with error code: %s'
+ % (p, s)), zLOG.ERROR)
+ else:
+ pstamp(('The kid, %s, died on me.' % pid),
+ zLOG.WARNING)
+ raise ForkError
+
+ raise KidDiedOnMeError
+ except OSError, num:
+ if num == 4:
+ # This is likely an interrupted system call
+ # inside os.waitpid caused by a signal.
+ # Though we have to catch it, we don't really
+ # care about it and we just pass.
+ pass
else:
# Child