Skip to content

Commit 3acd739

Browse files
author
Anselm Kruis
committed
merge 3.3-slp (Stackless python#119)
2 parents 542af6e + 2b3df1e commit 3acd739

File tree

12 files changed

+181
-80
lines changed

12 files changed

+181
-80
lines changed

Objects/abstract.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,14 +2054,14 @@ PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw)
20542054
#endif
20552055
Py_LeaveRecursiveCall();
20562056
#ifdef NDEBUG
2057-
if (STACKLESS_RETVAL(result) == NULL && !PyErr_Occurred()) {
2057+
if (STACKLESS_RETVAL(PyThreadState_GET(), result) == NULL && !PyErr_Occurred()) {
20582058
PyErr_SetString(
20592059
PyExc_SystemError,
20602060
"NULL result without error in PyObject_Call");
20612061
}
20622062
#else
2063-
assert((STACKLESS_RETVAL(result) != NULL && !PyErr_Occurred())
2064-
|| (STACKLESS_RETVAL(result) == NULL && PyErr_Occurred()));
2063+
assert((STACKLESS_RETVAL(PyThreadState_GET(), result) != NULL && !PyErr_Occurred())
2064+
|| (STACKLESS_RETVAL(PyThreadState_GET(), result) == NULL && PyErr_Occurred()));
20652065
#endif
20662066
return result;
20672067
}
@@ -2681,7 +2681,7 @@ PyIter_Next(PyObject *iter)
26812681
STACKLESS_PROMOTE_METHOD(iter, tp_iternext);
26822682
result = (*iter->ob_type->tp_iternext)(iter);
26832683
STACKLESS_ASSERT();
2684-
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(result, NULL);
2684+
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(PyThreadState_GET(), result, NULL);
26852685
if (result == NULL &&
26862686
PyErr_Occurred() &&
26872687
PyErr_ExceptionMatches(PyExc_StopIteration))

Objects/typeobject.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5460,7 +5460,7 @@ wrap_next(PyObject *self, PyObject *args, void *wrapped)
54605460
STACKLESS_PROMOTE_ALL();
54615461
res = (*func)(self);
54625462
STACKLESS_ASSERT();
5463-
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(res, NULL);
5463+
STACKLESS_ASSERT_UNWINDING_VALUE_IS_NOT(PyThreadState_GET(), res, NULL);
54645464
if (res == NULL && !PyErr_Occurred())
54655465
PyErr_SetNone(PyExc_StopIteration);
54665466
return res;
@@ -6335,7 +6335,7 @@ slp_tp_init_callback(PyFrameObject *f, int exc, PyObject *retval)
63356335
}
63366336
ts->frame = f;
63376337
Py_DECREF(cf);
6338-
return STACKLESS_PACK(retval);
6338+
return STACKLESS_PACK(ts, retval);
63396339
}
63406340
#endif
63416341

