Browse Source

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
Zane Bitter 4 months ago
parent
commit
159ef2e1d2
2 changed files with 18 additions and 5 deletions
  1. 2
    2
      oslo_service/service.py
  2. 16
    3
      oslo_service/tests/test_service.py

+ 2
- 2
oslo_service/service.py View File

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

+ 16
- 3
oslo_service/tests/test_service.py View File

@@ -478,17 +478,30 @@ class ProcessLauncherTest(base.ServiceBaseTestCase):
478 478
         signal_handler.clear()
479 479
 
480 480
     @mock.patch('sys.version_info', (3, 5))
481
-    @mock.patch.object(service, 'select', spec=[])
482
-    def test_setup_signal_interruption_no_select_poll(self, mock_select):
481
+    def test_setup_signal_interruption_no_select_poll(self):
483 482
         # NOTE(claudiub): SignalHandler is a singleton, which means that it
484 483
         # might already be initialized. We need to clear to clear the cache
485 484
         # in order to prevent race conditions between tests.
486 485
         service.SignalHandler.__class__._instances.clear()
487
-        signal_handler = service.SignalHandler()
486
+        with mock.patch('eventlet.patcher.original',
487
+                        return_value=object()) as get_original:
488
+            signal_handler = service.SignalHandler()
489
+            get_original.assert_called_with('select')
488 490
         self.addCleanup(service.SignalHandler.__class__._instances.clear)
489 491
         self.assertFalse(
490 492
             signal_handler._SignalHandler__force_interrupt_on_signal)
491 493
 
494
+    @mock.patch('sys.version_info', (3, 5))
495
+    def test_setup_signal_interruption_select_poll(self):
496
+        # NOTE(claudiub): SignalHandler is a singleton, which means that it
497
+        # might already be initialized. We need to clear to clear the cache
498
+        # in order to prevent race conditions between tests.
499
+        service.SignalHandler.__class__._instances.clear()
500
+        signal_handler = service.SignalHandler()
501
+        self.addCleanup(service.SignalHandler.__class__._instances.clear)
502
+        self.assertTrue(
503
+            signal_handler._SignalHandler__force_interrupt_on_signal)
504
+
492 505
     @mock.patch('signal.alarm')
493 506
     @mock.patch("os.kill")
494 507
     @mock.patch("oslo_service.service.ProcessLauncher.stop")

Loading…
Cancel
Save