Socket: Use select.select() instead of checking sockets one by one. Closes GH-431. Closes GH-420.

This commit is contained in:
Valentin Lorentz 2012-12-07 21:41:50 +01:00
parent 7d22d3dc36
commit 8cf094a628

View File

@ -56,7 +56,10 @@ except:
class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
_instances = []
_selecting = [False] # We want it to be mutable.
def __init__(self, irc): def __init__(self, irc):
self._instances.append(self)
self.irc = irc self.irc = irc
drivers.IrcDriver.__init__(self, irc) drivers.IrcDriver.__init__(self, irc)
drivers.ServersMixin.__init__(self, irc) drivers.ServersMixin.__init__(self, irc)
@ -99,6 +102,8 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
# hasn't finished yet. We'll keep track of how many we get. # hasn't finished yet. We'll keep track of how many we get.
if e.args[0] != 11 or self.eagains > 120: if e.args[0] != 11 or self.eagains > 120:
drivers.log.disconnect(self.currentServer, e) drivers.log.disconnect(self.currentServer, e)
if self in self._instances:
self._instances.remove(self)
try: try:
self.conn.close() self.conn.close()
except: except:
@ -129,6 +134,32 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
if self.zombie and not self.outbuffer: if self.zombie and not self.outbuffer:
self._reallyDie() self._reallyDie()
@classmethod
def _select(cls):
if cls._selecting[0]:
return
print repr(map(lambda x:x.name(), cls._instances))
try:
cls._selecting[0] = True
for inst in cls._instances:
# Do not use a list comprehension here, we have to edit the list
# and not to reassign it.
if inst.conn._sock.__class__ is socket._closedsocket:
cls._instances.remove(inst)
if not cls._instances:
return
rlist, wlist, xlist = select.select([x.conn for x in cls._instances],
[], [], conf.supybot.drivers.poll())
for instance in cls._instances:
if instance.conn in rlist:
instance._read()
finally:
cls._selecting[0] = False
for instance in cls._instances:
if not instance.irc.zombie:
instance._sendIfMsgs()
def run(self): def run(self):
now = time.time() now = time.time()
if self.nextReconnectTime is not None and now > self.nextReconnectTime: if self.nextReconnectTime is not None and now > self.nextReconnectTime:
@ -141,6 +172,10 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
time.sleep(conf.supybot.drivers.poll()) time.sleep(conf.supybot.drivers.poll())
return return
self._sendIfMsgs() self._sendIfMsgs()
self._select()
def _read(self):
"""Called by _select() when we can read data."""
try: try:
self.inbuffer += self.conn.recv(1024) self.inbuffer += self.conn.recv(1024)
self.eagains = 0 # If we successfully recv'ed, we can reset this. self.eagains = 0 # If we successfully recv'ed, we can reset this.
@ -173,6 +208,9 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
self.nextReconnectTime = None self.nextReconnectTime = None
if self.connected: if self.connected:
drivers.log.reconnect(self.irc.network) drivers.log.reconnect(self.irc.network)
if self in self._instances:
self._instances.remove(self)
self.conn.shutdown(socket.SHUT_RDWR)
self.conn.close() self.conn.close()
self.connected = False self.connected = False
if reset: if reset:
@ -225,6 +263,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
drivers.log.connectError(self.currentServer, e) drivers.log.connectError(self.currentServer, e)
self.scheduleReconnect() self.scheduleReconnect()
return return
self._instances.append(self)
def _checkAndWriteOrReconnect(self): def _checkAndWriteOrReconnect(self):
self.writeCheckTime = None self.writeCheckTime = None
@ -250,6 +289,8 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
self.nextReconnectTime = when self.nextReconnectTime = when
def die(self): def die(self):
if self in self._instances:
self._instances.remove(self)
self.zombie = True self.zombie = True
if self.nextReconnectTime is not None: if self.nextReconnectTime is not None:
self.nextReconnectTime = None self.nextReconnectTime = None
@ -259,6 +300,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
def _reallyDie(self): def _reallyDie(self):
if self.conn is not None: if self.conn is not None:
self.conn.shutdown(socket.SHUT_RDWR)
self.conn.close() self.conn.close()
drivers.IrcDriver.die(self) drivers.IrcDriver.die(self)
# self.irc.die() Kill off the ircs yourself, jerk! # self.irc.die() Kill off the ircs yourself, jerk!