codekingpro/portable-devtools
115k
1/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
2#ifndef PYGREENLET_CPP
3#define PYGREENLET_CPP
4/*****************
5The Python slot functions for TGreenlet.
6 */
7
8
9#define PY_SSIZE_T_CLEAN
10#include <Python.h>
11#include "structmember.h" // PyMemberDef
12
13#include "greenlet_internal.hpp"
14#include "TThreadStateDestroy.cpp"
15#include "TGreenlet.hpp"
16// #include "TUserGreenlet.cpp"
17// #include "TMainGreenlet.cpp"
18// #include "TBrokenGreenlet.cpp"
19
20
21#include "greenlet_refs.hpp"
22#include "greenlet_slp_switch.hpp"
23
24#include "greenlet_thread_support.hpp"
25#include "TGreenlet.hpp"
26
27#include "TGreenletGlobals.cpp"
28#include "TThreadStateDestroy.cpp"
29#include "PyGreenlet.hpp"
30// #include "TGreenlet.cpp"
31
32// #include "TExceptionState.cpp"
33// #include "TPythonState.cpp"
34// #include "TStackState.cpp"
35
36using greenlet::LockGuard;
37using greenlet::LockInitError;
38using greenlet::PyErrOccurred;
39using greenlet::Require;
40
41using greenlet::g_handle_exit;
42using greenlet::single_result;
43
44using greenlet::Greenlet;
45using greenlet::UserGreenlet;
46using greenlet::MainGreenlet;
47using greenlet::BrokenGreenlet;
48using greenlet::ThreadState;
49using greenlet::PythonState;
50using greenlet::refs::PyCriticalObjectSection;
51
52
53static PyGreenlet*
54green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds))
55{
56 PyGreenlet* o =
57 (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict);
58 if (o) {
59 // Recall: borrowing or getting the current greenlet
60 // causes the "deleteme list" to get cleared. So constructing a greenlet
61 // can do things like cause other greenlets to get finalized.
62 UserGreenlet* c = new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current());
63 assert(Py_REFCNT(o) == 1);
64 // Also: This looks like a memory leak, but isn't.
65 // Constructing the C++ object assigns it to the pimpl pointer
66 // of the Python object (o); we'll need that later.
67 assert(c == o->pimpl);
68 }
69 return o;
70}
71
72
73// green_init is used in the tp_init slot. So it's important that
74// it can be called directly from CPython. Thus, we don't use
75// BorrowedGreenlet and BorrowedObject --- although in theory
76// these should be binary layout compatible, that may not be
77// guaranteed to be the case (32-bit linux ppc possibly).
78static int
79green_init(PyGreenlet* self, PyObject* args, PyObject* kwargs)
80{
81 PyArgParseParam run;
82 PyArgParseParam nparent;
83 static const char* kwlist[] = {
84 "run",
85 "parent",
86 NULL
87 };
88
89 // recall: The O specifier does NOT increase the reference count.
90 if (!PyArg_ParseTupleAndKeywords(
91 args, kwargs, "|OO:green", (char**)kwlist, &run, &nparent)) {
92 return -1;
93 }
94
95 if (run) {
96 if (green_setrun(self, run, NULL)) {
97 return -1;
98 }
99 }
100 if (nparent && !nparent.is_None()) {
101 return green_setparent(self, nparent, NULL);
102 }
103 return 0;
104}
105
106
107
108static int
109green_traverse(PyGreenlet* self, visitproc visit, void* arg)
110{
111 // We must only visit referenced objects, i.e. only objects
112 // Py_INCREF'ed by this greenlet (directly or indirectly):
113 //
114 // - stack_prev is not visited: holds previous stack pointer, but it's not
115 // referenced
116 // - frames are not visited as we don't strongly reference them;
117 // alive greenlets are not garbage collected
118 // anyway. This can be a problem, however, if this greenlet is
119 // never allowed to finish, and is referenced from the frame: we
120 // have an uncollectible cycle in that case. Note that the
121 // frame object itself is also frequently not even tracked by the GC
122 // starting with Python 3.7 (frames are allocated by the
123 // interpreter untracked, and only become tracked when their
124 // evaluation is finished if they have a refcount > 1). All of
125 // this is to say that we should probably strongly reference
126 // the frame object. Doing so, while always allowing GC on a
127 // greenlet, solves several leaks for us.
128
129 Py_VISIT(self->dict);
130 if (!self->pimpl) {
131 // Hmm. I have seen this at interpreter shutdown time,
132 // I think. That's very odd because this doesn't go away until
133 // we're ``green_dealloc()``, at which point we shouldn't be
134 // traversed anymore.
135 return 0;
136 }
137
138 return self->pimpl->tp_traverse(visit, arg);
139}
140
141static int
142green_is_gc(PyObject* _self)
143{
144 BorrowedGreenlet self(_self);
145 int result = 0;
146 /* Main greenlet can be garbage collected since it can only
147 become unreachable if the underlying thread exited.
148 Active greenlets --- including those that are suspended ---
149 cannot be garbage collected, however.
150 */
151 if (self->main() || !self->active()) {
152 result = 1;
153 }
154 // The main greenlet pointer will eventually go away after the thread dies.
155 if (self->was_running_in_dead_thread()) {
156 // Our thread is dead! We can never run again. Might as well
157 // GC us. Note that if a tuple containing only us and other
158 // immutable objects had been scanned before this, when we
159 // would have returned 0, the tuple will take itself out of GC
160 // tracking and never be investigated again. So that could
161 // result in both us and the tuple leaking due to an
162 // unreachable/uncollectible reference. The same goes for
163 // dictionaries.
164 //
165 // It's not a great idea to be changing our GC state on the
166 // fly.
167 result = 1;
168 }
169 return result;
170}
171
172
173static int
174green_clear(PyGreenlet* self)
175{
176 /* Greenlet is only cleared if it is about to be collected.
177 Since active greenlets are not garbage collectable, we can
178 be sure that, even if they are deallocated during clear,
179 nothing they reference is in unreachable or finalizers,
180 so even if it switches we are relatively safe. */
181 // XXX: Are we responsible for clearing weakrefs here?
182 Py_CLEAR(self->dict);
183 return self->pimpl->tp_clear();
184}
185
186/**
187 * Returns 0 on failure (the object was resurrected) or 1 on success.
188 **/
189static int
190_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self)
191{
192 // During interpreter finalization, we cannot safely throw GreenletExit
193 // into the greenlet. Doing so calls g_switch(), which performs a stack
194 // switch and runs Python code via _PyEval_EvalFrameDefault. On Python
195 // < 3.11, executing Python code in a partially-torn-down interpreter
196 // leads to SIGSEGV (greenlet 3.x) or SIGABRT (greenlet 2.x).
197 //
198 // Python 3.11+ restructured interpreter finalization internals (frame
199 // representation, data stack management, recursion tracking) so that
200 // g_switch() during finalization is safe. On older Pythons, we simply
201 // mark the greenlet dead without throwing, which avoids the crash at
202 // the cost of not running any cleanup code inside the greenlet.
203 //
204 // See: https://github.com/python-greenlet/greenlet/issues/411
205 // https://github.com/python-greenlet/greenlet/issues/351
206 if (greenlet::IsShuttingDown()) {
207 self->murder_in_place();
208 return 1;
209 }
210
211 /* Hacks hacks hacks copied from instance_dealloc() */
212 /* Temporarily resurrect the greenlet. */
213 assert(self.REFCNT() == 0);
214 Py_SET_REFCNT(self.borrow(), 1);
215 /* Save the current exception, if any. */
216 PyErrPieces saved_err;
217 try {
218 // BY THE TIME WE GET HERE, the state may actually be going
219 // away
220 // if we're shutting down the interpreter and freeing thread
221 // entries,
222 // this could result in freeing greenlets that were leaked. So
223 // we can't try to read the state.
224 self->deallocing_greenlet_in_thread(
225 self->thread_state()
226 ? static_cast<ThreadState*>(GET_THREAD_STATE())
227 : nullptr);
228 }
229 catch (const PyErrOccurred&) {
230 PyErr_WriteUnraisable(self.borrow_o());
231 /* XXX what else should we do? */
232 }
233 /* Check for no resurrection must be done while we keep
234 * our internal reference, otherwise PyFile_WriteObject
235 * causes recursion if using Py_INCREF/Py_DECREF
236 */
237 if (self.REFCNT() == 1 && self->active()) {
238 /* Not resurrected, but still not dead!
239 XXX what else should we do? we complain. */
240 PyObject* f = PySys_GetObject("stderr");
241 Py_INCREF(self.borrow_o()); /* leak! */
242 if (f != NULL) {
243 // PySys_GetObject returns a borrowed ref which could go
244 // away when we run arbitrary code, as we do for any of
245 // the ``PyFile_Write`` APIs.
246 Py_INCREF(f);
247 // Note that we're not handling errors here. They either
248 // work or they don't, and any exception they raised will
249 // be replaced by PyErrRestore.
250 PyFile_WriteString("GreenletExit did not kill ", f);
251 PyFile_WriteObject(self.borrow_o(), f, 0);
252 PyFile_WriteString("\n", f);
253 Py_DECREF(f);
254 }
255 }
256 /* Restore the saved exception. */
257 saved_err.PyErrRestore();
258 /* Undo the temporary resurrection; can't use DECREF here,
259 * it would cause a recursive call.
260 */
261 assert(self.REFCNT() > 0);
262
263 Py_ssize_t refcnt = self.REFCNT() - 1;
264 Py_SET_REFCNT(self.borrow_o(), refcnt);
265 if (refcnt != 0) {
266 /* Resurrected! */
267 _Py_NewReference(self.borrow_o());
268 Py_SET_REFCNT(self.borrow_o(), refcnt);
269 /* Better to use tp_finalizer slot (PEP 442)
270 * and call ``PyObject_CallFinalizerFromDealloc``,
271 * but that's only supported in Python 3.4+; see
272 * Modules/_io/iobase.c for an example.
273 * TODO: We no longer run on anything that old, switch to finalizers.
274 *
275 * The following approach is copied from iobase.c in CPython 2.7.
276 * (along with much of this function in general). Here's their
277 * comment:
278 *
279 * When called from a heap type's dealloc, the type will be
280 * decref'ed on return (see e.g. subtype_dealloc in typeobject.c).
281 *
282 * On free-threaded builds of CPython, the type is meant to be immortal
283 * so we probably shouldn't mess with this? See
284 * test_issue_245_reference_counting_subclass_no_threads
285 */
286 if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) {
287 Py_INCREF(self.TYPE());
288 }
289
290 PyObject_GC_Track((PyObject*)self);
291
292 GREENLET_Py_DEC_REFTOTAL;
293#ifdef COUNT_ALLOCS
294 --Py_TYPE(self)->tp_frees;
295 --Py_TYPE(self)->tp_allocs;
296#endif /* COUNT_ALLOCS */
297 return 0;
298 }
299 return 1;
300}
301
302
303static void
304green_dealloc(PyGreenlet* self)
305{
306 PyObject_GC_UnTrack(self);
307 BorrowedGreenlet me(self);
308 if (me->active()
309 && me->started()
310 && !me->main()) {
311 if (!_green_dealloc_kill_started_non_main_greenlet(me)) {
312 return;
313 }
314 }
315
316 if (self->weakreflist != NULL) {
317 PyObject_ClearWeakRefs((PyObject*)self);
318 }
319 Py_CLEAR(self->dict);
320
321 if (self->pimpl) {
322 // In case deleting this, which frees some memory,
323 // somehow winds up calling back into us. That's usually a
324 //bug in our code.
325 Greenlet* p = self->pimpl;
326 self->pimpl = nullptr;
327 delete p;
328 }
329 // and finally we're done. self is now invalid.
330 Py_TYPE(self)->tp_free((PyObject*)self);
331}
332
333
334
335static OwnedObject
336internal_green_throw(BorrowedGreenlet self, PyErrPieces& err_pieces)
337{
338 PyObject* result = nullptr;
339 err_pieces.PyErrRestore();
340 assert(PyErr_Occurred());
341 if (self->started() && !self->active()) {
342 /* dead greenlet: turn GreenletExit into a regular return */
343 result = g_handle_exit(OwnedObject()).relinquish_ownership();
344 }
345 self->args() <<= result;
346
347 return single_result(self->g_switch());
348}
349
350
351
352PyDoc_STRVAR(
353 green_switch_doc,
354 "switch(*args, **kwargs)\n"
355 "\n"
356 "Switch execution to this greenlet.\n"
357 "\n"
358 "If this greenlet has never been run, then this greenlet\n"
359 "will be switched to using the body of ``self.run(*args, **kwargs)``.\n"
360 "\n"
361 "If the greenlet is active (has been run, but was switch()'ed\n"
362 "out before leaving its run function), then this greenlet will\n"
363 "be resumed and the return value to its switch call will be\n"
364 "None if no arguments are given, the given argument if one\n"
365 "argument is given, or the args tuple and keyword args dict if\n"
366 "multiple arguments are given.\n"
367 "\n"
368 "If the greenlet is dead, or is the current greenlet then this\n"
369 "function will simply return the arguments using the same rules as\n"
370 "above.\n");
371
372static PyObject*
373green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs)
374{
375 // Our use of Greenlet::args() makes this method non-reentrant.
376 // Therefore, check to be sure the switch will be allowed ---
377 // we're calling from the same thread that ``self`` belongs to ---
378 // BEFORE doing anything with args(). If we don't do this, we can
379 // find args() getting clobbered by switches that will never
380 // succeed.
381 //
382 // TODO: We're only doing this for free-threaded builds because
383 // those are the only ones that have demonstrated an issue,
384 // trusting our later checks in g_switch to perform the same
385 // function and the GIL to keep us from being reentered in regular
386 // builds. BUT should we always do this as an extra measure of
387 // safety in case we run code at unexpected times (e.g., a GC?)
388#ifdef Py_GIL_DISABLED
389 try {
390 self->pimpl->check_switch_allowed();
391 }
392 catch (const PyErrOccurred&) {
393 return nullptr;
394 }
395#endif
396
397
398 using greenlet::SwitchingArgs;
399 SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs));
400 self->pimpl->may_switch_away();
401 self->pimpl->args() <<= switch_args;
402
403 // If we're switching out of a greenlet, and that switch is the
404 // last thing the greenlet does, the greenlet ought to be able to
405 // go ahead and die at that point. Currently, someone else must
406 // manually switch back to the greenlet so that we "fall off the
407 // end" and can perform cleanup. You'd think we'd be able to
408 // figure out that this is happening using the frame's ``f_lasti``
409 // member, which is supposed to be an index into
410 // ``frame->f_code->co_code``, the bytecode string. However, in
411 // recent interpreters, ``f_lasti`` tends not to be updated thanks
412 // to things like the PREDICT() macros in ceval.c. So it doesn't
413 // really work to do that in many cases. For example, the Python
414 // code:
415 // def run():
416 // greenlet.getcurrent().parent.switch()
417 // produces bytecode of len 16, with the actual call to switch()
418 // being at index 10 (in Python 3.10). However, the reported
419 // ``f_lasti`` we actually see is...5! (Which happens to be the
420 // second byte of the CALL_METHOD op for ``getcurrent()``).
421
422 try {
423 OwnedObject result(single_result(self->pimpl->g_switch()));
424#ifndef NDEBUG
425 // Note that the current greenlet isn't necessarily self. If self
426 // finished, we went to one of its parents.
427 assert(!self->pimpl->args());
428
429 const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current();
430 // It's possible it's never been switched to.
431 assert(!current->args());
432#endif
433 PyObject* p = result.relinquish_ownership();
434
435 if (!p && !PyErr_Occurred()) {
436 // This shouldn't be happening anymore, so the asserts
437 // are there for debug builds. Non-debug builds
438 // crash "gracefully" in this case, although there is an
439 // argument to be made for killing the process in all
440 // cases --- for this to be the case, our switches
441 // probably nested in an incorrect way, so the state is
442 // suspicious. Nothing should be corrupt though, just
443 // confused at the Python level. Letting this propagate is
444 // probably good enough.
445 assert(p || PyErr_Occurred());
446 throw PyErrOccurred(
447 mod_globs->PyExc_GreenletError,
448 "Greenlet.switch() returned NULL without an exception set."
449 );
450 }
451 return p;
452 }
453 catch(const PyErrOccurred&) {
454 return nullptr;
455 }
456}
457
458PyDoc_STRVAR(
459 green_throw_doc,
460 "Switches execution to this greenlet, but immediately raises the\n"
461 "given exception in this greenlet. If no argument is provided, the "
462 "exception\n"
463 "defaults to `greenlet.GreenletExit`. The normal exception\n"
464 "propagation rules apply, as described for `switch`. Note that calling "
465 "this\n"
466 "method is almost equivalent to the following::\n"
467 "\n"
468 " def raiser():\n"
469 " raise typ, val, tb\n"
470 " g_raiser = greenlet(raiser, parent=g)\n"
471 " g_raiser.switch()\n"
472 "\n"
473 "except that this trick does not work for the\n"
474 "`greenlet.GreenletExit` exception, which would not propagate\n"
475 "from ``g_raiser`` to ``g``.\n");
476
477static PyObject*
478green_throw(PyGreenlet* self, PyObject* args)
479{
480 // See green_switch for why we call this early.
481#ifdef Py_GIL_DISABLED
482 try {
483 self->pimpl->check_switch_allowed();
484 }
485 catch (const PyErrOccurred&) {
486 return nullptr;
487 }
488#endif
489
490 PyArgParseParam typ(mod_globs->PyExc_GreenletExit);
491 PyArgParseParam val;
492 PyArgParseParam tb;
493
494 if (!PyArg_ParseTuple(args, "|OOO:throw", &typ, &val, &tb)) {
495 return nullptr;
496 }
497
498 assert(typ.borrow() || val.borrow());
499
500 self->pimpl->may_switch_away();
501 try {
502 // Both normalizing the error and the actual throw_greenlet
503 // could throw PyErrOccurred.
504 PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow());
505
506 return internal_green_throw(self, err_pieces).relinquish_ownership();
507 }
508 catch (const PyErrOccurred&) {
509 return nullptr;
510 }
511}
512
513static int
514green_bool(PyGreenlet* self)
515{
516 return self->pimpl->active();
517}
518
519/**
520 * CAUTION: Allocates memory, may run GC and arbitrary Python code.
521 */
522static PyObject*
523green_getdict(PyGreenlet* self, void* UNUSED(context))
524{
525 PyCriticalObjectSection cs(self);
526 if (self->dict == NULL) {
527 self->dict = PyDict_New();
528 if (self->dict == NULL) {
529 return NULL;
530 }
531 }
532 Py_INCREF(self->dict);
533 return self->dict;
534}
535
536static int
537green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context))
538{
539 if (val == NULL) {
540 PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted");
541 return -1;
542 }
543 if (!PyDict_Check(val)) {
544 PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary");
545 return -1;
546 }
547 PyCriticalObjectSection cs(self);
548 PyObject* tmp = self->dict;
549 Py_INCREF(val);
550 self->dict = val;
551 Py_XDECREF(tmp);
552 return 0;
553}
554
555static bool
556_green_not_dead(BorrowedGreenlet self)
557{
558 // XXX: Where else should we do this?
559 // Probably on entry to most Python-facing functions?
560 if (self->was_running_in_dead_thread()) {
561 self->deactivate_and_free();
562 return false;
563 }
564 return self->active() || !self->started();
565}
566
567
568static PyObject*
569green_getdead(PyGreenlet* self, void* UNUSED(context))
570{
571 PyCriticalObjectSection cs(self);
572 if (_green_not_dead(self)) {
573 Py_RETURN_FALSE;
574 }
575 else {
576 Py_RETURN_TRUE;
577 }
578}
579
580static PyObject*
581green_get_stack_saved(PyGreenlet* self, void* UNUSED(context))
582{
583 return PyLong_FromSsize_t(self->pimpl->stack_saved());
584}
585
586
587static PyObject*
588green_getrun(PyGreenlet* self, void* UNUSED(context))
589{
590 PyCriticalObjectSection cs(self);
591 try {
592 OwnedObject result(BorrowedGreenlet(self)->run());
593 return result.relinquish_ownership();
594 }
595 catch(const PyErrOccurred&) {
596 return nullptr;
597 }
598}
599
600
601static int
602green_setrun(PyGreenlet* self, PyObject* nrun, void* UNUSED(context))
603{
604 PyCriticalObjectSection cs(self);
605 try {
606 BorrowedGreenlet(self)->run(nrun);
607 return 0;
608 }
609 catch(const PyErrOccurred&) {
610 return -1;
611 }
612}
613
614static PyObject*
615green_getparent(PyGreenlet* self, void* UNUSED(context))
616{
617 PyCriticalObjectSection cs(self);
618 return BorrowedGreenlet(self)->parent().acquire_or_None();
619}
620
621
622static int
623green_setparent(PyGreenlet* self, PyObject* nparent, void* UNUSED(context))
624{
625 PyCriticalObjectSection cs(self);
626 try {
627 BorrowedGreenlet(self)->parent(nparent);
628 }
629 catch(const PyErrOccurred&) {
630 return -1;
631 }
632 return 0;
633}
634
635
636static PyObject*
637green_getcontext(const PyGreenlet* self, void* UNUSED(context))
638{
639 PyCriticalObjectSection cs(self);
640 const Greenlet *const g = self->pimpl;
641 try {
642 OwnedObject result(g->context());
643 return result.relinquish_ownership();
644 }
645 catch(const PyErrOccurred&) {
646 return nullptr;
647 }
648}
649
650static int
651green_setcontext(PyGreenlet* self, PyObject* nctx, void* UNUSED(context))
652{
653 PyCriticalObjectSection cs(self);
654 try {
655 BorrowedGreenlet(self)->context(nctx);
656 return 0;
657 }
658 catch(const PyErrOccurred&) {
659 return -1;
660 }
661}
662
663
664static PyObject*
665green_getframe(PyGreenlet* self, void* UNUSED(context))
666{
667 PyCriticalObjectSection cs(self);
668 const PythonState::OwnedFrame& top_frame = BorrowedGreenlet(self)->top_frame();
669 return top_frame.acquire_or_None();
670}
671
672
673static PyObject*
674green_getstate(PyGreenlet* self)
675{
676 PyErr_Format(PyExc_TypeError,
677 "cannot serialize '%s' object",
678 Py_TYPE(self)->tp_name);
679 return nullptr;
680}
681
682static PyObject*
683green_repr(PyGreenlet* _self)
684{
685 BorrowedGreenlet self(_self);
686 /*
687 Return a string like
688 <greenlet.greenlet at 0xdeadbeef [current][active started]|dead main>
689
690 The handling of greenlets across threads is not super good.
691 We mostly use the internal definitions of these terms, but they
692 generally should make sense to users as well.
693 */
694 PyObject* result;
695 int never_started = !self->started() && !self->active();
696
697 const char* const tp_name = Py_TYPE(self)->tp_name;
698
699 if (_green_not_dead(self)) {
700 /* XXX: The otid= is almost useless because you can't correlate it to
701 any thread identifier exposed to Python. We could use
702 PyThreadState_GET()->thread_id, but we'd need to save that in the
703 greenlet, or save the whole PyThreadState object itself.
704
705 As it stands, its only useful for identifying greenlets from the same thread.
706 */
707 const char* state_in_thread;
708 if (self->was_running_in_dead_thread()) {
709 // The thread it was running in is dead!
710 // This can happen, especially at interpreter shut down.
711 // It complicates debugging output because it may be
712 // impossible to access the current thread state at that
713 // time. Thus, don't access the current thread state.
714 state_in_thread = " (thread exited)";
715 }
716 else {
717 state_in_thread = GET_THREAD_STATE().state().is_current(self)
718 ? " current"
719 : (self->started() ? " suspended" : "");
720 }
721 result = PyUnicode_FromFormat(
722 "<%s object at %p (otid=%p)%s%s%s%s>",
723 tp_name,
724 self.borrow_o(),
725 self->thread_state(),
726 state_in_thread,
727 self->active() ? " active" : "",
728 never_started ? " pending" : " started",
729 self->main() ? " main" : ""
730 );
731 }
732 else {
733 result = PyUnicode_FromFormat(
734 "<%s object at %p (otid=%p) %sdead>",
735 tp_name,
736 self.borrow_o(),
737 self->thread_state(),
738 self->was_running_in_dead_thread()
739 ? "(thread exited) "
740 : ""
741 );
742 }
743
744 return result;
745}
746
747
748static PyMethodDef green_methods[] = {
749 {
750 .ml_name="switch",
751 .ml_meth=reinterpret_cast<PyCFunction>(green_switch),
752 .ml_flags=METH_VARARGS | METH_KEYWORDS,
753 .ml_doc=green_switch_doc
754 },
755 {.ml_name="throw", .ml_meth=(PyCFunction)green_throw, .ml_flags=METH_VARARGS, .ml_doc=green_throw_doc},
756 {.ml_name="__getstate__", .ml_meth=(PyCFunction)green_getstate, .ml_flags=METH_NOARGS, .ml_doc=NULL},
757 {.ml_name=NULL, .ml_meth=NULL} /* sentinel */
758};
759
760static PyGetSetDef green_getsets[] = {
761 /* name, getter, setter, doc, context pointer */
762 {.name="__dict__", .get=(getter)green_getdict, .set=(setter)green_setdict},
763 {.name="run", .get=(getter)green_getrun, .set=(setter)green_setrun},
764 {.name="parent", .get=(getter)green_getparent, .set=(setter)green_setparent},
765 {.name="gr_frame", .get=(getter)green_getframe },
766 {
767 .name="gr_context",
768 .get=(getter)green_getcontext,
769 .set=(setter)green_setcontext
770 },
771 {.name="dead", .get=(getter)green_getdead},
772 {.name="_stack_saved", .get=(getter)green_get_stack_saved},
773 {.name=NULL}
774};
775
776static PyMemberDef green_members[] = {
777 {.name=NULL}
778};
779
780static PyNumberMethods green_as_number = {
781 .nb_bool=(inquiry)green_bool,
782};
783
784
785PyTypeObject PyGreenlet_Type = {
786 .ob_base=PyVarObject_HEAD_INIT(NULL, 0)
787 .tp_name="greenlet.greenlet", /* tp_name */
788 .tp_basicsize=sizeof(PyGreenlet), /* tp_basicsize */
789 /* methods */
790 .tp_dealloc=(destructor)green_dealloc, /* tp_dealloc */
791 .tp_repr=(reprfunc)green_repr, /* tp_repr */
792 .tp_as_number=&green_as_number, /* tp_as _number*/
793 .tp_flags=G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
794 .tp_doc="greenlet(run=None, parent=None) -> greenlet\n\n"
795 "Creates a new greenlet object (without running it).\n\n"
796 " - *run* -- The callable to invoke.\n"
797 " - *parent* -- The parent greenlet. The default is the current "
798 "greenlet.", /* tp_doc */
799 .tp_traverse=(traverseproc)green_traverse, /* tp_traverse */
800 .tp_clear=(inquiry)green_clear, /* tp_clear */
801 .tp_weaklistoffset=offsetof(PyGreenlet, weakreflist), /* tp_weaklistoffset */
802
803 .tp_methods=green_methods, /* tp_methods */
804 .tp_members=green_members, /* tp_members */
805 .tp_getset=green_getsets, /* tp_getset */
806 .tp_dictoffset=offsetof(PyGreenlet, dict), /* tp_dictoffset */
807 .tp_init=(initproc)green_init, /* tp_init */
808 .tp_alloc=PyType_GenericAlloc, /* tp_alloc */
809 .tp_new=(newfunc)green_new, /* tp_new */
810 .tp_free=PyObject_GC_Del, /* tp_free */
811#ifndef Py_GIL_DISABLED
812/*
813 We may have been handling this wrong all along.
814
815 It shows as a problem with the GIL disabled. In builds of 3.14 with
816 assertions enabled, we break the garbage collector if we *ever*
817 return false from this function. The docs say this is to distinguish
818 some objects that are collectable vs some that are not, specifically
819 giving the example of PyTypeObject as the only place this is done,
820 where it distinguishes between static types like this one (allocated
821 by the C runtime at load time) and dynamic heap types (created at
822 runtime as objects). With the GIL disabled, all allocations that are
823 potentially collectable go in the mimalloc heap, and the collector
824 asserts that tp_is_gc() is true for them as it walks through the
825 heap object by object. Since we set the Py_TPFLAGS_HAS_GC bit, we
826 are always allocated in that mimalloc heap, so we must always be
827 collectable.
828
829 XXX: TODO: Could this be responsible for some apparent leaks, even
830 on GIL builds, at least in 3.14? See if we can catch an assertion
831 failure in the GC on regular 3.14 as well.
832 */
833 .tp_is_gc=(inquiry)green_is_gc, /* tp_is_gc */
834#endif
835};
836
837#endif
838
839// Local Variables:
840// flycheck-clang-include-path: ("/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8")
841// End:
842 