Qucs-S S-parameter Viewer & RF Synthesis Tools
Loading...
Searching...
No Matches
TGreenlet.hpp
1#ifndef GREENLET_GREENLET_HPP
2#define GREENLET_GREENLET_HPP
3/*
4 * Declarations of the core data structures.
5*/
6
7#define PY_SSIZE_T_CLEAN
8#include <Python.h>
9
10#include "greenlet_compiler_compat.hpp"
11#include "greenlet_refs.hpp"
12#include "greenlet_cpython_compat.hpp"
13#include "greenlet_allocator.hpp"
14
19
20#if PY_VERSION_HEX < 0x30B00A6
21# define _PyCFrame CFrame
22# define _PyInterpreterFrame _interpreter_frame
23#endif
24
25#if GREENLET_PY312
26# define Py_BUILD_CORE
27# include "internal/pycore_frame.h"
28#endif
29
30#if GREENLET_PY314
31# include "internal/pycore_interpframe_structs.h"
32#if defined(_MSC_VER) || defined(__MINGW64__)
33# include "greenlet_msvc_compat.hpp"
34#else
35# include "internal/pycore_interpframe.h"
36#endif
37#ifdef Py_GIL_DISABLED
38# include "internal/pycore_tstate.h"
39#endif
40#endif
41
42// XXX: TODO: Work to remove all virtual functions
43// for speed of calling and size of objects (no vtable).
44// One pattern is the Curiously Recurring Template
45namespace greenlet
46{
48 {
49 private:
50 G_NO_COPIES_OF_CLS(ExceptionState);
51
52 // Even though these are borrowed objects, we actually own
53 // them, when they're not null.
54 // XXX: Express that in the API.
55 private:
56 _PyErr_StackItem* exc_info;
57 _PyErr_StackItem exc_state;
58 public:
60 void operator<<(const PyThreadState *const tstate) noexcept;
61 void operator>>(PyThreadState* tstate) noexcept;
62 void clear() noexcept;
63
64 int tp_traverse(visitproc visit, void* arg) noexcept;
65 void tp_clear() noexcept;
66 };
67
68 template<typename T>
69 void operator<<(const PyThreadState *const tstate, T& exc);
70
72 {
73 protected:
75 public:
76 inline const greenlet::refs::OwnedContext& context() const
77 {
78 return this->_context;
79 }
80 inline greenlet::refs::OwnedContext& context()
81 {
82 return this->_context;
83 }
84
85 inline void tp_clear()
86 {
87 this->_context.CLEAR();
88 }
89
90 template<typename T>
91 inline static PyObject* context(T* tstate)
92 {
93 return tstate->context;
94 }
95
96 template<typename T>
97 inline static void context(T* tstate, PyObject* new_context)
98 {
99 tstate->context = new_context;
100 tstate->context_ver++;
101 }
102 };
103 class SwitchingArgs;
105 {
106 public:
108 private:
109 G_NO_COPIES_OF_CLS(PythonState);
110 // We own this if we're suspended (although currently we don't
111 // tp_traverse into it; that's a TODO). If we're running, it's
112 // empty. If we get deallocated and *still* have a frame, it
113 // won't be reachable from the place that normally decref's
114 // it, so we need to do it (hence owning it).
115 OwnedFrame _top_frame;
116#if GREENLET_USE_CFRAME
117 _PyCFrame* cframe;
118 int use_tracing;
119#endif
120#if GREENLET_PY314
121 int py_recursion_depth;
122 // I think this is only used by the JIT. At least,
123 // we only got errors not switching it when the JIT was enabled.
124 // Python/generated_cases.c.h:12469: _PyEval_EvalFrameDefault:
125 // Assertion `tstate->current_executor == NULL' failed.
126 // see https://github.com/python-greenlet/greenlet/issues/460
127 PyObject* current_executor;
128 _PyStackRef* stackpointer;
129 #ifdef Py_GIL_DISABLED
130 _PyCStackRef* c_stack_refs;
131 #endif
132#elif GREENLET_PY312
133 int py_recursion_depth;
134 int c_recursion_depth;
135#else
136 int recursion_depth;
137#endif
138#if GREENLET_PY313
139 PyObject *delete_later;
140#else
141 int trash_delete_nesting;
142#endif
143#if GREENLET_PY311
144 _PyInterpreterFrame* current_frame;
145 _PyStackChunk* datastack_chunk;
146 PyObject** datastack_top;
147 PyObject** datastack_limit;
148#endif
149 // The PyInterpreterFrame list on 3.12+ contains some entries that are
150 // on the C stack, which can't be directly accessed while a greenlet is
151 // suspended. In order to keep greenlet gr_frame introspection working,
152 // we adjust stack switching to rewrite the interpreter frame list
153 // to skip these C-stack frames; we call this "exposing" the greenlet's
154 // frames because it makes them valid to work with in Python. Then when
155 // the greenlet is resumed we need to remember to reverse the operation
156 // we did. The C-stack frames are "entry frames" which are a low-level
157 // interpreter detail; they're not needed for introspection, but do
158 // need to be present for the eval loop to work.
159 void unexpose_frames();
160
161 public:
162
163 PythonState();
164 // You can use this for testing whether we have a frame
165 // or not. It returns const so they can't modify it.
166 const OwnedFrame& top_frame() const noexcept;
167
168 inline void operator<<(const PyThreadState *const tstate) noexcept;
169 inline void operator>>(PyThreadState* tstate) noexcept;
170 void clear() noexcept;
171
172 int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) noexcept;
173 void tp_clear(bool own_top_frame) noexcept;
174 void set_initial_state(const PyThreadState* const tstate) noexcept;
175#if GREENLET_USE_CFRAME
176 void set_new_cframe(_PyCFrame& frame) noexcept;
177#endif
178
179 void may_switch_away() noexcept;
180 inline void will_switch_from(PyThreadState *const origin_tstate) noexcept;
181 void did_finish(PyThreadState* tstate) noexcept;
182 };
183
185 {
186 // By having only plain C (POD) members, no virtual functions
187 // or bases, we get a trivial assignment operator generated
188 // for us. However, that's not safe since we do manage memory.
189 // So we declare an assignment operator that only works if we
190 // don't have any memory allocated. (We don't use
191 // std::shared_ptr for reference counting just to keep this
192 // object small)
193 private:
194 char* _stack_start;
195 char* stack_stop;
196 char* stack_copy;
197 intptr_t _stack_saved;
198 StackState* stack_prev;
199 inline int copy_stack_to_heap_up_to(const char* const stop) noexcept;
200 inline void free_stack_copy() noexcept;
201
202 public:
207 StackState(void* mark, StackState& current);
211 StackState();
212 ~StackState();
213 StackState(const StackState& other);
214 StackState& operator=(const StackState& other);
215 inline void copy_heap_to_stack(const StackState& current) noexcept;
216 inline int copy_stack_to_heap(char* const stackref, const StackState& current) noexcept;
217 inline bool started() const noexcept;
218 inline bool main() const noexcept;
219 inline bool active() const noexcept;
220 inline void set_active() noexcept;
221 inline void set_inactive() noexcept;
222 inline intptr_t stack_saved() const noexcept;
223 inline char* stack_start() const noexcept;
224 static inline StackState make_main() noexcept;
225#ifdef GREENLET_USE_STDIO
226 friend std::ostream& operator<<(std::ostream& os, const StackState& s);
227#endif
228
229 // Fill in [dest, dest + n) with the values that would be at
230 // [src, src + n) while this greenlet is running. This is like memcpy
231 // except that if the greenlet is suspended it accounts for the portion
232 // of the greenlet's stack that was spilled to the heap. `src` may
233 // be on this greenlet's stack, or on the heap, but not on a different
234 // greenlet's stack.
235 void copy_from_stack(void* dest, const void* src, size_t n) const;
236 };
237#ifdef GREENLET_USE_STDIO
238 std::ostream& operator<<(std::ostream& os, const StackState& s);
239#endif
240
242 {
243 private:
244 G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs);
245 // If args and kwargs are both false (NULL), this is a *throw*, not a
246 // switch. PyErr_... must have been called already.
247 OwnedObject _args;
248 OwnedObject _kwargs;
249 public:
250
252 {}
253
254 SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs)
255 : _args(args),
256 _kwargs(kwargs)
257 {}
258
259 SwitchingArgs(const SwitchingArgs& other)
260 : _args(other._args),
261 _kwargs(other._kwargs)
262 {}
263
264 const OwnedObject& args()
265 {
266 return this->_args;
267 }
268
269 const OwnedObject& kwargs()
270 {
271 return this->_kwargs;
272 }
273
278 {
279 if (this != &other) {
280 this->_args = other._args;
281 this->_kwargs = other._kwargs;
282 other.CLEAR();
283 }
284 return *this;
285 }
286
290 SwitchingArgs& operator<<=(PyObject* args)
291 {
292 this->_args = OwnedObject::consuming(args);
293 this->_kwargs.CLEAR();
294 return *this;
295 }
296
302 SwitchingArgs& operator<<=(OwnedObject& args)
303 {
304 assert(&args != &this->_args);
305 this->_args = args;
306 this->_kwargs.CLEAR();
307 args.CLEAR();
308
309 return *this;
310 }
311
312 explicit operator bool() const noexcept
313 {
314 return this->_args || this->_kwargs;
315 }
316
317 inline void CLEAR()
318 {
319 this->_args.CLEAR();
320 this->_kwargs.CLEAR();
321 }
322
323 const std::string as_str() const noexcept
324 {
325 return PyUnicode_AsUTF8(
326 OwnedObject::consuming(
327 PyUnicode_FromFormat(
328 "SwitchingArgs(args=%R, kwargs=%R)",
329 this->_args.borrow(),
330 this->_kwargs.borrow()
331 )
332 ).borrow()
333 );
334 }
335 };
336
337 class ThreadState;
338
339 class UserGreenlet;
340 class MainGreenlet;
341
343 {
344 private:
345 G_NO_COPIES_OF_CLS(Greenlet);
346 PyGreenlet* const _self;
347 private:
348 // XXX: Work to remove these.
349 friend class ThreadState;
350 friend class UserGreenlet;
351 friend class MainGreenlet;
352 protected:
353 ExceptionState exception_state;
354 SwitchingArgs switch_args;
355 StackState stack_state;
356 PythonState python_state;
357 Greenlet(PyGreenlet* p, const StackState& initial_state);
358 public:
359 // This constructor takes ownership of the PyGreenlet, by
360 // setting ``p->pimpl = this;``.
362 virtual ~Greenlet();
363
364 const OwnedObject context() const;
365
366 // You MUST call this _very_ early in the switching process to
367 // prepare anything that may need prepared. This might perform
368 // garbage collections or otherwise run arbitrary Python code.
369 //
370 // One specific use of it is for Python 3.11+, preventing
371 // running arbitrary code at unsafe times. See
372 // PythonState::may_switch_away().
373 inline void may_switch_away()
374 {
375 this->python_state.may_switch_away();
376 }
377
378 inline void context(refs::BorrowedObject new_context);
379
380 inline SwitchingArgs& args()
381 {
382 return this->switch_args;
383 }
384
385 virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0;
386
387 inline intptr_t stack_saved() const noexcept
388 {
389 return this->stack_state.stack_saved();
390 }
391
392 // This is used by the macro SLP_SAVE_STATE to compute the
393 // difference in stack sizes. It might be nice to handle the
394 // computation ourself, but the type of the result
395 // varies by platform, so doing it in the macro is the
396 // simplest way.
397 inline const char* stack_start() const noexcept
398 {
399 return this->stack_state.stack_start();
400 }
401
402 virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state);
403 virtual OwnedObject g_switch() = 0;
410 virtual void murder_in_place();
411
419 inline void deactivate_and_free();
420
421
422 // Called when some thread wants to deallocate a greenlet
423 // object.
424 // The thread may or may not be the same thread the greenlet
425 // was running in.
426 // The thread state will be null if the thread the greenlet
427 // was running in was known to have exited.
428 void deallocing_greenlet_in_thread(const ThreadState* current_state);
429
430 // Must be called on 3.12+ before exposing a suspended greenlet's
431 // frames to user code. This rewrites the linked list of interpreter
432 // frames to skip the ones that are being stored on the C stack (which
433 // can't be safely accessed while the greenlet is suspended because
434 // that stack space might be hosting a different greenlet), and
435 // sets PythonState::frames_were_exposed so we remember to restore
436 // the original list before resuming the greenlet. The C-stack frames
437 // are a low-level interpreter implementation detail; while they're
438 // important to the bytecode eval loop, they're superfluous for
439 // introspection purposes.
440 void expose_frames();
441
442
443 // TODO: Figure out how to make these non-public.
444 inline void slp_restore_state() noexcept;
445 inline int slp_save_state(char *const stackref) noexcept;
446
447 inline bool is_currently_running_in_some_thread() const;
448 virtual bool belongs_to_thread(const ThreadState* state) const;
449
450 inline bool started() const
451 {
452 return this->stack_state.started();
453 }
454 inline bool active() const
455 {
456 return this->stack_state.active();
457 }
458 inline bool main() const
459 {
460 return this->stack_state.main();
461 }
462 virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0;
463
464 virtual const OwnedGreenlet parent() const = 0;
465 virtual void parent(const refs::BorrowedObject new_parent) = 0;
466
467 inline const PythonState::OwnedFrame& top_frame()
468 {
469 return this->python_state.top_frame();
470 }
471
472 virtual const OwnedObject& run() const = 0;
473 virtual void run(const refs::BorrowedObject nrun) = 0;
474
475
476 virtual int tp_traverse(visitproc visit, void* arg);
477 virtual int tp_clear();
478
479
480 // Return the thread state that the greenlet is running in, or
481 // null if the greenlet is not running or the thread is known
482 // to have exited.
483 virtual ThreadState* thread_state() const noexcept = 0;
484
485 // Return true if the greenlet is known to have been running
486 // (active) in a thread that has now exited.
487 virtual bool was_running_in_dead_thread() const noexcept = 0;
488
489 // Return a borrowed greenlet that is the Python object
490 // this object represents.
491 inline BorrowedGreenlet self() const noexcept
492 {
493 return BorrowedGreenlet(this->_self);
494 }
495
496 // For testing. If this returns true, we should pretend that
497 // slp_switch() failed.
498 virtual bool force_slp_switch_error() const noexcept;
499
500 protected:
501 inline void release_args();
502
503 // The functions that must not be inlined are declared virtual.
504 // We also mark them as protected, not private, so that the
505 // compiler is forced to call them through a function pointer.
506 // (A sufficiently smart compiler could directly call a private
507 // virtual function since it can never be overridden in a
508 // subclass).
509
510 // Also TODO: Switch away from integer error codes and to enums,
511 // or throw exceptions when possible.
513 {
514 int status;
515 Greenlet* the_new_current_greenlet;
516 OwnedGreenlet origin_greenlet;
517
519 : status(0),
520 the_new_current_greenlet(nullptr)
521 {}
522
523 switchstack_result_t(int err)
524 : status(err),
525 the_new_current_greenlet(nullptr)
526 {}
527
528 switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin)
529 : status(err),
530 the_new_current_greenlet(state),
531 origin_greenlet(origin)
532 {
533 }
534
535 switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin)
536 : status(err),
537 the_new_current_greenlet(state),
538 origin_greenlet(origin)
539 {
540 }
541
543 : status(other.status),
544 the_new_current_greenlet(other.the_new_current_greenlet),
545 origin_greenlet(other.origin_greenlet)
546 {}
547
548 switchstack_result_t& operator=(const switchstack_result_t& other)
549 {
550 this->status = other.status;
551 this->the_new_current_greenlet = other.the_new_current_greenlet;
552 this->origin_greenlet = other.origin_greenlet;
553 return *this;
554 }
555 };
556
558 Greenlet* target,
559 const switchstack_result_t& err,
560 const bool target_was_me=false,
561 const bool was_initial_stub=false);
562
563 // Returns the previous greenlet we just switched away from.
564 virtual OwnedGreenlet g_switchstack_success() noexcept;
565
566
567 // Check the preconditions for switching to this greenlet; if they
568 // aren't met, throws PyErrOccurred. Most callers will want to
569 // catch this and clear the arguments
570 inline void check_switch_allowed() const;
571 class GreenletStartedWhileInPython : public std::runtime_error
572 {
573 public:
574 GreenletStartedWhileInPython() : std::runtime_error("")
575 {}
576 };
577
578 protected:
579
580
613 // Made virtual to facilitate subclassing UserGreenlet for testing.
615
617{
618private:
619 PyThreadState* tstate;
620public:
622 : tstate(PyThreadState_GET())
623 {
624 PyThreadState_EnterTracing(this->tstate);
625 }
626
628 {
629 PyThreadState_LeaveTracing(this->tstate);
630 this->tstate = nullptr;
631 }
632
633 inline void CallTraceFunction(const OwnedObject& tracefunc,
635 const BorrowedGreenlet& origin,
636 const BorrowedGreenlet& target)
637 {
638 // TODO: This calls tracefunc(event, (origin, target)). Add a shortcut
639 // function for that that's specialized to avoid the Py_BuildValue
640 // string parsing, or start with just using "ON" format with PyTuple_Pack(2,
641 // origin, target). That seems like what the N format is meant
642 // for.
643 // XXX: Why does event not automatically cast back to a PyObject?
644 // It tries to call the "deleted constructor ImmortalEventName
645 // const" instead.
646 assert(tracefunc);
647 assert(event);
648 assert(origin);
649 assert(target);
651 PyObject_CallFunction(
652 tracefunc.borrow(),
653 "O(OO)",
654 event.borrow(),
655 origin.borrow(),
656 target.borrow()
657 ));
658 if (!retval) {
659 throw PyErrOccurred::from_current();
660 }
661 }
662};
663
664 static void
665 g_calltrace(const OwnedObject& tracefunc,
668 const BorrowedGreenlet& target);
669 private:
670 OwnedObject g_switch_finish(const switchstack_result_t& err);
671
672 };
673
674 class UserGreenlet : public Greenlet
675 {
676 private:
678 OwnedMainGreenlet _main_greenlet;
679 OwnedObject _run_callable;
680 OwnedGreenlet _parent;
681 public:
682 static void* operator new(size_t UNUSED(count));
683 static void operator delete(void* ptr);
684
685 UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent);
686 virtual ~UserGreenlet();
687
688 virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;
689 virtual bool was_running_in_dead_thread() const noexcept;
690 virtual ThreadState* thread_state() const noexcept;
691 virtual OwnedObject g_switch();
692 virtual const OwnedObject& run() const
693 {
694 if (this->started() || !this->_run_callable) {
695 throw AttributeError("run");
696 }
697 return this->_run_callable;
698 }
699 virtual void run(const refs::BorrowedObject nrun);
700
701 virtual const OwnedGreenlet parent() const;
702 virtual void parent(const refs::BorrowedObject new_parent);
703
704 virtual const refs::BorrowedMainGreenlet main_greenlet() const;
705
706 virtual void murder_in_place();
707 virtual bool belongs_to_thread(const ThreadState* state) const;
708 virtual int tp_traverse(visitproc visit, void* arg);
709 virtual int tp_clear();
711 {
712 private:
713 OwnedGreenlet oldparent;
715 G_NO_COPIES_OF_CLS(ParentIsCurrentGuard);
716 public:
717 ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state);
719 };
720 virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state);
721 protected:
722 virtual switchstack_result_t g_initialstub(void* mark);
723 private:
724 // This function isn't meant to return.
725 // This accepts raw pointers and the ownership of them at the
726 // same time. The caller should use ``inner_bootstrap(origin.relinquish_ownership())``.
727 void inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run);
728 };
729
731 {
732 private:
734 public:
735 bool _force_switch_error = false;
736 bool _force_slp_switch_error = false;
737
738 static void* operator new(size_t UNUSED(count));
739 static void operator delete(void* ptr);
740 BrokenGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent)
741 : UserGreenlet(p, the_parent)
742 {}
743 virtual ~BrokenGreenlet()
744 {}
745
747 virtual bool force_slp_switch_error() const noexcept;
748
749 };
750
751 class MainGreenlet : public Greenlet
752 {
753 private:
756 ThreadState* _thread_state;
757 G_NO_COPIES_OF_CLS(MainGreenlet);
758 public:
759 static void* operator new(size_t UNUSED(count));
760 static void operator delete(void* ptr);
761
762 MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*);
763 virtual ~MainGreenlet();
764
765
766 virtual const OwnedObject& run() const;
767 virtual void run(const refs::BorrowedObject nrun);
768
769 virtual const OwnedGreenlet parent() const;
770 virtual void parent(const refs::BorrowedObject new_parent);
771
772 virtual const refs::BorrowedMainGreenlet main_greenlet() const;
773
774 virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;
775 virtual bool was_running_in_dead_thread() const noexcept;
776 virtual ThreadState* thread_state() const noexcept;
777 void thread_state(ThreadState*) noexcept;
778 virtual OwnedObject g_switch();
779 virtual int tp_traverse(visitproc visit, void* arg);
780 };
781
782 // Instantiate one on the stack to save the GC state,
783 // and then disable GC. When it goes out of scope, GC will be
784 // restored to its original state. Sadly, these APIs are only
785 // available on 3.10+; luckily, we only need them on 3.11+.
786#if GREENLET_PY310
787 class GCDisabledGuard
788 {
789 private:
790 int was_enabled = 0;
791 public:
792 GCDisabledGuard()
793 : was_enabled(PyGC_IsEnabled())
794 {
795 PyGC_Disable();
796 }
797
798 ~GCDisabledGuard()
799 {
800 if (this->was_enabled) {
801 PyGC_Enable();
802 }
803 }
804 };
805#endif
806
807 OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept;
808
809 //TODO: Greenlet::g_switch() should call this automatically on its
810 //return value. As it is, the module code is calling it.
811 static inline OwnedObject
812 single_result(const OwnedObject& results)
813 {
814 if (results
815 && PyTuple_Check(results.borrow())
816 && PyTuple_GET_SIZE(results.borrow()) == 1) {
817 PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0);
818 assert(result);
819 return OwnedObject::owning(result);
820 }
821 return results;
822 }
823
824
825 static OwnedObject
826 g_handle_exit(const OwnedObject& greenlet_result);
827
828
829 template<typename T>
830 void operator<<(const PyThreadState *const lhs, T& rhs)
831 {
832 rhs.operator<<(lhs);
833 }
834
835} // namespace greenlet ;
836
837#endif
Definition greenlet_exceptions.hpp:126
Definition TGreenlet.hpp:731
virtual switchstack_result_t g_switchstack(void)
Definition TBrokenGreenlet.cpp:37
Definition TGreenlet.hpp:48
Definition TGreenlet.hpp:617
Definition TGreenlet.hpp:343
virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState &current_thread_state)
Definition TGreenlet.cpp:60
OwnedObject on_switchstack_or_initialstub_failure(Greenlet *target, const switchstack_result_t &err, const bool target_was_me=false, const bool was_initial_stub=false)
Definition TGreenlet.cpp:101
virtual void murder_in_place()
Definition TGreenlet.cpp:499
void deactivate_and_free()
Definition TGreenlet.cpp:508
virtual switchstack_result_t g_switchstack(void)
Definition TGreenlet.cpp:146
Definition TGreenlet.hpp:752
Definition TGreenlet.hpp:72
Definition TGreenlet.hpp:105
Definition TGreenlet.hpp:185
StackState()
Definition TStackState.cpp:38
Definition TGreenlet.hpp:242
SwitchingArgs & operator<<=(SwitchingArgs &other)
Definition TGreenlet.hpp:277
SwitchingArgs & operator<<=(OwnedObject &args)
Definition TGreenlet.hpp:302
SwitchingArgs & operator<<=(PyObject *args)
Definition TGreenlet.hpp:290
Definition TThreadState.hpp:87
Definition TGreenlet.hpp:675
virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState &current_thread_state)
Definition TUserGreenlet.cpp:83
virtual void murder_in_place()
Definition TUserGreenlet.cpp:614
Definition greenlet_refs.hpp:600
Definition greenlet_refs.hpp:534
Definition greenlet_refs.hpp:686
Definition greenlet_refs.hpp:435
Definition greenlet_refs.hpp:301
Definition greenlet_refs.hpp:560
Definition greenlet_refs.hpp:471
Definition __init__.py:1
OwnedObject & operator<<=(OwnedObject &lhs, greenlet::SwitchingArgs &rhs) noexcept
Definition TGreenlet.cpp:359
Definition greenlet.h:22
Definition TGreenlet.hpp:513
Definition greenlet_allocator.hpp:17