reactor: Terminate any greenlets on finalize() call

Make sure to terminate any greenlets that are in a pause() state.
This is necessary to ensure the reactor can be deallocated.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2020-09-16 21:40:01 -04:00
parent 760a0f8df5
commit 7d83aed410
1 changed files with 12 additions and 1 deletions

View File

@ -3,7 +3,7 @@
# Copyright (C) 2016-2019 Kevin O'Connor <kevin@koconnor.net> # Copyright (C) 2016-2019 Kevin O'Connor <kevin@koconnor.net>
# #
# This file may be distributed under the terms of the GNU GPLv3 license. # This file may be distributed under the terms of the GNU GPLv3 license.
import os, select, math, time, Queue as queue import os, select, math, time, logging, Queue as queue
import greenlet import greenlet
import chelper, util import chelper, util
@ -108,6 +108,7 @@ class SelectReactor:
# Greenlets # Greenlets
self._g_dispatch = None self._g_dispatch = None
self._greenlets = [] self._greenlets = []
self._all_greenlets = []
# Timers # Timers
def update_timer(self, timer_handler, waketime): def update_timer(self, timer_handler, waketime):
timer_handler.waketime = waketime timer_handler.waketime = waketime
@ -197,6 +198,7 @@ class SelectReactor:
g_next = self._greenlets.pop() g_next = self._greenlets.pop()
else: else:
g_next = ReactorGreenlet(run=self._dispatch_loop) g_next = ReactorGreenlet(run=self._dispatch_loop)
self._all_greenlets.append(g_next)
g_next.parent = g.parent g_next.parent = g.parent
g.timer = self.register_timer(g.switch, waketime) g.timer = self.register_timer(g.switch, waketime)
self._next_timer = self.NOW self._next_timer = self.NOW
@ -243,10 +245,19 @@ class SelectReactor:
self._setup_async_callbacks() self._setup_async_callbacks()
self._process = True self._process = True
g_next = ReactorGreenlet(run=self._dispatch_loop) g_next = ReactorGreenlet(run=self._dispatch_loop)
self._all_greenlets.append(g_next)
g_next.switch() g_next.switch()
def end(self): def end(self):
self._process = False self._process = False
def finalize(self): def finalize(self):
self._g_dispatch = None
self._greenlets = []
for g in self._all_greenlets:
try:
g.throw()
except:
logging.exception("reactor finalize greenlet terminate")
self._all_greenlets = []
if self._pipe_fds is not None: if self._pipe_fds is not None:
os.close(self._pipe_fds[0]) os.close(self._pipe_fds[0])
os.close(self._pipe_fds[1]) os.close(self._pipe_fds[1])