summaryrefslogtreecommitdiff
path: root/waitress
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2019-04-02 00:25:28 -0500
committerMichael Merickel <michael@merickel.org>2019-04-02 00:25:28 -0500
commitfab8f1a75145a9397cc013fe830c12e65a62ece7 (patch)
treee308cdd182563f12ed0ab206c89e5fed57da6183 /waitress
parent2493202b51fb1891de38cf181489124494446cb0 (diff)
downloadwaitress-fab8f1a75145a9397cc013fe830c12e65a62ece7.tar.gz
fix a deadlock when the client disconnects while flushing data
Diffstat (limited to 'waitress')
-rw-r--r--waitress/channel.py16
1 files changed, 10 insertions, 6 deletions
diff --git a/waitress/channel.py b/waitress/channel.py
index a377a54..e717dd7 100644
--- a/waitress/channel.py
+++ b/waitress/channel.py
@@ -151,7 +151,7 @@ class HTTPChannel(wasyncore.dispatcher, object):
self.will_close = True
if self.will_close:
- self.handle_close()
+ self.handle_close(lock=False)
def readable(self):
# We might want to create a new task. We can only do this if:
@@ -168,7 +168,7 @@ class HTTPChannel(wasyncore.dispatcher, object):
except socket.error:
if self.adj.log_socket_errors:
self.logger.exception('Socket error')
- self.handle_close()
+ self.handle_close(lock=True)
return
if data:
self.last_activity = time.time()
@@ -274,10 +274,11 @@ class HTTPChannel(wasyncore.dispatcher, object):
return False
- def handle_close(self):
- # avoid closing the outbufs while a task is potentially adding data
- # to them in write_soon
- with self.outbuf_lock:
+ def handle_close(self, lock=True):
+ # NB: default to True for when asyncore calls this function directly
+ if lock:
+ self.outbuf_lock.acquire()
+ try:
for outbuf in self.outbufs:
try:
outbuf.close()
@@ -285,6 +286,9 @@ class HTTPChannel(wasyncore.dispatcher, object):
self.logger.exception(
'Unknown exception while trying to close outbuf')
self.connected = False
+ finally:
+ if lock:
+ self.outbuf_lock.release()
wasyncore.dispatcher.close(self)
def add_channel(self, map=None):