Skip to content

Commit 97c7054

Browse files
committed
Reap dead threads when opening a new one.
1 parent 365ef2f commit 97c7054

File tree

2 files changed

+14
-21
lines changed

2 files changed

+14
-21
lines changed

Lib/socketserver.py

+11-17
Original file line numberDiff line numberDiff line change
@@ -642,18 +642,6 @@ def append(self, thread):
642642
with self._lock:
643643
super().append(thread)
644644

645-
def remove(self, thread):
646-
with self._lock:
647-
# should not happen, but safe to ignore
648-
with contextlib.suppress(ValueError):
649-
super().remove(thread)
650-
651-
def remove_current(self):
652-
"""Remove a current non-daemon thread."""
653-
thread = threading.current_thread()
654-
if not thread.daemon:
655-
self.remove(thread)
656-
657645
def pop_all(self):
658646
with self._lock:
659647
self[:], result = [], self[:]
@@ -663,6 +651,14 @@ def join(self):
663651
for thread in self.pop_all():
664652
thread.join()
665653

654+
def reap(self):
655+
with self._lock:
656+
dead = [thread for thread in self if not thread.is_alive()]
657+
for thread in dead:
658+
# should not happen, but safe to ignore
659+
with contextlib.suppress(ValueError):
660+
self.remove(thread)
661+
666662

667663
class _NoThreads:
668664
"""
@@ -674,7 +670,7 @@ def append(self, thread):
674670
def join(self):
675671
pass
676672

677-
def remove_current(self):
673+
def reap(self):
678674
pass
679675

680676

@@ -701,15 +697,13 @@ def process_request_thread(self, request, client_address):
701697
except Exception:
702698
self.handle_error(request, client_address)
703699
finally:
704-
try:
705-
self.shutdown_request(request)
706-
finally:
707-
self._threads.remove_current()
700+
self.shutdown_request(request)
708701

709702
def process_request(self, request, client_address):
710703
"""Start a new thread to process the request."""
711704
if self.block_on_close:
712705
vars(self).setdefault('_threads', _Threads())
706+
self._threads.reap()
713707
t = threading.Thread(target = self.process_request_thread,
714708
args = (request, client_address))
715709
t.daemon = self.daemon_threads

Lib/test/test_socketserver.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,8 @@ def shutdown_request(self, request):
501501
def test_threads_reaped(self):
502502
"""
503503
In #37193, users reported a memory leak
504-
due to the saving of every request thread. Ensure that the
505-
threads are cleaned up after the requests complete.
504+
due to the saving of every request thread. Ensure that
505+
not all threads are kept forever.
506506
"""
507507
class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
508508
pass
@@ -511,8 +511,7 @@ class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
511511
for n in range(10):
512512
with socket.create_connection(server.server_address):
513513
server.handle_request()
514-
[thread.join() for thread in server._threads]
515-
self.assertEqual(len(server._threads), 0)
514+
self.assertLess(len(server._threads), 10)
516515
server.server_close()
517516

518517

0 commit comments

Comments
 (0)