@@ -749,8 +749,7 @@ free_threadstate(PyThreadState *tstate)
749
749
static void
750
750
init_threadstate (PyThreadState * tstate ,
751
751
PyInterpreterState * interp , uint64_t id ,
752
- PyThreadState * next ,
753
- _PyStackChunk * datastack_chunk )
752
+ PyThreadState * next )
754
753
{
755
754
if (tstate -> _initialized ) {
756
755
Py_FatalError ("thread state already initialized" );
@@ -784,11 +783,9 @@ init_threadstate(PyThreadState *tstate,
784
783
tstate -> exc_info = & tstate -> exc_state ;
785
784
786
785
tstate -> cframe = & tstate -> root_cframe ;
787
- assert (datastack_chunk != NULL );
788
- tstate -> datastack_chunk = datastack_chunk ;
789
- /* If top points to entry 0, then _PyThreadState_PopFrame will try to pop this chunk */
790
- tstate -> datastack_top = & tstate -> datastack_chunk -> data [1 ];
791
- tstate -> datastack_limit = (PyObject * * )(((char * )tstate -> datastack_chunk ) + DATA_STACK_CHUNK_SIZE );
786
+ tstate -> datastack_chunk = NULL ;
787
+ tstate -> datastack_top = NULL ;
788
+ tstate -> datastack_limit = NULL ;
792
789
793
790
tstate -> _initialized = 1 ;
794
791
}
@@ -799,11 +796,6 @@ new_threadstate(PyInterpreterState *interp)
799
796
PyThreadState * tstate ;
800
797
_PyRuntimeState * runtime = interp -> runtime ;
801
798
802
- _PyStackChunk * datastack_chunk = allocate_chunk (DATA_STACK_CHUNK_SIZE , NULL );
803
- if (datastack_chunk == NULL ) {
804
- return NULL ;
805
- }
806
-
807
799
/* We serialize concurrent creation to protect global state. */
808
800
HEAD_LOCK (runtime );
809
801
@@ -833,14 +825,13 @@ new_threadstate(PyInterpreterState *interp)
833
825
}
834
826
interp -> threads .head = tstate ;
835
827
836
- init_threadstate (tstate , interp , id , old_head , datastack_chunk );
828
+ init_threadstate (tstate , interp , id , old_head );
837
829
838
830
HEAD_UNLOCK (runtime );
839
831
return tstate ;
840
832
841
833
error :
842
834
HEAD_UNLOCK (runtime );
843
- _PyObject_VirtualFree (datastack_chunk , datastack_chunk -> size );
844
835
return NULL ;
845
836
}
846
837
@@ -2186,8 +2177,6 @@ _Py_GetConfig(void)
2186
2177
static PyObject * *
2187
2178
push_chunk (PyThreadState * tstate , int size )
2188
2179
{
2189
- assert (tstate -> datastack_top + size >= tstate -> datastack_limit );
2190
-
2191
2180
int allocate_size = DATA_STACK_CHUNK_SIZE ;
2192
2181
while (allocate_size < (int )sizeof (PyObject * )* (size + MINIMUM_OVERHEAD )) {
2193
2182
allocate_size *= 2 ;
@@ -2196,10 +2185,16 @@ push_chunk(PyThreadState *tstate, int size)
2196
2185
if (new == NULL ) {
2197
2186
return NULL ;
2198
2187
}
2199
- tstate -> datastack_chunk -> top = tstate -> datastack_top - & tstate -> datastack_chunk -> data [0 ];
2188
+ if (tstate -> datastack_chunk ) {
2189
+ tstate -> datastack_chunk -> top = tstate -> datastack_top -
2190
+ & tstate -> datastack_chunk -> data [0 ];
2191
+ }
2200
2192
tstate -> datastack_chunk = new ;
2201
2193
tstate -> datastack_limit = (PyObject * * )(((char * )new ) + allocate_size );
2202
- PyObject * * res = & new -> data [0 ];
2194
+ // When new is the "root" chunk (i.e. new->previous == NULL), we can keep
2195
+ // _PyThreadState_PopFrame from freeing it later by "skipping" over the
2196
+ // first element:
2197
+ PyObject * * res = & new -> data [new -> previous == NULL ];
2203
2198
tstate -> datastack_top = res + size ;
2204
2199
return res ;
2205
2200
}
@@ -2212,9 +2207,6 @@ _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size)
2212
2207
PyObject * * top = base + size ;
2213
2208
if (top >= tstate -> datastack_limit ) {
2214
2209
base = push_chunk (tstate , (int )size );
2215
- if (base == NULL ) {
2216
- return NULL ;
2217
- }
2218
2210
}
2219
2211
else {
2220
2212
tstate -> datastack_top = top ;
@@ -2244,16 +2236,20 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFunctionObject *func, PyObject
2244
2236
void
2245
2237
_PyThreadState_PopFrame (PyThreadState * tstate , InterpreterFrame * frame )
2246
2238
{
2239
+ assert (tstate -> datastack_chunk );
2247
2240
PyObject * * base = (PyObject * * )frame ;
2248
2241
if (base == & tstate -> datastack_chunk -> data [0 ]) {
2249
2242
_PyStackChunk * chunk = tstate -> datastack_chunk ;
2250
2243
_PyStackChunk * previous = chunk -> previous ;
2244
+ // push_chunk ensures that the root chunk is never popped:
2245
+ assert (previous );
2251
2246
tstate -> datastack_top = & previous -> data [previous -> top ];
2252
2247
tstate -> datastack_chunk = previous ;
2253
2248
_PyObject_VirtualFree (chunk , chunk -> size );
2254
2249
tstate -> datastack_limit = (PyObject * * )(((char * )previous ) + previous -> size );
2255
2250
}
2256
2251
else {
2252
+ assert (tstate -> datastack_top );
2257
2253
assert (tstate -> datastack_top >= base );
2258
2254
tstate -> datastack_top = base ;
2259
2255
}
0 commit comments