common.py
Go to the documentation of this file.
00001 """Lowest-common-denominator implementations of platform functionality."""
00002 from __future__ import absolute_import, division, with_statement
00003 
00004 import errno
00005 import socket
00006 
00007 from tornado.platform import interface
00008 from tornado.util import b
00009 
00010 
00011 class Waker(interface.Waker):
00012     """Create an OS independent asynchronous pipe.
00013 
00014     For use on platforms that don't have os.pipe() (or where pipes cannot
00015     be passed to select()), but do have sockets.  This includes Windows
00016     and Jython.
00017     """
00018     def __init__(self):
00019         # Based on Zope async.py: http://svn.zope.org/zc.ngi/trunk/src/zc/ngi/async.py
00020 
00021         self.writer = socket.socket()
00022         # Disable buffering -- pulling the trigger sends 1 byte,
00023         # and we want that sent immediately, to wake up ASAP.
00024         self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
00025 
00026         count = 0
00027         while 1:
00028             count += 1
00029             # Bind to a local port; for efficiency, let the OS pick
00030             # a free port for us.
00031             # Unfortunately, stress tests showed that we may not
00032             # be able to connect to that port ("Address already in
00033             # use") despite that the OS picked it.  This appears
00034             # to be a race bug in the Windows socket implementation.
00035             # So we loop until a connect() succeeds (almost always
00036             # on the first try).  See the long thread at
00037             # http://mail.zope.org/pipermail/zope/2005-July/160433.html
00038             # for hideous details.
00039             a = socket.socket()
00040             a.bind(("127.0.0.1", 0))
00041             a.listen(1)
00042             connect_address = a.getsockname()  # assigned (host, port) pair
00043             try:
00044                 self.writer.connect(connect_address)
00045                 break    # success
00046             except socket.error, detail:
00047                 if (not hasattr(errno, 'WSAEADDRINUSE') or
00048                     detail[0] != errno.WSAEADDRINUSE):
00049                     # "Address already in use" is the only error
00050                     # I've seen on two WinXP Pro SP2 boxes, under
00051                     # Pythons 2.3.5 and 2.4.1.
00052                     raise
00053                 # (10048, 'Address already in use')
00054                 # assert count <= 2 # never triggered in Tim's tests
00055                 if count >= 10:  # I've never seen it go above 2
00056                     a.close()
00057                     self.writer.close()
00058                     raise socket.error("Cannot bind trigger!")
00059                 # Close `a` and try again.  Note:  I originally put a short
00060                 # sleep() here, but it didn't appear to help or hurt.
00061                 a.close()
00062 
00063         self.reader, addr = a.accept()
00064         self.reader.setblocking(0)
00065         self.writer.setblocking(0)
00066         a.close()
00067         self.reader_fd = self.reader.fileno()
00068 
00069     def fileno(self):
00070         return self.reader.fileno()
00071 
00072     def wake(self):
00073         try:
00074             self.writer.send(b("x"))
00075         except (IOError, socket.error):
00076             pass
00077 
00078     def consume(self):
00079         try:
00080             while True:
00081                 result = self.reader.recv(1024)
00082                 if not result:
00083                     break
00084         except (IOError, socket.error):
00085             pass
00086 
00087     def close(self):
00088         self.reader.close()
00089         self.writer.close()


roswww
Author(s): Jonathan Mace
autogenerated on Thu Jan 2 2014 11:53:30