summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp
diff options
context:
space:
mode:
authorcyfraeviolae <cyfraeviolae>2024-04-03 03:17:55 -0400
committercyfraeviolae <cyfraeviolae>2024-04-03 03:17:55 -0400
commit12cf076118570eebbff08c6b3090e0d4798447a1 (patch)
tree3ba25e17e3c3a5e82316558ba3864b955919ff72 /venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp
parentc45662ff3923b34614ddcc8feb9195541166dcc5 (diff)
no venv
Diffstat (limited to 'venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp')
-rw-r--r--venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp805
1 files changed, 0 insertions, 805 deletions
diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp
deleted file mode 100644
index d52ce1f..0000000
--- a/venv/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp
+++ /dev/null
@@ -1,805 +0,0 @@
-#ifndef GREENLET_GREENLET_HPP
-#define GREENLET_GREENLET_HPP
-/*
- * Declarations of the core data structures.
-*/
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-
-#include "greenlet_compiler_compat.hpp"
-#include "greenlet_refs.hpp"
-#include "greenlet_cpython_compat.hpp"
-#include "greenlet_allocator.hpp"
-
-using greenlet::refs::OwnedObject;
-using greenlet::refs::OwnedGreenlet;
-using greenlet::refs::OwnedMainGreenlet;
-using greenlet::refs::BorrowedGreenlet;
-
-#if PY_VERSION_HEX < 0x30B00A6
-# define _PyCFrame CFrame
-# define _PyInterpreterFrame _interpreter_frame
-#endif
-
-#if GREENLET_PY312
-# include "internal/pycore_frame.h"
-#endif
-
-// XXX: TODO: Work to remove all virtual functions
-// for speed of calling and size of objects (no vtable).
-// One pattern is the Curiously Recurring Template
-namespace greenlet
-{
- class ExceptionState
- {
- private:
- G_NO_COPIES_OF_CLS(ExceptionState);
-
- // Even though these are borrowed objects, we actually own
- // them, when they're not null.
- // XXX: Express that in the API.
- private:
- _PyErr_StackItem* exc_info;
- _PyErr_StackItem exc_state;
- public:
- ExceptionState();
- void operator<<(const PyThreadState *const tstate) noexcept;
- void operator>>(PyThreadState* tstate) noexcept;
- void clear() noexcept;
-
- int tp_traverse(visitproc visit, void* arg) noexcept;
- void tp_clear() noexcept;
- };
-
- template<typename T>
- void operator<<(const PyThreadState *const tstate, T& exc);
-
- class PythonStateContext
- {
- protected:
- greenlet::refs::OwnedContext _context;
- public:
- inline const greenlet::refs::OwnedContext& context() const
- {
- return this->_context;
- }
- inline greenlet::refs::OwnedContext& context()
- {
- return this->_context;
- }
-
- inline void tp_clear()
- {
- this->_context.CLEAR();
- }
-
- template<typename T>
- inline static PyObject* context(T* tstate)
- {
- return tstate->context;
- }
-
- template<typename T>
- inline static void context(T* tstate, PyObject* new_context)
- {
- tstate->context = new_context;
- tstate->context_ver++;
- }
- };
- class SwitchingArgs;
- class PythonState : public PythonStateContext
- {
- public:
- typedef greenlet::refs::OwnedReference<struct _frame> OwnedFrame;
- private:
- G_NO_COPIES_OF_CLS(PythonState);
- // We own this if we're suspended (although currently we don't
- // tp_traverse into it; that's a TODO). If we're running, it's
- // empty. If we get deallocated and *still* have a frame, it
- // won't be reachable from the place that normally decref's
- // it, so we need to do it (hence owning it).
- OwnedFrame _top_frame;
-#if GREENLET_USE_CFRAME
- _PyCFrame* cframe;
- int use_tracing;
-#endif
-#if GREENLET_PY312
- int py_recursion_depth;
- int c_recursion_depth;
-#else
- int recursion_depth;
-#endif
- int trash_delete_nesting;
-#if GREENLET_PY311
- _PyInterpreterFrame* current_frame;
- _PyStackChunk* datastack_chunk;
- PyObject** datastack_top;
- PyObject** datastack_limit;
-#endif
- // The PyInterpreterFrame list on 3.12+ contains some entries that are
- // on the C stack, which can't be directly accessed while a greenlet is
- // suspended. In order to keep greenlet gr_frame introspection working,
- // we adjust stack switching to rewrite the interpreter frame list
- // to skip these C-stack frames; we call this "exposing" the greenlet's
- // frames because it makes them valid to work with in Python. Then when
- // the greenlet is resumed we need to remember to reverse the operation
- // we did. The C-stack frames are "entry frames" which are a low-level
- // interpreter detail; they're not needed for introspection, but do
- // need to be present for the eval loop to work.
- void unexpose_frames();
-
- public:
-
- PythonState();
- // You can use this for testing whether we have a frame
- // or not. It returns const so they can't modify it.
- const OwnedFrame& top_frame() const noexcept;
-
- inline void operator<<(const PyThreadState *const tstate) noexcept;
- inline void operator>>(PyThreadState* tstate) noexcept;
- void clear() noexcept;
-
- int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) noexcept;
- void tp_clear(bool own_top_frame) noexcept;
- void set_initial_state(const PyThreadState* const tstate) noexcept;
-#if GREENLET_USE_CFRAME
- void set_new_cframe(_PyCFrame& frame) noexcept;
-#endif
-
- inline void may_switch_away() noexcept;
- inline void will_switch_from(PyThreadState *const origin_tstate) noexcept;
- void did_finish(PyThreadState* tstate) noexcept;
- };
-
- class StackState
- {
- // By having only plain C (POD) members, no virtual functions
- // or bases, we get a trivial assignment operator generated
- // for us. However, that's not safe since we do manage memory.
- // So we declare an assignment operator that only works if we
- // don't have any memory allocated. (We don't use
- // std::shared_ptr for reference counting just to keep this
- // object small)
- private:
- char* _stack_start;
- char* stack_stop;
- char* stack_copy;
- intptr_t _stack_saved;
- StackState* stack_prev;
- inline int copy_stack_to_heap_up_to(const char* const stop) noexcept;
- inline void free_stack_copy() noexcept;
-
- public:
- /**
- * Creates a started, but inactive, state, using *current*
- * as the previous.
- */
- StackState(void* mark, StackState& current);
- /**
- * Creates an inactive, unstarted, state.
- */
- StackState();
- ~StackState();
- StackState(const StackState& other);
- StackState& operator=(const StackState& other);
- inline void copy_heap_to_stack(const StackState& current) noexcept;
- inline int copy_stack_to_heap(char* const stackref, const StackState& current) noexcept;
- inline bool started() const noexcept;
- inline bool main() const noexcept;
- inline bool active() const noexcept;
- inline void set_active() noexcept;
- inline void set_inactive() noexcept;
- inline intptr_t stack_saved() const noexcept;
- inline char* stack_start() const noexcept;
- static inline StackState make_main() noexcept;
-#ifdef GREENLET_USE_STDIO
- friend std::ostream& operator<<(std::ostream& os, const StackState& s);
-#endif
-
- // Fill in [dest, dest + n) with the values that would be at
- // [src, src + n) while this greenlet is running. This is like memcpy
- // except that if the greenlet is suspended it accounts for the portion
- // of the greenlet's stack that was spilled to the heap. `src` may
- // be on this greenlet's stack, or on the heap, but not on a different
- // greenlet's stack.
- void copy_from_stack(void* dest, const void* src, size_t n) const;
- };
-#ifdef GREENLET_USE_STDIO
- std::ostream& operator<<(std::ostream& os, const StackState& s);
-#endif
-
- class SwitchingArgs
- {
- private:
- G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs);
- // If args and kwargs are both false (NULL), this is a *throw*, not a
- // switch. PyErr_... must have been called already.
- OwnedObject _args;
- OwnedObject _kwargs;
- public:
-
- SwitchingArgs()
- {}
-
- SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs)
- : _args(args),
- _kwargs(kwargs)
- {}
-
- SwitchingArgs(const SwitchingArgs& other)
- : _args(other._args),
- _kwargs(other._kwargs)
- {}
-
- const OwnedObject& args()
- {
- return this->_args;
- }
-
- const OwnedObject& kwargs()
- {
- return this->_kwargs;
- }
-
- /**
- * Moves ownership from the argument to this object.
- */
- SwitchingArgs& operator<<=(SwitchingArgs& other)
- {
- if (this != &other) {
- this->_args = other._args;
- this->_kwargs = other._kwargs;
- other.CLEAR();
- }
- return *this;
- }
-
- /**
- * Acquires ownership of the argument (consumes the reference).
- */
- SwitchingArgs& operator<<=(PyObject* args)
- {
- this->_args = OwnedObject::consuming(args);
- this->_kwargs.CLEAR();
- return *this;
- }
-
- /**
- * Acquires ownership of the argument.
- *
- * Sets the args to be the given value; clears the kwargs.
- */
- SwitchingArgs& operator<<=(OwnedObject& args)
- {
- assert(&args != &this->_args);
- this->_args = args;
- this->_kwargs.CLEAR();
- args.CLEAR();
-
- return *this;
- }
-
- explicit operator bool() const noexcept
- {
- return this->_args || this->_kwargs;
- }
-
- inline void CLEAR()
- {
- this->_args.CLEAR();
- this->_kwargs.CLEAR();
- }
-
- const std::string as_str() const noexcept
- {
- return PyUnicode_AsUTF8(
- OwnedObject::consuming(
- PyUnicode_FromFormat(
- "SwitchingArgs(args=%R, kwargs=%R)",
- this->_args.borrow(),
- this->_kwargs.borrow()
- )
- ).borrow()
- );
- }
- };
-
- class ThreadState;
-
- class UserGreenlet;
- class MainGreenlet;
-
- class Greenlet
- {
- private:
- G_NO_COPIES_OF_CLS(Greenlet);
- private:
- // XXX: Work to remove these.
- friend class ThreadState;
- friend class UserGreenlet;
- friend class MainGreenlet;
- protected:
- ExceptionState exception_state;
- SwitchingArgs switch_args;
- StackState stack_state;
- PythonState python_state;
- Greenlet(PyGreenlet* p, const StackState& initial_state);
- public:
- Greenlet(PyGreenlet* p);
- virtual ~Greenlet();
-
- const OwnedObject context() const;
-
- // You MUST call this _very_ early in the switching process to
- // prepare anything that may need prepared. This might perform
- // garbage collections or otherwise run arbitrary Python code.
- //
- // One specific use of it is for Python 3.11+, preventing
- // running arbitrary code at unsafe times. See
- // PythonState::may_switch_away().
- inline void may_switch_away()
- {
- this->python_state.may_switch_away();
- }
-
- inline void context(refs::BorrowedObject new_context);
-
- inline SwitchingArgs& args()
- {
- return this->switch_args;
- }
-
- virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0;
-
- inline intptr_t stack_saved() const noexcept
- {
- return this->stack_state.stack_saved();
- }
-
- // This is used by the macro SLP_SAVE_STATE to compute the
- // difference in stack sizes. It might be nice to handle the
- // computation ourself, but the type of the result
- // varies by platform, so doing it in the macro is the
- // simplest way.
- inline const char* stack_start() const noexcept
- {
- return this->stack_state.stack_start();
- }
-
- virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state);
- virtual OwnedObject g_switch() = 0;
- /**
- * Force the greenlet to appear dead. Used when it's not
- * possible to throw an exception into a greenlet anymore.
- *
- * This losses access to the thread state and the main greenlet.
- */
- virtual void murder_in_place();
-
- /**
- * Called when somebody notices we were running in a dead
- * thread to allow cleaning up resources (because we can't
- * raise GreenletExit into it anymore).
- * This is very similar to ``murder_in_place()``, except that
- * it DOES NOT lose the main greenlet or thread state.
- */
- inline void deactivate_and_free();
-
-
- // Called when some thread wants to deallocate a greenlet
- // object.
- // The thread may or may not be the same thread the greenlet
- // was running in.
- // The thread state will be null if the thread the greenlet
- // was running in was known to have exited.
- void deallocing_greenlet_in_thread(const ThreadState* current_state);
-
- // Must be called on 3.12+ before exposing a suspended greenlet's
- // frames to user code. This rewrites the linked list of interpreter
- // frames to skip the ones that are being stored on the C stack (which
- // can't be safely accessed while the greenlet is suspended because
- // that stack space might be hosting a different greenlet), and
- // sets PythonState::frames_were_exposed so we remember to restore
- // the original list before resuming the greenlet. The C-stack frames
- // are a low-level interpreter implementation detail; while they're
- // important to the bytecode eval loop, they're superfluous for
- // introspection purposes.
- void expose_frames();
-
-
- // TODO: Figure out how to make these non-public.
- inline void slp_restore_state() noexcept;
- inline int slp_save_state(char *const stackref) noexcept;
-
- inline bool is_currently_running_in_some_thread() const;
- virtual bool belongs_to_thread(const ThreadState* state) const;
-
- inline bool started() const
- {
- return this->stack_state.started();
- }
- inline bool active() const
- {
- return this->stack_state.active();
- }
- inline bool main() const
- {
- return this->stack_state.main();
- }
- virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0;
-
- virtual const OwnedGreenlet parent() const = 0;
- virtual void parent(const refs::BorrowedObject new_parent) = 0;
-
- inline const PythonState::OwnedFrame& top_frame()
- {
- return this->python_state.top_frame();
- }
-
- virtual const OwnedObject& run() const = 0;
- virtual void run(const refs::BorrowedObject nrun) = 0;
-
-
- virtual int tp_traverse(visitproc visit, void* arg);
- virtual int tp_clear();
-
-
- // Return the thread state that the greenlet is running in, or
- // null if the greenlet is not running or the thread is known
- // to have exited.
- virtual ThreadState* thread_state() const noexcept = 0;
-
- // Return true if the greenlet is known to have been running
- // (active) in a thread that has now exited.
- virtual bool was_running_in_dead_thread() const noexcept = 0;
-
- // Return a borrowed greenlet that is the Python object
- // this object represents.
- virtual BorrowedGreenlet self() const noexcept = 0;
-
- // For testing. If this returns true, we should pretend that
- // slp_switch() failed.
- virtual bool force_slp_switch_error() const noexcept;
-
- protected:
- inline void release_args();
-
- // The functions that must not be inlined are declared virtual.
- // We also mark them as protected, not private, so that the
- // compiler is forced to call them through a function pointer.
- // (A sufficiently smart compiler could directly call a private
- // virtual function since it can never be overridden in a
- // subclass).
-
- // Also TODO: Switch away from integer error codes and to enums,
- // or throw exceptions when possible.
- struct switchstack_result_t
- {
- int status;
- Greenlet* the_new_current_greenlet;
- OwnedGreenlet origin_greenlet;
-
- switchstack_result_t()
- : status(0),
- the_new_current_greenlet(nullptr)
- {}
-
- switchstack_result_t(int err)
- : status(err),
- the_new_current_greenlet(nullptr)
- {}
-
- switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin)
- : status(err),
- the_new_current_greenlet(state),
- origin_greenlet(origin)
- {
- }
-
- switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin)
- : status(err),
- the_new_current_greenlet(state),
- origin_greenlet(origin)
- {
- }
-
- switchstack_result_t(const switchstack_result_t& other)
- : status(other.status),
- the_new_current_greenlet(other.the_new_current_greenlet),
- origin_greenlet(other.origin_greenlet)
- {}
-
- switchstack_result_t& operator=(const switchstack_result_t& other)
- {
- this->status = other.status;
- this->the_new_current_greenlet = other.the_new_current_greenlet;
- this->origin_greenlet = other.origin_greenlet;
- return *this;
- }
- };
-
- 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);
-
- // Returns the previous greenlet we just switched away from.
- virtual OwnedGreenlet g_switchstack_success() noexcept;
-
-
- // Check the preconditions for switching to this greenlet; if they
- // aren't met, throws PyErrOccurred. Most callers will want to
- // catch this and clear the arguments
- inline void check_switch_allowed() const;
- class GreenletStartedWhileInPython : public std::runtime_error
- {
- public:
- GreenletStartedWhileInPython() : std::runtime_error("")
- {}
- };
-
- protected:
-
-
- /**
- Perform a stack switch into this greenlet.
-
- This temporarily sets the global variable
- ``switching_thread_state`` to this greenlet; as soon as the
- call to ``slp_switch`` completes, this is reset to NULL.
- Consequently, this depends on the GIL.
-
- TODO: Adopt the stackman model and pass ``slp_switch`` a
- callback function and context pointer; this eliminates the
- need for global variables altogether.
-
- Because the stack switch happens in this function, this
- function can't use its own stack (local) variables, set
- before the switch, and then accessed after the switch.
-
- Further, you con't even access ``g_thread_state_global``
- before and after the switch from the global variable.
- Because it is thread local some compilers cache it in a
- register/on the stack, notably new versions of MSVC; this
- breaks with strange crashes sometime later, because writing
- to anything in ``g_thread_state_global`` after the switch
- is actually writing to random memory. For this reason, we
- call a non-inlined function to finish the operation. (XXX:
- The ``/GT`` MSVC compiler argument probably fixes that.)
-
- It is very important that stack switch is 'atomic', i.e. no
- calls into other Python code allowed (except very few that
- are safe), because global variables are very fragile. (This
- should no longer be the case with thread-local variables.)
-
- */
- // Made virtual to facilitate subclassing UserGreenlet for testing.
- virtual switchstack_result_t g_switchstack(void);
-
-class TracingGuard
-{
-private:
- PyThreadState* tstate;
-public:
- TracingGuard()
- : tstate(PyThreadState_GET())
- {
- PyThreadState_EnterTracing(this->tstate);
- }
-
- ~TracingGuard()
- {
- PyThreadState_LeaveTracing(this->tstate);
- this->tstate = nullptr;
- }
-
- inline void CallTraceFunction(const OwnedObject& tracefunc,
- const greenlet::refs::ImmortalEventName& event,
- const BorrowedGreenlet& origin,
- const BorrowedGreenlet& target)
- {
- // TODO: This calls tracefunc(event, (origin, target)). Add a shortcut
- // function for that that's specialized to avoid the Py_BuildValue
- // string parsing, or start with just using "ON" format with PyTuple_Pack(2,
- // origin, target). That seems like what the N format is meant
- // for.
- // XXX: Why does event not automatically cast back to a PyObject?
- // It tries to call the "deleted constructor ImmortalEventName
- // const" instead.
- assert(tracefunc);
- assert(event);
- assert(origin);
- assert(target);
- greenlet::refs::NewReference retval(
- PyObject_CallFunction(
- tracefunc.borrow(),
- "O(OO)",
- event.borrow(),
- origin.borrow(),
- target.borrow()
- ));
- if (!retval) {
- throw PyErrOccurred::from_current();
- }
- }
-};
-
- static void
- g_calltrace(const OwnedObject& tracefunc,
- const greenlet::refs::ImmortalEventName& event,
- const greenlet::refs::BorrowedGreenlet& origin,
- const BorrowedGreenlet& target);
- private:
- OwnedObject g_switch_finish(const switchstack_result_t& err);
-
- };
-
- class UserGreenlet : public Greenlet
- {
- private:
- static greenlet::PythonAllocator<UserGreenlet> allocator;
- BorrowedGreenlet _self;
- OwnedMainGreenlet _main_greenlet;
- OwnedObject _run_callable;
- OwnedGreenlet _parent;
- public:
- static void* operator new(size_t UNUSED(count));
- static void operator delete(void* ptr);
-
- UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent);
- virtual ~UserGreenlet();
-
- virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;
- virtual bool was_running_in_dead_thread() const noexcept;
- virtual ThreadState* thread_state() const noexcept;
- virtual OwnedObject g_switch();
- virtual const OwnedObject& run() const
- {
- if (this->started() || !this->_run_callable) {
- throw AttributeError("run");
- }
- return this->_run_callable;
- }
- virtual void run(const refs::BorrowedObject nrun);
-
- virtual const OwnedGreenlet parent() const;
- virtual void parent(const refs::BorrowedObject new_parent);
-
- virtual const refs::BorrowedMainGreenlet main_greenlet() const;
-
- virtual BorrowedGreenlet self() const noexcept;
- virtual void murder_in_place();
- virtual bool belongs_to_thread(const ThreadState* state) const;
- virtual int tp_traverse(visitproc visit, void* arg);
- virtual int tp_clear();
- class ParentIsCurrentGuard
- {
- private:
- OwnedGreenlet oldparent;
- UserGreenlet* greenlet;
- G_NO_COPIES_OF_CLS(ParentIsCurrentGuard);
- public:
- ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state);
- ~ParentIsCurrentGuard();
- };
- virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state);
- protected:
- virtual switchstack_result_t g_initialstub(void* mark);
- private:
- // This function isn't meant to return.
- // This accepts raw pointers and the ownership of them at the
- // same time. The caller should use ``inner_bootstrap(origin.relinquish_ownership())``.
- void inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run);
- };
-
- class BrokenGreenlet : public UserGreenlet
- {
- private:
- static greenlet::PythonAllocator<BrokenGreenlet> allocator;
- public:
- bool _force_switch_error = false;
- bool _force_slp_switch_error = false;
-
- static void* operator new(size_t UNUSED(count));
- static void operator delete(void* ptr);
- BrokenGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent)
- : UserGreenlet(p, the_parent)
- {}
- virtual ~BrokenGreenlet()
- {}
-
- virtual switchstack_result_t g_switchstack(void);
- virtual bool force_slp_switch_error() const noexcept;
-
- };
-
- class MainGreenlet : public Greenlet
- {
- private:
- static greenlet::PythonAllocator<MainGreenlet> allocator;
- refs::BorrowedMainGreenlet _self;
- ThreadState* _thread_state;
- G_NO_COPIES_OF_CLS(MainGreenlet);
- public:
- static void* operator new(size_t UNUSED(count));
- static void operator delete(void* ptr);
-
- MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*);
- virtual ~MainGreenlet();
-
-
- virtual const OwnedObject& run() const;
- virtual void run(const refs::BorrowedObject nrun);
-
- virtual const OwnedGreenlet parent() const;
- virtual void parent(const refs::BorrowedObject new_parent);
-
- virtual const refs::BorrowedMainGreenlet main_greenlet() const;
-
- virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;
- virtual bool was_running_in_dead_thread() const noexcept;
- virtual ThreadState* thread_state() const noexcept;
- void thread_state(ThreadState*) noexcept;
- virtual OwnedObject g_switch();
- virtual BorrowedGreenlet self() const noexcept;
- virtual int tp_traverse(visitproc visit, void* arg);
- };
-
- // Instantiate one on the stack to save the GC state,
- // and then disable GC. When it goes out of scope, GC will be
- // restored to its original state. Sadly, these APIs are only
- // available on 3.10+; luckily, we only need them on 3.11+.
-#if GREENLET_PY310
- class GCDisabledGuard
- {
- private:
- int was_enabled = 0;
- public:
- GCDisabledGuard()
- : was_enabled(PyGC_IsEnabled())
- {
- PyGC_Disable();
- }
-
- ~GCDisabledGuard()
- {
- if (this->was_enabled) {
- PyGC_Enable();
- }
- }
- };
-#endif
-
- OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept;
-
- //TODO: Greenlet::g_switch() should call this automatically on its
- //return value. As it is, the module code is calling it.
- static inline OwnedObject
- single_result(const OwnedObject& results)
- {
- if (results
- && PyTuple_Check(results.borrow())
- && PyTuple_GET_SIZE(results.borrow()) == 1) {
- PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0);
- assert(result);
- return OwnedObject::owning(result);
- }
- return results;
- }
-
-
- static OwnedObject
- g_handle_exit(const OwnedObject& greenlet_result);
-
-
- template<typename T>
- void operator<<(const PyThreadState *const lhs, T& rhs)
- {
- rhs.operator<<(lhs);
- }
-
-} // namespace greenlet ;
-
-#endif