9#define PY_SSIZE_T_CLEAN
11#include "structmember.h"
13#include "greenlet_internal.hpp"
14#include "TThreadStateDestroy.cpp"
15#include "TGreenlet.hpp"
21#include "greenlet_refs.hpp"
22#include "greenlet_slp_switch.hpp"
24#include "greenlet_thread_support.hpp"
25#include "TGreenlet.hpp"
27#include "TGreenletGlobals.cpp"
28#include "TThreadStateDestroy.cpp"
29#include "PyGreenlet.hpp"
36using greenlet::LockGuard;
39using greenlet::Require;
41using greenlet::g_handle_exit;
42using greenlet::single_result;
54green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds))
57 (
PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict);
63 assert(Py_REFCNT(o) == 1);
67 assert(c == o->pimpl);
79green_init(
PyGreenlet* self, PyObject* args, PyObject* kwargs)
83 static const char* kwlist[] = {
90 if (!PyArg_ParseTupleAndKeywords(
91 args, kwargs,
"|OO:green", (
char**)kwlist, &run, &nparent)) {
96 if (green_setrun(self, run, NULL)) {
100 if (nparent && !nparent.is_None()) {
101 return green_setparent(self, nparent, NULL);
109green_traverse(
PyGreenlet* self, visitproc visit,
void* arg)
129 Py_VISIT(self->dict);
138 return self->pimpl->tp_traverse(visit, arg);
142green_is_gc(PyObject* _self)
144 BorrowedGreenlet self(_self);
151 if (self->main() || !self->active()) {
155 if (self->was_running_in_dead_thread()) {
182 Py_CLEAR(self->dict);
183 return self->pimpl->tp_clear();
190_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self)
194 assert(self.REFCNT() == 0);
195 Py_SET_REFCNT(self.borrow(), 1);
205 self->deallocing_greenlet_in_thread(
211 PyErr_WriteUnraisable(self.borrow_o());
218 if (self.REFCNT() == 1 && self->active()) {
221 PyObject* f = PySys_GetObject(
"stderr");
222 Py_INCREF(self.borrow_o());
224 PyFile_WriteString(
"GreenletExit did not kill ", f);
225 PyFile_WriteObject(self.borrow_o(), f, 0);
226 PyFile_WriteString(
"\n", f);
230 saved_err.PyErrRestore();
234 assert(self.REFCNT() > 0);
236 Py_ssize_t refcnt = self.REFCNT() - 1;
237 Py_SET_REFCNT(self.borrow_o(), refcnt);
240 _Py_NewReference(self.borrow_o());
241 Py_SET_REFCNT(self.borrow_o(), refcnt);
259 if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) {
260 Py_INCREF(self.TYPE());
263 PyObject_GC_Track((PyObject*)self);
265 GREENLET_Py_DEC_REFTOTAL;
267 --Py_TYPE(self)->tp_frees;
268 --Py_TYPE(self)->tp_allocs;
279 PyObject_GC_UnTrack(self);
280 BorrowedGreenlet me(self);
284 if (!_green_dealloc_kill_started_non_main_greenlet(me)) {
289 if (self->weakreflist != NULL) {
290 PyObject_ClearWeakRefs((PyObject*)self);
292 Py_CLEAR(self->dict);
299 self->pimpl =
nullptr;
303 Py_TYPE(self)->tp_free((PyObject*)self);
309internal_green_throw(BorrowedGreenlet self,
PyErrPieces& err_pieces)
311 PyObject* result =
nullptr;
312 err_pieces.PyErrRestore();
313 assert(PyErr_Occurred());
314 if (self->started() && !self->active()) {
316 result = g_handle_exit(OwnedObject()).relinquish_ownership();
318 self->args() <<= result;
320 return single_result(self->g_switch());
327 "switch(*args, **kwargs)\n"
329 "Switch execution to this greenlet.\n"
331 "If this greenlet has never been run, then this greenlet\n"
332 "will be switched to using the body of ``self.run(*args, **kwargs)``.\n"
334 "If the greenlet is active (has been run, but was switch()'ed\n"
335 "out before leaving its run function), then this greenlet will\n"
336 "be resumed and the return value to its switch call will be\n"
337 "None if no arguments are given, the given argument if one\n"
338 "argument is given, or the args tuple and keyword args dict if\n"
339 "multiple arguments are given.\n"
341 "If the greenlet is dead, or is the current greenlet then this\n"
342 "function will simply return the arguments using the same rules as\n"
346green_switch(
PyGreenlet* self, PyObject* args, PyObject* kwargs)
349 SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs));
350 self->pimpl->may_switch_away();
351 self->pimpl->args() <<= switch_args;
374 OwnedObject result(single_result(self->pimpl->g_switch()));
378 assert(!self->pimpl->args());
380 const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current();
382 assert(!current->args());
384 PyObject* p = result.relinquish_ownership();
386 if (!p && !PyErr_Occurred()) {
396 assert(p || PyErr_Occurred());
398 mod_globs->PyExc_GreenletError,
399 "Greenlet.switch() returned NULL without an exception set."
411 "Switches execution to this greenlet, but immediately raises the\n"
412 "given exception in this greenlet. If no argument is provided, the "
414 "defaults to `greenlet.GreenletExit`. The normal exception\n"
415 "propagation rules apply, as described for `switch`. Note that calling "
417 "method is almost equivalent to the following::\n"
420 " raise typ, val, tb\n"
421 " g_raiser = greenlet(raiser, parent=g)\n"
422 " g_raiser.switch()\n"
424 "except that this trick does not work for the\n"
425 "`greenlet.GreenletExit` exception, which would not propagate\n"
426 "from ``g_raiser`` to ``g``.\n");
435 if (!PyArg_ParseTuple(args,
"|OOO:throw", &typ, &val, &tb)) {
439 assert(typ.borrow() || val.borrow());
441 self->pimpl->may_switch_away();
445 PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow());
447 return internal_green_throw(self, err_pieces).relinquish_ownership();
457 return self->pimpl->active();
464green_getdict(
PyGreenlet* self,
void* UNUSED(context))
466 if (self->dict == NULL) {
467 self->dict = PyDict_New();
468 if (self->dict == NULL) {
472 Py_INCREF(self->dict);
477green_setdict(
PyGreenlet* self, PyObject* val,
void* UNUSED(context))
482 PyErr_SetString(PyExc_TypeError,
"__dict__ may not be deleted");
485 if (!PyDict_Check(val)) {
486 PyErr_SetString(PyExc_TypeError,
"__dict__ must be a dictionary");
497_green_not_dead(BorrowedGreenlet self)
501 if (self->was_running_in_dead_thread()) {
502 self->deactivate_and_free();
505 return self->active() || !self->started();
510green_getdead(
PyGreenlet* self,
void* UNUSED(context))
512 if (_green_not_dead(self)) {
521green_get_stack_saved(
PyGreenlet* self,
void* UNUSED(context))
523 return PyLong_FromSsize_t(self->pimpl->stack_saved());
528green_getrun(
PyGreenlet* self,
void* UNUSED(context))
531 OwnedObject result(BorrowedGreenlet(self)->run());
532 return result.relinquish_ownership();
541green_setrun(
PyGreenlet* self, PyObject* nrun,
void* UNUSED(context))
544 BorrowedGreenlet(self)->run(nrun);
553green_getparent(
PyGreenlet* self,
void* UNUSED(context))
555 return BorrowedGreenlet(self)->parent().acquire_or_None();
560green_setparent(
PyGreenlet* self, PyObject* nparent,
void* UNUSED(context))
563 BorrowedGreenlet(self)->parent(nparent);
573green_getcontext(
const PyGreenlet* self,
void* UNUSED(context))
575 const Greenlet *
const g = self->pimpl;
577 OwnedObject result(g->context());
578 return result.relinquish_ownership();
586green_setcontext(
PyGreenlet* self, PyObject* nctx,
void* UNUSED(context))
589 BorrowedGreenlet(self)->context(nctx);
599green_getframe(
PyGreenlet* self,
void* UNUSED(context))
601 const PythonState::OwnedFrame& top_frame = BorrowedGreenlet(self)->top_frame();
602 return top_frame.acquire_or_None();
609 PyErr_Format(PyExc_TypeError,
610 "cannot serialize '%s' object",
611 Py_TYPE(self)->tp_name);
618 BorrowedGreenlet self(_self);
628 int never_started = !self->started() && !self->active();
630 const char*
const tp_name = Py_TYPE(self)->tp_name;
632 if (_green_not_dead(self)) {
640 const char* state_in_thread;
641 if (self->was_running_in_dead_thread()) {
647 state_in_thread =
" (thread exited)";
650 state_in_thread = GET_THREAD_STATE().state().is_current(self)
652 : (self->started() ?
" suspended" :
"");
654 result = PyUnicode_FromFormat(
655 "<%s object at %p (otid=%p)%s%s%s%s>",
658 self->thread_state(),
660 self->active() ?
" active" :
"",
661 never_started ?
" pending" :
" started",
662 self->main() ?
" main" :
""
666 result = PyUnicode_FromFormat(
667 "<%s object at %p (otid=%p) %sdead>",
670 self->thread_state(),
671 self->was_running_in_dead_thread()
681static PyMethodDef green_methods[] = {
684 .ml_meth=
reinterpret_cast<PyCFunction
>(green_switch),
685 .ml_flags=METH_VARARGS | METH_KEYWORDS,
686 .ml_doc=green_switch_doc
688 {.ml_name=
"throw", .ml_meth=(PyCFunction)green_throw, .ml_flags=METH_VARARGS, .ml_doc=green_throw_doc},
689 {.ml_name=
"__getstate__", .ml_meth=(PyCFunction)green_getstate, .ml_flags=METH_NOARGS, .ml_doc=NULL},
690 {.ml_name=NULL, .ml_meth=NULL}
693static PyGetSetDef green_getsets[] = {
695 {.name=
"__dict__", .get=(getter)green_getdict, .set=(setter)green_setdict},
696 {.name=
"run", .get=(getter)green_getrun, .set=(setter)green_setrun},
697 {.name=
"parent", .get=(getter)green_getparent, .set=(setter)green_setparent},
698 {.name=
"gr_frame", .get=(getter)green_getframe },
701 .get=(getter)green_getcontext,
702 .set=(setter)green_setcontext
704 {.name=
"dead", .get=(getter)green_getdead},
705 {.name=
"_stack_saved", .get=(getter)green_get_stack_saved},
709static PyMemberDef green_members[] = {
713static PyNumberMethods green_as_number = {
714 .nb_bool=(inquiry)green_bool,
718PyTypeObject PyGreenlet_Type = {
719 .ob_base=PyVarObject_HEAD_INIT(NULL, 0)
720 .tp_name=
"greenlet.greenlet",
723 .tp_dealloc=(destructor)green_dealloc,
724 .tp_repr=(reprfunc)green_repr,
725 .tp_as_number=&green_as_number,
726 .tp_flags=G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
727 .tp_doc=
"greenlet(run=None, parent=None) -> greenlet\n\n"
728 "Creates a new greenlet object (without running it).\n\n"
729 " - *run* -- The callable to invoke.\n"
730 " - *parent* -- The parent greenlet. The default is the current "
732 .tp_traverse=(traverseproc)green_traverse,
733 .tp_clear=(inquiry)green_clear,
734 .tp_weaklistoffset=offsetof(
PyGreenlet, weakreflist),
736 .tp_methods=green_methods,
737 .tp_members=green_members,
738 .tp_getset=green_getsets,
740 .tp_init=(initproc)green_init,
741 .tp_alloc=PyType_GenericAlloc,
742 .tp_new=(newfunc)green_new,
743 .tp_free=PyObject_GC_Del,
744#ifndef Py_GIL_DISABLED
766 .tp_is_gc=(inquiry)green_is_gc,
Definition TGreenlet.hpp:731
Definition TGreenlet.hpp:343
Definition greenlet_thread_support.hpp:23
Definition TGreenlet.hpp:752
Definition greenlet_exceptions.hpp:17
Definition TGreenlet.hpp:105
Definition TGreenlet.hpp:242
Definition TThreadState.hpp:87
Definition TGreenlet.hpp:675
Definition greenlet_refs.hpp:1102
Definition greenlet_refs.hpp:995