Restore correct signal handling in Python3

The patch 2ee3894f49 broke the original
fix cad75e4e13 that ensured eventlet could
be interrupted while sleeping after PEP475 was implemented in Python
3.5. Eventlet monkey-patches the signal module with its own version, so
we have to look up the original module to determine whether the
underlying OS actually supports the poll() function.

Change-Id: Ia712c9a83d8081bf0b5e6fe36f169f9028aae3dc
Closes-Bug: #1803731
Related-Bug: #1788022
Related-Bug: #1705047
This commit is contained in:
Zane Bitter 2018-12-10 19:42:30 +13:00
parent b85d9353fb
commit 159ef2e1d2
2 changed files with 18 additions and 5 deletions

View File

@ -28,7 +28,6 @@ import io
import logging import logging
import os import os
import random import random
import select
import signal import signal
import six import six
import sys import sys
@ -204,8 +203,9 @@ class SignalHandler(object):
For Python 3.5 and later, deal with the changes in PEP 475 that prevent For Python 3.5 and later, deal with the changes in PEP 475 that prevent
a signal from interrupting eventlet's call to poll() or sleep(). a signal from interrupting eventlet's call to poll() or sleep().
""" """
select_module = eventlet.patcher.original('select')
self.__force_interrupt_on_signal = (sys.version_info >= (3, 5) and self.__force_interrupt_on_signal = (sys.version_info >= (3, 5) and
hasattr(select, 'poll')) hasattr(select_module, 'poll'))
if self.__force_interrupt_on_signal: if self.__force_interrupt_on_signal:
try: try:

View File

@ -478,15 +478,28 @@ class ProcessLauncherTest(base.ServiceBaseTestCase):
signal_handler.clear() signal_handler.clear()
@mock.patch('sys.version_info', (3, 5)) @mock.patch('sys.version_info', (3, 5))
@mock.patch.object(service, 'select', spec=[]) def test_setup_signal_interruption_no_select_poll(self):
def test_setup_signal_interruption_no_select_poll(self, mock_select): # NOTE(claudiub): SignalHandler is a singleton, which means that it
# might already be initialized. We need to clear to clear the cache
# in order to prevent race conditions between tests.
service.SignalHandler.__class__._instances.clear()
with mock.patch('eventlet.patcher.original',
return_value=object()) as get_original:
signal_handler = service.SignalHandler()
get_original.assert_called_with('select')
self.addCleanup(service.SignalHandler.__class__._instances.clear)
self.assertFalse(
signal_handler._SignalHandler__force_interrupt_on_signal)
@mock.patch('sys.version_info', (3, 5))
def test_setup_signal_interruption_select_poll(self):
# NOTE(claudiub): SignalHandler is a singleton, which means that it # NOTE(claudiub): SignalHandler is a singleton, which means that it
# might already be initialized. We need to clear to clear the cache # might already be initialized. We need to clear to clear the cache
# in order to prevent race conditions between tests. # in order to prevent race conditions between tests.
service.SignalHandler.__class__._instances.clear() service.SignalHandler.__class__._instances.clear()
signal_handler = service.SignalHandler() signal_handler = service.SignalHandler()
self.addCleanup(service.SignalHandler.__class__._instances.clear) self.addCleanup(service.SignalHandler.__class__._instances.clear)
self.assertFalse( self.assertTrue(
signal_handler._SignalHandler__force_interrupt_on_signal) signal_handler._SignalHandler__force_interrupt_on_signal)
@mock.patch('signal.alarm') @mock.patch('signal.alarm')