Skip to content

Commit 9530e6d

Browse files
committed
Only check evalbreaker after calls and on backwards egdes. Makes sure that __exit__ or __aexit__ is called in with statments in case of interrupt.
1 parent 232f4cb commit 9530e6d

File tree

2 files changed

+40
-46
lines changed

2 files changed

+40
-46
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Only handle asynchronous exceptions and requests to drop the GIL when
2+
returning from a call or on the back edges of loops. Makes sure that
3+
:meth:`__exit__` is always called in with statements, even for interrupts.

Python/ceval.c

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
13311331
TARGET_##op
13321332

13331333
#ifdef LLTRACE
1334-
#define FAST_DISPATCH() \
1334+
#define DISPATCH() \
13351335
{ \
13361336
if (!lltrace && !_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
13371337
f->f_lasti = INSTR_OFFSET(); \
@@ -1341,7 +1341,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
13411341
goto fast_next_opcode; \
13421342
}
13431343
#else
1344-
#define FAST_DISPATCH() \
1344+
#define DISPATCH() \
13451345
{ \
13461346
if (!_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
13471347
f->f_lasti = INSTR_OFFSET(); \
@@ -1352,20 +1352,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
13521352
}
13531353
#endif
13541354

1355-
#define DISPATCH() \
1356-
{ \
1357-
if (!_Py_atomic_load_relaxed(eval_breaker)) { \
1358-
FAST_DISPATCH(); \
1359-
} \
1360-
continue; \
1361-
}
1362-
13631355
#else
13641356
#define TARGET(op) op
1365-
#define FAST_DISPATCH() goto fast_next_opcode
1366-
#define DISPATCH() continue
1357+
#define DISPATCH() goto fast_next_opcode
1358+
13671359
#endif
13681360

1361+
#define CHECK_EVAL_BREAKER() \
1362+
if (_Py_atomic_load_relaxed(eval_breaker)) { \
1363+
continue; \
1364+
}
1365+
13691366

13701367
/* Tuple access macros */
13711368

@@ -1857,7 +1854,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
18571854
and that all operation that succeed call [FAST_]DISPATCH() ! */
18581855

18591856
case TARGET(NOP): {
1860-
FAST_DISPATCH();
1857+
DISPATCH();
18611858
}
18621859

18631860
case TARGET(LOAD_FAST): {
@@ -1870,36 +1867,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
18701867
}
18711868
Py_INCREF(value);
18721869
PUSH(value);
1873-
FAST_DISPATCH();
1870+
DISPATCH();
18741871
}
18751872

18761873
case TARGET(LOAD_CONST): {
18771874
PREDICTED(LOAD_CONST);
18781875
PyObject *value = GETITEM(consts, oparg);
18791876
Py_INCREF(value);
18801877
PUSH(value);
1881-
FAST_DISPATCH();
1878+
DISPATCH();
18821879
}
18831880

18841881
case TARGET(STORE_FAST): {
18851882
PREDICTED(STORE_FAST);
18861883
PyObject *value = POP();
18871884
SETLOCAL(oparg, value);
1888-
FAST_DISPATCH();
1885+
DISPATCH();
18891886
}
18901887

18911888
case TARGET(POP_TOP): {
18921889
PyObject *value = POP();
18931890
Py_DECREF(value);
1894-
FAST_DISPATCH();
1891+
DISPATCH();
18951892
}
18961893

18971894
case TARGET(ROT_TWO): {
18981895
PyObject *top = TOP();
18991896
PyObject *second = SECOND();
19001897
SET_TOP(second);
19011898
SET_SECOND(top);
1902-
FAST_DISPATCH();
1899+
DISPATCH();
19031900
}
19041901

19051902
case TARGET(ROT_THREE): {
@@ -1909,7 +1906,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
19091906
SET_TOP(second);
19101907
SET_SECOND(third);
19111908
SET_THIRD(top);
1912-
FAST_DISPATCH();
1909+
DISPATCH();
19131910
}
19141911

19151912
case TARGET(ROT_FOUR): {
@@ -1921,14 +1918,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
19211918
SET_SECOND(third);
19221919
SET_THIRD(fourth);
19231920
SET_FOURTH(top);
1924-
FAST_DISPATCH();
1921+
DISPATCH();
19251922
}
19261923

19271924
case TARGET(DUP_TOP): {
19281925
PyObject *top = TOP();
19291926
Py_INCREF(top);
19301927
PUSH(top);
1931-
FAST_DISPATCH();
1928+
DISPATCH();
19321929
}
19331930

19341931
case TARGET(DUP_TOP_TWO): {
@@ -1939,7 +1936,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
19391936
STACK_GROW(2);
19401937
SET_TOP(top);
19411938
SET_SECOND(second);
1942-
FAST_DISPATCH();
1939+
DISPATCH();
19431940
}
19441941

19451942
case TARGET(UNARY_POSITIVE): {
@@ -2704,7 +2701,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
27042701
UNWIND_EXCEPT_HANDLER(b);
27052702
Py_DECREF(POP());
27062703
JUMPBY(oparg);
2707-
FAST_DISPATCH();
2704+
DISPATCH();
27082705
}
27092706
else {
27102707
PyObject *val = POP();
@@ -2718,7 +2715,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
27182715
PyObject *value = PyExc_AssertionError;
27192716
Py_INCREF(value);
27202717
PUSH(value);
2721-
FAST_DISPATCH();
2718+
DISPATCH();
27222719
}
27232720

27242721
case TARGET(LOAD_BUILD_CLASS): {
@@ -3620,7 +3617,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
36203617
Py_DECREF(right);
36213618
PREDICT(POP_JUMP_IF_FALSE);
36223619
PREDICT(POP_JUMP_IF_TRUE);
3623-
FAST_DISPATCH();
3620+
DISPATCH();
36243621
}
36253622

36263623
case TARGET(CONTAINS_OP): {
@@ -3637,7 +3634,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
36373634
PUSH(b);
36383635
PREDICT(POP_JUMP_IF_FALSE);
36393636
PREDICT(POP_JUMP_IF_TRUE);
3640-
FAST_DISPATCH();
3637+
DISPATCH();
36413638
}
36423639

36433640
#define CANNOT_CATCH_MSG "catching classes that do not inherit from "\
@@ -3734,7 +3731,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37343731

37353732
case TARGET(JUMP_FORWARD): {
37363733
JUMPBY(oparg);
3737-
FAST_DISPATCH();
3734+
DISPATCH();
37383735
}
37393736

37403737
case TARGET(POP_JUMP_IF_FALSE): {
@@ -3743,12 +3740,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37433740
int err;
37443741
if (cond == Py_True) {
37453742
Py_DECREF(cond);
3746-
FAST_DISPATCH();
3743+
DISPATCH();
37473744
}
37483745
if (cond == Py_False) {
37493746
Py_DECREF(cond);
37503747
JUMPTO(oparg);
3751-
FAST_DISPATCH();
3748+
DISPATCH();
37523749
}
37533750
err = PyObject_IsTrue(cond);
37543751
Py_DECREF(cond);
@@ -3767,12 +3764,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37673764
int err;
37683765
if (cond == Py_False) {
37693766
Py_DECREF(cond);
3770-
FAST_DISPATCH();
3767+
DISPATCH();
37713768
}
37723769
if (cond == Py_True) {
37733770
Py_DECREF(cond);
37743771
JUMPTO(oparg);
3775-
FAST_DISPATCH();
3772+
DISPATCH();
37763773
}
37773774
err = PyObject_IsTrue(cond);
37783775
Py_DECREF(cond);
@@ -3792,11 +3789,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37923789
if (cond == Py_True) {
37933790
STACK_SHRINK(1);
37943791
Py_DECREF(cond);
3795-
FAST_DISPATCH();
3792+
DISPATCH();
37963793
}
37973794
if (cond == Py_False) {
37983795
JUMPTO(oparg);
3799-
FAST_DISPATCH();
3796+
DISPATCH();
38003797
}
38013798
err = PyObject_IsTrue(cond);
38023799
if (err > 0) {
@@ -3816,11 +3813,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
38163813
if (cond == Py_False) {
38173814
STACK_SHRINK(1);
38183815
Py_DECREF(cond);
3819-
FAST_DISPATCH();
3816+
DISPATCH();
38203817
}
38213818
if (cond == Py_True) {
38223819
JUMPTO(oparg);
3823-
FAST_DISPATCH();
3820+
DISPATCH();
38243821
}
38253822
err = PyObject_IsTrue(cond);
38263823
if (err > 0) {
@@ -3838,18 +3835,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
38383835
case TARGET(JUMP_ABSOLUTE): {
38393836
PREDICTED(JUMP_ABSOLUTE);
38403837
JUMPTO(oparg);
3841-
#if FAST_LOOPS
3842-
/* Enabling this path speeds-up all while and for-loops by bypassing
3843-
the per-loop checks for signals. By default, this should be turned-off
3844-
because it prevents detection of a control-break in tight loops like
3845-
"while 1: pass". Compile with this option turned-on when you need
3846-
the speed-up and do not need break checking inside tight loops (ones
3847-
that contain only instructions ending with FAST_DISPATCH).
3848-
*/
3849-
FAST_DISPATCH();
3850-
#else
3838+
CHECK_EVAL_BREAKER();
38513839
DISPATCH();
3852-
#endif
38533840
}
38543841

38553842
case TARGET(GET_LEN): {
@@ -4260,6 +4247,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
42604247
PUSH(res);
42614248
if (res == NULL)
42624249
goto error;
4250+
CHECK_EVAL_BREAKER();
42634251
DISPATCH();
42644252
}
42654253

@@ -4273,6 +4261,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
42734261
if (res == NULL) {
42744262
goto error;
42754263
}
4264+
CHECK_EVAL_BREAKER();
42764265
DISPATCH();
42774266
}
42784267

@@ -4292,6 +4281,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
42924281
if (res == NULL) {
42934282
goto error;
42944283
}
4284+
CHECK_EVAL_BREAKER();
42954285
DISPATCH();
42964286
}
42974287

@@ -4338,6 +4328,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
43384328
if (result == NULL) {
43394329
goto error;
43404330
}
4331+
CHECK_EVAL_BREAKER();
43414332
DISPATCH();
43424333
}
43434334

0 commit comments

Comments
 (0)