
- sys.exc_clear does not exist in 3.x - objects are not comparable by default in in 3.x. Timer needs to have __lt__ operator to be used by heapq. - callable is gone in 3.x. - tpool communication pipe changed to exchange binary data. It makes current GreenPipe work in 3.x. It is also faster and have less translation layers. - 3.x socket uses bytes not str class. Used s2b to make tests working on both.
113 lines
3.6 KiB
Python
113 lines
3.6 KiB
Python
import sys
|
|
import errno
|
|
from eventlet import patcher
|
|
select = patcher.original('select')
|
|
time = patcher.original('time')
|
|
sleep = time.sleep
|
|
|
|
from eventlet.common import get_errno, clear_sys_exc_info
|
|
from eventlet.hubs.hub import BaseHub, READ, WRITE
|
|
|
|
EXC_MASK = select.POLLERR | select.POLLHUP
|
|
READ_MASK = select.POLLIN | select.POLLPRI
|
|
WRITE_MASK = select.POLLOUT
|
|
|
|
class Hub(BaseHub):
|
|
WAIT_MULTIPLIER=1000.0 # poll.poll's timeout is measured in milliseconds
|
|
|
|
def __init__(self, clock=time.time):
|
|
super(Hub, self).__init__(clock)
|
|
self.poll = select.poll()
|
|
# poll.modify is new to 2.6
|
|
try:
|
|
self.modify = self.poll.modify
|
|
except AttributeError:
|
|
self.modify = self.poll.register
|
|
|
|
def add(self, evtype, fileno, cb):
|
|
listener = super(Hub, self).add(evtype, fileno, cb)
|
|
self.register(fileno, new=True)
|
|
return listener
|
|
|
|
def remove(self, listener):
|
|
super(Hub, self).remove(listener)
|
|
self.register(listener.fileno)
|
|
|
|
def register(self, fileno, new=False):
|
|
mask = 0
|
|
if self.listeners[READ].get(fileno):
|
|
mask |= READ_MASK | EXC_MASK
|
|
if self.listeners[WRITE].get(fileno):
|
|
mask |= WRITE_MASK | EXC_MASK
|
|
if mask:
|
|
if new:
|
|
self.poll.register(fileno, mask)
|
|
else:
|
|
try:
|
|
self.modify(fileno, mask)
|
|
except (IOError, OSError):
|
|
self.poll.register(fileno, mask)
|
|
else:
|
|
try:
|
|
self.poll.unregister(fileno)
|
|
except KeyError:
|
|
pass
|
|
except (IOError, OSError):
|
|
# raised if we try to remove a fileno that was
|
|
# already removed/invalid
|
|
pass
|
|
|
|
def remove_descriptor(self, fileno):
|
|
super(Hub, self).remove_descriptor(fileno)
|
|
try:
|
|
self.poll.unregister(fileno)
|
|
except (KeyError, ValueError):
|
|
pass
|
|
except (IOError, OSError):
|
|
# raised if we try to remove a fileno that was
|
|
# already removed/invalid
|
|
pass
|
|
|
|
def wait(self, seconds=None):
|
|
readers = self.listeners[READ]
|
|
writers = self.listeners[WRITE]
|
|
|
|
if not readers and not writers:
|
|
if seconds:
|
|
sleep(seconds)
|
|
return
|
|
try:
|
|
presult = self.poll.poll(seconds * self.WAIT_MULTIPLIER)
|
|
except select.error, e:
|
|
if get_errno(e) == errno.EINTR:
|
|
return
|
|
raise
|
|
SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
|
|
|
|
for fileno, event in presult:
|
|
try:
|
|
listener = None
|
|
try:
|
|
if event & READ_MASK:
|
|
listener = readers[fileno][0]
|
|
if event & WRITE_MASK:
|
|
listener = writers[fileno][0]
|
|
except KeyError:
|
|
pass
|
|
else:
|
|
if listener:
|
|
listener(fileno)
|
|
if event & select.POLLNVAL:
|
|
self.remove_descriptor(fileno)
|
|
continue
|
|
if event & EXC_MASK:
|
|
for listeners in (readers.get(fileno, []),
|
|
writers.get(fileno, [])):
|
|
for listener in listeners:
|
|
listener(fileno)
|
|
except SYSTEM_EXCEPTIONS:
|
|
raise
|
|
except:
|
|
self.squelch_exception(fileno, sys.exc_info())
|
|
clear_sys_exc_info()
|