Skip to content

Commit 6824a28

Browse files
author
Anselm Kruis
committed
merge 3.4-slp (Stackless python#119)
2 parents bd826b3 + 3acd739 commit 6824a28

12 files changed

Lines changed: 173 additions & 72 deletions

File tree

Objects/abstract.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,7 +2081,7 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where)
20812081

20822082
assert((func != NULL) ^ (where != NULL));
20832083

2084-
if (STACKLESS_RETVAL(result) == NULL) {
2084+
if (STACKLESS_RETVAL(PyThreadState_GET(), result) == NULL) {
20852085
if (!err_occurred) {
20862086
if (func)
20872087
PyErr_Format(PyExc_SystemError,
@@ -2103,7 +2103,7 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where)
21032103
PyObject *exc, *val, *tb;
21042104
PyErr_Fetch(&exc, &val, &tb);
21052105

2106-
Py_DECREF(STACKLESS_RETVAL(result));
2106+
Py_DECREF(STACKLESS_RETVAL(PyThreadState_GET(), result));
21072107

21082108
if (func)
21092109
PyErr_Format(PyExc_SystemError,
@@ -2791,7 +2791,7 @@ PyIter_Next(PyObject *iter)
27912791
STACKLESS_PROMOTE_METHOD(iter, tp_iternext);
27922792
result = (*iter->ob_type->tp_iternext)(iter);
27932793
STACKLESS_ASSERT();
2794-
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(result, NULL);
2794+
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(PyThreadState_GET(), result, NULL);
27952795
if (result == NULL &&
27962796
PyErr_Occurred() &&
27972797
PyErr_ExceptionMatches(PyExc_StopIteration))

Objects/typeobject.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,7 +5481,7 @@ wrap_next(PyObject *self, PyObject *args, void *wrapped)
54815481
STACKLESS_PROMOTE_ALL();
54825482
res = (*func)(self);
54835483
STACKLESS_ASSERT();
5484-
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(res, NULL);
5484+
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(PyThreadState_GET(), res, NULL);
54855485
if (res == NULL && !PyErr_Occurred())
54865486
PyErr_SetNone(PyExc_StopIteration);
54875487
return res;
@@ -6358,7 +6358,7 @@ slp_tp_init_callback(PyFrameObject *f, int exc, PyObject *retval)
63586358
}
63596359
ts->frame = f;
63606360
Py_DECREF(cf);
6361-
return STACKLESS_PACK(retval);
6361+
return STACKLESS_PACK(ts, retval);
63626362
}
63636363
#endif
63646364

@@ -6389,7 +6389,7 @@ slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds)
63896389
#ifdef STACKLESS
63906390
if (stackless && !STACKLESS_UNWINDING(res)) {
63916391
/* required, because added a C-frame */
6392-
STACKLESS_PACK(res);
6392+
STACKLESS_PACK(PyThreadState_GET(), res);
63936393
return STACKLESS_UNWINDING_MAGIC;
63946394
}
63956395
if (STACKLESS_UNWINDING(res)) {

Python/ceval.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4015,7 +4015,7 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
40154015
if (why != WHY_RETURN)
40164016
retval = NULL;
40174017

4018-
assert((STACKLESS_RETVAL(retval) != NULL) ^ (PyErr_Occurred() != NULL));
4018+
assert((STACKLESS_RETVAL(tstate, retval) != NULL) ^ (PyErr_Occurred() != NULL));
40194019

40204020
fast_yield:
40214021
if (co->co_flags & CO_GENERATOR) {
@@ -4113,7 +4113,7 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
41134113
f->f_lasti = INSTR_OFFSET() - 1;
41144114
if (tstate->frame->f_back != f)
41154115
return retval;
4116-
STACKLESS_UNPACK(retval);
4116+
STACKLESS_UNPACK(tstate, retval);
41174117
retval = tstate->frame->f_execute(tstate->frame, 0, retval);
41184118
if (tstate->frame != f) {
41194119
assert(f->f_execute == slp_eval_frame_value || f->f_execute == slp_eval_frame_noval ||
@@ -4123,7 +4123,7 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
41234123
return retval;
41244124
}
41254125
if (STACKLESS_UNWINDING(retval))
4126-
STACKLESS_UNPACK(retval);
4126+
STACKLESS_UNPACK(tstate, retval);
41274127

41284128
f->f_stacktop = NULL;
41294129
if (f->f_execute == slp_eval_frame_iter) {
@@ -4518,7 +4518,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
45184518
retval = Py_None;
45194519
if (stackless) {
45204520
tstate->frame = f;
4521-
return STACKLESS_PACK(retval);
4521+
return STACKLESS_PACK(tstate, retval);
45224522
}
45234523
else {
45244524
if (f->f_back != NULL)
@@ -5253,7 +5253,7 @@ call_function(PyObject ***pp_stack, int oparg
52535253
READ_TIMESTAMP(*pintr1);
52545254
Py_DECREF(func);
52555255

5256-
assert((STACKLESS_RETVAL(x) != NULL) ^ (PyErr_Occurred() != NULL));
5256+
assert((STACKLESS_RETVAL(PyThreadState_GET(), x) != NULL) ^ (PyErr_Occurred() != NULL));
52575257
}
52585258

52595259
/* Clear the stack of the function object. Also removes
@@ -5266,7 +5266,7 @@ call_function(PyObject ***pp_stack, int oparg
52665266
PCALL(PCALL_POP);
52675267
}
52685268

5269-
assert((STACKLESS_RETVAL(x) != NULL) ^ (PyErr_Occurred() != NULL));
5269+
assert((STACKLESS_RETVAL(PyThreadState_GET(), x) != NULL) ^ (PyErr_Occurred() != NULL));
52705270
return x;
52715271
}
52725272

@@ -5322,11 +5322,11 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
53225322
}
53235323
#ifdef STACKLESS
53245324
f->f_execute = PyEval_EvalFrameEx_slp;
5325-
if (slp_enable_softswitch) {
5325+
if (STACKLESS_POSSIBLE()) {
53265326
Py_INCREF(Py_None);
53275327
retval = Py_None;
53285328
tstate->frame = f;
5329-
return STACKLESS_PACK(retval);
5329+
return STACKLESS_PACK(tstate, retval);
53305330
}
53315331
return slp_eval_frame(f);
53325332
#else

Stackless/changelog.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ What's New in Stackless 3.X.X?
99

1010
*Release date: 20XX-XX-XX*
1111

12+
- https://bitbucket.org/stackless-dev/stackless/issues/119
13+
Fix a rare bug in the stack unwinding mechanism, that caused a SystemError
14+
exception or an assertion violation, if a __del__()-method or a weakref
15+
callback runs during stack unwinding.
16+
1217
- https://bitbucket.org/stackless-dev/stackless/issues/115
1318
Fix an unlikely crash caused by an context manager, which silences an
1419
exception.

Stackless/core/stackless_impl.h

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ PyObject * slp_tp_init_callback(PyFrameObject *f, int exc, PyObject *retval);
117117

118118
typedef struct {
119119
PyObject_HEAD
120-
PyObject *tempval;
121120
} PyUnwindObject;
122121

123122
PyAPI_DATA(PyUnwindObject *) Py_UnwindToken;
@@ -139,45 +138,36 @@ PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type;
139138
PyTaskletObject * slp_get_watchdog(PyThreadState *ts, int interrupt);
140139

141140

142-
/* fast (release) and safe (debug) access to the unwind token and retval */
141+
/* access to the unwind token and retval */
143142

144-
#ifdef Py_DEBUG
145-
146-
#define STACKLESS_PACK(retval) \
147-
(assert(Py_UnwindToken->tempval == NULL), \
148-
Py_UnwindToken->tempval = (retval), \
143+
#define STACKLESS_PACK(tstate, retval) \
144+
(assert((tstate)->st.unwinding_retval == NULL), \
145+
(tstate)->st.unwinding_retval = (retval), \
149146
(PyObject *) Py_UnwindToken)
150147

151-
#define STACKLESS_UNPACK(retval) \
148+
#define STACKLESS_UNPACK(tstate, retval) \
152149
((void)(assert(STACKLESS_UNWINDING(retval)), \
153-
retval = Py_UnwindToken->tempval, \
154-
Py_UnwindToken->tempval = NULL, retval))
155-
156-
#else
157-
158-
#define STACKLESS_PACK(retval) \
159-
(Py_UnwindToken->tempval = (retval), \
160-
(PyObject *) Py_UnwindToken)
161-
162-
#define STACKLESS_UNPACK(retval) \
163-
((void)(retval = Py_UnwindToken->tempval, retval))
164-
165-
#endif
150+
retval = (tstate)->st.unwinding_retval, \
151+
(tstate)->st.unwinding_retval = NULL, retval))
166152

167153
#define STACKLESS_UNWINDING(obj) \
168154
((PyObject *) (obj) == (PyObject *) Py_UnwindToken)
169155

170156
/* an arbitrary positive number */
171157
#define STACKLESS_UNWINDING_MAGIC 0x7fedcba9
172158

173-
#define STACKLESS_RETVAL(obj) \
174-
(STACKLESS_UNWINDING(obj) ? Py_UnwindToken->tempval : (obj))
159+
#define STACKLESS_RETVAL(tstate, obj) \
160+
(STACKLESS_UNWINDING(obj) ? (tstate)->st.unwinding_retval : (obj))
175161

176-
#define STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(obj, val) \
177-
assert(!STACKLESS_UNWINDING(obj) || ((Py_UnwindToken->tempval) != (val)))
162+
#define STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(tstate, obj, val) \
163+
assert(!STACKLESS_UNWINDING(obj) || (((tstate)->st.unwinding_retval) != (val)))
178164

179165
/* macros for setting/resetting the stackless flag */
180166

167+
#define STACKLESS_POSSIBLE() \
168+
(slp_enable_softswitch && \
169+
PyThreadState_GET()->st.unwinding_retval == NULL)
170+
181171
#define STACKLESS_GETARG() int stackless = (stackless = slp_try_stackless, \
182172
slp_try_stackless = 0, stackless)
183173

@@ -199,16 +189,16 @@ PyTaskletObject * slp_get_watchdog(PyThreadState *ts, int interrupt);
199189

200190
#define STACKLESS_PROMOTE_ALL() ((void)(slp_try_stackless = stackless, NULL))
201191

202-
#define STACKLESS_PROPOSE(func) {int stackless = slp_enable_softswitch; \
192+
#define STACKLESS_PROPOSE(func) {int stackless = STACKLESS_POSSIBLE(); \
203193
STACKLESS_PROMOTE(func);}
204194

205-
#define STACKLESS_PROPOSE_FLAG(flag) {int stackless = slp_enable_softswitch; \
195+
#define STACKLESS_PROPOSE_FLAG(flag) {int stackless = STACKLESS_POSSIBLE(); \
206196
STACKLESS_PROMOTE_FLAG(flag);}
207197

208-
#define STACKLESS_PROPOSE_METHOD(obj, meth) {int stackless = slp_enable_softswitch; \
198+
#define STACKLESS_PROPOSE_METHOD(obj, meth) {int stackless = STACKLESS_POSSIBLE(); \
209199
STACKLESS_PROMOTE_METHOD(obj, meth);}
210200

211-
#define STACKLESS_PROPOSE_ALL() slp_try_stackless = slp_enable_softswitch;
201+
#define STACKLESS_PROPOSE_ALL() slp_try_stackless = STACKLESS_POSSIBLE()
212202

213203
#define STACKLESS_RETRACT() slp_try_stackless = 0;
214204

@@ -541,8 +531,8 @@ PyObject * slp_get_channel_callback(void);
541531
#define STACKLESS_RETRACT() assert(1)
542532
#define STACKLESS_ASSERT() assert(1)
543533

544-
#define STACKLESS_RETVAL(obj) (obj)
545-
#define STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(obj, val) assert(1)
534+
#define STACKLESS_RETVAL(tstate, obj) (obj)
535+
#define STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(tstate, obj, val) assert(1)
546536

547537
#define STACKLESS_DECLARE_METHOD(type, meth)
548538

Stackless/core/stackless_tstate.h

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,30 @@ typedef struct _sts {
2424
struct _tasklet *main;
2525
/* runnable tasklets */
2626
struct _tasklet *current;
27-
int runcount;
2827

2928
/* scheduling */
3029
long tick_counter;
3130
long tick_watermark;
3231
long interval;
3332
PyObject * (*interrupt) (void); /* the fast scheduler */
34-
/* trap recursive scheduling via callbacks */
35-
int schedlock;
36-
int runflags; /* flags for stackless.run() behaviour */
3733
#ifdef WITH_THREAD
3834
struct {
3935
PyObject *block_lock; /* to block the thread */
4036
int is_blocked; /* waiting to be unblocked */
4137
int is_idle; /* unblocked, but waiting for GIL */
4238
} thread;
4339
#endif
44-
/* number of nested interpreters (1.0/2.0 merge) */
45-
int nesting_level;
4640
PyObject *del_post_switch; /* To decref after a switch */
4741
PyObject *interrupted; /* The interrupted tasklet in stackles.run() */
48-
int switch_trap; /* if non-zero, switching is forbidden */
4942
PyObject *watchdogs; /* the stack of currently running watchdogs */
43+
PyObject *unwinding_retval; /* The return value during stack unwinding */
44+
int runcount;
45+
/* trap recursive scheduling via callbacks */
46+
int schedlock;
47+
int runflags; /* flags for stackless.run() behaviour */
48+
/* number of nested interpreters (1.0/2.0 merge) */
49+
int nesting_level;
50+
int switch_trap; /* if non-zero, switching is forbidden */
5051
} PyStacklessState;
5152

5253
/* internal macro to temporarily disable soft interrupts */
@@ -59,20 +60,21 @@ typedef struct _sts {
5960
tstate->st.serial_last_jump = 0; \
6061
tstate->st.cstack_base = NULL; \
6162
tstate->st.cstack_root = NULL; \
63+
tstate->st.main = NULL; \
64+
tstate->st.current = NULL; \
6265
tstate->st.tick_counter = 0; \
6366
tstate->st.tick_watermark = 0; \
6467
tstate->st.interval = 0; \
6568
tstate->st.interrupt = NULL; \
66-
tstate->st.schedlock = 0; \
67-
tstate->st.main = NULL; \
68-
tstate->st.current = NULL; \
69+
tstate->st.del_post_switch = NULL; \
70+
tstate->st.interrupted = NULL; \
71+
tstate->st.watchdogs = NULL; \
72+
tstate->st.unwinding_retval = NULL; \
6973
tstate->st.runcount = 0; \
74+
tstate->st.schedlock = 0; \
7075
tstate->st.nesting_level = 0; \
7176
tstate->st.runflags = 0; \
72-
tstate->st.del_post_switch = NULL; \
73-
tstate->st.interrupted = NULL; \
74-
tstate->st.switch_trap = 0; \
75-
tstate->st.watchdogs = NULL;
77+
tstate->st.switch_trap = 0;
7678

7779

7880
/* note that the scheduler knows how to zap. It checks if it is in charge
@@ -89,7 +91,8 @@ void slp_kill_tasks_with_stacks(struct _ts *tstate);
8991
Py_CLEAR(tstate->st.initial_stub); \
9092
Py_CLEAR(tstate->st.del_post_switch); \
9193
Py_CLEAR(tstate->st.interrupted); \
92-
Py_CLEAR(tstate->st.watchdogs);
94+
Py_CLEAR(tstate->st.watchdogs); \
95+
Py_CLEAR(tstate->st.unwinding_retval);
9396

9497
#ifdef WITH_THREAD
9598

Stackless/core/stackless_util.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ slp_return_wrapper(PyObject *retval)
7171
if (retval == NULL)
7272
return -1;
7373
if (STACKLESS_UNWINDING(retval)) {
74-
STACKLESS_UNPACK(retval);
74+
STACKLESS_UNPACK(PyThreadState_GET(), retval);
7575
Py_XDECREF(retval);
7676
return 1;
7777
}

Stackless/core/stacklesseval.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ slp_gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
932932

933933
if (stackless) {
934934
assert(exc == 0);
935-
return STACKLESS_PACK(retval);
935+
return STACKLESS_PACK(ts, retval);
936936
}
937937
return slp_frame_dispatch(f, stopframe, exc, retval);
938938
}
@@ -1046,6 +1046,7 @@ unwind_repr(PyObject *op)
10461046

10471047
/* dummy deallocator, just in case */
10481048
static void unwind_dealloc(PyObject *op) {
1049+
assert(0); /*should never be called*/
10491050
}
10501051

10511052
static PyTypeObject PyUnwindToken_Type = {
@@ -1067,7 +1068,6 @@ static PyTypeObject PyUnwindToken_Type = {
10671068

10681069
static PyUnwindObject unwind_token = {
10691070
PyObject_HEAD_INIT(&PyUnwindToken_Type)
1070-
NULL
10711071
};
10721072

10731073
PyUnwindObject *Py_UnwindToken = &unwind_token;
@@ -1099,7 +1099,7 @@ slp_frame_dispatch(PyFrameObject *f, PyFrameObject *stopframe, int exc, PyObject
10991099
while (1) {
11001100
retval = f->f_execute(f, exc, retval);
11011101
if (STACKLESS_UNWINDING(retval))
1102-
STACKLESS_UNPACK(retval);
1102+
STACKLESS_UNPACK(ts, retval);
11031103
/* A soft switch is only complete here */
11041104
Py_CLEAR(ts->st.del_post_switch);
11051105
f = ts->frame;
@@ -1128,7 +1128,7 @@ slp_frame_dispatch_top(PyObject *retval)
11281128

11291129
retval = f->f_execute(f, 0, retval);
11301130
if (STACKLESS_UNWINDING(retval))
1131-
STACKLESS_UNPACK(retval);
1131+
STACKLESS_UNPACK(ts, retval);
11321132
/* A soft switch is only complete here */
11331133
Py_CLEAR(ts->st.del_post_switch);
11341134
f = ts->frame;

Stackless/module/channelobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ channel_send_sequence(PyChannelObject *self, PyObject *v)
10221022
f->n = 0;
10231023
ts->frame = (PyFrameObject *) f;
10241024
Py_INCREF(Py_None);
1025-
return STACKLESS_PACK(Py_None);
1025+
return STACKLESS_PACK(ts, Py_None);
10261026
error:
10271027
Py_DECREF(it);
10281028
return NULL;

0 commit comments

Comments
 (0)