Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r60582:5a1110abb728 Date: 2013-01-28 08:47 +0100 http://bitbucket.org/pypy/pypy/changeset/5a1110abb728/
Log: Replace two pages of code with only one: in the multithreaded case, keep the pending signals in the C-level data structure inspected by pypysig_poll(). This avoids yet another list of pending signals here. diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py --- a/pypy/module/signal/interp_signal.py +++ b/pypy/module/signal/interp_signal.py @@ -19,7 +19,8 @@ class SignalActionFlag(AbstractActionFlag): # This class uses the C-level pypysig_counter variable as the tick # counter. The C-level signal handler will reset it to -1 whenever - # a signal is received. + # a signal is received. This causes CheckSignalAction.perform() to + # be called. def get_ticker(self): p = pypysig_getaddr_occurred() @@ -47,45 +48,40 @@ def __init__(self, space): AsyncAction.__init__(self, space) self.handlers_w = {} - if space.config.objspace.usemodules.thread: - # need a helper action in case signals arrive in a non-main thread - self.pending_signals = {} - self.reissue_signal_action = ReissueSignalAction(space) - else: - self.reissue_signal_action = None + self.emulated_sigint = False @jit.dont_look_inside def perform(self, executioncontext, frame): - while True: - n = pypysig_poll() - if n < 0: - break - self.perform_signal(executioncontext, n) - - @jit.dont_look_inside - def perform_signal(self, executioncontext, n): - if self.reissue_signal_action is None: - # no threads: we can report the signal immediately - self.report_signal(n) + if self.space.config.objspace.usemodules.thread: + main_ec = self.space.threadlocals.getmainthreadvalue() + in_main = executioncontext is main_ec else: - main_ec = self.space.threadlocals.getmainthreadvalue() - if executioncontext is main_ec: - # running in the main thread: we can report the - # signal immediately - self.report_signal(n) - else: - # running in another thread: we need to hack a bit - self.pending_signals[n] = None - self.reissue_signal_action.fire_after_thread_switch() + in_main = True + # If we are in the main thread, poll and report the signals now. + if in_main: + if self.emulated_sigint: + self.emulated_sigint = False + self._report_signal(cpy_signal.SIGINT) + while True: + n = pypysig_poll() + if n < 0: + break + self._report_signal(n) + else: + # Otherwise, don't call pypysig_poll() at all. Instead, + # arrange for perform() to be called again after a thread + # switch. It might be called again and again, until we + # land in the main thread. + self.fire_after_thread_switch() @jit.dont_look_inside def set_interrupt(self): "Simulates the effect of a SIGINT signal arriving" ec = self.space.getexecutioncontext() - self.perform_signal(ec, cpy_signal.SIGINT) + self.emulated_sigint = True + self.perform(ec, None) - @jit.dont_look_inside - def report_signal(self, n): + def _report_signal(self, n): try: w_handler = self.handlers_w[n] except KeyError: @@ -100,39 +96,6 @@ w_frame = space.wrap(ec.gettopframe_nohidden()) space.call_function(w_handler, space.wrap(n), w_frame) - @jit.dont_look_inside - def report_pending_signals(self): - # XXX this logic isn't so complicated but I have no clue how - # to test it :-( - pending_signals = self.pending_signals.keys() - self.pending_signals.clear() - try: - while pending_signals: - self.report_signal(pending_signals.pop()) - finally: - # in case of exception, put the undelivered signals back - # into the dict instead of silently swallowing them - if pending_signals: - for n in pending_signals: - self.pending_signals[n] = None - self.reissue_signal_action.fire() - - -class ReissueSignalAction(AsyncAction): - """A special action to help deliver signals to the main thread. If - a non-main thread caught a signal, this action fires after every - thread switch until we land in the main thread. - """ - - def perform(self, executioncontext, frame): - main_ec = self.space.threadlocals.getmainthreadvalue() - if executioncontext is main_ec: - # now running in the main thread: we can really report the signals - self.space.check_signal_action.report_pending_signals() - else: - # still running in some other thread: try again later - self.fire_after_thread_switch() - @unwrap_spec(signum=int) def getsignal(space, signum): _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit