tags:

views:

129

answers:

2

Apparently when my signal handler exits, my program CONTINUE TO RUN. this is evident by the exception raised even AFTER the "log Done, close now". Can someone explain why this is so? Note the functions have been simplified

^Clog   Ctrl-C
backup  State: not_span 328, pos 22, all_cycles 19
backup  backup complete, you may force exit now
log     Done, close now
Traceback (most recent call last):
  File "singleEdger.py", line 219, in <module>
    mySingleEdger.outputAllCycles()
  File "singleEdger.py", line 141, in outputAllCycles
    r = self.returnCycle( self.dfs_tree, self.not_span[self.pos])
  File "singleEdger.py", line 72, in returnCycle
    udfs = nx.Graph(dfs)                    # The trick is to make it undirected
  File "/var/lib/python-support/python2.6/networkx/graph.py", line 86, in __init__
    convert.from_whatever(data,create_using=self)
  File "/var/lib/python-support/python2.6/networkx/convert.py", line 76, in from_whatever
    "Input is not a correct NetworkX graph."
networkx.exception.NetworkXError: Input is not a correct NetworkX graph.

These are the functions for reference

    def sigHandler(self, arg1, arg2):
        out('log', 'Ctrl-C')
        self.backup()
        out('log', 'Done, close now')
        exit()


    def outputAllCycles(self):
        while self.pos < len(self.not_span):
            r = self.returnCycle( self.dfs_tree, self.not_span[self.pos])
            if r:
                self.all_cycles.append( r )
                for each in r:      # now it's [ (3,4), (5,6) ]
                    each = (sellHash(each[0]), sellHash( each[1]) )
                    self.outfo.write( each[0] +'\t'+ each[1] )
                    self.outfo.write( '\n')
                self.outfo.write( '\n')
            self.pos += 1
        out( "singleEdger", "outputAllCycles done")


    def backup(self):
        out( 'backup', 'State: not_span %i, pos %i, all_cycles %i' % ( len(self.not_span), self.pos, len(self.all_cycles)) )
        out( 'backup', 'backup complete, you may force exit now')
+1  A: 

I don't think your code is still running. Despite its position in the code, the exception output is not guaranteed to appear before your final print message. Exception output is going to STDERR, but your print statement is going to STDOUT; both just happen to be writing to the same terminal device in this example. The two are buffered independently so the order of output is not mandated; i.e. you can't infer anything from the relative position of the outputs.

You can see the same phenomena with the unit testing framework, if you put print statements into your unit tests.

ire_and_curses
ok the funny thing is SOMETIMES, this happens, sometimes it doesn't. SO I don't really know what to trust.
Actually that's kind of funny since I think it might be related to how the OS handles python, but I am not sure
Also note that there's no guarantee that the SystemExit exception will cause the system to, in fact, exit. If caught and handled by an exception handler, the code will keep on truckin' as if nothing happened.
Cide
@phroxy: Well, yes, that's the whole point. Which buffer prints first is a race condition that depends on a variety of system factors. Sometimes it will go one way, sometimes the other. The point is: you can't rely on this behaviour. So you can't use the order of the output to do anything useful.
ire_and_curses
A: 

Something else that you should be aware of is that you should avoid lengthy processing (calling backup() indicates a potentially lengthy process) in the signal handler; it's better to set a flag, return from the signal handler and then do your processing. The reason is that (in Python) the signal handler will still be registered and any subsequent signal of the same type will interrupt the signal handler itself, causing it to execute again. This may not be what you'd like to happen.

Or you could ignore the signal within the handler, e.g.

import signal
def sigHandler(sig, frame):
    oldHandler = signal.signal(sig, signal.SIG_IGN)
    backup()    # lengthy processing here...
    signal.signal(sig, oldHandler)

but note that that will only ignore the same signal - it is still possible to be interrupted by other signals. Is your backup() reentrant?

This discussion on reentrancy is relevant, although it's wrt C and Python is a bit different, e.g. signals can not be blocked (unless you use ctypes).

mhawke