From 283270075a4675a671618b30f016d04b0aeab884 Mon Sep 17 00:00:00 2001 From: donovan Date: Thu, 17 Jul 2008 15:30:39 -0700 Subject: [PATCH] Fixed a major CPU leak when using select hub. When adding a descriptor to the hub, entries were made in all three dictionaries, readers, writers, and exc, even if the callback is None. Thus every fd would be passed into all three lists when calling select regardless of whether there was a callback for that event or not. When reading the next request out of a keepalive socket, the socket would come back as ready for writing, the hub would notice the callback is None and ignore it, and then loop as fast as possible consuming CPU. --- NEWS | 2 ++ eventlet/hubs/hub.py | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index ae64b3a..86efb0c 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ Fix a major memory leak when using the libevent or libev hubs. Timers were not b It's now possible to use eventlet's SSL client to talk to eventlet's SSL server. (Thanks to Ryan Williams) +Fixed a major CPU leak when using select hub. When adding a descriptor to the hub, entries were made in all three dictionaries, readers, writers, and exc, even if the callback is None. Thus every fd would be passed into all three lists when calling select regardless of whether there was a callback for that event or not. When reading the next request out of a keepalive socket, the socket would come back as ready for writing, the hub would notice the callback is None and ignore it, and then loop as fast as possible consuming CPU. + 0.6.x ===== diff --git a/eventlet/hubs/hub.py b/eventlet/hubs/hub.py index ca52c48..a5a3eb9 100644 --- a/eventlet/hubs/hub.py +++ b/eventlet/hubs/hub.py @@ -78,10 +78,21 @@ class BaseHub(object): so the exc callback happens instead of the respective read or write callback. """ - - self.readers[fileno] = read or self.readers.get(fileno) - self.writers[fileno] = write or self.writers.get(fileno) - self.excs[fileno] = exc or self.excs.get(fileno) + read = read or self.readers.get(fileno) + if read is not None: + self.readers[fileno] = read + else: + self.readers.pop(fileno, None) + write = write or self.writers.get(fileno) + if write is not None: + self.writers[fileno] = write + else: + self.writers.pop(fileno, None) + exc = exc or self.excs.get(fileno) + if exc is not None: + self.excs[fileno] = exc + else: + self.excs.pop(fileno, None) self.waiters_by_greenlet[greenlet.getcurrent()] = fileno def remove_descriptor(self, fileno):