1#ifndef GREENLET_PYTHON_STATE_CPP
2#define GREENLET_PYTHON_STATE_CPP
5#include "TGreenlet.hpp"
9PythonState::PythonState()
11#if GREENLET_USE_CFRAME
16 ,py_recursion_depth(0)
17 ,current_executor(nullptr)
18 ,stackpointer(nullptr)
19 #ifdef Py_GIL_DISABLED
20 ,c_stack_refs(nullptr)
23 ,py_recursion_depth(0)
29 ,delete_later(nullptr)
31 ,trash_delete_nesting(0)
34 ,current_frame(nullptr)
35 ,datastack_chunk(nullptr)
36 ,datastack_top(nullptr)
37 ,datastack_limit(nullptr)
40#if GREENLET_USE_CFRAME
90 this->cframe = &PyThreadState_GET()->root_cframe;
95inline void PythonState::may_switch_away() noexcept
117 GCDisabledGuard no_gc;
118 Py_XDECREF(PyThreadState_GetFrame(PyThreadState_GET()));
122void PythonState::operator<<(
const PyThreadState *
const tstate)
noexcept
124 this->_context.steal(tstate->context);
125#if GREENLET_USE_CFRAME
136 this->cframe = tstate->cframe;
138 this->use_tracing = tstate->cframe->use_tracing;
143 this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
144 this->current_executor = tstate->current_executor;
145 #ifdef Py_GIL_DISABLED
146 this->c_stack_refs = ((_PyThreadStateImpl*)tstate)->c_stack_refs;
149 this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
150 this->c_recursion_depth = Py_C_RECURSION_LIMIT - tstate->c_recursion_remaining;
152 this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
155 this->current_frame = tstate->current_frame;
156 #elif GREENLET_USE_CFRAME
157 this->current_frame = tstate->cframe->current_frame;
159 this->datastack_chunk = tstate->datastack_chunk;
160 this->datastack_top = tstate->datastack_top;
161 this->datastack_limit = tstate->datastack_limit;
163 PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate);
166 this->_top_frame.steal(frame);
168 if (this->top_frame()) {
169 this->stackpointer = this->_top_frame->f_frame->stackpointer;
172 this->stackpointer =
nullptr;
176 this->delete_later = Py_XNewRef(tstate->delete_later);
178 this->trash_delete_nesting = tstate->trash.delete_nesting;
180 this->trash_delete_nesting = tstate->trash_delete_nesting;
183 this->recursion_depth = tstate->recursion_depth;
184 this->_top_frame.steal(tstate->frame);
185 this->trash_delete_nesting = tstate->trash_delete_nesting;
190void GREENLET_NOINLINE(PythonState::unexpose_frames)()
192 if (!this->top_frame()) {
198 _PyInterpreterFrame *iframe = this->_top_frame->f_frame;
199 while (iframe !=
nullptr) {
200 _PyInterpreterFrame *prev_exposed = iframe->previous;
201 assert(iframe->frame_obj);
202 memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0],
204 iframe = prev_exposed;
208void PythonState::unexpose_frames()
212void PythonState::operator>>(PyThreadState *
const tstate)
noexcept
214 tstate->context = this->_context.relinquish_ownership();
217 tstate->context_ver++;
218#if GREENLET_USE_CFRAME
219 tstate->cframe = this->cframe;
227 tstate->cframe->use_tracing = this->use_tracing;
232 tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth;
233 tstate->current_executor = this->current_executor;
234 #ifdef Py_GIL_DISABLED
235 ((_PyThreadStateImpl*)tstate)->c_stack_refs = this->c_stack_refs;
237 this->unexpose_frames();
239 tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth;
240 tstate->c_recursion_remaining = Py_C_RECURSION_LIMIT - this->c_recursion_depth;
241 this->unexpose_frames();
243 tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;
246 tstate->current_frame = this->current_frame;
247 #elif GREENLET_USE_CFRAME
248 tstate->cframe->current_frame = this->current_frame;
250 tstate->datastack_chunk = this->datastack_chunk;
251 tstate->datastack_top = this->datastack_top;
252 tstate->datastack_limit = this->datastack_limit;
253#if GREENLET_PY314 && defined(Py_GIL_DISABLED)
254 if (this->top_frame()) {
255 this->_top_frame->f_frame->stackpointer = this->stackpointer;
258 this->_top_frame.relinquish_ownership();
260 Py_XDECREF(tstate->delete_later);
261 tstate->delete_later = this->delete_later;
262 Py_CLEAR(this->delete_later);
264 tstate->trash.delete_nesting = this->trash_delete_nesting;
266 tstate->trash_delete_nesting = this->trash_delete_nesting;
269 tstate->frame = this->_top_frame.relinquish_ownership();
270 tstate->recursion_depth = this->recursion_depth;
271 tstate->trash_delete_nesting = this->trash_delete_nesting;
275inline void PythonState::will_switch_from(PyThreadState *
const origin_tstate)
noexcept
277#if GREENLET_USE_CFRAME && !GREENLET_PY312
282 this->use_tracing = origin_tstate->cframe->use_tracing;
286void PythonState::set_initial_state(
const PyThreadState*
const tstate)
noexcept
288 this->_top_frame =
nullptr;
290 this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
291 this->current_executor = tstate->current_executor;
293 this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
298 this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
300 this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
302 this->recursion_depth = tstate->recursion_depth;
306int PythonState::tp_traverse(visitproc visit,
void* arg,
bool own_top_frame)
noexcept
308 Py_VISIT(this->_context.borrow());
310 Py_VISIT(this->_top_frame.borrow());
325void PythonState::tp_clear(
bool own_top_frame)
noexcept
327 PythonStateContext::tp_clear();
332 this->_top_frame.CLEAR();
336#if GREENLET_USE_CFRAME
337void PythonState::set_new_cframe(_PyCFrame& frame)
noexcept
339 frame = *PyThreadState_GET()->cframe;
341 this->cframe = &frame;
346 this->cframe->previous = &PyThreadState_GET()->root_cframe;
350const PythonState::OwnedFrame& PythonState::top_frame() const noexcept
352 return this->_top_frame;
355void PythonState::did_finish(PyThreadState* tstate)
noexcept
392 PyObjectArenaAllocator alloc;
393 _PyStackChunk* chunk =
nullptr;
396 chunk = tstate->datastack_chunk;
403 PyObject_GetArenaAllocator(&alloc);
404 tstate->datastack_chunk =
nullptr;
405 tstate->datastack_limit =
nullptr;
406 tstate->datastack_top =
nullptr;
409 else if (this->datastack_chunk) {
416 chunk = this->datastack_chunk;
417 PyObject_GetArenaAllocator(&alloc);
420 if (alloc.free && chunk) {
423 _PyStackChunk *prev = chunk->previous;
424 chunk->previous =
nullptr;
425 alloc.free(alloc.ctx, chunk, chunk->size);
430 this->datastack_chunk =
nullptr;
431 this->datastack_limit =
nullptr;
432 this->datastack_top =
nullptr;