Problem with signals & exceptions...

Donn Cave donn at u.washington.edu
Wed Jul 28 12:38:38 EDT 1999


Eric Lee Green <e_l_green at hotmail.com> writes:
| I'm having trouble catching my thrown exceptions under FreeBSD 3.2. I am
| using the Python 1.5.2 that came with FreeBSD 3.2 (well, on disk 1 of
| the <n>-disk set). The following program works properly under Red Hat
| Linux version 6.0 running a self-compiled Python 1.5.2 (in place of the
| 1.5.1 which comes with Red Hat 6.0, which does not properly handle
| signals during socket i/o calls). How it works: it listens to port 6664.
| When it gets a connection, it then sets an alarm handler and alarm and
| then tries to read from the socket. If it does not get data within 10
| seconds, it then times out, at which point the alarm handler throws an
| exception and aborts the socket read.  

I tried this exception-from-handler notion on Digital UNIX and BeOS,
and it does seem to work the way I guess you expect, but I do find it
weird. A signal handler executes outside the normal flow of control,
so it's not obvious to me where its exceptions ought to surface.
Probably it should be expected to work the same way on various platforms
for any given version of Python, but would future versions of Python be
guaranteed to work this way also?

Now I can't really make out what you are seeing on FreeBSD.  In the
example output - is that from FreeBSD? - I think you are seeing a
problem with a change to exceptions in recent versions of Python.
Your "why" object prints "READ_TIMEOUT", but it's not that string,
rather an Exception instance with that string as args[0].  So you
need to test if why.args[0] == READ_TIMEOUT.  I get the same output
from your program, on Digital UNIX.

What if your signal handler simply returns, without raising an exception?
C socket I/O functions should return error status with errno EINTR, which
translates to a Python exception.  So you shouldn't need to raise your
own exception, you'd expect one anyway, because the signal interrupts the
function.  Use global state to disambiguate various possible interrupts,
if necessary.

	Donn Cave, University Computing Services, University of Washington
	donn at u.washington.edu
-----------------------------
| The test:
|   In one shell window, type:
|      python testalrm.py
|   in the other shell window type:
|      telnet localhost 6664
| type NOTHING just let it time out...
|
| The output in the first window:
|
| bash-2.03$ python testalarm.py
| Got alarm!
| READ_TIMEOUT
| Traceback (innermost last):
|   File "testalarm.py", line 30, in ?
|     raise IOError, why
| IOError: READ_TIMEOUT
| bash-2.03$ 
|
| The program:
| ----------------------------testalarm.py------------------
|
| # A routine to test the 'alarm' signal handling.
|
| import socket
| import signal
|
| READ_TIMEOUT="READ_TIMEOUT"
|
| def alarmhandler(signum,stackframe):
|     print "Got alarm!"
|     raise IOError,READ_TIMEOUT
|
|
| s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
| addr=("",6664)
| s.bind(addr)
| s.listen(5)
|
| connection,address=s.accept()
|
| oldhandler=signal.signal(signal.SIGALRM,alarmhandler)
|
| signal.alarm(10)  # wait 10 seconds for an alarm!
| try:
|         str=connection.recv(4096) # get a string
| except IOError, why:
|         print why
|         if why == READ_TIMEOUT :
|                 print "why = read timeout"
|         else:
|                 raise IOError, why
| signal.alarm(0)
| print str
| ----------------end program-------------------------------------




More information about the Python-list mailing list