Skip to content

Commit 070195f

Browse files
committed
Move periodic check to before the call
1 parent 9c7b2af commit 070195f

8 files changed

Lines changed: 289 additions & 315 deletions

File tree

Include/internal/pycore_opcode_metadata.h

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_io.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4737,6 +4737,8 @@ class PyMiscIOTest(MiscIOTest):
47374737
extra_exported = "BlockingIOError", "open_code",
47384738
not_exported = "valid_seek_flags",
47394739

4740+
def nop():
4741+
pass
47404742

47414743
@unittest.skipIf(os.name == 'nt', 'POSIX signals required for this test.')
47424744
class SignalsTest(unittest.TestCase):
@@ -4806,6 +4808,8 @@ def _read():
48064808
# The buffered IO layer must check for pending signal
48074809
# handlers, which in this case will invoke alarm_interrupt().
48084810
signal.alarm(1)
4811+
# Force VM to check for signals
4812+
nop()
48094813
try:
48104814
self.assertRaises(ZeroDivisionError, wio.write, large_data)
48114815
finally:

Lib/test/test_signal.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,10 +1439,13 @@ def handler(a, b):
14391439
def test__thread_interrupt_main(self):
14401440
# See https://github.com/python/cpython/issues/102397
14411441
code = """if 1:
1442+
def nop():
1443+
pass
14421444
import _thread
14431445
class Foo():
14441446
def __del__(self):
14451447
_thread.interrupt_main()
1448+
nop()
14461449
14471450
x = Foo()
14481451
"""
@@ -1451,6 +1454,9 @@ def __del__(self):
14511454
self.assertIn(b'OSError: Signal 2 ignored due to race condition', err)
14521455

14531456

1457+
def nop():
1458+
pass
1459+
14541460

14551461
class PidfdSignalTest(unittest.TestCase):
14561462

@@ -1472,6 +1478,8 @@ def test_pidfd_send_signal(self):
14721478
signal.pidfd_send_signal(my_pidfd, signal.SIGINT, object(), 0)
14731479
with self.assertRaises(KeyboardInterrupt):
14741480
signal.pidfd_send_signal(my_pidfd, signal.SIGINT)
1481+
# Force VM to check for signal
1482+
nop()
14751483

14761484
def tearDownModule():
14771485
support.reap_children()

Lib/test/test_threading.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,10 @@ def work():
23662366
self.assertEqual(name2, "new name")
23672367

23682368

2369+
def nop():
2370+
pass
2371+
2372+
23692373
class InterruptMainTests(unittest.TestCase):
23702374
def check_interrupt_main_with_signal_handler(self, signum):
23712375
def handler(signum, frame):
@@ -2376,6 +2380,9 @@ def handler(signum, frame):
23762380

23772381
with self.assertRaises(ZeroDivisionError):
23782382
_thread.interrupt_main()
2383+
# Force VM to check for interrupts
2384+
nop()
2385+
23792386

23802387
def check_interrupt_main_noerror(self, signum):
23812388
handler = signal.getsignal(signum)
@@ -2400,13 +2407,17 @@ def call_interrupt():
24002407
with self.assertRaises(KeyboardInterrupt):
24012408
t.start()
24022409
t.join()
2410+
# Force VM to check for interrupts
2411+
nop()
24032412
t.join()
24042413

24052414
def test_interrupt_main_mainthread(self):
24062415
# Make sure that if interrupt_main is called in main thread that
24072416
# KeyboardInterrupt is raised instantly.
24082417
with self.assertRaises(KeyboardInterrupt):
24092418
_thread.interrupt_main()
2419+
# Force VM to check for interrupts
2420+
nop()
24102421

24112422
def test_interrupt_main_with_signal_handler(self):
24122423
self.check_interrupt_main_with_signal_handler(signal.SIGINT)

Lib/threading.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,20 @@ def wait(self, timeout=None):
368368
gotit = waiter.acquire(False)
369369
return gotit
370370
finally:
371-
self._acquire_restore(saved_state)
371+
e = None
372+
try:
373+
# If a keybord interrupt is pending it will trigger here
374+
self._acquire_restore(saved_state)
375+
except KeyboardInterrupt as ex:
376+
self._acquire_restore(saved_state)
377+
e = ex
372378
if not gotit:
373379
try:
374380
self._waiters.remove(waiter)
375381
except ValueError:
376382
pass
383+
if e is not None:
384+
raise e from None
377385

