[SOLVED] RE: Repost: Can't sys.exit() from SIGTERM handler?

Andrew Athan aathan-python-5923 at cloakmail.com
Tue Jan 6 04:11:18 CET 2004


Ok, with Jeff's pointer to SystemExit I was able to solve the problem.

Firstly, please ignore the below post which is the result of having missed a
try:except: in the main program, thus having a case where as Jeff suggested,
a "blanket" exception handler was catching the SystemExit silently.

A lesson for other silly pythoners like myself :-)

Thanks again!
A.

PS:  All the complexity below was the result of complex interaction between
the caught and uncaught exceptions, and my own ambiguous debug logs.

-----Original Message-----
From: python-list-bounces+aathan-python-5923=cloakmail.com at python.org
[mailto:python-list-bounces+aathan-python-5923=cloakmail.com at python.org]
On Behalf Of Andrew Athan
Sent: Monday, January 05, 2004 9:35 PM
To: Jeff Epler
Cc: python-list at python.org
Subject: RE: Repost: Can't sys.exit() from SIGTERM handler?



Yes, but it gets stranger (see below).  It seems if I try to catch
exceptions from within the SIGTERM handler, they are instead caught by the
main program.

Perhaps this is because a second signal is raised from within the SIGTERM
handler and python doesn't handle nested signals well?

---------------------------------------------------------
So #1:

But first, the "simple" question:  It seems really onerous to have to
explicitly trap SystemExit and re-raise everywhere in my program, just so I
can make sure that proper exit handlers (atexit(), etc.) are called.  What
is the idiom to "force" and exit while still "properly" shutting down the
interpreter?

----------------------------------------------------------
#2
Now the hard question...

It seems my problem is caused by my atexit() handler.  It is meant to kill
the children, and then os.waitpid() for them to make sure they are dead.  I
added this because killing the python process was not reliably killing the
children (this surprised me since I thought the shell sent the signal to all
processes in a process group??!!!  perhaps cdparanoia has some incorrect
exception handling which causes it not to reliably die on SIGTERM)

I attribute my woes to the atexit() handler because when I changed my code
to explicitly call the function I register with atexit() (called
killChildren()) from within my SIGTERM handler, then the behavior got even
weirder.

The code I have basically looks something like this (pseudocode)

childrenList=[]
def sigterm(a,b):
  killChildren()
  childrenList=[]
  sys.exit()

def sigchild(a,b):
  pass

def killChildren():
  try:
    os.kill(pid,signal.SIGTERM)
    os.waitpid(pid,0)
  pass:
    pass

signal.signal(sigchild,signal.SIGCHILD)
signal.signal(sigterm,signal.SIGTERM)
childrenList.append(fork(...))
sys.atexit(killChildren)
...
while 1:
  try:
    foo=read()
  except Exception,e:
    print 'Here: %s'%e
    pass

If I send a SIGTERM, then I occasionally get 'Here: [Errno 10] No child
processes' printed out!!!

Stranger still, if I leave the normal atexit() handler alone by doing this
instead:

def sigterm(a,b):
  sys.exit()

then *no* exception is printed out and the program keeps running.  I *still*
don't get anything printed even if I explicitly catch SystemExit within the
while 1: loop and print a debug statement.

The only conclusion I can draw is that (a) atexit's exception handling is
strange and/or (b) if the child is still running when I os.kill() it in in
the atexit() handler that occurs after the sys.exit() in, the SIGCHILD that
gets raised as a result of the kill() is interfering in some very strange
way.

HELP! Any comments?

Thanks,
A.

-----Original Message-----
From: Jeff Epler [mailto:jepler at unpythonic.net]
Sent: Monday, January 05, 2004 8:37 PM
To: Andrew Athan
Cc: python-list at python.org
Subject: Re: Repost: Can't sys.exit() from SIGTERM handler?


If I had to guess, I'd bet you had a blanket exception handler
somewhere.  sys.exit merely raises SystemExit, and if this exception
propogates all the way back up, Python treats it specially by exiting
instead of printing the exception's traceback.

:r term.py
import os, signal, time, sys, traceback

def sigterm(a, b):
	print "sigterm"
	sys.exit()

signal.signal(signal.SIGTERM, sigterm)

os.system("(sleep 1; kill %s) &" % os.getpid())

print "Sleeping (should be killed)"

try:
	time.sleep(2)
except SystemExit:
	traceback.print_exc()
	raise

print "sleep finished (!?)"

:r!python -u term.py

Sleeping (should be killed)
sigterm
Traceback (most recent call last):
  File "term.py", line 14, in ?
    time.sleep(2)
  File "term.py", line 5, in sigterm
    sys.exit()
SystemExit


--
http://mail.python.org/mailman/listinfo/python-list





More information about the Python-list mailing list