1 """Lowest-common-denominator implementations of platform functionality."""
2 from __future__ import absolute_import, division, print_function, with_statement
7 from . import interface
10 class Waker(interface.Waker):
11 """Create an OS independent asynchronous pipe.
13 For use on platforms that don't have os.pipe() (or where pipes cannot
14 be passed to select()), but do have sockets. This includes Windows
18 # Based on Zope async.py: http://svn.zope.org/zc.ngi/trunk/src/zc/ngi/async.py
20 self.writer = socket.socket()
21 # Disable buffering -- pulling the trigger sends 1 byte,
22 # and we want that sent immediately, to wake up ASAP.
23 self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
28 # Bind to a local port; for efficiency, let the OS pick
30 # Unfortunately, stress tests showed that we may not
31 # be able to connect to that port ("Address already in
32 # use") despite that the OS picked it. This appears
33 # to be a race bug in the Windows socket implementation.
34 # So we loop until a connect() succeeds (almost always
35 # on the first try). See the long thread at
36 # http://mail.zope.org/pipermail/zope/2005-July/160433.html
37 # for hideous details.
39 a.bind(("127.0.0.1", 0))
41 connect_address = a.getsockname() # assigned (host, port) pair
43 self.writer.connect(connect_address)
45 except socket.error as detail:
46 if (not hasattr(errno, 'WSAEADDRINUSE') or
47 detail[0] != errno.WSAEADDRINUSE):
48 # "Address already in use" is the only error
49 # I've seen on two WinXP Pro SP2 boxes, under
50 # Pythons 2.3.5 and 2.4.1.
52 # (10048, 'Address already in use')
53 # assert count <= 2 # never triggered in Tim's tests
54 if count >= 10: # I've never seen it go above 2
57 raise socket.error("Cannot bind trigger!")
58 # Close `a` and try again. Note: I originally put a short
59 # sleep() here, but it didn't appear to help or hurt.
62 self.reader, addr = a.accept()
63 self.reader.setblocking(0)
64 self.writer.setblocking(0)
66 self.reader_fd = self.reader.fileno()
69 return self.reader.fileno()
71 def write_fileno(self):
72 return self.writer.fileno()
76 self.writer.send(b"x")
77 except (IOError, socket.error):
83 result = self.reader.recv(1024)
86 except (IOError, socket.error):