378386
def wait_for(self, predicate, timeout=None):
379387
"""Wait until a condition evaluates to True.

Lib/unittest/case.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ def _raiseFailure(self, standardMsg):
206206
msg = self.test_case._formatMessage(self.msg, standardMsg)
207207
raise self.test_case.failureException(msg)
208208

209+
def nop():
210+
pass
211+
209212
class _AssertRaisesBaseContext(_BaseTestCaseContext):
210213

211214
def __init__(self, expected, test_case, expected_regex=None):
@@ -243,6 +246,8 @@ def handle(self, name, args, kwargs):
243246
self.obj_name = str(callable_obj)
244247
with self:
245248
callable_obj(*args, **kwargs)
249+
# Force asynchronous exceptions
250+
nop()
246251
finally:
247252
# bpo-23890: manually break a reference cycle
248253
self = None

Python/bytecodes.c

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3790,8 +3790,8 @@ dummy_func(
37903790
ERROR_IF(err);
37913791
}
37923792

3793-
macro(CALL) = _SPECIALIZE_CALL + unused/2 + _MAYBE_EXPAND_METHOD + _DO_CALL + _CHECK_PERIODIC;
3794-
macro(INSTRUMENTED_CALL) = unused/3 + _MAYBE_EXPAND_METHOD + _MONITOR_CALL + _DO_CALL + _CHECK_PERIODIC;
3793+
macro(CALL) = _SPECIALIZE_CALL + _CHECK_PERIODIC + unused/2 + _MAYBE_EXPAND_METHOD + _DO_CALL;
3794+
macro(INSTRUMENTED_CALL) = _CHECK_PERIODIC + unused/3 + _MAYBE_EXPAND_METHOD + _MONITOR_CALL + _DO_CALL;
37953795

37963796
op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame)) {
37973797
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -3911,8 +3911,8 @@ dummy_func(
39113911
unused/1 + // Skip over the counter
39123912
unused/2 +
39133913
_CHECK_IS_NOT_PY_CALLABLE +
3914-
_CALL_NON_PY_GENERAL +
3915-
_CHECK_PERIODIC;
3914+
_CHECK_PERIODIC +
3915+
_CALL_NON_PY_GENERAL;
39163916

39173917
op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) {
39183918
EXIT_IF(!PyStackRef_IsNull(null));
@@ -4068,8 +4068,8 @@ dummy_func(
40684068
unused/2 +
40694069
_GUARD_NOS_NULL +
40704070
_GUARD_CALLABLE_STR_1 +
4071-
_CALL_STR_1 +
4072-
_CHECK_PERIODIC;
4071+
_CHECK_PERIODIC +
4072+
_CALL_STR_1;
40734073

40744074
op(_GUARD_CALLABLE_TUPLE_1, (callable, unused, unused -- callable, unused, unused)) {
40754075
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -4096,8 +4096,8 @@ dummy_func(
40964096
unused/2 +
40974097
_GUARD_NOS_NULL +
40984098
_GUARD_CALLABLE_TUPLE_1 +
4099-
_CALL_TUPLE_1 +
4100-
_CHECK_PERIODIC;
4099+
_CHECK_PERIODIC +
4100+
_CALL_TUPLE_1;
41014101

41024102
op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
41034103
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -4192,8 +4192,8 @@ dummy_func(
41924192
macro(CALL_BUILTIN_CLASS) =
41934193
unused/1 +
41944194
unused/2 +
4195-
_CALL_BUILTIN_CLASS +
4196-
_CHECK_PERIODIC;
4195+
_CHECK_PERIODIC +
4196+
_CALL_BUILTIN_CLASS;
41974197

41984198
op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res)) {
41994199
/* Builtin METH_O functions */
@@ -4227,8 +4227,8 @@ dummy_func(
42274227
macro(CALL_BUILTIN_O) =
42284228
unused/1 +
42294229
unused/2 +
4230-
_CALL_BUILTIN_O +
4231-
_CHECK_PERIODIC;
4230+
_CHECK_PERIODIC +
4231+
_CALL_BUILTIN_O;
42324232

42334233
op(_CALL_BUILTIN_FAST, (callable, self_or_null, args[oparg] -- res)) {
42344234
/* Builtin METH_FASTCALL functions, without keywords */
@@ -4264,8 +4264,8 @@ dummy_func(
42644264
macro(CALL_BUILTIN_FAST) =
42654265
unused/1 +
42664266
unused/2 +
4267-
_CALL_BUILTIN_FAST +
4268-
_CHECK_PERIODIC;
4267+
_CHECK_PERIODIC +
4268+
_CALL_BUILTIN_FAST;
42694269

42704270
op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable, self_or_null, args[oparg] -- res)) {
42714271
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
@@ -4300,8 +4300,8 @@ dummy_func(
43004300
macro(CALL_BUILTIN_FAST_WITH_KEYWORDS) =
43014301
unused/1 +
43024302
unused/2 +
4303-
_CALL_BUILTIN_FAST_WITH_KEYWORDS +
4304-
_CHECK_PERIODIC;
4303+
_CHECK_PERIODIC +
4304+
_CALL_BUILTIN_FAST_WITH_KEYWORDS;
43054305

43064306
macro(CALL_LEN) =
43074307
unused/1 +
@@ -4438,8 +4438,8 @@ dummy_func(
44384438
macro(CALL_METHOD_DESCRIPTOR_O) =
44394439
unused/1 +
44404440
unused/2 +
4441-
_CALL_METHOD_DESCRIPTOR_O +
4442-
_CHECK_PERIODIC;
4441+
_CHECK_PERIODIC +
4442+
_CALL_METHOD_DESCRIPTOR_O;
44434443

44444444
op(_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (callable, self_or_null, args[oparg] -- res)) {
44454445
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -4480,8 +4480,8 @@ dummy_func(
44804480
macro(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) =
44814481
unused/1 +
44824482
unused/2 +
4483-
_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS +
4484-
_CHECK_PERIODIC;
4483+
_CHECK_PERIODIC +
4484+
_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS;
44854485

44864486
op(_CALL_METHOD_DESCRIPTOR_NOARGS, (callable, self_or_null, args[oparg] -- res)) {
44874487
assert(oparg == 0 || oparg == 1);
@@ -4518,8 +4518,8 @@ dummy_func(
45184518
macro(CALL_METHOD_DESCRIPTOR_NOARGS) =
45194519
unused/1 +
45204520
unused/2 +
4521-
_CALL_METHOD_DESCRIPTOR_NOARGS +
4522-
_CHECK_PERIODIC;
4521+
_CHECK_PERIODIC +
4522+
_CALL_METHOD_DESCRIPTOR_NOARGS;
45234523

45244524
op(_CALL_METHOD_DESCRIPTOR_FAST, (callable, self_or_null, args[oparg] -- res)) {
45254525
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
@@ -4559,8 +4559,8 @@ dummy_func(
45594559
macro(CALL_METHOD_DESCRIPTOR_FAST) =
45604560
unused/1 +
45614561
unused/2 +
4562-
_CALL_METHOD_DESCRIPTOR_FAST +
4563-
_CHECK_PERIODIC;
4562+
_CHECK_PERIODIC +
4563+
_CALL_METHOD_DESCRIPTOR_FAST;
45644564

45654565
// Cache layout: counter/1, func_version/2
45664566
family(CALL_KW, INLINE_CACHE_ENTRIES_CALL_KW) = {
@@ -4815,8 +4815,8 @@ dummy_func(
48154815
unused/1 + // Skip over the counter
48164816
unused/2 +
48174817
_CHECK_IS_NOT_PY_CALLABLE_KW +
4818-
_CALL_KW_NON_PY +
4819-
_CHECK_PERIODIC;
4818+
_CHECK_PERIODIC +
4819+
_CALL_KW_NON_PY;
48204820

48214821
op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs -- func, unused, callargs, kwargs)) {
48224822
PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs);
@@ -4916,13 +4916,13 @@ dummy_func(
49164916

49174917
macro(CALL_FUNCTION_EX) =
49184918
_MAKE_CALLARGS_A_TUPLE +
4919-
_DO_CALL_FUNCTION_EX +
4920-
_CHECK_PERIODIC;
4919+
_CHECK_PERIODIC +
4920+
_DO_CALL_FUNCTION_EX;
49214921

49224922
macro(INSTRUMENTED_CALL_FUNCTION_EX) =
49234923
_MAKE_CALLARGS_A_TUPLE +
4924-
_DO_CALL_FUNCTION_EX +
4925-
_CHECK_PERIODIC;
4924+
_CHECK_PERIODIC +
4925+
_DO_CALL_FUNCTION_EX;
49264926

49274927
inst(MAKE_FUNCTION, (codeobj_st -- func)) {
49284928
PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st);

0 commit comments

Comments
 (0)