@@ -4119,12 +4119,31 @@ def test_wait_pidfd_open_error(self, patch_point="os.pidfd_open"):
41194119 def test_wait_kqueue_error (self , patch_point = "os.pidfd_open" ):
41204120 self .assert_fast_waitpid_error ("select.kqueue" )
41214121
4122- # ---
4122+ @unittest .skipIf (
4123+ not subprocess ._can_use_kqueue (), reason = "macOS / BSD only"
4124+ )
4125+ def test_kqueue_control_error (self ):
4126+ # Emulate a case where kqueue.control() fails due to too many
4127+ # open files. _busy_wait() should be used as fallback.
4128+ p = subprocess .Popen ([sys .executable ,
4129+ "-c" , "import time; time.sleep(0.3)" ])
4130+ kq_mock = mock .Mock ()
4131+ kq_mock .control .side_effect = OSError (
4132+ errno .EPERM , os .strerror (errno .EPERM )
4133+ )
4134+ kq_mock .close = mock .Mock ()
4135+
4136+ with mock .patch ("select.kqueue" , return_value = kq_mock ) as m :
4137+ with self .assertRaises (subprocess .TimeoutExpired ):
4138+ p .wait (timeout = 0.0001 )
4139+ self .assertEqual (p .wait (timeout = support .SHORT_TIMEOUT ), 0 )
4140+ assert m .called
4141+
41234142
41244143 def assert_wait_pid_race (self , patch_target , real_func ):
4125- # Call pidfd_open() / kqueue, then terminate the process. Make
4126- # sure that the next poll() / kqueue.control() call still works
4127- # for a terminated PID.
4144+ # Call pidfd_open() / kqueue() , then terminate the process.
4145+ # Make sure that the next poll() / kqueue.control() call still
4146+ # works for a terminated PID.
41284147 p = subprocess .Popen ([sys .executable ,
41294148 "-c" , "import time; time.sleep(0.3)" ])
41304149
0 commit comments