@@ -6366,7 +6366,7 @@ slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds)
63666366
#ifdef STACKLESS
63676367
if (stackless && !STACKLESS_UNWINDING(res)) {
63686368
/* required, because added a C-frame */
6369-
STACKLESS_PACK(res);
6369+
STACKLESS_PACK(PyThreadState_GET(), res);
63706370
return STACKLESS_UNWINDING_MAGIC;
63716371
}
63726372
if (STACKLESS_UNWINDING(res)) {

Python/ceval.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3838,8 +3838,8 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
38383838
if (why != WHY_RETURN)
38393839
retval = NULL;
38403840

3841-
assert((STACKLESS_RETVAL(retval) != NULL && !PyErr_Occurred())
3842-
|| (STACKLESS_RETVAL(retval) == NULL && PyErr_Occurred()));
3841+
assert((STACKLESS_RETVAL(tstate, retval) != NULL && !PyErr_Occurred())
3842+
|| (STACKLESS_RETVAL(tstate, retval) == NULL && PyErr_Occurred()));
38433843

38443844
fast_yield:
38453845
if (co->co_flags & CO_GENERATOR) {
@@ -3936,7 +3936,7 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
39363936
f->f_lasti = INSTR_OFFSET() - 1;
39373937
if (tstate->frame->f_back != f)
39383938
return retval;
3939-
STACKLESS_UNPACK(retval);
3939+
STACKLESS_UNPACK(tstate, retval);
39403940
retval = tstate->frame->f_execute(tstate->frame, 0, retval);
39413941
if (tstate->frame != f) {
39423942
assert(f->f_execute == slp_eval_frame_value || f->f_execute == slp_eval_frame_noval ||
@@ -3946,7 +3946,7 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
39463946
return retval;
39473947
}
39483948
if (STACKLESS_UNWINDING(retval))
3949-
STACKLESS_UNPACK(retval);
3949+
STACKLESS_UNPACK(tstate, retval);
39503950

39513951
f->f_stacktop = NULL;
39523952
if (f->f_execute == slp_eval_frame_iter) {
@@ -4340,7 +4340,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
43404340
retval = Py_None;
43414341
if (stackless) {
43424342
tstate->frame = f;
4343-
return STACKLESS_PACK(retval);
4343+
return STACKLESS_PACK(tstate, retval);
43444344
}
43454345
else {
43464346
if (f->f_back != NULL)
@@ -4896,8 +4896,8 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
48964896
STACKLESS_ASSERT();
48974897
Py_DECREF(arg);
48984898

4899-
assert((STACKLESS_RETVAL(result) != NULL && !PyErr_Occurred())
4900-
|| (STACKLESS_RETVAL(result) == NULL && PyErr_Occurred()));
4899+
assert((STACKLESS_RETVAL(PyThreadState_GET(), result) != NULL && !PyErr_Occurred())
4900+
|| (STACKLESS_RETVAL(PyThreadState_GET(), result) == NULL && PyErr_Occurred()));
49014901
return result;
49024902
}
49034903

@@ -5052,8 +5052,8 @@ call_function(PyObject ***pp_stack, int oparg
50525052
READ_TIMESTAMP(*pintr1);
50535053
Py_DECREF(func);
50545054
}
5055-
assert((STACKLESS_RETVAL(x) != NULL && !PyErr_Occurred())
5056-
|| (STACKLESS_RETVAL(x) == NULL && PyErr_Occurred()));
5055+
assert((STACKLESS_RETVAL(PyThreadState_GET(), x) != NULL && !PyErr_Occurred())
5056+
|| (STACKLESS_RETVAL(PyThreadState_GET(), x) == NULL && PyErr_Occurred()));
50575057

50585058
/* Clear the stack of the function object. Also removes
50595059
the arguments in case they weren't consumed already
@@ -5065,8 +5065,8 @@ call_function(PyObject ***pp_stack, int oparg
50655065
PCALL(PCALL_POP);
50665066
}
50675067

5068-
assert((STACKLESS_RETVAL(x) != NULL && !PyErr_Occurred())
5069-
|| (STACKLESS_RETVAL(x) == NULL && PyErr_Occurred()));
5068+
assert((STACKLESS_RETVAL(PyThreadState_GET(), x) != NULL && !PyErr_Occurred())
5069+
|| (STACKLESS_RETVAL(PyThreadState_GET(), x) == NULL && PyErr_Occurred()));
50705070
return x;
50715071
}
50725072

@@ -5120,11 +5120,11 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
51205120
}
51215121
#ifdef STACKLESS
51225122
f->f_execute = PyEval_EvalFrameEx_slp;
5123-
if (slp_enable_softswitch) {
5123+
if (STACKLESS_POSSIBLE()) {
51245124
Py_INCREF(Py_None);
51255125
retval = Py_None;
51265126
tstate->frame = f;
5127-
return STACKLESS_PACK(retval);
5127+
return STACKLESS_PACK(tstate, retval);
51285128
}
51295129
return slp_eval_frame(f);
51305130
#else
@@ -5366,8 +5366,8 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
53665366
Py_XDECREF(callargs);
53675367
Py_XDECREF(kwdict);
53685368
Py_XDECREF(stararg);
5369-
assert((STACKLESS_RETVAL(result) != NULL && !PyErr_Occurred())
5370-
|| (STACKLESS_RETVAL(result) == NULL && PyErr_Occurred()));
5369+
assert((STACKLESS_RETVAL(PyThreadState_GET(), result) != NULL && !PyErr_Occurred())
5370+
|| (STACKLESS_RETVAL(PyThreadState_GET(), result) == NULL && PyErr_Occurred()));
53715371
return result;
53725372
}
53735373

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
}
@@ -1021,6 +1021,7 @@ unwind_repr(PyObject *op)
10211021

10221022
/* dummy deallocator, just in case */
10231023
static void unwind_dealloc(PyObject *op) {
1024+
assert(0); /*should never be called*/
10241025
}
10251026

10261027
static PyTypeObject PyUnwindToken_Type = {
@@ -1042,7 +1043,6 @@ static PyTypeObject PyUnwindToken_Type = {
10421043

10431044
static PyUnwindObject unwind_token = {
10441045
PyObject_HEAD_INIT(&PyUnwindToken_Type)
1045-
NULL
10461046
};
10471047

10481048
PyUnwindObject *Py_UnwindToken = &unwind_token;
@@ -1074,7 +1074,7 @@ slp_frame_dispatch(PyFrameObject *f, PyFrameObject *stopframe, int exc, PyObject
10741074
while (1) {
10751075
retval = f->f_execute(f, exc, retval);
10761076
if (STACKLESS_UNWINDING(retval))
1077-
STACKLESS_UNPACK(retval);
1077+
STACKLESS_UNPACK(ts, retval);
10781078
/* A soft switch is only complete here */
10791079
Py_CLEAR(ts->st.del_post_switch);
10801080
f = ts->frame;
@@ -1103,7 +1103,7 @@ slp_frame_dispatch_top(PyObject *retval)
11031103

11041104
retval = f->f_execute(f, 0, retval);
11051105
if (STACKLESS_UNWINDING(retval))
1106-
STACKLESS_UNPACK(retval);
1106+
STACKLESS_UNPACK(ts, retval);
11071107
/* A soft switch is only complete here */
11081108
Py_CLEAR(ts->st.del_post_switch);
11091109
f = ts->frame;

0 commit comments

Comments
 (0)