14#include "greenlet_internal.hpp"
15#include "TGreenlet.hpp"
18#include "TGreenletGlobals.cpp"
19#include "TThreadStateDestroy.cpp"
24 : Greenlet(p, StackState())
28Greenlet::Greenlet(
PyGreenlet* p,
const StackState& initial_stack)
29 : _self(p), stack_state(initial_stack)
31 assert(p->pimpl ==
nullptr);
40 this->_self->pimpl =
nullptr;
44Greenlet::force_slp_switch_error() const noexcept
50Greenlet::release_args()
52 this->switch_args.CLEAR();
60Greenlet::throw_GreenletExit_during_dealloc(
const ThreadState& UNUSED(current_thread_state))
65 PyErr_SetString(mod_globs->PyExc_GreenletExit,
66 "Killing the greenlet because all references have vanished.");
68 return this->g_switch();
72Greenlet::slp_restore_state() noexcept
74#ifdef SLP_BEFORE_RESTORE_STATE
75 SLP_BEFORE_RESTORE_STATE();
77 this->stack_state.copy_heap_to_stack(
78 this->thread_state()->borrow_current()->stack_state);
83Greenlet::slp_save_state(
char *
const stackref)
noexcept
89#ifdef SLP_BEFORE_SAVE_STATE
90 SLP_BEFORE_SAVE_STATE();
92 return this->stack_state.copy_stack_to_heap(stackref,
93 this->thread_state()->borrow_current()->stack_state);
101Greenlet::on_switchstack_or_initialstub_failure(
104 const bool target_was_me,
105 const bool was_initial_stub)
110 if (!PyErr_Occurred()) {
114 ?
"Failed to switch stacks into a greenlet for the first time."
115 :
"Failed to switch stacks into a running greenlet.");
117 this->release_args();
119 if (target && !target_was_me) {
120 target->murder_in_place();
123 assert(!err.the_new_current_greenlet);
124 assert(!err.origin_greenlet);
125 return OwnedObject();
130Greenlet::g_switchstack_success() noexcept
132 PyThreadState* tstate = PyThreadState_GET();
134 this->python_state >> tstate;
135 this->exception_state >> tstate;
140 thread_state->set_current(this->self());
145Greenlet::switchstack_result_t
146Greenlet::g_switchstack(
void)
156 assert(this->args() || PyErr_Occurred());
158 if (this->thread_state()->is_current(this->self())) {
163 this, this->thread_state()->borrow_current());
165 BorrowedGreenlet current = this->thread_state()->
borrow_current();
166 PyThreadState* tstate = PyThreadState_GET();
168 current->python_state << tstate;
169 current->exception_state << tstate;
170 this->python_state.will_switch_from(tstate);
171 switching_thread_state =
this;
172 current->expose_frames();
174 assert(this->args() || PyErr_Occurred());
179 if (this->force_slp_switch_error()) {
196 Py_FatalError(
"greenlet: Failed low-level slp_switch(). The stack is probably corrupt.");
203 Greenlet* greenlet_that_switched_in = switching_thread_state;
204 switching_thread_state =
nullptr;
211 OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success();
212 assert(greenlet_that_switched_in->args() || PyErr_Occurred());
218Greenlet::check_switch_allowed()
const
239 if (!main_greenlet) {
241 "cannot switch to a garbage collected greenlet");
244 if (!main_greenlet->thread_state()) {
245 throw PyErrOccurred(mod_globs->PyExc_GreenletError,
246 "cannot switch to a different thread (which happens to have exited)");
258 const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet();
261 current_main_greenlet != main_greenlet
264 this->main_greenlet()
267 && current_main_greenlet != main_greenlet)
271 || (!current_main_greenlet->thread_state())) {
275 mod_globs->PyExc_GreenletError,
276 "Cannot switch to a different thread\n\tCurrent: %R\n\tExpected: %R",
277 current_main_greenlet, main_greenlet);
282Greenlet::context()
const
287 if (this->is_currently_running_in_some_thread()) {
290 if (GET_THREAD_STATE().state().is_current(this->self())) {
291 result = PythonStateContext::context(PyThreadState_GET());
295 "cannot get context of a "
296 "greenlet that is running in a different thread");
301 result = this->python_state.context();
304 result = OwnedObject::None();
311Greenlet::context(BorrowedObject given)
315 throw AttributeError(
"can't delete context attribute");
317 if (given.is_None()) {
324 PyThreadState* tstate = PyThreadState_GET();
326 if (this->is_currently_running_in_some_thread()) {
327 if (!GET_THREAD_STATE().state().is_current(this->self())) {
328 throw ValueError(
"cannot set context of a greenlet"
329 " that is running in a different thread");
334 OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate));
335 PythonStateContext::context(tstate, context.relinquish_ownership());
340 this->python_state.context() = context;
365 OwnedObject args = rhs.args();
366 OwnedObject kwargs = rhs.kwargs();
369 assert(args || kwargs);
375 else if (!PyDict_Size(kwargs.borrow())) {
378 else if (!PySequence_Length(args.borrow())) {
384 lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow()));
390g_handle_exit(
const OwnedObject& greenlet_result)
392 if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) {
397 return OwnedObject::None();
399 return OwnedObject(val);
402 if (greenlet_result) {
407 return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow()));
410 return OwnedObject();
419Greenlet::g_switch_finish(
const switchstack_result_t& err)
421 assert(err.the_new_current_greenlet ==
this);
423 ThreadState& state = *this->thread_state();
430 result <<= this->args();
433 assert(PyErr_Occurred());
435 assert(!this->args());
438 assert(err.status >= 0);
439 assert(state.borrow_current() == this->self());
440 if (OwnedObject tracefunc = state.get_tracefunc()) {
441 assert(result || PyErr_Occurred());
442 g_calltrace(tracefunc,
443 result ? mod_globs->event_switch : mod_globs->event_throw,
451 if (PyErr_Occurred()) {
457 throw PyErrOccurred::from_current();
461 catch (
const PyErrOccurred&) {
464 this->release_args();
470Greenlet::g_calltrace(
const OwnedObject& tracefunc,
472 const BorrowedGreenlet& origin,
473 const BorrowedGreenlet& target)
477 TracingGuard tracing_guard;
481 tracing_guard.CallTraceFunction(tracefunc, event, origin, target);
483 catch (
const PyErrOccurred&) {
487 GET_THREAD_STATE().state().set_tracefunc(Py_None);
491 saved_exc.PyErrRestore();
493 (event == mod_globs->event_throw && PyErr_Occurred())
494 || (event == mod_globs->event_switch && !PyErr_Occurred())
499Greenlet::murder_in_place()
501 if (this->active()) {
502 assert(!this->is_currently_running_in_some_thread());
503 this->deactivate_and_free();
508Greenlet::deactivate_and_free()
510 if (!this->active()) {
515 assert(!this->stack_state.active());
527 this->python_state.tp_clear(
true);
531Greenlet::belongs_to_thread(
const ThreadState* thread_state)
const
533 if (!this->thread_state()
543Greenlet::deallocing_greenlet_in_thread(
const ThreadState* current_thread_state)
547 if (this->belongs_to_thread(current_thread_state)) {
548 assert(current_thread_state);
554 this->throw_GreenletExit_during_dealloc(*current_thread_state);
566 ThreadState *
const thread_state = this->thread_state();
568 thread_state->delete_when_thread_running(this->self());
574 this->deactivate_and_free();
581Greenlet::tp_traverse(visitproc visit,
void* arg)
585 if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) {
590 bool visit_top_frame = this->was_running_in_dead_thread();
594 if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) {
603 bool own_top_frame = this->was_running_in_dead_thread();
604 this->exception_state.tp_clear();
605 this->python_state.tp_clear(own_top_frame);
609bool Greenlet::is_currently_running_in_some_thread()
const
611 return this->stack_state.active() && !this->python_state.top_frame();
615void GREENLET_NOINLINE(Greenlet::expose_frames)()
617 if (!this->python_state.top_frame()) {
621 _PyInterpreterFrame* last_complete_iframe =
nullptr;
622 _PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame;
627 _PyInterpreterFrame iframe_copy;
628 this->stack_state.copy_from_stack(&iframe_copy, iframe,
sizeof(*iframe));
629 if (!_PyFrame_IsIncomplete(&iframe_copy)) {
636 assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK);
655 if (!iframe->frame_obj) {
656 PyFrameObject dummy_frame;
657 _PyInterpreterFrame dummy_iframe;
658 dummy_frame.f_back =
nullptr;
659 dummy_frame.f_frame = &dummy_iframe;
662 dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR;
663 dummy_iframe.previous = iframe;
664 assert(!_PyFrame_IsIncomplete(&dummy_iframe));
667 Py_XDECREF(PyFrame_GetBack(&dummy_frame));
668 assert(iframe->frame_obj);
683 assert(iframe->owner == FRAME_OWNED_BY_THREAD
684 || iframe->owner == FRAME_OWNED_BY_GENERATOR);
685 if (last_complete_iframe) {
686 assert(last_complete_iframe->frame_obj);
687 memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
688 &last_complete_iframe->previous,
sizeof(
void *));
689 last_complete_iframe->previous = iframe;
691 last_complete_iframe = iframe;
698 iframe = iframe_copy.previous;
704 if (last_complete_iframe) {
705 assert(last_complete_iframe->frame_obj);
706 memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
707 &last_complete_iframe->previous,
sizeof(
void *));
708 last_complete_iframe->previous =
nullptr;
712void Greenlet::expose_frames()
Definition TGreenlet.hpp:343
Definition greenlet_exceptions.hpp:17
Definition TGreenlet.hpp:72
Definition TGreenlet.hpp:185
Definition TGreenlet.hpp:242
Definition TThreadState.hpp:87
OwnedGreenlet get_current()
Definition TThreadState.hpp:233
BorrowedGreenlet borrow_current()
Definition TThreadState.hpp:246
Definition greenlet_refs.hpp:600
Definition greenlet_refs.hpp:686
Definition greenlet_refs.hpp:925
Definition greenlet_refs.hpp:995
OwnedObject & operator<<=(OwnedObject &lhs, greenlet::SwitchingArgs &rhs) noexcept
Definition TGreenlet.cpp:359
Definition TGreenlet.hpp:513