diff options
| author | cyfraeviolae <cyfraeviolae> | 2024-04-03 03:17:55 -0400 | 
|---|---|---|
| committer | cyfraeviolae <cyfraeviolae> | 2024-04-03 03:17:55 -0400 | 
| commit | 12cf076118570eebbff08c6b3090e0d4798447a1 (patch) | |
| tree | 3ba25e17e3c3a5e82316558ba3864b955919ff72 /venv/lib/python3.11/site-packages/greenlet | |
| parent | c45662ff3923b34614ddcc8feb9195541166dcc5 (diff) | |
no venv
Diffstat (limited to 'venv/lib/python3.11/site-packages/greenlet')
107 files changed, 0 insertions, 14437 deletions
| diff --git a/venv/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp b/venv/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp deleted file mode 100644 index 11a3bea..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::UserGreenlet. - * - * Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ - -#include "greenlet_greenlet.hpp" - -namespace greenlet { - -void* BrokenGreenlet::operator new(size_t UNUSED(count)) -{ -    return allocator.allocate(1); -} - - -void BrokenGreenlet::operator delete(void* ptr) -{ -    return allocator.deallocate(static_cast<BrokenGreenlet*>(ptr), -                                1); -} - -greenlet::PythonAllocator<greenlet::BrokenGreenlet> greenlet::BrokenGreenlet::allocator; - -bool -BrokenGreenlet::force_slp_switch_error() const noexcept -{ -    return this->_force_slp_switch_error; -} - -UserGreenlet::switchstack_result_t BrokenGreenlet::g_switchstack(void) -{ -  if (this->_force_switch_error) { -    return switchstack_result_t(-1); -  } -  return UserGreenlet::g_switchstack(); -} - -}; //namespace greenlet diff --git a/venv/lib/python3.11/site-packages/greenlet/TExceptionState.cpp b/venv/lib/python3.11/site-packages/greenlet/TExceptionState.cpp deleted file mode 100644 index ee6b191..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TExceptionState.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef GREENLET_EXCEPTION_STATE_CPP -#define GREENLET_EXCEPTION_STATE_CPP - -#include <Python.h> -#include "greenlet_greenlet.hpp" - -namespace greenlet { - - -ExceptionState::ExceptionState() -{ -    this->clear(); -} - -void ExceptionState::operator<<(const PyThreadState *const tstate) noexcept -{ -    this->exc_info = tstate->exc_info; -    this->exc_state = tstate->exc_state; -} - -void ExceptionState::operator>>(PyThreadState *const tstate) noexcept -{ -    tstate->exc_state = this->exc_state; -    tstate->exc_info = -        this->exc_info ? this->exc_info : &tstate->exc_state; -    this->clear(); -} - -void ExceptionState::clear() noexcept -{ -    this->exc_info = nullptr; -    this->exc_state.exc_value = nullptr; -#if !GREENLET_PY311 -    this->exc_state.exc_type = nullptr; -    this->exc_state.exc_traceback = nullptr; -#endif -    this->exc_state.previous_item = nullptr; -} - -int ExceptionState::tp_traverse(visitproc visit, void* arg) noexcept -{ -    Py_VISIT(this->exc_state.exc_value); -#if !GREENLET_PY311 -    Py_VISIT(this->exc_state.exc_type); -    Py_VISIT(this->exc_state.exc_traceback); -#endif -    return 0; -} - -void ExceptionState::tp_clear() noexcept -{ -    Py_CLEAR(this->exc_state.exc_value); -#if !GREENLET_PY311 -    Py_CLEAR(this->exc_state.exc_type); -    Py_CLEAR(this->exc_state.exc_traceback); -#endif -} - - -}; // namespace greenlet - -#endif // GREENLET_EXCEPTION_STATE_CPP diff --git a/venv/lib/python3.11/site-packages/greenlet/TGreenlet.cpp b/venv/lib/python3.11/site-packages/greenlet/TGreenlet.cpp deleted file mode 100644 index 51f8995..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TGreenlet.cpp +++ /dev/null @@ -1,714 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::Greenlet. - * - * Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ - -#include "greenlet_internal.hpp" -#include "greenlet_greenlet.hpp" -#include "greenlet_thread_state.hpp" - -#include "TGreenletGlobals.cpp" -#include "TThreadStateDestroy.cpp" - -namespace greenlet { - -Greenlet::Greenlet(PyGreenlet* p) -{ -    p ->pimpl = this; -} - -Greenlet::~Greenlet() -{ -    // XXX: Can't do this. tp_clear is a virtual function, and by the -    // time we're here, we've sliced off our child classes. -    //this->tp_clear(); -} - -Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack) -    : stack_state(initial_stack) -{ -    // can't use a delegating constructor because of -    // MSVC for Python 2.7 -    p->pimpl = this; -} - -bool -Greenlet::force_slp_switch_error() const noexcept -{ -    return false; -} - -void -Greenlet::release_args() -{ -    this->switch_args.CLEAR(); -} - -/** - * CAUTION: This will allocate memory and may trigger garbage - * collection and arbitrary Python code. - */ -OwnedObject -Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state)) -{ -    // If we're killed because we lost all references in the -    // middle of a switch, that's ok. Don't reset the args/kwargs, -    // we still want to pass them to the parent. -    PyErr_SetString(mod_globs->PyExc_GreenletExit, -                    "Killing the greenlet because all references have vanished."); -    // To get here it had to have run before -    return this->g_switch(); -} - -inline void -Greenlet::slp_restore_state() noexcept -{ -#ifdef SLP_BEFORE_RESTORE_STATE -    SLP_BEFORE_RESTORE_STATE(); -#endif -    this->stack_state.copy_heap_to_stack( -           this->thread_state()->borrow_current()->stack_state); -} - - -inline int -Greenlet::slp_save_state(char *const stackref) noexcept -{ -    // XXX: This used to happen in the middle, before saving, but -    // after finding the next owner. Does that matter? This is -    // only defined for Sparc/GCC where it flushes register -    // windows to the stack (I think) -#ifdef SLP_BEFORE_SAVE_STATE -    SLP_BEFORE_SAVE_STATE(); -#endif -    return this->stack_state.copy_stack_to_heap(stackref, -                                                this->thread_state()->borrow_current()->stack_state); -} - -/** - * CAUTION: This will allocate memory and may trigger garbage - * collection and arbitrary Python code. - */ -OwnedObject -Greenlet::on_switchstack_or_initialstub_failure( -    Greenlet* target, -    const Greenlet::switchstack_result_t& err, -    const bool target_was_me, -    const bool was_initial_stub) -{ -    // If we get here, either g_initialstub() -    // failed, or g_switchstack() failed. Either one of those -    // cases SHOULD leave us in the original greenlet with a valid stack. -    if (!PyErr_Occurred()) { -        PyErr_SetString( -            PyExc_SystemError, -            was_initial_stub -            ? "Failed to switch stacks into a greenlet for the first time." -            : "Failed to switch stacks into a running greenlet."); -    } -    this->release_args(); - -    if (target && !target_was_me) { -        target->murder_in_place(); -    } - -    assert(!err.the_new_current_greenlet); -    assert(!err.origin_greenlet); -    return OwnedObject(); - -} - -OwnedGreenlet -Greenlet::g_switchstack_success() noexcept -{ -    PyThreadState* tstate = PyThreadState_GET(); -    // restore the saved state -    this->python_state >> tstate; -    this->exception_state >> tstate; - -    // The thread state hasn't been changed yet. -    ThreadState* thread_state = this->thread_state(); -    OwnedGreenlet result(thread_state->get_current()); -    thread_state->set_current(this->self()); -    //assert(thread_state->borrow_current().borrow() == this->_self); -    return result; -} - -Greenlet::switchstack_result_t -Greenlet::g_switchstack(void) -{ -    // if any of these assertions fail, it's likely because we -    // switched away and tried to switch back to us. Early stages of -    // switching are not reentrant because we re-use ``this->args()``. -    // Switching away would happen if we trigger a garbage collection -    // (by just using some Python APIs that happen to allocate Python -    // objects) and some garbage had weakref callbacks or __del__ that -    // switches (people don't write code like that by hand, but with -    // gevent it's possible without realizing it) -    assert(this->args() || PyErr_Occurred()); -    { /* save state */ -        if (this->thread_state()->is_current(this->self())) { -            // Hmm, nothing to do. -            // TODO: Does this bypass trace events that are -            // important? -            return switchstack_result_t(0, -                                        this, this->thread_state()->borrow_current()); -        } -        BorrowedGreenlet current = this->thread_state()->borrow_current(); -        PyThreadState* tstate = PyThreadState_GET(); - -        current->python_state << tstate; -        current->exception_state << tstate; -        this->python_state.will_switch_from(tstate); -        switching_thread_state = this; -        current->expose_frames(); -    } -    assert(this->args() || PyErr_Occurred()); -    // If this is the first switch into a greenlet, this will -    // return twice, once with 1 in the new greenlet, once with 0 -    // in the origin. -    int err; -    if (this->force_slp_switch_error()) { -        err = -1; -    } -    else { -        err = slp_switch(); -    } - -    if (err < 0) { /* error */ -        // Tested by -        // test_greenlet.TestBrokenGreenlets.test_failed_to_slp_switch_into_running -        // -        // It's not clear if it's worth trying to clean up and -        // continue here. Failing to switch stacks is a big deal which -        // may not be recoverable (who knows what state the stack is in). -        // Also, we've stolen references in preparation for calling -        // ``g_switchstack_success()`` and we don't have a clean -        // mechanism for backing that all out. -        Py_FatalError("greenlet: Failed low-level slp_switch(). The stack is probably corrupt."); -    } - -    // No stack-based variables are valid anymore. - -    // But the global is volatile so we can reload it without the -    // compiler caching it from earlier. -    Greenlet* greenlet_that_switched_in = switching_thread_state; // aka this -    switching_thread_state = nullptr; -    // except that no stack variables are valid, we would: -    // assert(this == greenlet_that_switched_in); - -    // switchstack success is where we restore the exception state, -    // etc. It returns the origin greenlet because its convenient. - -    OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success(); -    assert(greenlet_that_switched_in->args() || PyErr_Occurred()); -    return switchstack_result_t(err, greenlet_that_switched_in, origin); -} - - -inline void -Greenlet::check_switch_allowed() const -{ -    // TODO: Make this take a parameter of the current greenlet, -    // or current main greenlet, to make the check for -    // cross-thread switching cheaper. Surely somewhere up the -    // call stack we've already accessed the thread local variable. - -    // We expect to always have a main greenlet now; accessing the thread state -    // created it. However, if we get here and cleanup has already -    // begun because we're a greenlet that was running in a -    // (now dead) thread, these invariants will not hold true. In -    // fact, accessing `this->thread_state` may not even be possible. - -    // If the thread this greenlet was running in is dead, -    // we'll still have a reference to a main greenlet, but the -    // thread state pointer we have is bogus. -    // TODO: Give the objects an API to determine if they belong -    // to a dead thread. - -    const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage(); - -    if (!main_greenlet) { -        throw PyErrOccurred(mod_globs->PyExc_GreenletError, -                            "cannot switch to a garbage collected greenlet"); -    } - -    if (!main_greenlet->thread_state()) { -        throw PyErrOccurred(mod_globs->PyExc_GreenletError, -                            "cannot switch to a different thread (which happens to have exited)"); -    } - -    // The main greenlet we found was from the .parent lineage. -    // That may or may not have any relationship to the main -    // greenlet of the running thread. We can't actually access -    // our this->thread_state members to try to check that, -    // because it could be in the process of getting destroyed, -    // but setting the main_greenlet->thread_state member to NULL -    // may not be visible yet. So we need to check against the -    // current thread state (once the cheaper checks are out of -    // the way) -    const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet(); -    if ( -        // lineage main greenlet is not this thread's greenlet -        current_main_greenlet != main_greenlet -        || ( -            // atteched to some thread -            this->main_greenlet() -            // XXX: Same condition as above. Was this supposed to be -            // this->main_greenlet()? -            && current_main_greenlet != main_greenlet) -        // switching into a known dead thread (XXX: which, if we get here, -        // is bad, because we just accessed the thread state, which is -        // gone!) -        || (!current_main_greenlet->thread_state())) { -        // CAUTION: This may trigger memory allocations, gc, and -        // arbitrary Python code. -        throw PyErrOccurred(mod_globs->PyExc_GreenletError, -                            "cannot switch to a different thread"); -    } -} - -const OwnedObject -Greenlet::context() const -{ -    using greenlet::PythonStateContext; -    OwnedObject result; - -    if (this->is_currently_running_in_some_thread()) { -        /* Currently running greenlet: context is stored in the thread state, -           not the greenlet object. */ -        if (GET_THREAD_STATE().state().is_current(this->self())) { -            result = PythonStateContext::context(PyThreadState_GET()); -        } -        else { -            throw ValueError( -                            "cannot get context of a " -                            "greenlet that is running in a different thread"); -        } -    } -    else { -        /* Greenlet is not running: just return context. */ -        result = this->python_state.context(); -    } -    if (!result) { -        result = OwnedObject::None(); -    } -    return result; -} - - -void -Greenlet::context(BorrowedObject given) -{ -    using greenlet::PythonStateContext; -    if (!given) { -        throw AttributeError("can't delete context attribute"); -    } -    if (given.is_None()) { -        /* "Empty context" is stored as NULL, not None. */ -        given = nullptr; -    } - -    //checks type, incrs refcnt -    greenlet::refs::OwnedContext context(given); -    PyThreadState* tstate = PyThreadState_GET(); - -    if (this->is_currently_running_in_some_thread()) { -        if (!GET_THREAD_STATE().state().is_current(this->self())) { -            throw ValueError("cannot set context of a greenlet" -                             " that is running in a different thread"); -        } - -        /* Currently running greenlet: context is stored in the thread state, -           not the greenlet object. */ -        OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate)); -        PythonStateContext::context(tstate, context.relinquish_ownership()); -    } -    else { -        /* Greenlet is not running: just set context. Note that the -           greenlet may be dead.*/ -        this->python_state.context() = context; -    } -} - -/** - * CAUTION: May invoke arbitrary Python code. - * - * Figure out what the result of ``greenlet.switch(arg, kwargs)`` - * should be and transfers ownership of it to the left-hand-side. - * - * If switch() was just passed an arg tuple, then we'll just return that. - * If only keyword arguments were passed, then we'll pass the keyword - * argument dict. Otherwise, we'll create a tuple of (args, kwargs) and - * return both. - * - * CAUTION: This may allocate a new tuple object, which may - * cause the Python garbage collector to run, which in turn may - * run arbitrary Python code that switches. - */ -OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept -{ -    // Because this may invoke arbitrary Python code, which could -    // result in switching back to us, we need to get the -    // arguments locally on the stack. -    assert(rhs); -    OwnedObject args = rhs.args(); -    OwnedObject kwargs = rhs.kwargs(); -    rhs.CLEAR(); -    // We shouldn't be called twice for the same switch. -    assert(args || kwargs); -    assert(!rhs); - -    if (!kwargs) { -        lhs = args; -    } -    else if (!PyDict_Size(kwargs.borrow())) { -        lhs = args; -    } -    else if (!PySequence_Length(args.borrow())) { -        lhs = kwargs; -    } -    else { -        // PyTuple_Pack allocates memory, may GC, may run arbitrary -        // Python code. -        lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow())); -    } -    return lhs; -} - -static OwnedObject -g_handle_exit(const OwnedObject& greenlet_result) -{ -    if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) { -        /* catch and ignore GreenletExit */ -        PyErrFetchParam val; -        PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam()); -        if (!val) { -            return OwnedObject::None(); -        } -        return OwnedObject(val); -    } - -    if (greenlet_result) { -        // package the result into a 1-tuple -        // PyTuple_Pack increments the reference of its arguments, -        // so we always need to decref the greenlet result; -        // the owner will do that. -        return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow())); -    } - -    return OwnedObject(); -} - - - -/** - * May run arbitrary Python code. - */ -OwnedObject -Greenlet::g_switch_finish(const switchstack_result_t& err) -{ -    assert(err.the_new_current_greenlet == this); - -    ThreadState& state = *this->thread_state(); -    // Because calling the trace function could do arbitrary things, -    // including switching away from this greenlet and then maybe -    // switching back, we need to capture the arguments now so that -    // they don't change. -    OwnedObject result; -    if (this->args()) { -        result <<= this->args(); -    } -    else { -        assert(PyErr_Occurred()); -    } -    assert(!this->args()); -    try { -        // Our only caller handles the bad error case -        assert(err.status >= 0); -        assert(state.borrow_current() == this->self()); -        if (OwnedObject tracefunc = state.get_tracefunc()) { -            assert(result || PyErr_Occurred()); -            g_calltrace(tracefunc, -                        result ? mod_globs->event_switch : mod_globs->event_throw, -                        err.origin_greenlet, -                        this->self()); -        } -        // The above could have invoked arbitrary Python code, but -        // it couldn't switch back to this object and *also* -        // throw an exception, so the args won't have changed. - -        if (PyErr_Occurred()) { -            // We get here if we fell of the end of the run() function -            // raising an exception. The switch itself was -            // successful, but the function raised. -            // valgrind reports that memory allocated here can still -            // be reached after a test run. -            throw PyErrOccurred::from_current(); -        } -        return result; -    } -    catch (const PyErrOccurred&) { -        /* Turn switch errors into switch throws */ -        /* Turn trace errors into switch throws */ -        this->release_args(); -        throw; -    } -} - -void -Greenlet::g_calltrace(const OwnedObject& tracefunc, -                      const greenlet::refs::ImmortalEventName& event, -                      const BorrowedGreenlet& origin, -                      const BorrowedGreenlet& target) -{ -    PyErrPieces saved_exc; -    try { -        TracingGuard tracing_guard; -        // TODO: We have saved the active exception (if any) that's -        // about to be raised. In the 'throw' case, we could provide -        // the exception to the tracefunction, which seems very helpful. -        tracing_guard.CallTraceFunction(tracefunc, event, origin, target); -    } -    catch (const PyErrOccurred&) { -        // In case of exceptions trace function is removed, -        // and any existing exception is replaced with the tracing -        // exception. -        GET_THREAD_STATE().state().set_tracefunc(Py_None); -        throw; -    } - -    saved_exc.PyErrRestore(); -    assert( -        (event == mod_globs->event_throw && PyErr_Occurred()) -        || (event == mod_globs->event_switch && !PyErr_Occurred()) -    ); -} - -void -Greenlet::murder_in_place() -{ -    if (this->active()) { -        assert(!this->is_currently_running_in_some_thread()); -        this->deactivate_and_free(); -    } -} - -inline void -Greenlet::deactivate_and_free() -{ -    if (!this->active()) { -        return; -    } -    // Throw away any saved stack. -    this->stack_state = StackState(); -    assert(!this->stack_state.active()); -    // Throw away any Python references. -    // We're holding a borrowed reference to the last -    // frame we executed. Since we borrowed it, the -    // normal traversal, clear, and dealloc functions -    // ignore it, meaning it leaks. (The thread state -    // object can't find it to clear it when that's -    // deallocated either, because by definition if we -    // got an object on this list, it wasn't -    // running and the thread state doesn't have -    // this frame.) -    // So here, we *do* clear it. -    this->python_state.tp_clear(true); -} - -bool -Greenlet::belongs_to_thread(const ThreadState* thread_state) const -{ -    if (!this->thread_state() // not running anywhere, or thread -                              // exited -        || !thread_state) { // same, or there is no thread state. -        return false; -    } -    return true; -} - - -void -Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state) -{ -    /* Cannot raise an exception to kill the greenlet if -       it is not running in the same thread! */ -    if (this->belongs_to_thread(current_thread_state)) { -        assert(current_thread_state); -        // To get here it had to have run before -        /* Send the greenlet a GreenletExit exception. */ - -        // We don't care about the return value, only whether an -        // exception happened. -        this->throw_GreenletExit_during_dealloc(*current_thread_state); -        return; -    } - -    // Not the same thread! Temporarily save the greenlet -    // into its thread's deleteme list, *if* it exists. -    // If that thread has already exited, and processed its pending -    // cleanup, we'll never be able to clean everything up: we won't -    // be able to raise an exception. -    // That's mostly OK! Since we can't add it to a list, our refcount -    // won't increase, and we'll go ahead with the DECREFs later. -    ThreadState *const  thread_state = this->thread_state(); -    if (thread_state) { -        thread_state->delete_when_thread_running(this->self()); -    } -    else { -        // The thread is dead, we can't raise an exception. -        // We need to make it look non-active, though, so that dealloc -        // finishes killing it. -        this->deactivate_and_free(); -    } -    return; -} - - -int -Greenlet::tp_traverse(visitproc visit, void* arg) -{ - -    int result; -    if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) { -        return result; -    } -    //XXX: This is ugly. But so is handling everything having to do -    //with the top frame. -    bool visit_top_frame = this->was_running_in_dead_thread(); -    // When true, the thread is dead. Our implicit weak reference to the -    // frame is now all that's left; we consider ourselves to -    // strongly own it now. -    if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) { -        return result; -    } -    return 0; -} - -int -Greenlet::tp_clear() -{ -    bool own_top_frame = this->was_running_in_dead_thread(); -    this->exception_state.tp_clear(); -    this->python_state.tp_clear(own_top_frame); -    return 0; -} - -bool Greenlet::is_currently_running_in_some_thread() const -{ -    return this->stack_state.active() && !this->python_state.top_frame(); -} - -#if GREENLET_PY312 -void GREENLET_NOINLINE(Greenlet::expose_frames)() -{ -    if (!this->python_state.top_frame()) { -        return; -    } - -    _PyInterpreterFrame* last_complete_iframe = nullptr; -    _PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame; -    while (iframe) { -        // We must make a copy before looking at the iframe contents, -        // since iframe might point to a portion of the greenlet's C stack -        // that was spilled when switching greenlets. -        _PyInterpreterFrame iframe_copy; -        this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe)); -        if (!_PyFrame_IsIncomplete(&iframe_copy)) { -            // If the iframe were OWNED_BY_CSTACK then it would always be -            // incomplete. Since it's not incomplete, it's not on the C stack -            // and we can access it through the original `iframe` pointer -            // directly.  This is important since GetFrameObject might -            // lazily _create_ the frame object and we don't want the -            // interpreter to lose track of it. -            assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK); - -            // We really want to just write: -            //     PyFrameObject* frame = _PyFrame_GetFrameObject(iframe); -            // but _PyFrame_GetFrameObject calls _PyFrame_MakeAndSetFrameObject -            // which is not a visible symbol in libpython. The easiest -            // way to get a public function to call it is using -            // PyFrame_GetBack, which is defined as follows: -            //     assert(frame != NULL); -            //     assert(!_PyFrame_IsIncomplete(frame->f_frame)); -            //     PyFrameObject *back = frame->f_back; -            //     if (back == NULL) { -            //         _PyInterpreterFrame *prev = frame->f_frame->previous; -            //         prev = _PyFrame_GetFirstComplete(prev); -            //         if (prev) { -            //             back = _PyFrame_GetFrameObject(prev); -            //         } -            //     } -            //     return (PyFrameObject*)Py_XNewRef(back); -            if (!iframe->frame_obj) { -                PyFrameObject dummy_frame; -                _PyInterpreterFrame dummy_iframe; -                dummy_frame.f_back = nullptr; -                dummy_frame.f_frame = &dummy_iframe; -                // force the iframe to be considered complete without -                // needing to check its code object: -                dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR; -                dummy_iframe.previous = iframe; -                assert(!_PyFrame_IsIncomplete(&dummy_iframe)); -                // Drop the returned reference immediately; the iframe -                // continues to hold a strong reference -                Py_XDECREF(PyFrame_GetBack(&dummy_frame)); -                assert(iframe->frame_obj); -            } - -            // This is a complete frame, so make the last one of those we saw -            // point at it, bypassing any incomplete frames (which may have -            // been on the C stack) in between the two. We're overwriting -            // last_complete_iframe->previous and need that to be reversible, -            // so we store the original previous ptr in the frame object -            // (which we must have created on a previous iteration through -            // this loop). The frame object has a bunch of storage that is -            // only used when its iframe is OWNED_BY_FRAME_OBJECT, which only -            // occurs when the frame object outlives the frame's execution, -            // which can't have happened yet because the frame is currently -            // executing as far as the interpreter is concerned. So, we can -            // reuse it for our own purposes. -            assert(iframe->owner == FRAME_OWNED_BY_THREAD -                   || iframe->owner == FRAME_OWNED_BY_GENERATOR); -            if (last_complete_iframe) { -                assert(last_complete_iframe->frame_obj); -                memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], -                       &last_complete_iframe->previous, sizeof(void *)); -                last_complete_iframe->previous = iframe; -            } -            last_complete_iframe = iframe; -        } -        // Frames that are OWNED_BY_FRAME_OBJECT are linked via the -        // frame's f_back while all others are linked via the iframe's -        // previous ptr. Since all the frames we traverse are running -        // as far as the interpreter is concerned, we don't have to -        // worry about the OWNED_BY_FRAME_OBJECT case. -        iframe = iframe_copy.previous; -    } - -    // Give the outermost complete iframe a null previous pointer to -    // account for any potential incomplete/C-stack iframes between it -    // and the actual top-of-stack -    if (last_complete_iframe) { -        assert(last_complete_iframe->frame_obj); -        memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], -               &last_complete_iframe->previous, sizeof(void *)); -        last_complete_iframe->previous = nullptr; -    } -} -#else -void Greenlet::expose_frames() -{ - -} -#endif - -}; // namespace greenlet diff --git a/venv/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp b/venv/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp deleted file mode 100644 index c71c963..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of GreenletGlobals. - * - * Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef T_GREENLET_GLOBALS -#define T_GREENLET_GLOBALS - -#include "greenlet_refs.hpp" -#include "greenlet_exceptions.hpp" -#include "greenlet_thread_support.hpp" -#include "greenlet_thread_state.hpp" - -namespace greenlet { - -// This encapsulates what were previously module global "constants" -// established at init time. -// This is a step towards Python3 style module state that allows -// reloading. -// -// In an earlier iteration of this code, we used placement new to be -// able to allocate this object statically still, so that references -// to its members don't incur an extra pointer indirection. -// But under some scenarios, that could result in crashes at -// shutdown because apparently the destructor was getting run twice? -class GreenletGlobals -{ - -public: -    const greenlet::refs::ImmortalEventName event_switch; -    const greenlet::refs::ImmortalEventName event_throw; -    const greenlet::refs::ImmortalException PyExc_GreenletError; -    const greenlet::refs::ImmortalException PyExc_GreenletExit; -    const greenlet::refs::ImmortalObject empty_tuple; -    const greenlet::refs::ImmortalObject empty_dict; -    const greenlet::refs::ImmortalString str_run; -    Mutex* const thread_states_to_destroy_lock; -    greenlet::cleanup_queue_t thread_states_to_destroy; - -    GreenletGlobals() : -        event_switch("switch"), -        event_throw("throw"), -        PyExc_GreenletError("greenlet.error"), -        PyExc_GreenletExit("greenlet.GreenletExit", PyExc_BaseException), -        empty_tuple(Require(PyTuple_New(0))), -        empty_dict(Require(PyDict_New())), -        str_run("run"), -        thread_states_to_destroy_lock(new Mutex()) -    {} - -    ~GreenletGlobals() -    { -        // This object is (currently) effectively immortal, and not -        // just because of those placement new tricks; if we try to -        // deallocate the static object we allocated, and overwrote, -        // we would be doing so at C++ teardown time, which is after -        // the final Python GIL is released, and we can't use the API -        // then. -        // (The members will still be destructed, but they also don't -        // do any deallocation.) -    } - -    void queue_to_destroy(ThreadState* ts) const -    { -        // we're currently accessed through a static const object, -        // implicitly marking our members as const, so code can't just -        // call push_back (or pop_back) without casting away the -        // const. -        // -        // Do that for callers. -        greenlet::cleanup_queue_t& q = const_cast<greenlet::cleanup_queue_t&>(this->thread_states_to_destroy); -        q.push_back(ts); -    } - -    ThreadState* take_next_to_destroy() const -    { -        greenlet::cleanup_queue_t& q = const_cast<greenlet::cleanup_queue_t&>(this->thread_states_to_destroy); -        ThreadState* result = q.back(); -        q.pop_back(); -        return result; -    } -}; - -}; // namespace greenlet - -static const greenlet::GreenletGlobals* mod_globs; - -#endif // T_GREENLET_GLOBALS diff --git a/venv/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp b/venv/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp deleted file mode 100644 index c33aadb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::MainGreenlet. - * - * Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ - -#include "greenlet_greenlet.hpp" -#include "greenlet_thread_state.hpp" - - -// Protected by the GIL. Incremented when we create a main greenlet, -// in a new thread, decremented when it is destroyed. -static Py_ssize_t G_TOTAL_MAIN_GREENLETS; - -namespace greenlet { -greenlet::PythonAllocator<MainGreenlet> MainGreenlet::allocator; - -void* MainGreenlet::operator new(size_t UNUSED(count)) -{ -    return allocator.allocate(1); -} - - -void MainGreenlet::operator delete(void* ptr) -{ -    return allocator.deallocate(static_cast<MainGreenlet*>(ptr), -                                1); -} - - -MainGreenlet::MainGreenlet(PyGreenlet* p, ThreadState* state) -    : Greenlet(p, StackState::make_main()), -      _self(p), -      _thread_state(state) -{ -    G_TOTAL_MAIN_GREENLETS++; -} - -MainGreenlet::~MainGreenlet() -{ -    G_TOTAL_MAIN_GREENLETS--; -    this->tp_clear(); -} - -ThreadState* -MainGreenlet::thread_state() const noexcept -{ -    return this->_thread_state; -} - -void -MainGreenlet::thread_state(ThreadState* t) noexcept -{ -    assert(!t); -    this->_thread_state = t; -} - -BorrowedGreenlet -MainGreenlet::self() const noexcept -{ -    return BorrowedGreenlet(this->_self.borrow()); -} - - -const BorrowedMainGreenlet -MainGreenlet::main_greenlet() const -{ -    return this->_self; -} - -BorrowedMainGreenlet -MainGreenlet::find_main_greenlet_in_lineage() const -{ -    return BorrowedMainGreenlet(this->_self); -} - -bool -MainGreenlet::was_running_in_dead_thread() const noexcept -{ -    return !this->_thread_state; -} - -OwnedObject -MainGreenlet::g_switch() -{ -    try { -        this->check_switch_allowed(); -    } -    catch (const PyErrOccurred&) { -        this->release_args(); -        throw; -    } - -    switchstack_result_t err = this->g_switchstack(); -    if (err.status < 0) { -        // XXX: This code path is untested, but it is shared -        // with the UserGreenlet path that is tested. -        return this->on_switchstack_or_initialstub_failure( -            this, -            err, -            true, // target was me -            false // was initial stub -        ); -    } - -    return err.the_new_current_greenlet->g_switch_finish(err); -} - -int -MainGreenlet::tp_traverse(visitproc visit, void* arg) -{ -    if (this->_thread_state) { -        // we've already traversed main, (self), don't do it again. -        int result = this->_thread_state->tp_traverse(visit, arg, false); -        if (result) { -            return result; -        } -    } -    return Greenlet::tp_traverse(visit, arg); -} - -const OwnedObject& -MainGreenlet::run() const -{ -    throw AttributeError("Main greenlets do not have a run attribute."); -} - -void -MainGreenlet::run(const BorrowedObject UNUSED(nrun)) -{ -   throw AttributeError("Main greenlets do not have a run attribute."); -} - -void -MainGreenlet::parent(const BorrowedObject raw_new_parent) -{ -    if (!raw_new_parent) { -        throw AttributeError("can't delete attribute"); -    } -    throw AttributeError("cannot set the parent of a main greenlet"); -} - -const OwnedGreenlet -MainGreenlet::parent() const -{ -    return OwnedGreenlet(); // null becomes None -} - -}; // namespace greenlet diff --git a/venv/lib/python3.11/site-packages/greenlet/TPythonState.cpp b/venv/lib/python3.11/site-packages/greenlet/TPythonState.cpp deleted file mode 100644 index 465d417..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TPythonState.cpp +++ /dev/null @@ -1,375 +0,0 @@ -#ifndef GREENLET_PYTHON_STATE_CPP -#define GREENLET_PYTHON_STATE_CPP - -#include <Python.h> -#include "greenlet_greenlet.hpp" - -namespace greenlet { - -PythonState::PythonState() -    : _top_frame() -#if GREENLET_USE_CFRAME -    ,cframe(nullptr) -    ,use_tracing(0) -#endif -#if GREENLET_PY312 -    ,py_recursion_depth(0) -    ,c_recursion_depth(0) -#else -    ,recursion_depth(0) -#endif -    ,trash_delete_nesting(0) -#if GREENLET_PY311 -    ,current_frame(nullptr) -    ,datastack_chunk(nullptr) -    ,datastack_top(nullptr) -    ,datastack_limit(nullptr) -#endif -{ -#if GREENLET_USE_CFRAME -    /* -      The PyThreadState->cframe pointer usually points to memory on -      the stack, alloceted in a call into PyEval_EvalFrameDefault. - -      Initially, before any evaluation begins, it points to the -      initial PyThreadState object's ``root_cframe`` object, which is -      statically allocated for the lifetime of the thread. - -      A greenlet can last for longer than a call to -      PyEval_EvalFrameDefault, so we can't set its ``cframe`` pointer -      to be the current ``PyThreadState->cframe``; nor could we use -      one from the greenlet parent for the same reason. Yet a further -      no: we can't allocate one scoped to the greenlet and then -      destroy it when the greenlet is deallocated, because inside the -      interpreter the _PyCFrame objects form a linked list, and that too -      can result in accessing memory beyond its dynamic lifetime (if -      the greenlet doesn't actually finish before it dies, its entry -      could still be in the list). - -      Using the ``root_cframe`` is problematic, though, because its -      members are never modified by the interpreter and are set to 0, -      meaning that its ``use_tracing`` flag is never updated. We don't -      want to modify that value in the ``root_cframe`` ourself: it -      *shouldn't* matter much because we should probably never get -      back to the point where that's the only cframe on the stack; -      even if it did matter, the major consequence of an incorrect -      value for ``use_tracing`` is that if its true the interpreter -      does some extra work --- however, it's just good code hygiene. - -      Our solution: before a greenlet runs, after its initial -      creation, it uses the ``root_cframe`` just to have something to -      put there. However, once the greenlet is actually switched to -      for the first time, ``g_initialstub`` (which doesn't actually -      "return" while the greenlet is running) stores a new _PyCFrame on -      its local stack, and copies the appropriate values from the -      currently running _PyCFrame; this is then made the _PyCFrame for the -      newly-minted greenlet. ``g_initialstub`` then proceeds to call -      ``glet.run()``, which results in ``PyEval_...`` adding the -      _PyCFrame to the list. Switches continue as normal. Finally, when -      the greenlet finishes, the call to ``glet.run()`` returns and -      the _PyCFrame is taken out of the linked list and the stack value -      is now unused and free to expire. - -      XXX: I think we can do better. If we're deallocing in the same -      thread, can't we traverse the list and unlink our frame? -      Can we just keep a reference to the thread state in case we -      dealloc in another thread? (Is that even possible if we're still -      running and haven't returned from g_initialstub?) -    */ -    this->cframe = &PyThreadState_GET()->root_cframe; -#endif -} - - -inline void PythonState::may_switch_away() noexcept -{ -#if GREENLET_PY311 -    // PyThreadState_GetFrame is probably going to have to allocate a -    // new frame object. That may trigger garbage collection. Because -    // we call this during the early phases of a switch (it doesn't -    // matter to which greenlet, as this has a global effect), if a GC -    // triggers a switch away, two things can happen, both bad: -    // - We might not get switched back to, halting forward progress. -    //   this is pathological, but possible. -    // - We might get switched back to with a different set of -    //   arguments or a throw instead of a switch. That would corrupt -    //   our state (specifically, PyErr_Occurred() and this->args() -    //   would no longer agree). -    // -    // Thus, when we call this API, we need to have GC disabled. -    // This method serves as a bottleneck we call when maybe beginning -    // a switch. In this way, it is always safe -- no risk of GC -- to -    // use ``_GetFrame()`` whenever we need to, just as it was in -    // <=3.10 (because subsequent calls will be cached and not -    // allocate memory). - -    GCDisabledGuard no_gc; -    Py_XDECREF(PyThreadState_GetFrame(PyThreadState_GET())); -#endif -} - -void PythonState::operator<<(const PyThreadState *const tstate) noexcept -{ -    this->_context.steal(tstate->context); -#if GREENLET_USE_CFRAME -    /* -      IMPORTANT: ``cframe`` is a pointer into the STACK. Thus, because -      the call to ``slp_switch()`` changes the contents of the stack, -      you cannot read from ``ts_current->cframe`` after that call and -      necessarily get the same values you get from reading it here. -      Anything you need to restore from now to then must be saved in a -      global/threadlocal variable (because we can't use stack -      variables here either). For things that need to persist across -      the switch, use `will_switch_from`. -    */ -    this->cframe = tstate->cframe; -  #if !GREENLET_PY312 -    this->use_tracing = tstate->cframe->use_tracing; -  #endif -#endif // GREENLET_USE_CFRAME -#if GREENLET_PY311 -  #if GREENLET_PY312 -    this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; -    this->c_recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; -  #else // not 312 -    this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; -  #endif // GREENLET_PY312 -    this->current_frame = tstate->cframe->current_frame; -    this->datastack_chunk = tstate->datastack_chunk; -    this->datastack_top = tstate->datastack_top; -    this->datastack_limit = tstate->datastack_limit; - -    PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); -    Py_XDECREF(frame);  // PyThreadState_GetFrame gives us a new -                        // reference. -    this->_top_frame.steal(frame); -  #if GREENLET_PY312 -    this->trash_delete_nesting = tstate->trash.delete_nesting; -  #else // not 312 -    this->trash_delete_nesting = tstate->trash_delete_nesting; -  #endif // GREENLET_PY312 -#else // Not 311 -    this->recursion_depth = tstate->recursion_depth; -    this->_top_frame.steal(tstate->frame); -    this->trash_delete_nesting = tstate->trash_delete_nesting; -#endif // GREENLET_PY311 -} - -#if GREENLET_PY312 -void GREENLET_NOINLINE(PythonState::unexpose_frames)() -{ -    if (!this->top_frame()) { -        return; -    } - -    // See GreenletState::expose_frames() and the comment on frames_were_exposed -    // for more information about this logic. -    _PyInterpreterFrame *iframe = this->_top_frame->f_frame; -    while (iframe != nullptr) { -        _PyInterpreterFrame *prev_exposed = iframe->previous; -        assert(iframe->frame_obj); -        memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0], -               sizeof(void *)); -        iframe = prev_exposed; -    } -} -#else -void PythonState::unexpose_frames() -{} -#endif - -void PythonState::operator>>(PyThreadState *const tstate) noexcept -{ -    tstate->context = this->_context.relinquish_ownership(); -    /* Incrementing this value invalidates the contextvars cache, -       which would otherwise remain valid across switches */ -    tstate->context_ver++; -#if GREENLET_USE_CFRAME -    tstate->cframe = this->cframe; -    /* -      If we were tracing, we need to keep tracing. -      There should never be the possibility of hitting the -      root_cframe here. See note above about why we can't -      just copy this from ``origin->cframe->use_tracing``. -    */ -  #if !GREENLET_PY312 -    tstate->cframe->use_tracing = this->use_tracing; -  #endif -#endif // GREENLET_USE_CFRAME -#if GREENLET_PY311 -  #if GREENLET_PY312 -    tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth; -    tstate->c_recursion_remaining = C_RECURSION_LIMIT - this->c_recursion_depth; -    this->unexpose_frames(); -  #else // \/ 3.11 -    tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; -  #endif // GREENLET_PY312 -    tstate->cframe->current_frame = this->current_frame; -    tstate->datastack_chunk = this->datastack_chunk; -    tstate->datastack_top = this->datastack_top; -    tstate->datastack_limit = this->datastack_limit; -    this->_top_frame.relinquish_ownership(); -  #if GREENLET_PY312 -    tstate->trash.delete_nesting = this->trash_delete_nesting; -  #else // not 3.12 -    tstate->trash_delete_nesting = this->trash_delete_nesting; -  #endif // GREENLET_PY312 -#else // not 3.11 -    tstate->frame = this->_top_frame.relinquish_ownership(); -    tstate->recursion_depth = this->recursion_depth; -    tstate->trash_delete_nesting = this->trash_delete_nesting; -#endif // GREENLET_PY311 -} - -inline void PythonState::will_switch_from(PyThreadState *const origin_tstate) noexcept -{ -#if GREENLET_USE_CFRAME && !GREENLET_PY312 -    // The weird thing is, we don't actually save this for an -    // effect on the current greenlet, it's saved for an -    // effect on the target greenlet. That is, we want -    // continuity of this setting across the greenlet switch. -    this->use_tracing = origin_tstate->cframe->use_tracing; -#endif -} - -void PythonState::set_initial_state(const PyThreadState* const tstate) noexcept -{ -    this->_top_frame = nullptr; -#if GREENLET_PY312 -    this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; -    // XXX: TODO: Comment from a reviewer: -    //     Should this be ``C_RECURSION_LIMIT - tstate->c_recursion_remaining``? -    // But to me it looks more like that might not be the right -    // initialization either? -    this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; -#elif GREENLET_PY311 -    this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; -#else -    this->recursion_depth = tstate->recursion_depth; -#endif -} -// TODO: Better state management about when we own the top frame. -int PythonState::tp_traverse(visitproc visit, void* arg, bool own_top_frame) noexcept -{ -    Py_VISIT(this->_context.borrow()); -    if (own_top_frame) { -        Py_VISIT(this->_top_frame.borrow()); -    } -    return 0; -} - -void PythonState::tp_clear(bool own_top_frame) noexcept -{ -    PythonStateContext::tp_clear(); -    // If we get here owning a frame, -    // we got dealloc'd without being finished. We may or may not be -    // in the same thread. -    if (own_top_frame) { -        this->_top_frame.CLEAR(); -    } -} - -#if GREENLET_USE_CFRAME -void PythonState::set_new_cframe(_PyCFrame& frame) noexcept -{ -    frame = *PyThreadState_GET()->cframe; -    /* Make the target greenlet refer to the stack value. */ -    this->cframe = &frame; -    /* -      And restore the link to the previous frame so this one gets -      unliked appropriately. -    */ -    this->cframe->previous = &PyThreadState_GET()->root_cframe; -} -#endif - -const PythonState::OwnedFrame& PythonState::top_frame() const noexcept -{ -    return this->_top_frame; -} - -void PythonState::did_finish(PyThreadState* tstate) noexcept -{ -#if GREENLET_PY311 -    // See https://github.com/gevent/gevent/issues/1924 and -    // https://github.com/python-greenlet/greenlet/issues/328. In -    // short, Python 3.11 allocates memory for frames as a sort of -    // linked list that's kept as part of PyThreadState in the -    // ``datastack_chunk`` member and friends. These are saved and -    // restored as part of switching greenlets. -    // -    // When we initially switch to a greenlet, we set those to NULL. -    // That causes the frame management code to treat this like a -    // brand new thread and start a fresh list of chunks, beginning -    // with a new "root" chunk. As we make calls in this greenlet, -    // those chunks get added, and as calls return, they get popped. -    // But the frame code (pystate.c) is careful to make sure that the -    // root chunk never gets popped. -    // -    // Thus, when a greenlet exits for the last time, there will be at -    // least a single root chunk that we must be responsible for -    // deallocating. -    // -    // The complex part is that these chunks are allocated and freed -    // using ``_PyObject_VirtualAlloc``/``Free``. Those aren't public -    // functions, and they aren't exported for linking. It so happens -    // that we know they are just thin wrappers around the Arena -    // allocator, so we can use that directly to deallocate in a -    // compatible way. -    // -    // CAUTION: Check this implementation detail on every major version. -    // -    // It might be nice to be able to do this in our destructor, but -    // can we be sure that no one else is using that memory? Plus, as -    // described below, our pointers may not even be valid anymore. As -    // a special case, there is one time that we know we can do this, -    // and that's from the destructor of the associated UserGreenlet -    // (NOT main greenlet) -    PyObjectArenaAllocator alloc; -    _PyStackChunk* chunk = nullptr; -    if (tstate) { -        // We really did finish, we can never be switched to again. -        chunk = tstate->datastack_chunk; -        // Unfortunately, we can't do much sanity checking. Our -        // this->datastack_chunk pointer is out of date (evaluation may -        // have popped down through it already) so we can't verify that -        // we deallocate it. I don't think we can even check datastack_top -        // for the same reason. - -        PyObject_GetArenaAllocator(&alloc); -        tstate->datastack_chunk = nullptr; -        tstate->datastack_limit = nullptr; -        tstate->datastack_top = nullptr; - -    } -    else if (this->datastack_chunk) { -        // The UserGreenlet (NOT the main greenlet!) is being deallocated. If we're -        // still holding a stack chunk, it's garbage because we know -        // we can never switch back to let cPython clean it up. -        // Because the last time we got switched away from, and we -        // haven't run since then, we know our chain is valid and can -        // be dealloced. -        chunk = this->datastack_chunk; -        PyObject_GetArenaAllocator(&alloc); -    } - -    if (alloc.free && chunk) { -        // In case the arena mechanism has been torn down already. -        while (chunk) { -            _PyStackChunk *prev = chunk->previous; -            chunk->previous = nullptr; -            alloc.free(alloc.ctx, chunk, chunk->size); -            chunk = prev; -        } -    } - -    this->datastack_chunk = nullptr; -    this->datastack_limit = nullptr; -    this->datastack_top = nullptr; -#endif -} - - -}; // namespace greenlet - -#endif // GREENLET_PYTHON_STATE_CPP diff --git a/venv/lib/python3.11/site-packages/greenlet/TStackState.cpp b/venv/lib/python3.11/site-packages/greenlet/TStackState.cpp deleted file mode 100644 index 9aab596..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TStackState.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef GREENLET_STACK_STATE_CPP -#define GREENLET_STACK_STATE_CPP - -#include "greenlet_greenlet.hpp" - -namespace greenlet { - -#ifdef GREENLET_USE_STDIO -#include <iostream> -using std::cerr; -using std::endl; - -std::ostream& operator<<(std::ostream& os, const StackState& s) -{ -    os << "StackState(stack_start=" << (void*)s._stack_start -       << ", stack_stop=" << (void*)s.stack_stop -       << ", stack_copy=" << (void*)s.stack_copy -       << ", stack_saved=" << s._stack_saved -       << ", stack_prev=" << s.stack_prev -       << ", addr=" << &s -       << ")"; -    return os; -} -#endif - -StackState::StackState(void* mark, StackState& current) -    : _stack_start(nullptr), -      stack_stop((char*)mark), -      stack_copy(nullptr), -      _stack_saved(0), -      /* Skip a dying greenlet */ -      stack_prev(current._stack_start -                 ? ¤t -                 : current.stack_prev) -{ -} - -StackState::StackState() -    : _stack_start(nullptr), -      stack_stop(nullptr), -      stack_copy(nullptr), -      _stack_saved(0), -      stack_prev(nullptr) -{ -} - -StackState::StackState(const StackState& other) -// can't use a delegating constructor because of -// MSVC for Python 2.7 -    : _stack_start(nullptr), -      stack_stop(nullptr), -      stack_copy(nullptr), -      _stack_saved(0), -      stack_prev(nullptr) -{ -    this->operator=(other); -} - -StackState& StackState::operator=(const StackState& other) -{ -    if (&other == this) { -        return *this; -    } -    if (other._stack_saved) { -        throw std::runtime_error("Refusing to steal memory."); -    } - -    //If we have memory allocated, dispose of it -    this->free_stack_copy(); - -    this->_stack_start = other._stack_start; -    this->stack_stop = other.stack_stop; -    this->stack_copy = other.stack_copy; -    this->_stack_saved = other._stack_saved; -    this->stack_prev = other.stack_prev; -    return *this; -} - -inline void StackState::free_stack_copy() noexcept -{ -    PyMem_Free(this->stack_copy); -    this->stack_copy = nullptr; -    this->_stack_saved = 0; -} - -inline void StackState::copy_heap_to_stack(const StackState& current) noexcept -{ - -    /* Restore the heap copy back into the C stack */ -    if (this->_stack_saved != 0) { -        memcpy(this->_stack_start, this->stack_copy, this->_stack_saved); -        this->free_stack_copy(); -    } -    StackState* owner = const_cast<StackState*>(¤t); -    if (!owner->_stack_start) { -        owner = owner->stack_prev; /* greenlet is dying, skip it */ -    } -    while (owner && owner->stack_stop <= this->stack_stop) { -        // cerr << "\tOwner: " << owner << endl; -        owner = owner->stack_prev; /* find greenlet with more stack */ -    } -    this->stack_prev = owner; -    // cerr << "\tFinished with: " << *this << endl; -} - -inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept -{ -    /* Save more of g's stack into the heap -- at least up to 'stop' -       g->stack_stop |________| -                     |        | -                     |    __ stop       . . . . . -                     |        |    ==>  .       . -                     |________|          _______ -                     |        |         |       | -                     |        |         |       | -      g->stack_start |        |         |_______| g->stack_copy -     */ -    intptr_t sz1 = this->_stack_saved; -    intptr_t sz2 = stop - this->_stack_start; -    assert(this->_stack_start); -    if (sz2 > sz1) { -        char* c = (char*)PyMem_Realloc(this->stack_copy, sz2); -        if (!c) { -            PyErr_NoMemory(); -            return -1; -        } -        memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1); -        this->stack_copy = c; -        this->_stack_saved = sz2; -    } -    return 0; -} - -inline int StackState::copy_stack_to_heap(char* const stackref, -                                          const StackState& current) noexcept -{ -    /* must free all the C stack up to target_stop */ -    const char* const target_stop = this->stack_stop; - -    StackState* owner = const_cast<StackState*>(¤t); -    assert(owner->_stack_saved == 0); // everything is present on the stack -    if (!owner->_stack_start) { -        owner = owner->stack_prev; /* not saved if dying */ -    } -    else { -        owner->_stack_start = stackref; -    } - -    while (owner->stack_stop < target_stop) { -        /* ts_current is entierely within the area to free */ -        if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) { -            return -1; /* XXX */ -        } -        owner = owner->stack_prev; -    } -    if (owner != this) { -        if (owner->copy_stack_to_heap_up_to(target_stop)) { -            return -1; /* XXX */ -        } -    } -    return 0; -} - -inline bool StackState::started() const noexcept -{ -    return this->stack_stop != nullptr; -} - -inline bool StackState::main() const noexcept -{ -    return this->stack_stop == (char*)-1; -} - -inline bool StackState::active() const noexcept -{ -    return this->_stack_start != nullptr; -} - -inline void StackState::set_active() noexcept -{ -    assert(this->_stack_start == nullptr); -    this->_stack_start = (char*)1; -} - -inline void StackState::set_inactive() noexcept -{ -    this->_stack_start = nullptr; -    // XXX: What if we still have memory out there? -    // That case is actually triggered by -    // test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks) -    // and -    // test_issue251_issue252_need_to_collect_in_background -    // (greenlet.tests.test_leaks.TestLeaks) -    // -    // Those objects never get deallocated, so the destructor never -    // runs. -    // It *seems* safe to clean up the memory here? -    if (this->_stack_saved) { -        this->free_stack_copy(); -    } -} - -inline intptr_t StackState::stack_saved() const noexcept -{ -    return this->_stack_saved; -} - -inline char* StackState::stack_start() const noexcept -{ -    return this->_stack_start; -} - - -inline StackState StackState::make_main() noexcept -{ -    StackState s; -    s._stack_start = (char*)1; -    s.stack_stop = (char*)-1; -    return s; -} - -StackState::~StackState() -{ -    if (this->_stack_saved != 0) { -        this->free_stack_copy(); -    } -} - -void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const -{ -    char* dest = static_cast<char*>(vdest); -    const char* src = static_cast<const char*>(vsrc); -    if (src + n <= this->_stack_start -        || src >= this->_stack_start + this->_stack_saved -        || this->_stack_saved == 0) { -        // Nothing we're copying was spilled from the stack -        memcpy(dest, src, n); -        return; -    } - -    if (src < this->_stack_start) { -        // Copy the part before the saved stack. -        // We know src + n > _stack_start due to the test above. -        const size_t nbefore = this->_stack_start - src; -        memcpy(dest, src, nbefore); -        dest += nbefore; -        src += nbefore; -        n -= nbefore; -    } -    // We know src >= _stack_start after the before-copy, and -    // src < _stack_start + _stack_saved due to the first if condition -    size_t nspilled = std::min<size_t>(n, this->_stack_start + this->_stack_saved - src); -    memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled); -    dest += nspilled; -    src += nspilled; -    n -= nspilled; -    if (n > 0) { -        // Copy the part after the saved stack -        memcpy(dest, src, n); -    } -} - -}; // namespace greenlet - -#endif // GREENLET_STACK_STATE_CPP diff --git a/venv/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp b/venv/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp deleted file mode 100644 index a149a1a..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of the ThreadState destructors. - * - * Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#ifndef T_THREADSTATE_DESTROY -#define T_THREADSTATE_DESTROY - -#include "greenlet_greenlet.hpp" -#include "greenlet_thread_state.hpp" -#include "greenlet_thread_support.hpp" -#include "greenlet_cpython_add_pending.hpp" -#include "TGreenletGlobals.cpp" - -namespace greenlet { - -struct ThreadState_DestroyWithGIL -{ -    ThreadState_DestroyWithGIL(ThreadState* state) -    { -        if (state && state->has_main_greenlet()) { -            DestroyWithGIL(state); -        } -    } - -    static int -    DestroyWithGIL(ThreadState* state) -    { -        // Holding the GIL. -        // Passed a non-shared pointer to the actual thread state. -        // state -> main greenlet -        assert(state->has_main_greenlet()); -        PyGreenlet* main(state->borrow_main_greenlet()); -        // When we need to do cross-thread operations, we check this. -        // A NULL value means the thread died some time ago. -        // We do this here, rather than in a Python dealloc function -        // for the greenlet, in case there's still a reference out -        // there. -        static_cast<MainGreenlet*>(main->pimpl)->thread_state(nullptr); - -        delete state; // Deleting this runs the destructor, DECREFs the main greenlet. -        return 0; -    } -}; - - - -struct ThreadState_DestroyNoGIL -{ -    // ensure this is actually defined. -    static_assert(GREENLET_BROKEN_PY_ADD_PENDING == 1 || GREENLET_BROKEN_PY_ADD_PENDING == 0, -                  "GREENLET_BROKEN_PY_ADD_PENDING not defined correctly."); - -#if GREENLET_BROKEN_PY_ADD_PENDING -    static int _push_pending_call(struct _pending_calls *pending, -                                  int (*func)(void *), void *arg) -    { -        int i = pending->last; -        int j = (i + 1) % NPENDINGCALLS; -        if (j == pending->first) { -            return -1; /* Queue full */ -        } -        pending->calls[i].func = func; -        pending->calls[i].arg = arg; -        pending->last = j; -        return 0; -    } - -    static int AddPendingCall(int (*func)(void *), void *arg) -    { -        _PyRuntimeState *runtime = &_PyRuntime; -        if (!runtime) { -            // obviously impossible -            return 0; -        } -        struct _pending_calls *pending = &runtime->ceval.pending; -        if (!pending->lock) { -            return 0; -        } -        int result = 0; -        PyThread_acquire_lock(pending->lock, WAIT_LOCK); -        if (!pending->finishing) { -            result = _push_pending_call(pending, func, arg); -        } -        PyThread_release_lock(pending->lock); -        SIGNAL_PENDING_CALLS(&runtime->ceval); -        return result; -    } -#else -    // Python < 3.8 or >= 3.9 -    static int AddPendingCall(int (*func)(void*), void* arg) -    { -        return Py_AddPendingCall(func, arg); -    } -#endif - -    ThreadState_DestroyNoGIL(ThreadState* state) -    { -        // We are *NOT* holding the GIL. Our thread is in the middle -        // of its death throes and the Python thread state is already -        // gone so we can't use most Python APIs. One that is safe is -        // ``Py_AddPendingCall``, unless the interpreter itself has -        // been torn down. There is a limited number of calls that can -        // be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we -        // coalesce these calls using our own queue. -        if (state && state->has_main_greenlet()) { -            // mark the thread as dead ASAP. -            // this is racy! If we try to throw or switch to a -            // greenlet from this thread from some other thread before -            // we clear the state pointer, it won't realize the state -            // is dead which can crash the process. -            PyGreenlet* p = state->borrow_main_greenlet(); -            assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr); -            static_cast<MainGreenlet*>(p->pimpl)->thread_state(nullptr); -        } - -        // NOTE: Because we're not holding the GIL here, some other -        // Python thread could run and call ``os.fork()``, which would -        // be bad if that happenend while we are holding the cleanup -        // lock (it wouldn't function in the child process). -        // Make a best effort to try to keep the duration we hold the -        // lock short. -        // TODO: On platforms that support it, use ``pthread_atfork`` to -        // drop this lock. -        LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); - -        if (state && state->has_main_greenlet()) { -            // Because we don't have the GIL, this is a race condition. -            if (!PyInterpreterState_Head()) { -                // We have to leak the thread state, if the -                // interpreter has shut down when we're getting -                // deallocated, we can't run the cleanup code that -                // deleting it would imply. -                return; -            } - -            mod_globs->queue_to_destroy(state); -            if (mod_globs->thread_states_to_destroy.size() == 1) { -                // We added the first item to the queue. We need to schedule -                // the cleanup. -                int result = ThreadState_DestroyNoGIL::AddPendingCall( -                    ThreadState_DestroyNoGIL::DestroyQueueWithGIL, -                    NULL); -                if (result < 0) { -                    // Hmm, what can we do here? -                    fprintf(stderr, -                            "greenlet: WARNING: failed in call to Py_AddPendingCall; " -                            "expect a memory leak.\n"); -                } -            } -        } -    } - -    static int -    DestroyQueueWithGIL(void* UNUSED(arg)) -    { -        // We're holding the GIL here, so no Python code should be able to -        // run to call ``os.fork()``. -        while (1) { -            ThreadState* to_destroy; -            { -                LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); -                if (mod_globs->thread_states_to_destroy.empty()) { -                    break; -                } -                to_destroy = mod_globs->take_next_to_destroy(); -            } -            // Drop the lock while we do the actual deletion. -            ThreadState_DestroyWithGIL::DestroyWithGIL(to_destroy); -        } -        return 0; -    } - -}; - -}; // namespace greenlet - -// The intent when GET_THREAD_STATE() is needed multiple times in a -// function is to take a reference to its return value in a local -// variable, to avoid the thread-local indirection. On some platforms -// (macOS), accessing a thread-local involves a function call (plus an -// initial function call in each function that uses a thread local); -// in contrast, static volatile variables are at some pre-computed -// offset. -typedef greenlet::ThreadStateCreator<greenlet::ThreadState_DestroyNoGIL> ThreadStateCreator; -static thread_local ThreadStateCreator g_thread_state_global; -#define GET_THREAD_STATE() g_thread_state_global - -#endif //T_THREADSTATE_DESTROY diff --git a/venv/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp b/venv/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp deleted file mode 100644 index 495a794..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp +++ /dev/null @@ -1,667 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/** - * Implementation of greenlet::UserGreenlet. - * - * Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ - -#include "greenlet_internal.hpp" -#include "greenlet_greenlet.hpp" -#include "greenlet_thread_state.hpp" -#include "TThreadStateDestroy.cpp" - - -namespace greenlet { -using greenlet::refs::BorrowedMainGreenlet; -greenlet::PythonAllocator<UserGreenlet> UserGreenlet::allocator; - -void* UserGreenlet::operator new(size_t UNUSED(count)) -{ -    return allocator.allocate(1); -} - - -void UserGreenlet::operator delete(void* ptr) -{ -    return allocator.deallocate(static_cast<UserGreenlet*>(ptr), -                                1); -} - - -UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) -    : Greenlet(p), _parent(the_parent) -{ -    this->_self = p; -} - -UserGreenlet::~UserGreenlet() -{ -    // Python 3.11: If we don't clear out the raw frame datastack -    // when deleting an unfinished greenlet, -    // TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails. -    this->python_state.did_finish(nullptr); -    this->tp_clear(); -} - -BorrowedGreenlet -UserGreenlet::self() const noexcept -{ -    return this->_self; -} - - - -const BorrowedMainGreenlet -UserGreenlet::main_greenlet() const -{ -    return this->_main_greenlet; -} - - -BorrowedMainGreenlet -UserGreenlet::find_main_greenlet_in_lineage() const -{ -    if (this->started()) { -        assert(this->_main_greenlet); -        return BorrowedMainGreenlet(this->_main_greenlet); -    } - -    if (!this->_parent) { -        /* garbage collected greenlet in chain */ -        // XXX: WHAT? -        return BorrowedMainGreenlet(nullptr); -    } - -    return this->_parent->find_main_greenlet_in_lineage(); -} - - -/** - * CAUTION: This will allocate memory and may trigger garbage - * collection and arbitrary Python code. - */ -OwnedObject -UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state) -{ -    /* The dying greenlet cannot be a parent of ts_current -       because the 'parent' field chain would hold a -       reference */ -    UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state); - -    // We don't care about the return value, only whether an -    // exception happened. Whether or not an exception happens, -    // we need to restore the parent in case the greenlet gets -    // resurrected. -    return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state); -} - -ThreadState* -UserGreenlet::thread_state() const noexcept -{ -    // TODO: maybe make this throw, if the thread state isn't there? -    // if (!this->main_greenlet) { -    //     throw std::runtime_error("No thread state"); // TODO: Better exception -    // } -    if (!this->_main_greenlet) { -        return nullptr; -    } -    return this->_main_greenlet->thread_state(); -} - - -bool -UserGreenlet::was_running_in_dead_thread() const noexcept -{ -    return this->_main_greenlet && !this->thread_state(); -} - -OwnedObject -UserGreenlet::g_switch() -{ -    assert(this->args() || PyErr_Occurred()); - -    try { -        this->check_switch_allowed(); -    } -    catch (const PyErrOccurred&) { -        this->release_args(); -        throw; -    } - -    // Switching greenlets used to attempt to clean out ones that need -    // deleted *if* we detected a thread switch. Should it still do -    // that? -    // An issue is that if we delete a greenlet from another thread, -    // it gets queued to this thread, and ``kill_greenlet()`` switches -    // back into the greenlet - -    /* find the real target by ignoring dead greenlets, -       and if necessary starting a greenlet. */ -    switchstack_result_t err; -    Greenlet* target = this; -    // TODO: probably cleaner to handle the case where we do -    // switch to ourself separately from the other cases. -    // This can probably even further be simplified if we keep -    // track of the switching_state we're going for and just call -    // into g_switch() if it's not ourself. The main problem with that -    // is that we would be using more stack space. -    bool target_was_me = true; -    bool was_initial_stub = false; -    while (target) { -        if (target->active()) { -            if (!target_was_me) { -                target->args() <<= this->args(); -                assert(!this->args()); -            } -            err = target->g_switchstack(); -            break; -        } -        if (!target->started()) { -            // We never encounter a main greenlet that's not started. -            assert(!target->main()); -            UserGreenlet* real_target = static_cast<UserGreenlet*>(target); -            assert(real_target); -            void* dummymarker; -            was_initial_stub = true; -            if (!target_was_me) { -                target->args() <<= this->args(); -                assert(!this->args()); -            } -            try { -                // This can only throw back to us while we're -                // still in this greenlet. Once the new greenlet -                // is bootstrapped, it has its own exception state. -                err = real_target->g_initialstub(&dummymarker); -            } -            catch (const PyErrOccurred&) { -                this->release_args(); -                throw; -            } -            catch (const GreenletStartedWhileInPython&) { -                // The greenlet was started sometime before this -                // greenlet actually switched to it, i.e., -                // "concurrent" calls to switch() or throw(). -                // We need to retry the switch. -                // Note that the current greenlet has been reset -                // to this one (or we wouldn't be running!) -                continue; -            } -            break; -        } - -        target = target->parent(); -        target_was_me = false; -    } -    // The ``this`` pointer and all other stack or register based -    // variables are invalid now, at least where things succeed -    // above. -    // But this one, probably not so much? It's not clear if it's -    // safe to throw an exception at this point. - -    if (err.status < 0) { -        // If we get here, either g_initialstub() -        // failed, or g_switchstack() failed. Either one of those -        // cases SHOULD leave us in the original greenlet with a valid -        // stack. -        return this->on_switchstack_or_initialstub_failure(target, err, target_was_me, was_initial_stub); -    } - -    // err.the_new_current_greenlet would be the same as ``target``, -    // if target wasn't probably corrupt. -    return err.the_new_current_greenlet->g_switch_finish(err); -} - - - -Greenlet::switchstack_result_t -UserGreenlet::g_initialstub(void* mark) -{ -    OwnedObject run; - -    // We need to grab a reference to the current switch arguments -    // in case we're entered concurrently during the call to -    // GetAttr() and have to try again. -    // We'll restore them when we return in that case. -    // Scope them tightly to avoid ref leaks. -    { -        SwitchingArgs args(this->args()); - -        /* save exception in case getattr clears it */ -        PyErrPieces saved; - -        /* -          self.run is the object to call in the new greenlet. -          This could run arbitrary python code and switch greenlets! -        */ -        run = this->_self.PyRequireAttr(mod_globs->str_run); -        /* restore saved exception */ -        saved.PyErrRestore(); - - -        /* recheck that it's safe to switch in case greenlet reparented anywhere above */ -        this->check_switch_allowed(); - -        /* by the time we got here another start could happen elsewhere, -         * that means it should now be a regular switch. -         * This can happen if the Python code is a subclass that implements -         * __getattribute__ or __getattr__, or makes ``run`` a descriptor; -         * all of those can run arbitrary code that switches back into -         * this greenlet. -         */ -        if (this->stack_state.started()) { -            // the successful switch cleared these out, we need to -            // restore our version. They will be copied on up to the -            // next target. -            assert(!this->args()); -            this->args() <<= args; -            throw GreenletStartedWhileInPython(); -        } -    } - -    // Sweet, if we got here, we have the go-ahead and will switch -    // greenlets. -    // Nothing we do from here on out should allow for a thread or -    // greenlet switch: No arbitrary calls to Python, including -    // decref'ing - -#if GREENLET_USE_CFRAME -    /* OK, we need it, we're about to switch greenlets, save the state. */ -    /* -      See green_new(). This is a stack-allocated variable used -      while *self* is in PyObject_Call(). -      We want to defer copying the state info until we're sure -      we need it and are in a stable place to do so. -    */ -    _PyCFrame trace_info; - -    this->python_state.set_new_cframe(trace_info); -#endif -    /* start the greenlet */ -    ThreadState& thread_state = GET_THREAD_STATE().state(); -    this->stack_state = StackState(mark, -                                   thread_state.borrow_current()->stack_state); -    this->python_state.set_initial_state(PyThreadState_GET()); -    this->exception_state.clear(); -    this->_main_greenlet = thread_state.get_main_greenlet(); - -    /* perform the initial switch */ -    switchstack_result_t err = this->g_switchstack(); -    /* returns twice! -       The 1st time with ``err == 1``: we are in the new greenlet. -       This one owns a greenlet that used to be current. -       The 2nd time with ``err <= 0``: back in the caller's -       greenlet; this happens if the child finishes or switches -       explicitly to us. Either way, the ``err`` variable is -       created twice at the same memory location, but possibly -       having different ``origin`` values. Note that it's not -       constructed for the second time until the switch actually happens. -    */ -    if (err.status == 1) { -        // In the new greenlet. - -        // This never returns! Calling inner_bootstrap steals -        // the contents of our run object within this stack frame, so -        // it is not valid to do anything with it. -        try { -            this->inner_bootstrap(err.origin_greenlet.relinquish_ownership(), -                                  run.relinquish_ownership()); -        } -        // Getting a C++ exception here isn't good. It's probably a -        // bug in the underlying greenlet, meaning it's probably a -        // C++ extension. We're going to abort anyway, but try to -        // display some nice information *if* possible. Some obscure -        // platforms don't properly support this (old 32-bit Arm, see see -        // https://github.com/python-greenlet/greenlet/issues/385); that's not -        // great, but should usually be OK because, as mentioned above, we're -        // terminating anyway. -        // -        // The catching is tested by -        // ``test_cpp.CPPTests.test_unhandled_exception_in_greenlet_aborts``. -        // -        // PyErrOccurred can theoretically be thrown by -        // inner_bootstrap() -> g_switch_finish(), but that should -        // never make it back to here. It is a std::exception and -        // would be caught if it is. -        catch (const std::exception& e) { -            std::string base = "greenlet: Unhandled C++ exception: "; -            base += e.what(); -            Py_FatalError(base.c_str()); -        } -        catch (...) { -            // Some compilers/runtimes use exceptions internally. -            // It appears that GCC on Linux with libstdc++ throws an -            // exception internally at process shutdown time to unwind -            // stacks and clean up resources. Depending on exactly -            // where we are when the process exits, that could result -            // in an unknown exception getting here. If we -            // Py_FatalError() or abort() here, we interfere with -            // orderly process shutdown. Throwing the exception on up -            // is the right thing to do. -            // -            // gevent's ``examples/dns_mass_resolve.py`` demonstrates this. -#ifndef NDEBUG -            fprintf(stderr, -                    "greenlet: inner_bootstrap threw unknown exception; " -                    "is the process terminating?\n"); -#endif -            throw; -        } -        Py_FatalError("greenlet: inner_bootstrap returned with no exception.\n"); -    } - - -    // In contrast, notice that we're keeping the origin greenlet -    // around as an owned reference; we need it to call the trace -    // function for the switch back into the parent. It was only -    // captured at the time the switch actually happened, though, -    // so we haven't been keeping an extra reference around this -    // whole time. - -    /* back in the parent */ -    if (err.status < 0) { -        /* start failed badly, restore greenlet state */ -        this->stack_state = StackState(); -        this->_main_greenlet.CLEAR(); -        // CAUTION: This may run arbitrary Python code. -        run.CLEAR(); // inner_bootstrap didn't run, we own the reference. -    } - -    // In the success case, the spawned code (inner_bootstrap) will -    // take care of decrefing this, so we relinquish ownership so as -    // to not double-decref. - -    run.relinquish_ownership(); - -    return err; -} - - -void -UserGreenlet::inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run) -{ -    // The arguments here would be another great place for move. -    // As it is, we take them as a reference so that when we clear -    // them we clear what's on the stack above us. Do that NOW, and -    // without using a C++ RAII object, -    // so there's no way that exiting the parent frame can clear it, -    // or we clear it unexpectedly. This arises in the context of the -    // interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325 -    //PyObject* run = _run.relinquish_ownership(); - -    /* in the new greenlet */ -    assert(this->thread_state()->borrow_current() == this->_self); -    // C++ exceptions cannot propagate to the parent greenlet from -    // here. (TODO: Do we need a catch(...) clause, perhaps on the -    // function itself? ALl we could do is terminate the program.) -    // NOTE: On 32-bit Windows, the call chain is extremely -    // important here in ways that are subtle, having to do with -    // the depth of the SEH list. The call to restore it MUST NOT -    // add a new SEH handler to the list, or we'll restore it to -    // the wrong thing. -    this->thread_state()->restore_exception_state(); -    /* stack variables from above are no good and also will not unwind! */ -    // EXCEPT: That can't be true, we access run, among others, here. - -    this->stack_state.set_active(); /* running */ - -    // We're about to possibly run Python code again, which -    // could switch back/away to/from us, so we need to grab the -    // arguments locally. -    SwitchingArgs args; -    args <<= this->args(); -    assert(!this->args()); - -    // XXX: We could clear this much earlier, right? -    // Or would that introduce the possibility of running Python -    // code when we don't want to? -    // CAUTION: This may run arbitrary Python code. -    this->_run_callable.CLEAR(); - - -    // The first switch we need to manually call the trace -    // function here instead of in g_switch_finish, because we -    // never return there. -    if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) { -        OwnedGreenlet trace_origin; -        trace_origin = origin_greenlet; -        try { -            g_calltrace(tracefunc, -                        args ? mod_globs->event_switch : mod_globs->event_throw, -                        trace_origin, -                        this->_self); -        } -        catch (const PyErrOccurred&) { -            /* Turn trace errors into switch throws */ -            args.CLEAR(); -        } -    } - -    // We no longer need the origin, it was only here for -    // tracing. -    // We may never actually exit this stack frame so we need -    // to explicitly clear it. -    // This could run Python code and switch. -    Py_CLEAR(origin_greenlet); - -    OwnedObject result; -    if (!args) { -        /* pending exception */ -        result = NULL; -    } -    else { -        /* call g.run(*args, **kwargs) */ -        // This could result in further switches -        try { -            //result = run.PyCall(args.args(), args.kwargs()); -            // CAUTION: Just invoking this, before the function even -            // runs, may cause memory allocations, which may trigger -            // GC, which may run arbitrary Python code. -            result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow())); -        } -        catch (...) { -            // Unhandled C++ exception! - -            // If we declare ourselves as noexcept, if we don't catch -            // this here, most platforms will just abort() the -            // process. But on 64-bit Windows with older versions of -            // the C runtime, this can actually corrupt memory and -            // just return. We see this when compiling with the -            // Windows 7.0 SDK targeting Windows Server 2008, but not -            // when using the Appveyor Visual Studio 2019 image. So -            // this currently only affects Python 2.7 on Windows 64. -            // That is, the tests pass and the runtime aborts -            // everywhere else. -            // -            // However, if we catch it and try to continue with a -            // Python error, then all Windows 64 bit platforms corrupt -            // memory. So all we can do is manually abort, hopefully -            // with a good error message. (Note that the above was -            // tested WITHOUT the `/EHr` switch being used at compile -            // time, so MSVC may have "optimized" out important -            // checking. Using that switch, we may be in a better -            // place in terms of memory corruption.) But sometimes it -            // can't be caught here at all, which is confusing but not -            // terribly surprising; so again, the G_NOEXCEPT_WIN32 -            // plus "/EHr". -            // -            // Hopefully the basic C stdlib is still functional enough -            // for us to at least print an error. -            // -            // It gets more complicated than that, though, on some -            // platforms, specifically at least Linux/gcc/libstdc++. They use -            // an exception to unwind the stack when a background -            // thread exits. (See comments about noexcept.) So this -            // may not actually represent anything untoward. On those -            // platforms we allow throws of this to propagate, or -            // attempt to anyway. -# if defined(WIN32) || defined(_WIN32) -            Py_FatalError( -                "greenlet: Unhandled C++ exception from a greenlet run function. " -                "Because memory is likely corrupted, terminating process."); -            std::abort(); -#else -            throw; -#endif -        } -    } -    // These lines may run arbitrary code -    args.CLEAR(); -    Py_CLEAR(run); - -    if (!result -        && mod_globs->PyExc_GreenletExit.PyExceptionMatches() -        && (this->args())) { -        // This can happen, for example, if our only reference -        // goes away after we switch back to the parent. -        // See test_dealloc_switch_args_not_lost -        PyErrPieces clear_error; -        result <<= this->args(); -        result = single_result(result); -    } -    this->release_args(); -    this->python_state.did_finish(PyThreadState_GET()); - -    result = g_handle_exit(result); -    assert(this->thread_state()->borrow_current() == this->_self); - -    /* jump back to parent */ -    this->stack_state.set_inactive(); /* dead */ - - -    // TODO: Can we decref some things here? Release our main greenlet -    // and maybe parent? -    for (Greenlet* parent = this->_parent; -         parent; -         parent = parent->parent()) { -        // We need to somewhere consume a reference to -        // the result; in most cases we'll never have control -        // back in this stack frame again. Calling -        // green_switch actually adds another reference! -        // This would probably be clearer with a specific API -        // to hand results to the parent. -        parent->args() <<= result; -        assert(!result); -        // The parent greenlet now owns the result; in the -        // typical case we'll never get back here to assign to -        // result and thus release the reference. -        try { -            result = parent->g_switch(); -        } -        catch (const PyErrOccurred&) { -            // Ignore, keep passing the error on up. -        } - -        /* Return here means switch to parent failed, -         * in which case we throw *current* exception -         * to the next parent in chain. -         */ -        assert(!result); -    } -    /* We ran out of parents, cannot continue */ -    PyErr_WriteUnraisable(this->self().borrow_o()); -    Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; " -                  "cannot continue"); -    std::abort(); -} - -void -UserGreenlet::run(const BorrowedObject nrun) -{ -    if (this->started()) { -        throw AttributeError( -                        "run cannot be set " -                        "after the start of the greenlet"); -    } -    this->_run_callable = nrun; -} - -const OwnedGreenlet -UserGreenlet::parent() const -{ -    return this->_parent; -} - -void -UserGreenlet::parent(const BorrowedObject raw_new_parent) -{ -    if (!raw_new_parent) { -        throw AttributeError("can't delete attribute"); -    } - -    BorrowedMainGreenlet main_greenlet_of_new_parent; -    BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could -                                                          // throw -                                                          // TypeError! -    for (BorrowedGreenlet p = new_parent; p; p = p->parent()) { -        if (p == this->_self) { -            throw ValueError("cyclic parent chain"); -        } -        main_greenlet_of_new_parent = p->main_greenlet(); -    } - -    if (!main_greenlet_of_new_parent) { -        throw ValueError("parent must not be garbage collected"); -    } - -    if (this->started() -        && this->_main_greenlet != main_greenlet_of_new_parent) { -        throw ValueError("parent cannot be on a different thread"); -    } - -    this->_parent = new_parent; -} - -void -UserGreenlet::murder_in_place() -{ -    this->_main_greenlet.CLEAR(); -    Greenlet::murder_in_place(); -} - -bool -UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const -{ -    return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet(); -} - - -int -UserGreenlet::tp_traverse(visitproc visit, void* arg) -{ -    Py_VISIT(this->_parent.borrow_o()); -    Py_VISIT(this->_main_greenlet.borrow_o()); -    Py_VISIT(this->_run_callable.borrow_o()); - -    return Greenlet::tp_traverse(visit, arg); -} - -int -UserGreenlet::tp_clear() -{ -    Greenlet::tp_clear(); -    this->_parent.CLEAR(); -    this->_main_greenlet.CLEAR(); -    this->_run_callable.CLEAR(); -    return 0; -} - -UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p, -                                                     const ThreadState& thread_state) -    : oldparent(p->_parent), -      greenlet(p) -{ -    p->_parent = thread_state.get_current(); -} - -UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard() -{ -    this->greenlet->_parent = oldparent; -    oldparent.CLEAR(); -} - -}; //namespace greenlet diff --git a/venv/lib/python3.11/site-packages/greenlet/__init__.py b/venv/lib/python3.11/site-packages/greenlet/__init__.py deleted file mode 100644 index 298a19d..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/__init__.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -""" -The root of the greenlet package. -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -__all__ = [ -    '__version__', -    '_C_API', - -    'GreenletExit', -    'error', - -    'getcurrent', -    'greenlet', - -    'gettrace', -    'settrace', -] - -# pylint:disable=no-name-in-module - -### -# Metadata -### -__version__ = '3.0.3' -from ._greenlet import _C_API # pylint:disable=no-name-in-module - -### -# Exceptions -### -from ._greenlet import GreenletExit -from ._greenlet import error - -### -# greenlets -### -from ._greenlet import getcurrent -from ._greenlet import greenlet - -### -# tracing -### -try: -    from ._greenlet import gettrace -    from ._greenlet import settrace -except ImportError: -    # Tracing wasn't supported. -    # XXX: The option to disable it was removed in 1.0, -    # so this branch should be dead code. -    pass - -### -# Constants -# These constants aren't documented and aren't recommended. -# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS -# is the same as ``sys.version_info[:2] >= 3.7`` -### -from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import -from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import -from ._greenlet import GREENLET_USE_TRACING # pylint:disable=unused-import - -# Controlling the use of the gc module. Provisional API for this greenlet -# implementation in 2.0. -from ._greenlet import CLOCKS_PER_SEC # pylint:disable=unused-import -from ._greenlet import enable_optional_cleanup # pylint:disable=unused-import -from ._greenlet import get_clocks_used_doing_optional_cleanup # pylint:disable=unused-import - -# Other APIS in the _greenlet module are for test support. diff --git a/venv/lib/python3.11/site-packages/greenlet/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/__pycache__/__init__.cpython-311.pycBinary files differ deleted file mode 100644 index 88a0be3..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/__pycache__/__init__.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so b/venv/lib/python3.11/site-packages/greenlet/_greenlet.cpython-311-x86_64-linux-gnu.soBinary files differ deleted file mode 100755 index 1d293a3..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet.cpp b/venv/lib/python3.11/site-packages/greenlet/greenlet.cpp deleted file mode 100644 index 5a9818e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet.cpp +++ /dev/null @@ -1,1494 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -/* Format with: - *  clang-format -i --style=file src/greenlet/greenlet.c - * - * - * Fix missing braces with: - *   clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" -*/ -#include <cstdlib> -#include <string> -#include <algorithm> -#include <exception> - - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" // PyMemberDef - -#include "greenlet_internal.hpp" -// Code after this point can assume access to things declared in stdint.h, -// including the fixed-width types. This goes for the platform-specific switch functions -// as well. -#include "greenlet_refs.hpp" -#include "greenlet_slp_switch.hpp" -#include "greenlet_thread_state.hpp" -#include "greenlet_thread_support.hpp" -#include "greenlet_greenlet.hpp" - -#include "TGreenletGlobals.cpp" -#include "TThreadStateDestroy.cpp" -#include "TGreenlet.cpp" -#include "TMainGreenlet.cpp" -#include "TUserGreenlet.cpp" -#include "TBrokenGreenlet.cpp" -#include "TExceptionState.cpp" -#include "TPythonState.cpp" -#include "TStackState.cpp" - - -using greenlet::LockGuard; -using greenlet::LockInitError; -using greenlet::PyErrOccurred; -using greenlet::Require; - -using greenlet::g_handle_exit; -using greenlet::single_result; - -using greenlet::Greenlet; -using greenlet::UserGreenlet; -using greenlet::MainGreenlet; -using greenlet::BrokenGreenlet; -using greenlet::ThreadState; -using greenlet::PythonState; - - - -// ******* Implementation of things from included files -template<typename T, greenlet::refs::TypeChecker TC> -greenlet::refs::_BorrowedGreenlet<T, TC>& greenlet::refs::_BorrowedGreenlet<T, TC>::operator=(const greenlet::refs::BorrowedObject& other) -{ -    this->_set_raw_pointer(static_cast<PyObject*>(other)); -    return *this; -} - -template <typename T, greenlet::refs::TypeChecker TC> -inline greenlet::refs::_BorrowedGreenlet<T, TC>::operator Greenlet*() const noexcept -{ -    if (!this->p) { -        return nullptr; -    } -    return reinterpret_cast<PyGreenlet*>(this->p)->pimpl; -} - -template<typename T, greenlet::refs::TypeChecker TC> -greenlet::refs::_BorrowedGreenlet<T, TC>::_BorrowedGreenlet(const BorrowedObject& p) -    : BorrowedReference<T, TC>(nullptr) -{ - -    this->_set_raw_pointer(p.borrow()); -} - -template <typename T, greenlet::refs::TypeChecker TC> -inline greenlet::refs::_OwnedGreenlet<T, TC>::operator Greenlet*() const noexcept -{ -    if (!this->p) { -        return nullptr; -    } -    return reinterpret_cast<PyGreenlet*>(this->p)->pimpl; -} - - - -#ifdef __clang__ -#    pragma clang diagnostic push -#    pragma clang diagnostic ignored "-Wmissing-field-initializers" -#    pragma clang diagnostic ignored "-Wwritable-strings" -#elif defined(__GNUC__) -#    pragma GCC diagnostic push -//  warning: ISO C++ forbids converting a string constant to ‘char*’ -// (The python APIs aren't const correct and accept writable char*) -#    pragma GCC diagnostic ignored "-Wwrite-strings" -#endif - - -/*********************************************************** - -A PyGreenlet is a range of C stack addresses that must be -saved and restored in such a way that the full range of the -stack contains valid data when we switch to it. - -Stack layout for a greenlet: - -               |     ^^^       | -               |  older data   | -               |               | -  stack_stop . |_______________| -        .      |               | -        .      | greenlet data | -        .      |   in stack    | -        .    * |_______________| . .  _____________  stack_copy + stack_saved -        .      |               |     |             | -        .      |     data      |     |greenlet data| -        .      |   unrelated   |     |    saved    | -        .      |      to       |     |   in heap   | - stack_start . |     this      | . . |_____________| stack_copy -               |   greenlet    | -               |               | -               |  newer data   | -               |     vvv       | - - -Note that a greenlet's stack data is typically partly at its correct -place in the stack, and partly saved away in the heap, but always in -the above configuration: two blocks, the more recent one in the heap -and the older one still in the stack (either block may be empty). - -Greenlets are chained: each points to the previous greenlet, which is -the one that owns the data currently in the C stack above my -stack_stop.  The currently running greenlet is the first element of -this chain.  The main (initial) greenlet is the last one.  Greenlets -whose stack is entirely in the heap can be skipped from the chain. - -The chain is not related to execution order, but only to the order -in which bits of C stack happen to belong to greenlets at a particular -point in time. - -The main greenlet doesn't have a stack_stop: it is responsible for the -complete rest of the C stack, and we don't know where it begins.  We -use (char*) -1, the largest possible address. - -States: -  stack_stop == NULL && stack_start == NULL:  did not start yet -  stack_stop != NULL && stack_start == NULL:  already finished -  stack_stop != NULL && stack_start != NULL:  active - -The running greenlet's stack_start is undefined but not NULL. - - ***********************************************************/ - -static PyGreenlet* -green_create_main(ThreadState* state) -{ -    PyGreenlet* gmain; - -    /* create the main greenlet for this thread */ -    gmain = (PyGreenlet*)PyType_GenericAlloc(&PyGreenlet_Type, 0); -    if (gmain == NULL) { -        Py_FatalError("green_create_main failed to alloc"); -        return NULL; -    } -    new MainGreenlet(gmain, state); - -    assert(Py_REFCNT(gmain) == 1); -    return gmain; -} - - - -/***********************************************************/ - -/* Some functions must not be inlined: -   * slp_restore_state, when inlined into slp_switch might cause -     it to restore stack over its own local variables -   * slp_save_state, when inlined would add its own local -     variables to the saved stack, wasting space -   * slp_switch, cannot be inlined for obvious reasons -   * g_initialstub, when inlined would receive a pointer into its -     own stack frame, leading to incomplete stack save/restore - -g_initialstub is a member function and declared virtual so that the -compiler always calls it through a vtable. - -slp_save_state and slp_restore_state are also member functions. They -are called from trampoline functions that themselves are declared as -not eligible for inlining. -*/ - -extern "C" { -static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref) -{ -    return switching_thread_state->slp_save_state(stackref); -} -static void GREENLET_NOINLINE(slp_restore_state_trampoline)() -{ -    switching_thread_state->slp_restore_state(); -} -} - - -/***********************************************************/ - -static PyGreenlet* -green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) -{ -    PyGreenlet* o = -        (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); -    if (o) { -        new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current()); -        assert(Py_REFCNT(o) == 1); -    } -    return o; -} - -static PyGreenlet* -green_unswitchable_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) -{ -    PyGreenlet* o = -        (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); -    if (o) { -        new BrokenGreenlet(o, GET_THREAD_STATE().state().borrow_current()); -        assert(Py_REFCNT(o) == 1); -    } -    return o; -} - -static int -green_setrun(BorrowedGreenlet self, BorrowedObject nrun, void* c); -static int -green_setparent(BorrowedGreenlet self, BorrowedObject nparent, void* c); - -static int -green_init(BorrowedGreenlet self, BorrowedObject args, BorrowedObject kwargs) -{ -    PyArgParseParam run; -    PyArgParseParam nparent; -    static const char* const kwlist[] = { -        "run", -        "parent", -        NULL -    }; - -    // recall: The O specifier does NOT increase the reference count. -    if (!PyArg_ParseTupleAndKeywords( -             args, kwargs, "|OO:green", (char**)kwlist, &run, &nparent)) { -        return -1; -    } - -    if (run) { -        if (green_setrun(self, run, NULL)) { -            return -1; -        } -    } -    if (nparent && !nparent.is_None()) { -        return green_setparent(self, nparent, NULL); -    } -    return 0; -} - - - -static int -green_traverse(PyGreenlet* self, visitproc visit, void* arg) -{ -    // We must only visit referenced objects, i.e. only objects -    // Py_INCREF'ed by this greenlet (directly or indirectly): -    // -    // - stack_prev is not visited: holds previous stack pointer, but it's not -    //    referenced -    // - frames are not visited as we don't strongly reference them; -    //    alive greenlets are not garbage collected -    //    anyway. This can be a problem, however, if this greenlet is -    //    never allowed to finish, and is referenced from the frame: we -    //    have an uncollectible cycle in that case. Note that the -    //    frame object itself is also frequently not even tracked by the GC -    //    starting with Python 3.7 (frames are allocated by the -    //    interpreter untracked, and only become tracked when their -    //    evaluation is finished if they have a refcount > 1). All of -    //    this is to say that we should probably strongly reference -    //    the frame object. Doing so, while always allowing GC on a -    //    greenlet, solves several leaks for us. - -    Py_VISIT(self->dict); -    if (!self->pimpl) { -        // Hmm. I have seen this at interpreter shutdown time, -        // I think. That's very odd because this doesn't go away until -        // we're ``green_dealloc()``, at which point we shouldn't be -        // traversed anymore. -        return 0; -    } - -    return self->pimpl->tp_traverse(visit, arg); -} - -static int -green_is_gc(BorrowedGreenlet self) -{ -    int result = 0; -    /* Main greenlet can be garbage collected since it can only -       become unreachable if the underlying thread exited. -       Active greenlets --- including those that are suspended --- -       cannot be garbage collected, however. -    */ -    if (self->main() || !self->active()) { -        result = 1; -    } -    // The main greenlet pointer will eventually go away after the thread dies. -    if (self->was_running_in_dead_thread()) { -        // Our thread is dead! We can never run again. Might as well -        // GC us. Note that if a tuple containing only us and other -        // immutable objects had been scanned before this, when we -        // would have returned 0, the tuple will take itself out of GC -        // tracking and never be investigated again. So that could -        // result in both us and the tuple leaking due to an -        // unreachable/uncollectible reference. The same goes for -        // dictionaries. -        // -        // It's not a great idea to be changing our GC state on the -        // fly. -        result = 1; -    } -    return result; -} - - -static int -green_clear(PyGreenlet* self) -{ -    /* Greenlet is only cleared if it is about to be collected. -       Since active greenlets are not garbage collectable, we can -       be sure that, even if they are deallocated during clear, -       nothing they reference is in unreachable or finalizers, -       so even if it switches we are relatively safe. */ -    // XXX: Are we responsible for clearing weakrefs here? -    Py_CLEAR(self->dict); -    return self->pimpl->tp_clear(); -} - -/** - * Returns 0 on failure (the object was resurrected) or 1 on success. - **/ -static int -_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self) -{ -    /* Hacks hacks hacks copied from instance_dealloc() */ -    /* Temporarily resurrect the greenlet. */ -    assert(self.REFCNT() == 0); -    Py_SET_REFCNT(self.borrow(), 1); -    /* Save the current exception, if any. */ -    PyErrPieces saved_err; -    try { -        // BY THE TIME WE GET HERE, the state may actually be going -        // away -        // if we're shutting down the interpreter and freeing thread -        // entries, -        // this could result in freeing greenlets that were leaked. So -        // we can't try to read the state. -        self->deallocing_greenlet_in_thread( -              self->thread_state() -              ? static_cast<ThreadState*>(GET_THREAD_STATE()) -              : nullptr); -    } -    catch (const PyErrOccurred&) { -        PyErr_WriteUnraisable(self.borrow_o()); -        /* XXX what else should we do? */ -    } -    /* Check for no resurrection must be done while we keep -     * our internal reference, otherwise PyFile_WriteObject -     * causes recursion if using Py_INCREF/Py_DECREF -     */ -    if (self.REFCNT() == 1 && self->active()) { -        /* Not resurrected, but still not dead! -           XXX what else should we do? we complain. */ -        PyObject* f = PySys_GetObject("stderr"); -        Py_INCREF(self.borrow_o()); /* leak! */ -        if (f != NULL) { -            PyFile_WriteString("GreenletExit did not kill ", f); -            PyFile_WriteObject(self.borrow_o(), f, 0); -            PyFile_WriteString("\n", f); -        } -    } -    /* Restore the saved exception. */ -    saved_err.PyErrRestore(); -    /* Undo the temporary resurrection; can't use DECREF here, -     * it would cause a recursive call. -     */ -    assert(self.REFCNT() > 0); - -    Py_ssize_t refcnt = self.REFCNT() - 1; -    Py_SET_REFCNT(self.borrow_o(), refcnt); -    if (refcnt != 0) { -        /* Resurrected! */ -        _Py_NewReference(self.borrow_o()); -        Py_SET_REFCNT(self.borrow_o(), refcnt); -        /* Better to use tp_finalizer slot (PEP 442) -         * and call ``PyObject_CallFinalizerFromDealloc``, -         * but that's only supported in Python 3.4+; see -         * Modules/_io/iobase.c for an example. -         * -         * The following approach is copied from iobase.c in CPython 2.7. -         * (along with much of this function in general). Here's their -         * comment: -         * -         * When called from a heap type's dealloc, the type will be -         * decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ -        if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) { -            Py_INCREF(self.TYPE()); -        } - -        PyObject_GC_Track((PyObject*)self); - -        _Py_DEC_REFTOTAL; -#ifdef COUNT_ALLOCS -        --Py_TYPE(self)->tp_frees; -        --Py_TYPE(self)->tp_allocs; -#endif /* COUNT_ALLOCS */ -        return 0; -    } -    return 1; -} - - -static void -green_dealloc(PyGreenlet* self) -{ -    PyObject_GC_UnTrack(self); -    BorrowedGreenlet me(self); -    if (me->active() -        && me->started() -        && !me->main()) { -        if (!_green_dealloc_kill_started_non_main_greenlet(me)) { -            return; -        } -    } - -    if (self->weakreflist != NULL) { -        PyObject_ClearWeakRefs((PyObject*)self); -    } -    Py_CLEAR(self->dict); - -    if (self->pimpl) { -        // In case deleting this, which frees some memory, -        // somehow winds up calling back into us. That's usually a -        //bug in our code. -        Greenlet* p = self->pimpl; -        self->pimpl = nullptr; -        delete p; -    } -    // and finally we're done. self is now invalid. -    Py_TYPE(self)->tp_free((PyObject*)self); -} - - - -static OwnedObject -throw_greenlet(BorrowedGreenlet self, PyErrPieces& err_pieces) -{ -    PyObject* result = nullptr; -    err_pieces.PyErrRestore(); -    assert(PyErr_Occurred()); -    if (self->started() && !self->active()) { -        /* dead greenlet: turn GreenletExit into a regular return */ -        result = g_handle_exit(OwnedObject()).relinquish_ownership(); -    } -    self->args() <<= result; - -    return single_result(self->g_switch()); -} - - - -PyDoc_STRVAR( -    green_switch_doc, -    "switch(*args, **kwargs)\n" -    "\n" -    "Switch execution to this greenlet.\n" -    "\n" -    "If this greenlet has never been run, then this greenlet\n" -    "will be switched to using the body of ``self.run(*args, **kwargs)``.\n" -    "\n" -    "If the greenlet is active (has been run, but was switch()'ed\n" -    "out before leaving its run function), then this greenlet will\n" -    "be resumed and the return value to its switch call will be\n" -    "None if no arguments are given, the given argument if one\n" -    "argument is given, or the args tuple and keyword args dict if\n" -    "multiple arguments are given.\n" -    "\n" -    "If the greenlet is dead, or is the current greenlet then this\n" -    "function will simply return the arguments using the same rules as\n" -    "above.\n"); - -static PyObject* -green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) -{ -    using greenlet::SwitchingArgs; -    SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs)); -    self->pimpl->may_switch_away(); -    self->pimpl->args() <<= switch_args; - -    // If we're switching out of a greenlet, and that switch is the -    // last thing the greenlet does, the greenlet ought to be able to -    // go ahead and die at that point. Currently, someone else must -    // manually switch back to the greenlet so that we "fall off the -    // end" and can perform cleanup. You'd think we'd be able to -    // figure out that this is happening using the frame's ``f_lasti`` -    // member, which is supposed to be an index into -    // ``frame->f_code->co_code``, the bytecode string. However, in -    // recent interpreters, ``f_lasti`` tends not to be updated thanks -    // to things like the PREDICT() macros in ceval.c. So it doesn't -    // really work to do that in many cases. For example, the Python -    // code: -    //     def run(): -    //         greenlet.getcurrent().parent.switch() -    // produces bytecode of len 16, with the actual call to switch() -    // being at index 10 (in Python 3.10). However, the reported -    // ``f_lasti`` we actually see is...5! (Which happens to be the -    // second byte of the CALL_METHOD op for ``getcurrent()``). - -    try { -        //OwnedObject result = single_result(self->pimpl->g_switch()); -        OwnedObject result(single_result(self->pimpl->g_switch())); -#ifndef NDEBUG -        // Note that the current greenlet isn't necessarily self. If self -        // finished, we went to one of its parents. -        assert(!self->pimpl->args()); - -        const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current(); -        // It's possible it's never been switched to. -        assert(!current->args()); -#endif -        PyObject* p = result.relinquish_ownership(); - -        if (!p && !PyErr_Occurred()) { -            // This shouldn't be happening anymore, so the asserts -            // are there for debug builds. Non-debug builds -            // crash "gracefully" in this case, although there is an -            // argument to be made for killing the process in all -            // cases --- for this to be the case, our switches -            // probably nested in an incorrect way, so the state is -            // suspicious. Nothing should be corrupt though, just -            // confused at the Python level. Letting this propagate is -            // probably good enough. -            assert(p || PyErr_Occurred()); -            throw PyErrOccurred( -                mod_globs->PyExc_GreenletError, -                "Greenlet.switch() returned NULL without an exception set." -            ); -        } -        return p; -    } -    catch(const PyErrOccurred&) { -        return nullptr; -    } -} - -PyDoc_STRVAR( -    green_throw_doc, -    "Switches execution to this greenlet, but immediately raises the\n" -    "given exception in this greenlet.  If no argument is provided, the " -    "exception\n" -    "defaults to `greenlet.GreenletExit`.  The normal exception\n" -    "propagation rules apply, as described for `switch`.  Note that calling " -    "this\n" -    "method is almost equivalent to the following::\n" -    "\n" -    "    def raiser():\n" -    "        raise typ, val, tb\n" -    "    g_raiser = greenlet(raiser, parent=g)\n" -    "    g_raiser.switch()\n" -    "\n" -    "except that this trick does not work for the\n" -    "`greenlet.GreenletExit` exception, which would not propagate\n" -    "from ``g_raiser`` to ``g``.\n"); - -static PyObject* -green_throw(PyGreenlet* self, PyObject* args) -{ -    PyArgParseParam typ(mod_globs->PyExc_GreenletExit); -    PyArgParseParam val; -    PyArgParseParam tb; - -    if (!PyArg_ParseTuple(args, "|OOO:throw", &typ, &val, &tb)) { -        return nullptr; -    } - -    assert(typ.borrow() || val.borrow()); - -    self->pimpl->may_switch_away(); -    try { -        // Both normalizing the error and the actual throw_greenlet -        // could throw PyErrOccurred. -        PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow()); - -        return throw_greenlet(self, err_pieces).relinquish_ownership(); -    } -    catch (const PyErrOccurred&) { -        return nullptr; -    } -} - -static int -green_bool(PyGreenlet* self) -{ -    return self->pimpl->active(); -} - -/** - * CAUTION: Allocates memory, may run GC and arbitrary Python code. - */ -static PyObject* -green_getdict(PyGreenlet* self, void* UNUSED(context)) -{ -    if (self->dict == NULL) { -        self->dict = PyDict_New(); -        if (self->dict == NULL) { -            return NULL; -        } -    } -    Py_INCREF(self->dict); -    return self->dict; -} - -static int -green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context)) -{ -    PyObject* tmp; - -    if (val == NULL) { -        PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); -        return -1; -    } -    if (!PyDict_Check(val)) { -        PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); -        return -1; -    } -    tmp = self->dict; -    Py_INCREF(val); -    self->dict = val; -    Py_XDECREF(tmp); -    return 0; -} - -static bool -_green_not_dead(BorrowedGreenlet self) -{ -    // XXX: Where else should we do this? -    // Probably on entry to most Python-facing functions? -    if (self->was_running_in_dead_thread()) { -        self->deactivate_and_free(); -        return false; -    } -    return self->active() || !self->started(); -} - - -static PyObject* -green_getdead(BorrowedGreenlet self, void* UNUSED(context)) -{ -    if (_green_not_dead(self)) { -        Py_RETURN_FALSE; -    } -    else { -        Py_RETURN_TRUE; -    } -} - -static PyObject* -green_get_stack_saved(PyGreenlet* self, void* UNUSED(context)) -{ -    return PyLong_FromSsize_t(self->pimpl->stack_saved()); -} - - -static PyObject* -green_getrun(BorrowedGreenlet self, void* UNUSED(context)) -{ -    try { -        OwnedObject result(self->run()); -        return result.relinquish_ownership(); -    } -    catch(const PyErrOccurred&) { -        return nullptr; -    } -} - - - - - -static int -green_setrun(BorrowedGreenlet self, BorrowedObject nrun, void* UNUSED(context)) -{ -    try { -        self->run(nrun); -        return 0; -    } -    catch(const PyErrOccurred&) { -        return -1; -    } -} - -static PyObject* -green_getparent(BorrowedGreenlet self, void* UNUSED(context)) -{ -    return self->parent().acquire_or_None(); -} - - - -static int -green_setparent(BorrowedGreenlet self, BorrowedObject nparent, void* UNUSED(context)) -{ -    try { -        self->parent(nparent); -    } -    catch(const PyErrOccurred&) { -        return -1; -    } -    return 0; -} - - -static PyObject* -green_getcontext(const PyGreenlet* self, void* UNUSED(context)) -{ -    const Greenlet *const g = self->pimpl; -    try { -        OwnedObject result(g->context()); -        return result.relinquish_ownership(); -    } -    catch(const PyErrOccurred&) { -        return nullptr; -    } -} - -static int -green_setcontext(BorrowedGreenlet self, PyObject* nctx, void* UNUSED(context)) -{ -    try { -        self->context(nctx); -        return 0; -    } -    catch(const PyErrOccurred&) { -        return -1; -    } -} - - -static PyObject* -green_getframe(BorrowedGreenlet self, void* UNUSED(context)) -{ -    const PythonState::OwnedFrame& top_frame = self->top_frame(); -    return top_frame.acquire_or_None(); -} - - -static PyObject* -green_getstate(PyGreenlet* self) -{ -    PyErr_Format(PyExc_TypeError, -                 "cannot serialize '%s' object", -                 Py_TYPE(self)->tp_name); -    return nullptr; -} - -static PyObject* -green_repr(BorrowedGreenlet self) -{ -    /* -      Return a string like -      <greenlet.greenlet at 0xdeadbeef [current][active started]|dead main> - -      The handling of greenlets across threads is not super good. -      We mostly use the internal definitions of these terms, but they -      generally should make sense to users as well. -     */ -    PyObject* result; -    int never_started = !self->started() && !self->active(); - -    const char* const tp_name = Py_TYPE(self)->tp_name; - -    if (_green_not_dead(self)) { -        /* XXX: The otid= is almost useless because you can't correlate it to -         any thread identifier exposed to Python. We could use -         PyThreadState_GET()->thread_id, but we'd need to save that in the -         greenlet, or save the whole PyThreadState object itself. - -         As it stands, its only useful for identifying greenlets from the same thread. -        */ -        const char* state_in_thread; -        if (self->was_running_in_dead_thread()) { -            // The thread it was running in is dead! -            // This can happen, especially at interpreter shut down. -            // It complicates debugging output because it may be -            // impossible to access the current thread state at that -            // time. Thus, don't access the current thread state. -            state_in_thread = " (thread exited)"; -        } -        else { -            state_in_thread = GET_THREAD_STATE().state().is_current(self) -                ? " current" -                : (self->started() ? " suspended" : ""); -        } -        result = PyUnicode_FromFormat( -            "<%s object at %p (otid=%p)%s%s%s%s>", -            tp_name, -            self.borrow_o(), -            self->thread_state(), -            state_in_thread, -            self->active() ? " active" : "", -            never_started ? " pending" : " started", -            self->main() ? " main" : "" -        ); -    } -    else { -        result = PyUnicode_FromFormat( -            "<%s object at %p (otid=%p) %sdead>", -            tp_name, -            self.borrow_o(), -            self->thread_state(), -            self->was_running_in_dead_thread() -            ? "(thread exited) " -            : "" -            ); -    } - -    return result; -} - -/***************************************************************************** - * C interface - * - * These are exported using the CObject API - */ -extern "C" { -static PyGreenlet* -PyGreenlet_GetCurrent(void) -{ -    return GET_THREAD_STATE().state().get_current().relinquish_ownership(); -} - -static int -PyGreenlet_SetParent(PyGreenlet* g, PyGreenlet* nparent) -{ -    return green_setparent((PyGreenlet*)g, (PyObject*)nparent, NULL); -} - -static PyGreenlet* -PyGreenlet_New(PyObject* run, PyGreenlet* parent) -{ -    using greenlet::refs::NewDictReference; -    // In the past, we didn't use green_new and green_init, but that -    // was a maintenance issue because we duplicated code. This way is -    // much safer, but slightly slower. If that's a problem, we could -    // refactor green_init to separate argument parsing from initialization. -    OwnedGreenlet g = OwnedGreenlet::consuming(green_new(&PyGreenlet_Type, nullptr, nullptr)); -    if (!g) { -        return NULL; -    } - -    try { -        NewDictReference kwargs; -        if (run) { -            kwargs.SetItem(mod_globs->str_run, run); -        } -        if (parent) { -            kwargs.SetItem("parent", (PyObject*)parent); -        } - -        Require(green_init(g, mod_globs->empty_tuple, kwargs)); -    } -    catch (const PyErrOccurred&) { -        return nullptr; -    } - -    return g.relinquish_ownership(); -} - -static PyObject* -PyGreenlet_Switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) -{ -    if (!PyGreenlet_Check(self)) { -        PyErr_BadArgument(); -        return NULL; -    } - -    if (args == NULL) { -        args = mod_globs->empty_tuple; -    } - -    if (kwargs == NULL || !PyDict_Check(kwargs)) { -        kwargs = NULL; -    } - -    return green_switch(self, args, kwargs); -} - -static PyObject* -PyGreenlet_Throw(PyGreenlet* self, PyObject* typ, PyObject* val, PyObject* tb) -{ -    if (!PyGreenlet_Check(self)) { -        PyErr_BadArgument(); -        return nullptr; -    } -    try { -        PyErrPieces err_pieces(typ, val, tb); -        return throw_greenlet(self, err_pieces).relinquish_ownership(); -    } -    catch (const PyErrOccurred&) { -        return nullptr; -    } -} - -static int -Extern_PyGreenlet_MAIN(PyGreenlet* self) -{ -    if (!PyGreenlet_Check(self)) { -        PyErr_BadArgument(); -        return -1; -    } -    return self->pimpl->main(); -} - -static int -Extern_PyGreenlet_ACTIVE(PyGreenlet* self) -{ -    if (!PyGreenlet_Check(self)) { -        PyErr_BadArgument(); -        return -1; -    } -    return self->pimpl->active(); -} - -static int -Extern_PyGreenlet_STARTED(PyGreenlet* self) -{ -    if (!PyGreenlet_Check(self)) { -        PyErr_BadArgument(); -        return -1; -    } -    return self->pimpl->started(); -} - -static PyGreenlet* -Extern_PyGreenlet_GET_PARENT(PyGreenlet* self) -{ -    if (!PyGreenlet_Check(self)) { -        PyErr_BadArgument(); -        return NULL; -    } -    // This can return NULL even if there is no exception -    return self->pimpl->parent().acquire(); -} -} // extern C. - -/** End C API ****************************************************************/ - -static PyMethodDef green_methods[] = { -    {"switch", -     reinterpret_cast<PyCFunction>(green_switch), -     METH_VARARGS | METH_KEYWORDS, -     green_switch_doc}, -    {"throw", (PyCFunction)green_throw, METH_VARARGS, green_throw_doc}, -    {"__getstate__", (PyCFunction)green_getstate, METH_NOARGS, NULL}, -    {NULL, NULL} /* sentinel */ -}; - -static PyGetSetDef green_getsets[] = { -    /* name, getter, setter, doc, context pointer */ -    {"__dict__", (getter)green_getdict, (setter)green_setdict, /*XXX*/ NULL}, -    {"run", (getter)green_getrun, (setter)green_setrun, /*XXX*/ NULL}, -    {"parent", (getter)green_getparent, (setter)green_setparent, /*XXX*/ NULL}, -    {"gr_frame", (getter)green_getframe, NULL, /*XXX*/ NULL}, -    {"gr_context", -     (getter)green_getcontext, -     (setter)green_setcontext, -     /*XXX*/ NULL}, -    {"dead", (getter)green_getdead, NULL, /*XXX*/ NULL}, -    {"_stack_saved", (getter)green_get_stack_saved, NULL, /*XXX*/ NULL}, -    {NULL} -}; - -static PyMemberDef green_members[] = { -    {NULL} -}; - -static PyNumberMethods green_as_number = { -    NULL, /* nb_add */ -    NULL, /* nb_subtract */ -    NULL, /* nb_multiply */ -    NULL,                /* nb_remainder */ -    NULL,                /* nb_divmod */ -    NULL,                /* nb_power */ -    NULL,                /* nb_negative */ -    NULL,                /* nb_positive */ -    NULL,                /* nb_absolute */ -    (inquiry)green_bool, /* nb_bool */ -}; - - -PyTypeObject PyGreenlet_Type = { -    PyVarObject_HEAD_INIT(NULL, 0) -    "greenlet.greenlet", /* tp_name */ -    sizeof(PyGreenlet),  /* tp_basicsize */ -    0,                   /* tp_itemsize */ -    /* methods */ -    (destructor)green_dealloc, /* tp_dealloc */ -    0,                         /* tp_print */ -    0,                         /* tp_getattr */ -    0,                         /* tp_setattr */ -    0,                         /* tp_compare */ -    (reprfunc)green_repr,      /* tp_repr */ -    &green_as_number,          /* tp_as _number*/ -    0,                         /* tp_as _sequence*/ -    0,                         /* tp_as _mapping*/ -    0,                         /* tp_hash */ -    0,                         /* tp_call */ -    0,                         /* tp_str */ -    0,                         /* tp_getattro */ -    0,                         /* tp_setattro */ -    0,                         /* tp_as_buffer*/ -    G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ -    "greenlet(run=None, parent=None) -> greenlet\n\n" -    "Creates a new greenlet object (without running it).\n\n" -    " - *run* -- The callable to invoke.\n" -    " - *parent* -- The parent greenlet. The default is the current " -    "greenlet.",                        /* tp_doc */ -    (traverseproc)green_traverse, /* tp_traverse */ -    (inquiry)green_clear,         /* tp_clear */ -    0,                                  /* tp_richcompare */ -    offsetof(PyGreenlet, weakreflist),  /* tp_weaklistoffset */ -    0,                                  /* tp_iter */ -    0,                                  /* tp_iternext */ -    green_methods,                      /* tp_methods */ -    green_members,                      /* tp_members */ -    green_getsets,                      /* tp_getset */ -    0,                                  /* tp_base */ -    0,                                  /* tp_dict */ -    0,                                  /* tp_descr_get */ -    0,                                  /* tp_descr_set */ -    offsetof(PyGreenlet, dict),         /* tp_dictoffset */ -    (initproc)green_init,               /* tp_init */ -    PyType_GenericAlloc,                  /* tp_alloc */ -    (newfunc)green_new,                          /* tp_new */ -    PyObject_GC_Del,                   /* tp_free */ -    (inquiry)green_is_gc,         /* tp_is_gc */ -}; - - - -static PyObject* -green_unswitchable_getforce(PyGreenlet* self, void* UNUSED(context)) -{ -    BrokenGreenlet* broken = dynamic_cast<BrokenGreenlet*>(self->pimpl); -    return PyBool_FromLong(broken->_force_switch_error); -} - -static int -green_unswitchable_setforce(PyGreenlet* self, BorrowedObject nforce, void* UNUSED(context)) -{ -    if (!nforce) { -        PyErr_SetString( -            PyExc_AttributeError, -            "Cannot delete force_switch_error" -        ); -        return -1; -    } -    BrokenGreenlet* broken = dynamic_cast<BrokenGreenlet*>(self->pimpl); -    int is_true = PyObject_IsTrue(nforce); -    if (is_true == -1) { -        return -1; -    } -    broken->_force_switch_error = is_true; -    return 0; -} - -static PyObject* -green_unswitchable_getforceslp(PyGreenlet* self, void* UNUSED(context)) -{ -    BrokenGreenlet* broken = dynamic_cast<BrokenGreenlet*>(self->pimpl); -    return PyBool_FromLong(broken->_force_slp_switch_error); -} - -static int -green_unswitchable_setforceslp(PyGreenlet* self, BorrowedObject nforce, void* UNUSED(context)) -{ -    if (!nforce) { -        PyErr_SetString( -            PyExc_AttributeError, -            "Cannot delete force_slp_switch_error" -        ); -        return -1; -    } -    BrokenGreenlet* broken = dynamic_cast<BrokenGreenlet*>(self->pimpl); -    int is_true = PyObject_IsTrue(nforce); -    if (is_true == -1) { -        return -1; -    } -    broken->_force_slp_switch_error = is_true; -    return 0; -} - -static PyGetSetDef green_unswitchable_getsets[] = { -    /* name, getter, setter, doc, context pointer */ -    {"force_switch_error", -     (getter)green_unswitchable_getforce, -     (setter)green_unswitchable_setforce, -     /*XXX*/ NULL}, -    {"force_slp_switch_error", -     (getter)green_unswitchable_getforceslp, -     (setter)green_unswitchable_setforceslp, -     /*XXX*/ NULL}, - -    {NULL} -}; - -PyTypeObject PyGreenletUnswitchable_Type = { -    PyVarObject_HEAD_INIT(NULL, 0) -    "greenlet._greenlet.UnswitchableGreenlet", -    0,  /* tp_basicsize */ -    0,                   /* tp_itemsize */ -    /* methods */ -    (destructor)green_dealloc, /* tp_dealloc */ -    0,                         /* tp_print */ -    0,                         /* tp_getattr */ -    0,                         /* tp_setattr */ -    0,                         /* tp_compare */ -    0,      /* tp_repr */ -    0,          /* tp_as _number*/ -    0,                         /* tp_as _sequence*/ -    0,                         /* tp_as _mapping*/ -    0,                         /* tp_hash */ -    0,                         /* tp_call */ -    0,                         /* tp_str */ -    0,                         /* tp_getattro */ -    0,                         /* tp_setattro */ -    0,                         /* tp_as_buffer*/ -    G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ -    "Undocumented internal class",                        /* tp_doc */ -    (traverseproc)green_traverse, /* tp_traverse */ -    (inquiry)green_clear,         /* tp_clear */ -    0,                                  /* tp_richcompare */ -    0,  /* tp_weaklistoffset */ -    0,                                  /* tp_iter */ -    0,                                  /* tp_iternext */ -    0,                      /* tp_methods */ -    0,                      /* tp_members */ -    green_unswitchable_getsets,                      /* tp_getset */ -    &PyGreenlet_Type,                                  /* tp_base */ -    0,                                  /* tp_dict */ -    0,                                  /* tp_descr_get */ -    0,                                  /* tp_descr_set */ -    0,         /* tp_dictoffset */ -    (initproc)green_init,               /* tp_init */ -    PyType_GenericAlloc,                  /* tp_alloc */ -    (newfunc)green_unswitchable_new,                          /* tp_new */ -    PyObject_GC_Del,                   /* tp_free */ -    (inquiry)green_is_gc,         /* tp_is_gc */ -}; - - -PyDoc_STRVAR(mod_getcurrent_doc, -             "getcurrent() -> greenlet\n" -             "\n" -             "Returns the current greenlet (i.e. the one which called this " -             "function).\n"); - -static PyObject* -mod_getcurrent(PyObject* UNUSED(module)) -{ -    return GET_THREAD_STATE().state().get_current().relinquish_ownership_o(); -} - -PyDoc_STRVAR(mod_settrace_doc, -             "settrace(callback) -> object\n" -             "\n" -             "Sets a new tracing function and returns the previous one.\n"); -static PyObject* -mod_settrace(PyObject* UNUSED(module), PyObject* args) -{ -    PyArgParseParam tracefunc; -    if (!PyArg_ParseTuple(args, "O", &tracefunc)) { -        return NULL; -    } -    ThreadState& state = GET_THREAD_STATE(); -    OwnedObject previous = state.get_tracefunc(); -    if (!previous) { -        previous = Py_None; -    } - -    state.set_tracefunc(tracefunc); - -    return previous.relinquish_ownership(); -} - -PyDoc_STRVAR(mod_gettrace_doc, -             "gettrace() -> object\n" -             "\n" -             "Returns the currently set tracing function, or None.\n"); - -static PyObject* -mod_gettrace(PyObject* UNUSED(module)) -{ -    OwnedObject tracefunc = GET_THREAD_STATE().state().get_tracefunc(); -    if (!tracefunc) { -        tracefunc = Py_None; -    } -    return tracefunc.relinquish_ownership(); -} - -PyDoc_STRVAR(mod_set_thread_local_doc, -             "set_thread_local(key, value) -> None\n" -             "\n" -             "Set a value in the current thread-local dictionary. Debbuging only.\n"); - -static PyObject* -mod_set_thread_local(PyObject* UNUSED(module), PyObject* args) -{ -    PyArgParseParam key; -    PyArgParseParam value; -    PyObject* result = NULL; - -    if (PyArg_UnpackTuple(args, "set_thread_local", 2, 2, &key, &value)) { -        if(PyDict_SetItem( -                          PyThreadState_GetDict(), // borrow -                          key, -                          value) == 0 ) { -            // success -            Py_INCREF(Py_None); -            result = Py_None; -        } -    } -    return result; -} - -PyDoc_STRVAR(mod_get_pending_cleanup_count_doc, -             "get_pending_cleanup_count() -> Integer\n" -             "\n" -             "Get the number of greenlet cleanup operations pending. Testing only.\n"); - - -static PyObject* -mod_get_pending_cleanup_count(PyObject* UNUSED(module)) -{ -    LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); -    return PyLong_FromSize_t(mod_globs->thread_states_to_destroy.size()); -} - -PyDoc_STRVAR(mod_get_total_main_greenlets_doc, -             "get_total_main_greenlets() -> Integer\n" -             "\n" -             "Quickly return the number of main greenlets that exist. Testing only.\n"); - -static PyObject* -mod_get_total_main_greenlets(PyObject* UNUSED(module)) -{ -    return PyLong_FromSize_t(G_TOTAL_MAIN_GREENLETS); -} - -PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc, -             "get_clocks_used_doing_optional_cleanup() -> Integer\n" -             "\n" -             "Get the number of clock ticks the program has used doing optional " -             "greenlet cleanup.\n" -             "Beginning in greenlet 2.0, greenlet tries to find and dispose of greenlets\n" -             "that leaked after a thread exited. This requires invoking Python's garbage collector,\n" -             "which may have a performance cost proportional to the number of live objects.\n" -             "This function returns the amount of processor time\n" -             "greenlet has used to do this. In programs that run with very large amounts of live\n" -             "objects, this metric can be used to decide whether the cost of doing this cleanup\n" -             "is worth the memory leak being corrected. If not, you can disable the cleanup\n" -             "using ``enable_optional_cleanup(False)``.\n" -             "The units are arbitrary and can only be compared to themselves (similarly to ``time.clock()``);\n" -             "for example, to see how it scales with your heap. You can attempt to convert them into seconds\n" -             "by dividing by the value of CLOCKS_PER_SEC." -             "If cleanup has been disabled, returns None." -             "\n" -             "This is an implementation specific, provisional API. It may be changed or removed\n" -             "in the future.\n" -             ".. versionadded:: 2.0" -             ); -static PyObject* -mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module)) -{ -    std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); - -    if (clocks == std::clock_t(-1)) { -        Py_RETURN_NONE; -    } -    // This might not actually work on some implementations; clock_t -    // is an opaque type. -    return PyLong_FromSsize_t(clocks); -} - -PyDoc_STRVAR(mod_enable_optional_cleanup_doc, -             "mod_enable_optional_cleanup(bool) -> None\n" -             "\n" -             "Enable or disable optional cleanup operations.\n" -             "See ``get_clocks_used_doing_optional_cleanup()`` for details.\n" -             ); -static PyObject* -mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag) -{ -    int is_true = PyObject_IsTrue(flag); -    if (is_true == -1) { -        return nullptr; -    } - -    std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); -    if (is_true) { -        // If we already have a value, we don't want to lose it. -        if (clocks == std::clock_t(-1)) { -            clocks = 0; -        } -    } -    else { -        clocks = std::clock_t(-1); -    } -    Py_RETURN_NONE; -} - -PyDoc_STRVAR(mod_get_tstate_trash_delete_nesting_doc, -             "get_tstate_trash_delete_nesting() -> Integer\n" -             "\n" -             "Return the 'trash can' nesting level. Testing only.\n"); -static PyObject* -mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) -{ -    PyThreadState* tstate = PyThreadState_GET(); - -#if GREENLET_PY312 -    return PyLong_FromLong(tstate->trash.delete_nesting); -#else -    return PyLong_FromLong(tstate->trash_delete_nesting); -#endif -} - -static PyMethodDef GreenMethods[] = { -    {"getcurrent", -     (PyCFunction)mod_getcurrent, -     METH_NOARGS, -     mod_getcurrent_doc}, -    {"settrace", (PyCFunction)mod_settrace, METH_VARARGS, mod_settrace_doc}, -    {"gettrace", (PyCFunction)mod_gettrace, METH_NOARGS, mod_gettrace_doc}, -    {"set_thread_local", (PyCFunction)mod_set_thread_local, METH_VARARGS, mod_set_thread_local_doc}, -    {"get_pending_cleanup_count", (PyCFunction)mod_get_pending_cleanup_count, METH_NOARGS, mod_get_pending_cleanup_count_doc}, -    {"get_total_main_greenlets", (PyCFunction)mod_get_total_main_greenlets, METH_NOARGS, mod_get_total_main_greenlets_doc}, -    {"get_clocks_used_doing_optional_cleanup", (PyCFunction)mod_get_clocks_used_doing_optional_cleanup, METH_NOARGS, mod_get_clocks_used_doing_optional_cleanup_doc}, -    {"enable_optional_cleanup", (PyCFunction)mod_enable_optional_cleanup, METH_O, mod_enable_optional_cleanup_doc}, -    {"get_tstate_trash_delete_nesting", (PyCFunction)mod_get_tstate_trash_delete_nesting, METH_NOARGS, mod_get_tstate_trash_delete_nesting_doc}, -    {NULL, NULL} /* Sentinel */ -}; - -static const char* const copy_on_greentype[] = { -    "getcurrent", -    "error", -    "GreenletExit", -    "settrace", -    "gettrace", -    NULL -}; - -static struct PyModuleDef greenlet_module_def = { -    PyModuleDef_HEAD_INIT, -    "greenlet._greenlet", -    NULL, -    -1, -    GreenMethods, -}; - - - -static PyObject* -greenlet_internal_mod_init() noexcept -{ -    static void* _PyGreenlet_API[PyGreenlet_API_pointers]; - -    try { -        CreatedModule m(greenlet_module_def); - -        Require(PyType_Ready(&PyGreenlet_Type)); -        Require(PyType_Ready(&PyGreenletUnswitchable_Type)); - -        mod_globs = new greenlet::GreenletGlobals; -        ThreadState::init(); - -        m.PyAddObject("greenlet", PyGreenlet_Type); -        m.PyAddObject("UnswitchableGreenlet", PyGreenletUnswitchable_Type); -        m.PyAddObject("error", mod_globs->PyExc_GreenletError); -        m.PyAddObject("GreenletExit", mod_globs->PyExc_GreenletExit); - -        m.PyAddObject("GREENLET_USE_GC", 1); -        m.PyAddObject("GREENLET_USE_TRACING", 1); -        m.PyAddObject("GREENLET_USE_CONTEXT_VARS", 1L); -        m.PyAddObject("GREENLET_USE_STANDARD_THREADING", 1L); - -        OwnedObject clocks_per_sec = OwnedObject::consuming(PyLong_FromSsize_t(CLOCKS_PER_SEC)); -        m.PyAddObject("CLOCKS_PER_SEC", clocks_per_sec); - -        /* also publish module-level data as attributes of the greentype. */ -        // XXX: This is weird, and enables a strange pattern of -        // confusing the class greenlet with the module greenlet; with -        // the exception of (possibly) ``getcurrent()``, this -        // shouldn't be encouraged so don't add new items here. -        for (const char* const* p = copy_on_greentype; *p; p++) { -            OwnedObject o = m.PyRequireAttr(*p); -            PyDict_SetItemString(PyGreenlet_Type.tp_dict, *p, o.borrow()); -        } - -        /* -         * Expose C API -         */ - -        /* types */ -        _PyGreenlet_API[PyGreenlet_Type_NUM] = (void*)&PyGreenlet_Type; - -        /* exceptions */ -        _PyGreenlet_API[PyExc_GreenletError_NUM] = (void*)mod_globs->PyExc_GreenletError; -        _PyGreenlet_API[PyExc_GreenletExit_NUM] = (void*)mod_globs->PyExc_GreenletExit; - -        /* methods */ -        _PyGreenlet_API[PyGreenlet_New_NUM] = (void*)PyGreenlet_New; -        _PyGreenlet_API[PyGreenlet_GetCurrent_NUM] = (void*)PyGreenlet_GetCurrent; -        _PyGreenlet_API[PyGreenlet_Throw_NUM] = (void*)PyGreenlet_Throw; -        _PyGreenlet_API[PyGreenlet_Switch_NUM] = (void*)PyGreenlet_Switch; -        _PyGreenlet_API[PyGreenlet_SetParent_NUM] = (void*)PyGreenlet_SetParent; - -        /* Previously macros, but now need to be functions externally. */ -        _PyGreenlet_API[PyGreenlet_MAIN_NUM] = (void*)Extern_PyGreenlet_MAIN; -        _PyGreenlet_API[PyGreenlet_STARTED_NUM] = (void*)Extern_PyGreenlet_STARTED; -        _PyGreenlet_API[PyGreenlet_ACTIVE_NUM] = (void*)Extern_PyGreenlet_ACTIVE; -        _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM] = (void*)Extern_PyGreenlet_GET_PARENT; - -        /* XXX: Note that our module name is ``greenlet._greenlet``, but for -           backwards compatibility with existing C code, we need the _C_API to -           be directly in greenlet. -        */ -        const NewReference c_api_object(Require( -                                           PyCapsule_New( -                                               (void*)_PyGreenlet_API, -                                               "greenlet._C_API", -                                               NULL))); -        m.PyAddObject("_C_API", c_api_object); -        assert(c_api_object.REFCNT() == 2); - -        // cerr << "Sizes:" -        //      << "\n\tGreenlet       : " << sizeof(Greenlet) -        //      << "\n\tUserGreenlet   : " << sizeof(UserGreenlet) -        //      << "\n\tMainGreenlet   : " << sizeof(MainGreenlet) -        //      << "\n\tExceptionState : " << sizeof(greenlet::ExceptionState) -        //      << "\n\tPythonState    : " << sizeof(greenlet::PythonState) -        //      << "\n\tStackState     : " << sizeof(greenlet::StackState) -        //      << "\n\tSwitchingArgs  : " << sizeof(greenlet::SwitchingArgs) -        //      << "\n\tOwnedObject    : " << sizeof(greenlet::refs::OwnedObject) -        //      << "\n\tBorrowedObject : " << sizeof(greenlet::refs::BorrowedObject) -        //      << "\n\tPyGreenlet     : " << sizeof(PyGreenlet) -        //      << endl; - -        return m.borrow(); // But really it's the main reference. -    } -    catch (const LockInitError& e) { -        PyErr_SetString(PyExc_MemoryError, e.what()); -        return NULL; -    } -    catch (const PyErrOccurred&) { -        return NULL; -    } - -} - -extern "C" { - -PyMODINIT_FUNC -PyInit__greenlet(void) -{ -    return greenlet_internal_mod_init(); -} - -}; // extern C - -#ifdef __clang__ -#    pragma clang diagnostic pop -#elif defined(__GNUC__) -#    pragma GCC diagnostic pop -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet.h b/venv/lib/python3.11/site-packages/greenlet/greenlet.h deleted file mode 100644 index d02a16e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ - -/* Greenlet object interface */ - -#ifndef Py_GREENLETOBJECT_H -#define Py_GREENLETOBJECT_H - - -#include <Python.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is deprecated and undocumented. It does not change. */ -#define GREENLET_VERSION "1.0.0" - -#ifndef GREENLET_MODULE -#define implementation_ptr_t void* -#endif - -typedef struct _greenlet { -    PyObject_HEAD -    PyObject* weakreflist; -    PyObject* dict; -    implementation_ptr_t pimpl; -} PyGreenlet; - -#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) - - -/* C API functions */ - -/* Total number of symbols that are exported */ -#define PyGreenlet_API_pointers 12 - -#define PyGreenlet_Type_NUM 0 -#define PyExc_GreenletError_NUM 1 -#define PyExc_GreenletExit_NUM 2 - -#define PyGreenlet_New_NUM 3 -#define PyGreenlet_GetCurrent_NUM 4 -#define PyGreenlet_Throw_NUM 5 -#define PyGreenlet_Switch_NUM 6 -#define PyGreenlet_SetParent_NUM 7 - -#define PyGreenlet_MAIN_NUM 8 -#define PyGreenlet_STARTED_NUM 9 -#define PyGreenlet_ACTIVE_NUM 10 -#define PyGreenlet_GET_PARENT_NUM 11 - -#ifndef GREENLET_MODULE -/* This section is used by modules that uses the greenlet C API */ -static void** _PyGreenlet_API = NULL; - -#    define PyGreenlet_Type \ -        (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) - -#    define PyExc_GreenletError \ -        ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) - -#    define PyExc_GreenletExit \ -        ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) - -/* - * PyGreenlet_New(PyObject *args) - * - * greenlet.greenlet(run, parent=None) - */ -#    define PyGreenlet_New                                        \ -        (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ -             _PyGreenlet_API[PyGreenlet_New_NUM]) - -/* - * PyGreenlet_GetCurrent(void) - * - * greenlet.getcurrent() - */ -#    define PyGreenlet_GetCurrent \ -        (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) - -/* - * PyGreenlet_Throw( - *         PyGreenlet *greenlet, - *         PyObject *typ, - *         PyObject *val, - *         PyObject *tb) - * - * g.throw(...) - */ -#    define PyGreenlet_Throw                 \ -        (*(PyObject * (*)(PyGreenlet * self, \ -                          PyObject * typ,    \ -                          PyObject * val,    \ -                          PyObject * tb))    \ -             _PyGreenlet_API[PyGreenlet_Throw_NUM]) - -/* - * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) - * - * g.switch(*args, **kwargs) - */ -#    define PyGreenlet_Switch                                              \ -        (*(PyObject *                                                      \ -           (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ -             _PyGreenlet_API[PyGreenlet_Switch_NUM]) - -/* - * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) - * - * g.parent = new_parent - */ -#    define PyGreenlet_SetParent                                 \ -        (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ -             _PyGreenlet_API[PyGreenlet_SetParent_NUM]) - -/* - * PyGreenlet_GetParent(PyObject* greenlet) - * - * return greenlet.parent; - * - * This could return NULL even if there is no exception active. - * If it does not return NULL, you are responsible for decrementing the - * reference count. - */ -#     define PyGreenlet_GetParent                                    \ -    (*(PyGreenlet* (*)(PyGreenlet*))                                 \ -     _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) - -/* - * deprecated, undocumented alias. - */ -#     define PyGreenlet_GET_PARENT PyGreenlet_GetParent - -#     define PyGreenlet_MAIN                                         \ -    (*(int (*)(PyGreenlet*))                                         \ -     _PyGreenlet_API[PyGreenlet_MAIN_NUM]) - -#     define PyGreenlet_STARTED                                      \ -    (*(int (*)(PyGreenlet*))                                         \ -     _PyGreenlet_API[PyGreenlet_STARTED_NUM]) - -#     define PyGreenlet_ACTIVE                                       \ -    (*(int (*)(PyGreenlet*))                                         \ -     _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) - - - - -/* Macro that imports greenlet and initializes C API */ -/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we -   keep the older definition to be sure older code that might have a copy of -   the header still works. */ -#    define PyGreenlet_Import()                                               \ -        {                                                                     \ -            _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ -        } - -#endif /* GREENLET_MODULE */ - -#ifdef __cplusplus -} -#endif -#endif /* !Py_GREENLETOBJECT_H */ diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp deleted file mode 100644 index b452f54..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef GREENLET_ALLOCATOR_HPP -#define GREENLET_ALLOCATOR_HPP - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <memory> -#include "greenlet_compiler_compat.hpp" - - -namespace greenlet -{ -    // This allocator is stateless; all instances are identical. -    // It can *ONLY* be used when we're sure we're holding the GIL -    // (Python's allocators require the GIL). -    template <class T> -    struct PythonAllocator : public std::allocator<T> { - -        PythonAllocator(const PythonAllocator& UNUSED(other)) -            : std::allocator<T>() -        { -        } - -        PythonAllocator(const std::allocator<T> other) -            : std::allocator<T>(other) -        {} - -        template <class U> -        PythonAllocator(const std::allocator<U>& other) -            : std::allocator<T>(other) -        { -        } - -        PythonAllocator() : std::allocator<T>() {} - -        T* allocate(size_t number_objects, const void* UNUSED(hint)=0) -        { -            void* p; -            if (number_objects == 1) -                p = PyObject_Malloc(sizeof(T)); -            else -                p = PyMem_Malloc(sizeof(T) * number_objects); -            return static_cast<T*>(p); -        } - -        void deallocate(T* t, size_t n) -        { -            void* p = t; -            if (n == 1) { -                PyObject_Free(p); -            } -            else -                PyMem_Free(p); -        } -        // This member is deprecated in C++17 and removed in C++20 -        template< class U > -        struct rebind { -            typedef PythonAllocator<U> other; -        }; - -    }; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp deleted file mode 100644 index ee5bbdd..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef GREENLET_COMPILER_COMPAT_HPP -#define GREENLET_COMPILER_COMPAT_HPP - -/** - * Definitions to aid with compatibility with different compilers. - * - * .. caution:: Use extreme care with noexcept. - * Some compilers and runtimes, specifically gcc/libgcc/libstdc++ on - * Linux, implement stack unwinding by throwing an uncatchable - * exception, one that specifically does not appear to be an active - * exception to the rest of the runtime. If this happens while we're in a noexcept function, - * we have violated our dynamic exception contract, and so the runtime - * will call std::terminate(), which kills the process with the - * unhelpful message "terminate called without an active exception". - * - * This has happened in this scenario: A background thread is running - * a greenlet that has made a native call and released the GIL. - * Meanwhile, the main thread finishes and starts shutting down the - * interpreter. When the background thread is scheduled again and - * attempts to obtain the  GIL, it notices that the interpreter is - * exiting and calls ``pthread_exit()``. This in turn starts to unwind - * the stack by throwing that exception. But we had the ``PyCall`` - * functions annotated as noexcept, so the runtime terminated us. - * - * #2  0x00007fab26fec2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6 - * #3  0x00007fab26febb3c in __gxx_personality_v0 () from /lib/x86_64-linux-gnu/libstdc++.so.6 - * #4  0x00007fab26f34de6 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1 - * #6  0x00007fab276a34c6 in __GI___pthread_unwind  at ./nptl/unwind.c:130 - * #7  0x00007fab2769bd3a in __do_cancel () at ../sysdeps/nptl/pthreadP.h:280 - * #8  __GI___pthread_exit (value=value@entry=0x0) at ./nptl/pthread_exit.c:36 - * #9  0x000000000052e567 in PyThread_exit_thread () at ../Python/thread_pthread.h:370 - * #10 0x00000000004d60b5 in take_gil at ../Python/ceval_gil.h:224 - * #11 0x00000000004d65f9 in PyEval_RestoreThread  at ../Python/ceval.c:467 - * #12 0x000000000060cce3 in setipaddr  at ../Modules/socketmodule.c:1203 - * #13 0x00000000006101cd in socket_gethostbyname - */ - -#include <cstdint> - -# if defined(__clang__) -#  define G_FP_TMPL_STATIC static -# else -// GCC has no problem allowing static function pointers, but emits -// tons of warnings about "whose type uses the anonymous namespace [-Wsubobject-linkage]" -#  define G_FP_TMPL_STATIC -# endif - -#    define G_NO_COPIES_OF_CLS(Cls) private:     \ -    Cls(const Cls& other) = delete; \ -    Cls& operator=(const Cls& other) = delete - -#    define G_NO_ASSIGNMENT_OF_CLS(Cls) private:  \ -    Cls& operator=(const Cls& other) = delete - -#    define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \ -    Cls(const Cls& other) = delete; - - -// CAUTION: MSVC is stupidly picky: -// -// "The compiler ignores, without warning, any __declspec keywords -// placed after * or & and in front of the variable identifier in a -// declaration." -// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160) -// -// So pointer return types must be handled differently (because of the -// trailing *), or you get inscrutable compiler warnings like "error -// C2059: syntax error: ''" -// -// In C++ 11, there is a standard syntax for attributes, and -// GCC defines an attribute to use with this: [[gnu:noinline]]. -// In the future, this is expected to become standard. - -#if defined(__GNUC__) || defined(__clang__) -/* We used to check for GCC 4+ or 3.4+, but those compilers are -   laughably out of date. Just assume they support it. */ -#    define GREENLET_NOINLINE(name) __attribute__((noinline)) name -#    define GREENLET_NOINLINE_P(rtype, name) rtype __attribute__((noinline)) name -#    define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) -#elif defined(_MSC_VER) -/* We used to check for  && (_MSC_VER >= 1300) but that's also out of date. */ -#    define GREENLET_NOINLINE(name) __declspec(noinline) name -#    define GREENLET_NOINLINE_P(rtype, name) __declspec(noinline) rtype name -#    define UNUSED(x) UNUSED_ ## x -#endif - -#if defined(_MSC_VER) -#    define G_NOEXCEPT_WIN32 noexcept -#else -#    define G_NOEXCEPT_WIN32 -#endif - - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp deleted file mode 100644 index 0d28efd..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef GREENLET_CPYTHON_ADD_PENDING_HPP -#define GREENLET_CPYTHON_ADD_PENDING_HPP - -#if (PY_VERSION_HEX >= 0x30800A0 && PY_VERSION_HEX < 0x3090000) && !(defined(_WIN32) || defined(WIN32)) -// XXX: From Python 3.8a3 [1] up until Python 3.9a6 [2][3], -// ``Py_AddPendingCall`` would try to produce a Python exception if -// the interpreter was in the beginning of shutting down when this -// function is called. However, ``Py_AddPendingCall`` doesn't require -// the GIL, and we are absolutely not holding it when we make that -// call. That means that trying to create the Python exception is -// using the C API in an undefined state; here the C API detects this -// and aborts the process with an error ("Fatal Python error: Python -// memory allocator called without holding the GIL": Add -> -// PyErr_SetString -> PyUnicode_New -> PyObject_Malloc). This arises -// (obviously) in multi-threaded programs and happens if one thread is -// exiting and cleaning up its thread-local data while the other -// thread is trying to shut down the interpreter. A crash on shutdown -// is still a crash and could result in data loss (e.g., daemon -// threads are still running, pending signal handlers may be present, -// buffers may not be flushed, there may be __del__ that need run, -// etc), so we have to work around it. -// -// Of course, we can (and do) check for whether the interpreter is -// shutting down before calling ``Py_AddPendingCall``, but that's a -// race condition since we don't hold the GIL, and so we may not -// actually get the right answer. Plus, ``Py_FinalizeEx`` actually -// calls ``_Py_FinishPendingCalls`` (which sets the pending->finishing -// flag, which is used to gate creating the exceptioen) *before* -// publishing any other data that would let us detect the shutdown -// (such as runtime->finalizing). So that point is moot. -// -// Our solution for those versions is to inline the same code, without -// the problematic bit that sets the exception. Unfortunately, all of -// the structure definitions are private/opaque, *and* we can't -// actually count on being able to include their definitions from -// ``internal/pycore_*``, because on some platforms those header files -// are incomplete (i.e., on macOS with macports 3.8, the includes are -// fine, but on Ubuntu jammy with 3.8 from ppa:deadsnakes or GitHub -// Actions 3.8 (I think it's Ubuntu 18.04), they con't be used; at -// least, I couldn't get them to work). So we need to define the -// structures and _PyRuntime data member ourself. Yet more -// unfortunately, _PyRuntime  won't link on Windows, so we can only do -// this on other platforms. -// -// [1] https://github.com/python/cpython/commit/842a2f07f2f08a935ef470bfdaeef40f87490cfc -// [2] https://github.com/python/cpython/commit/cfc3c2f8b34d3864717ab584c5b6c260014ba55a -// [3] https://github.com/python/cpython/issues/81308 -# define GREENLET_BROKEN_PY_ADD_PENDING 1 - -// When defining these structures, the important thing is to get -// binary compatibility, i.e., structure layout. For that, we only -// need to define fields up to the ones we use; after that they're -// irrelevant UNLESS the structure is included in another structure -// *before* the structure we're interested in --- in that case, it -// must be complete. Ellipsis indicate elided trailing members. -// Pointer types are changed to void* to keep from having to define -// more structures. - -// From "internal/pycore_atomic.h" - -// There are several different definitions of this, including the -// plain ``int`` version, a ``volatile int`` and an ``_Atomic int`` -// I don't think any of those change the size/layout. -typedef struct _Py_atomic_int { -    volatile int _value; -} _Py_atomic_int; - -// This needs too much infrastructure, so we just do a regular store. -#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ -    (ATOMIC_VAL)->_value = NEW_VAL - - - -// From "internal/pycore_pymem.h" -#define NUM_GENERATIONS 3 - - -struct gc_generation { -    PyGC_Head head; // We already have this defined. -    int threshold; -    int count; -}; -struct gc_generation_stats { -    Py_ssize_t collections; -    Py_ssize_t collected; -    Py_ssize_t uncollectable; -}; - -struct _gc_runtime_state { -    void *trash_delete_later; -    int trash_delete_nesting; -    int enabled; -    int debug; -    struct gc_generation generations[NUM_GENERATIONS]; -    void *generation0; -    struct gc_generation permanent_generation; -    struct gc_generation_stats generation_stats[NUM_GENERATIONS]; -    int collecting; -    void *garbage; -    void *callbacks; -    Py_ssize_t long_lived_total; -    Py_ssize_t long_lived_pending; -}; - -// From "internal/pycore_pystate.h" -struct _pending_calls { -    int finishing; -    PyThread_type_lock lock; -    _Py_atomic_int calls_to_do; -    int async_exc; -#define NPENDINGCALLS 32 -    struct { -        int (*func)(void *); -        void *arg; -    } calls[NPENDINGCALLS]; -    int first; -    int last; -}; - -struct _ceval_runtime_state { -    int recursion_limit; -    int tracing_possible; -    _Py_atomic_int eval_breaker; -    _Py_atomic_int gil_drop_request; -    struct _pending_calls pending; -    // ... -}; - -typedef struct pyruntimestate { -    int preinitializing; -    int preinitialized; -    int core_initialized; -    int initialized; -    void *finalizing; - -    struct pyinterpreters { -        PyThread_type_lock mutex; -        void *head; -        void *main; -        int64_t next_id; -    } interpreters; -    // XXX Remove this field once we have a tp_* slot. -    struct _xidregistry { -        PyThread_type_lock mutex; -        void *head; -    } xidregistry; - -    unsigned long main_thread; - -#define NEXITFUNCS 32 -    void (*exitfuncs[NEXITFUNCS])(void); -    int nexitfuncs; - -    struct _gc_runtime_state gc; -    struct _ceval_runtime_state ceval; -    // ... -} _PyRuntimeState; - -#define SIGNAL_PENDING_CALLS(ceval) \ -    do { \ -        _Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 1); \ -        _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \ -    } while (0) - -extern _PyRuntimeState _PyRuntime; - -#else -# define GREENLET_BROKEN_PY_ADD_PENDING 0 -#endif - - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp deleted file mode 100644 index cdc1617..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef GREENLET_CPYTHON_COMPAT_H -#define GREENLET_CPYTHON_COMPAT_H - -/** - * Helpers for compatibility with multiple versions of CPython. - */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" - - -#if PY_VERSION_HEX >= 0x30A00B1 -#    define GREENLET_PY310 1 -/* -Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member. -See https://github.com/python/cpython/pull/25276 -We have to save and restore this as well. -*/ -#    define GREENLET_USE_CFRAME 1 -#else -#    define GREENLET_USE_CFRAME 0 -#    define GREENLET_PY310 0 -#endif - - - -#if PY_VERSION_HEX >= 0x30B00A4 -/* -Greenlet won't compile on anything older than Python 3.11 alpha 4 (see -https://bugs.python.org/issue46090). Summary of breaking internal changes: -- Python 3.11 alpha 1 changed how frame objects are represented internally. -  - https://github.com/python/cpython/pull/30122 -- Python 3.11 alpha 3 changed how recursion limits are stored. -  - https://github.com/python/cpython/pull/29524 -- Python 3.11 alpha 4 changed how exception state is stored. It also includes a -  change to help greenlet save and restore the interpreter frame "data stack". -  - https://github.com/python/cpython/pull/30122 -  - https://github.com/python/cpython/pull/30234 -*/ -#    define GREENLET_PY311 1 -#else -#    define GREENLET_PY311 0 -#endif - - -#if PY_VERSION_HEX >= 0x30C0000 -#    define GREENLET_PY312 1 -#else -#    define GREENLET_PY312 0 -#endif - -#ifndef Py_SET_REFCNT -/* Py_REFCNT and Py_SIZE macros are converted to functions -https://bugs.python.org/issue39573 */ -#    define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) -#endif - -#ifndef _Py_DEC_REFTOTAL -/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: -  https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 - -  The symbol we use to replace it was removed by at least 3.12. -*/ -#    ifdef Py_REF_DEBUG -#      if GREENLET_PY312 -#         define _Py_DEC_REFTOTAL -#      else -#        define _Py_DEC_REFTOTAL _Py_RefTotal-- -#      endif -#    else -#        define _Py_DEC_REFTOTAL -#    endif -#endif -// Define these flags like Cython does if we're on an old version. -#ifndef Py_TPFLAGS_CHECKTYPES -  #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX -  #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER -  #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif - -#ifndef Py_TPFLAGS_HAVE_VERSION_TAG -   #define Py_TPFLAGS_HAVE_VERSION_TAG 0 -#endif - -#define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC - - -#if PY_VERSION_HEX < 0x03090000 -// The official version only became available in 3.9 -#    define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o) -#endif - - -// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 -#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) -static inline void PyThreadState_EnterTracing(PyThreadState *tstate) -{ -    tstate->tracing++; -#if PY_VERSION_HEX >= 0x030A00A1 -    tstate->cframe->use_tracing = 0; -#else -    tstate->use_tracing = 0; -#endif -} -#endif - -// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 -#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) -static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) -{ -    tstate->tracing--; -    int use_tracing = (tstate->c_tracefunc != NULL -                       || tstate->c_profilefunc != NULL); -#if PY_VERSION_HEX >= 0x030A00A1 -    tstate->cframe->use_tracing = use_tracing; -#else -    tstate->use_tracing = use_tracing; -#endif -} -#endif - -#endif /* GREENLET_CPYTHON_COMPAT_H */ diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp deleted file mode 100644 index 3807018..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef GREENLET_EXCEPTIONS_HPP -#define GREENLET_EXCEPTIONS_HPP - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <stdexcept> -#include <string> - -#ifdef __clang__ -#    pragma clang diagnostic push -#    pragma clang diagnostic ignored "-Wunused-function" -#endif - -namespace greenlet { - -    class PyErrOccurred : public std::runtime_error -    { -    public: - -        // CAUTION: In debug builds, may run arbitrary Python code. -        static const PyErrOccurred -        from_current() -        { -            assert(PyErr_Occurred()); -#ifndef NDEBUG -            // This is not exception safe, and -            // not necessarily safe in general (what if it switches?) -            // But we only do this in debug mode, where we are in -            // tight control of what exceptions are getting raised and -            // can prevent those issues. - -            // You can't call PyObject_Str with a pending exception. -            PyObject* typ; -            PyObject* val; -            PyObject* tb; - -            PyErr_Fetch(&typ, &val, &tb); -            PyObject* typs = PyObject_Str(typ); -            PyObject* vals = PyObject_Str(val ? val : typ); -            const char* typ_msg = PyUnicode_AsUTF8(typs); -            const char* val_msg = PyUnicode_AsUTF8(vals); -            PyErr_Restore(typ, val, tb); - -            std::string msg(typ_msg); -            msg += ": "; -            msg += val_msg; -            PyErrOccurred ex(msg); -            Py_XDECREF(typs); -            Py_XDECREF(vals); - -            return ex; -#else -            return PyErrOccurred(); -#endif -        } - -        PyErrOccurred() : std::runtime_error("") -        { -            assert(PyErr_Occurred()); -        } - -        PyErrOccurred(const std::string& msg) : std::runtime_error(msg) -        { -            assert(PyErr_Occurred()); -        } - -        PyErrOccurred(PyObject* exc_kind, const char* const msg) -            : std::runtime_error(msg) -        { -            PyErr_SetString(exc_kind, msg); -        } - -        PyErrOccurred(PyObject* exc_kind, const std::string msg) -            : std::runtime_error(msg) -        { -            // This copies the c_str, so we don't have any lifetime -            // issues to worry about. -            PyErr_SetString(exc_kind, msg.c_str()); -        } -    }; - -    class TypeError : public PyErrOccurred -    { -    public: -        TypeError(const char* const what) -            : PyErrOccurred(PyExc_TypeError, what) -        { -        } -        TypeError(const std::string what) -            : PyErrOccurred(PyExc_TypeError, what) -        { -        } -    }; - -    class ValueError : public PyErrOccurred -    { -    public: -        ValueError(const char* const what) -            : PyErrOccurred(PyExc_ValueError, what) -        { -        } -    }; - -    class AttributeError : public PyErrOccurred -    { -    public: -        AttributeError(const char* const what) -            : PyErrOccurred(PyExc_AttributeError, what) -        { -        } -    }; - -    /** -     * Calls `Py_FatalError` when constructed, so you can't actually -     * throw this. It just makes static analysis easier. -     */ -    class PyFatalError : public std::runtime_error -    { -    public: -        PyFatalError(const char* const msg) -            : std::runtime_error(msg) -        { -            Py_FatalError(msg); -        } -    }; - -    static inline PyObject* -    Require(PyObject* p, const std::string& msg="") -    { -        if (!p) { -            throw PyErrOccurred(msg); -        } -        return p; -    }; - -    static inline void -    Require(const int retval) -    { -        if (retval < 0) { -            throw PyErrOccurred(); -        } -    }; - - -}; -#ifdef __clang__ -#    pragma clang diagnostic pop -#endif - -#endif 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 diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp deleted file mode 100644 index c8e3849..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ -#ifndef GREENLET_INTERNAL_H -#define GREENLET_INTERNAL_H -#ifdef __clang__ -#    pragma clang diagnostic push -#    pragma clang diagnostic ignored "-Wunused-function" -#    pragma clang diagnostic ignored "-Wmissing-field-initializers" -#    pragma clang diagnostic ignored "-Wunused-variable" -#endif - -/** - * Implementation helpers. - * - * C++ templates and inline functions should go here. - */ -#define PY_SSIZE_T_CLEAN -#include "greenlet_compiler_compat.hpp" -#include "greenlet_cpython_compat.hpp" -#include "greenlet_exceptions.hpp" -#include "greenlet_greenlet.hpp" -#include "greenlet_allocator.hpp" - -#include <vector> -#include <string> - -#define GREENLET_MODULE -struct _greenlet; -typedef struct _greenlet PyGreenlet; -namespace greenlet { - -    class ThreadState; - -}; - - -#define implementation_ptr_t greenlet::Greenlet* - - -#include "greenlet.h" - -G_FP_TMPL_STATIC inline void -greenlet::refs::MainGreenletExactChecker(void *p) -{ -    if (!p) { -        return; -    } -    // We control the class of the main greenlet exactly. -    if (Py_TYPE(p) != &PyGreenlet_Type) { -        std::string err("MainGreenlet: Expected exactly a greenlet, not a "); -        err += Py_TYPE(p)->tp_name; -        throw greenlet::TypeError(err); -    } - -    // Greenlets from dead threads no longer respond to main() with a -    // true value; so in that case we need to perform an additional -    // check. -    Greenlet* g = ((PyGreenlet*)p)->pimpl; -    if (g->main()) { -        return; -    } -    if (!dynamic_cast<MainGreenlet*>(g)) { -        std::string err("MainGreenlet: Expected exactly a main greenlet, not a "); -        err += Py_TYPE(p)->tp_name; -        throw greenlet::TypeError(err); -    } -} - - - -template <typename T, greenlet::refs::TypeChecker TC> -inline greenlet::Greenlet* greenlet::refs::_OwnedGreenlet<T, TC>::operator->() const noexcept -{ -    return reinterpret_cast<PyGreenlet*>(this->p)->pimpl; -} - -template <typename T, greenlet::refs::TypeChecker TC> -inline greenlet::Greenlet* greenlet::refs::_BorrowedGreenlet<T, TC>::operator->() const noexcept -{ -    return reinterpret_cast<PyGreenlet*>(this->p)->pimpl; -} - -#include <memory> -#include <stdexcept> - - -extern PyTypeObject PyGreenlet_Type; - - - -/** -  * Forward declarations needed in multiple files. -  */ -static PyGreenlet* green_create_main(greenlet::ThreadState*); -static PyObject* green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs); -static int green_is_gc(BorrowedGreenlet self); - -#ifdef __clang__ -#    pragma clang diagnostic pop -#endif - - -#endif - -// Local Variables: -// flycheck-clang-include-path: ("../../include" "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10") -// End: diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp deleted file mode 100644 index 72ee68b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp +++ /dev/null @@ -1,1100 +0,0 @@ -#ifndef GREENLET_REFS_HPP -#define GREENLET_REFS_HPP - -#define PY_SSIZE_T_CLEAN -#include <Python.h> -//#include "greenlet_internal.hpp" -#include "greenlet_compiler_compat.hpp" -#include "greenlet_cpython_compat.hpp" -#include "greenlet_exceptions.hpp" - -struct _greenlet; -struct _PyMainGreenlet; - -typedef struct _greenlet PyGreenlet; -extern PyTypeObject PyGreenlet_Type; - - -#ifdef  GREENLET_USE_STDIO -#include <iostream> -using std::cerr; -using std::endl; -#endif - -namespace greenlet -{ -    class Greenlet; - -    namespace refs -    { -        // Type checkers throw a TypeError if the argument is not -        // null, and isn't of the required Python type. -        // (We can't use most of the defined type checkers -        // like PyList_Check, etc, directly, because they are -        // implemented as macros.) -        typedef void (*TypeChecker)(void*); - -        G_FP_TMPL_STATIC inline void -        NoOpChecker(void*) -        { -            return; -        } - -        G_FP_TMPL_STATIC inline void -        GreenletChecker(void *p) -        { -            if (!p) { -                return; -            } - -            PyTypeObject* typ = Py_TYPE(p); -            // fast, common path. (PyObject_TypeCheck is a macro or -            // static inline function, and it also does a -            // direct comparison of the type pointers, but its fast -            // path only handles one type) -            if (typ == &PyGreenlet_Type) { -                return; -            } - -            if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) { -                std::string err("GreenletChecker: Expected any type of greenlet, not "); -                err += Py_TYPE(p)->tp_name; -                throw TypeError(err); -            } -        } - -        G_FP_TMPL_STATIC inline void -        MainGreenletExactChecker(void *p); - -        template <typename T, TypeChecker> -        class PyObjectPointer; - -        template<typename T, TypeChecker> -        class OwnedReference; - - -        template<typename T, TypeChecker> -        class BorrowedReference; - -        typedef BorrowedReference<PyObject, NoOpChecker> BorrowedObject; -        typedef OwnedReference<PyObject, NoOpChecker> OwnedObject; - -        class ImmortalObject; -        class ImmortalString; - -        template<typename T, TypeChecker TC> -        class _OwnedGreenlet; - -        typedef _OwnedGreenlet<PyGreenlet, GreenletChecker> OwnedGreenlet; -        typedef _OwnedGreenlet<PyGreenlet, MainGreenletExactChecker> OwnedMainGreenlet; - -        template<typename T, TypeChecker TC> -        class _BorrowedGreenlet; - -        typedef _BorrowedGreenlet<PyGreenlet, GreenletChecker> BorrowedGreenlet; - -        G_FP_TMPL_STATIC inline void -        ContextExactChecker(void *p) -        { -            if (!p) { -                return; -            } -            if (!PyContext_CheckExact(p)) { -                throw TypeError( -                    "greenlet context must be a contextvars.Context or None" -                ); -            } -        } - -        typedef OwnedReference<PyObject, ContextExactChecker> OwnedContext; -    } -} - -namespace greenlet { - - -    namespace refs { -    // A set of classes to make reference counting rules in python -    // code explicit. -    // -    // Rules of use: -    // (1) Functions returning a new reference that the caller of the -    // function is expected to dispose of should return a -    // ``OwnedObject`` object. This object automatically releases its -    // reference when it goes out of scope. It works like a ``std::shared_ptr`` -    // and can be copied or used as a function parameter (but don't do -    // that). Note that constructing a ``OwnedObject`` from a -    // PyObject* steals the reference. -    // (2) Parameters to functions should be either a -    // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``. -    // If the function needs to create its own new reference, it can -    // do so by copying to a local ``OwnedObject``. -    // (3) Functions returning an existing pointer that is NOT -    // incref'd, and which the caller MUST NOT decref, -    // should return a ``BorrowedObject``. - -    // -    // For a class with a single pointer member, whose constructor -    // does nothing but copy a pointer parameter into the member, and -    // which can then be converted back to the pointer type, compilers -    // generate code that's the same as just passing the pointer. -    // That is, func(BorrowedObject x) called like ``PyObject* p = -    // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the -    // pointer type with 0 overhead. -    // -    // If there are no virtual functions, no complex inheritance (maybe?) and -    // no destructor, these can be directly used as parameters in -    // Python callbacks like tp_init: the layout is the same as a -    // single pointer. Only subclasses with trivial constructors that -    // do nothing but set the single pointer member are safe to use -    // that way. - - -    // This is the base class for things that can be done with a -    // PyObject pointer. It assumes nothing about memory management. -    // NOTE: Nothing is virtual, so subclasses shouldn't add new -    // storage fields or try to override these methods. -    template <typename T=PyObject, TypeChecker TC=NoOpChecker> -    class PyObjectPointer -    { -    public: -        typedef T PyType; -    protected: -        T* p; -    public: -        explicit PyObjectPointer(T* it=nullptr) : p(it) -        { -            TC(p); -        } - -        // We don't allow automatic casting to PyObject* at this -        // level, because then we could be passed to Py_DECREF/INCREF, -        // but we want nothing to do with memory management. If you -        // know better, then you can use the get() method, like on a -        // std::shared_ptr. Except we name it borrow() to clarify that -        // if this is a reference-tracked object, the pointer you get -        // back will go away when the object does. -        // TODO: This should probably not exist here, but be moved -        // down to relevant sub-types. - -        inline T* borrow() const noexcept -        { -            return this->p; -        } - -        PyObject* borrow_o() const noexcept -        { -            return reinterpret_cast<PyObject*>(this->p); -        } - -        inline T* operator->() const noexcept -        { -            return this->p; -        } - -        bool is_None() const noexcept -        { -            return this->p == Py_None; -        } - -        inline PyObject* acquire_or_None() const noexcept -        { -            PyObject* result = this->p ? reinterpret_cast<PyObject*>(this->p) : Py_None; -            Py_INCREF(result); -            return result; -        } - -        explicit operator bool() const noexcept -        { -            return p != nullptr; -        } - -        inline Py_ssize_t REFCNT() const noexcept -        { -            return p ? Py_REFCNT(p) : -42; -        } - -        inline PyTypeObject* TYPE() const noexcept -        { -            return p ? Py_TYPE(p) : nullptr; -        } - -        inline OwnedObject PyStr() const noexcept; -        inline const std::string as_str() const noexcept; -        inline OwnedObject PyGetAttr(const ImmortalObject& name) const noexcept; -        inline OwnedObject PyRequireAttr(const char* const name) const; -        inline OwnedObject PyRequireAttr(const ImmortalString& name) const; -        inline OwnedObject PyCall(const BorrowedObject& arg) const; -        inline OwnedObject PyCall(PyGreenlet* arg) const ; -        inline OwnedObject PyCall(PyObject* arg) const ; -        // PyObject_Call(this, args, kwargs); -        inline OwnedObject PyCall(const BorrowedObject args, -                                  const BorrowedObject kwargs) const; -        inline OwnedObject PyCall(const OwnedObject& args, -                                  const OwnedObject& kwargs) const; - -    protected: -        void _set_raw_pointer(void* t) -        { -            TC(t); -            p = reinterpret_cast<T*>(t); -        } -        void* _get_raw_pointer() const -        { -            return p; -        } -    }; - -#ifdef GREENLET_USE_STDIO -        template<typename T, TypeChecker TC> -        std::ostream& operator<<(std::ostream& os, const PyObjectPointer<T, TC>& s) -        { -            const std::type_info& t = typeid(s); -            os << t.name() -               << "(addr=" << s.borrow() -               << ", refcnt=" << s.REFCNT() -               << ", value=" << s.as_str() -               << ")"; - -            return os; -        } -#endif - -    template<typename T, TypeChecker TC> -    inline bool operator==(const PyObjectPointer<T, TC>& lhs, const void* const rhs) noexcept -    { -        return lhs.borrow_o() == rhs; -    } - -    template<typename T, TypeChecker TC, typename X, TypeChecker XC> -    inline bool operator==(const PyObjectPointer<T, TC>& lhs, const PyObjectPointer<X, XC>& rhs) noexcept -    { -        return lhs.borrow_o() == rhs.borrow_o(); -    } - -    template<typename T, TypeChecker TC, typename X, TypeChecker XC> -    inline bool operator!=(const PyObjectPointer<T, TC>& lhs, -                           const PyObjectPointer<X, XC>& rhs) noexcept -    { -        return lhs.borrow_o() != rhs.borrow_o(); -    } - -    template<typename T=PyObject, TypeChecker TC=NoOpChecker> -    class OwnedReference : public PyObjectPointer<T, TC> -    { -    private: -        friend class OwnedList; - -    protected: -        explicit OwnedReference(T* it) : PyObjectPointer<T, TC>(it) -        { -        } - -    public: - -        // Constructors - -        static OwnedReference<T, TC> consuming(PyObject* p) -        { -            return OwnedReference<T, TC>(reinterpret_cast<T*>(p)); -        } - -        static OwnedReference<T, TC> owning(T* p) -        { -            OwnedReference<T, TC> result(p); -            Py_XINCREF(result.p); -            return result; -        } - -        OwnedReference() : PyObjectPointer<T, TC>(nullptr) -        {} - -        explicit OwnedReference(const PyObjectPointer<>& other) -            : PyObjectPointer<T, TC>(nullptr) -        { -            T* op = other.borrow(); -            TC(op); -            this->p = other.borrow(); -            Py_XINCREF(this->p); -        } - -        // It would be good to make use of the C++11 distinction -        // between move and copy operations, e.g., constructing from a -        // pointer should be a move operation. -        // In the common case of ``OwnedObject x = Py_SomeFunction()``, -        // the call to the copy constructor will be elided completely. -        OwnedReference(const OwnedReference<T, TC>& other) -            : PyObjectPointer<T, TC>(other.p) -        { -            Py_XINCREF(this->p); -        } - -        static OwnedReference<PyObject> None() -        { -            Py_INCREF(Py_None); -            return OwnedReference<PyObject>(Py_None); -        } - -        // We can assign from exactly our type without any extra checking -        OwnedReference<T, TC>& operator=(const OwnedReference<T, TC>& other) -        { -            Py_XINCREF(other.p); -            const T* tmp = this->p; -            this->p = other.p; -            Py_XDECREF(tmp); -            return *this; -        } - -        OwnedReference<T, TC>& operator=(const BorrowedReference<T, TC> other) -        { -            return this->operator=(other.borrow()); -        } - -        OwnedReference<T, TC>& operator=(T* const other) -        { -            TC(other); -            Py_XINCREF(other); -            T* tmp = this->p; -            this->p = other; -            Py_XDECREF(tmp); -            return *this; -        } - -        // We can assign from an arbitrary reference type -        // if it passes our check. -        template<typename X, TypeChecker XC> -        OwnedReference<T, TC>& operator=(const OwnedReference<X, XC>& other) -        { -            X* op = other.borrow(); -            TC(op); -            return this->operator=(reinterpret_cast<T*>(op)); -        } - -        inline void steal(T* other) -        { -            assert(this->p == nullptr); -            TC(other); -            this->p = other; -        } - -        T* relinquish_ownership() -        { -            T* result = this->p; -            this->p = nullptr; -            return result; -        } - -        T* acquire() const -        { -            // Return a new reference. -            // TODO: This may go away when we have reference objects -            // throughout the code. -            Py_XINCREF(this->p); -            return this->p; -        } - -        // Nothing else declares a destructor, we're the leaf, so we -        // should be able to get away without virtual. -        ~OwnedReference() -        { -            Py_CLEAR(this->p); -        } - -        void CLEAR() -        { -            Py_CLEAR(this->p); -            assert(this->p == nullptr); -        } -    }; - -    static inline -    void operator<<=(PyObject*& target, OwnedObject& o) -    { -        target = o.relinquish_ownership(); -    } - -    class NewReference : public OwnedObject -    { -    private: -        G_NO_COPIES_OF_CLS(NewReference); -    public: -        // Consumes the reference. Only use this -        // for API return values. -        NewReference(PyObject* it) : OwnedObject(it) -        { -        } -    }; - -    class NewDictReference : public NewReference -    { -    private: -        G_NO_COPIES_OF_CLS(NewDictReference); -    public: -        NewDictReference() : NewReference(PyDict_New()) -        { -            if (!this->p) { -                throw PyErrOccurred(); -            } -        } - -        void SetItem(const char* const key, PyObject* value) -        { -            Require(PyDict_SetItemString(this->p, key, value)); -        } - -        void SetItem(const PyObjectPointer<>& key, PyObject* value) -        { -            Require(PyDict_SetItem(this->p, key.borrow_o(), value)); -        } -    }; - -    template<typename T=PyGreenlet, TypeChecker TC=GreenletChecker> -    class _OwnedGreenlet: public OwnedReference<T, TC> -    { -    private: -    protected: -        _OwnedGreenlet(T* it) : OwnedReference<T, TC>(it) -        {} - -    public: -        _OwnedGreenlet() : OwnedReference<T, TC>() -        {} - -        _OwnedGreenlet(const _OwnedGreenlet<T, TC>& other) : OwnedReference<T, TC>(other) -        { -        } -        _OwnedGreenlet(OwnedMainGreenlet& other) : -            OwnedReference<T, TC>(reinterpret_cast<T*>(other.acquire())) -        { -        } -        _OwnedGreenlet(const BorrowedGreenlet& other); -        // Steals a reference. -        static _OwnedGreenlet<T, TC> consuming(PyGreenlet* it) -        { -            return _OwnedGreenlet<T, TC>(reinterpret_cast<T*>(it)); -        } - -        inline _OwnedGreenlet<T, TC>& operator=(const OwnedGreenlet& other) -        { -            return this->operator=(other.borrow()); -        } - -        inline _OwnedGreenlet<T, TC>& operator=(const BorrowedGreenlet& other); - -        _OwnedGreenlet<T, TC>& operator=(const OwnedMainGreenlet& other) -        { -            PyGreenlet* owned = other.acquire(); -            Py_XDECREF(this->p); -            this->p = reinterpret_cast<T*>(owned); -            return *this; -        } - -        _OwnedGreenlet<T, TC>& operator=(T* const other) -        { -            OwnedReference<T, TC>::operator=(other); -            return *this; -        } - -        T* relinquish_ownership() -        { -            T* result = this->p; -            this->p = nullptr; -            return result; -        } - -        PyObject* relinquish_ownership_o() -        { -            return reinterpret_cast<PyObject*>(relinquish_ownership()); -        } - -        inline Greenlet* operator->() const noexcept; -        inline operator Greenlet*() const noexcept; -    }; - -    template <typename T=PyObject, TypeChecker TC=NoOpChecker> -    class BorrowedReference : public PyObjectPointer<T, TC> -    { -    public: -        // Allow implicit creation from PyObject* pointers as we -        // transition to using these classes. Also allow automatic -        // conversion to PyObject* for passing to C API calls and even -        // for Py_INCREF/DECREF, because we ourselves do no memory management. -        BorrowedReference(T* it) : PyObjectPointer<T, TC>(it) -        {} - -        BorrowedReference(const PyObjectPointer<T>& ref) : PyObjectPointer<T, TC>(ref.borrow()) -        {} - -        BorrowedReference() : PyObjectPointer<T, TC>(nullptr) -        {} - -        operator T*() const -        { -            return this->p; -        } -    }; - -    typedef BorrowedReference<PyObject> BorrowedObject; -    //typedef BorrowedReference<PyGreenlet> BorrowedGreenlet; - -    template<typename T=PyGreenlet, TypeChecker TC=GreenletChecker> -    class _BorrowedGreenlet : public BorrowedReference<T, TC> -    { -    public: -        _BorrowedGreenlet() : -            BorrowedReference<T, TC>(nullptr) -        {} - -        _BorrowedGreenlet(T* it) : -            BorrowedReference<T, TC>(it) -        {} - -        _BorrowedGreenlet(const BorrowedObject& it); - -        _BorrowedGreenlet(const OwnedGreenlet& it) : -            BorrowedReference<T, TC>(it.borrow()) -        {} - -        _BorrowedGreenlet<T, TC>& operator=(const BorrowedObject& other); - -        // We get one of these for PyGreenlet, but one for PyObject -        // is handy as well -        operator PyObject*() const -        { -            return reinterpret_cast<PyObject*>(this->p); -        } -        inline Greenlet* operator->() const noexcept; -        inline operator Greenlet*() const noexcept; -    }; - -    typedef _BorrowedGreenlet<PyGreenlet> BorrowedGreenlet; - -    template<typename T, TypeChecker TC> -    _OwnedGreenlet<T, TC>::_OwnedGreenlet(const BorrowedGreenlet& other) -        : OwnedReference<T, TC>(reinterpret_cast<T*>(other.borrow())) -    { -        Py_XINCREF(this->p); -    } - - -     class BorrowedMainGreenlet -            : public _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker> -    { -    public: -        BorrowedMainGreenlet(const OwnedMainGreenlet& it) : -            _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>(it.borrow()) -        {} -        BorrowedMainGreenlet(PyGreenlet* it=nullptr) -            : _BorrowedGreenlet<PyGreenlet, MainGreenletExactChecker>(it) -        {} -    }; - -    template<typename T, TypeChecker TC> -    _OwnedGreenlet<T, TC>& _OwnedGreenlet<T, TC>::operator=(const BorrowedGreenlet& other) -    { -        return this->operator=(other.borrow()); -    } - - -    class ImmortalObject : public PyObjectPointer<> -    { -    private: -        G_NO_ASSIGNMENT_OF_CLS(ImmortalObject); -    public: -        explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it) -        { -        } - -        ImmortalObject(const ImmortalObject& other) -            : PyObjectPointer<>(other.p) -        { - -        } - -        /** -         * Become the new owner of the object. Does not change the -         * reference count. -         */ -        ImmortalObject& operator=(PyObject* it) -        { -            assert(this->p == nullptr); -            this->p = it; -            return *this; -        } - -        static ImmortalObject consuming(PyObject* it) -        { -            return ImmortalObject(it); -        } - -        inline operator PyObject*() const -        { -            return this->p; -        } -    }; - -    class ImmortalString : public ImmortalObject -    { -    private: -        G_NO_COPIES_OF_CLS(ImmortalString); -        const char* str; -    public: -        ImmortalString(const char* const str) : -            ImmortalObject(str ? Require(PyUnicode_InternFromString(str)) : nullptr) -        { -            this->str = str; -        } - -        inline ImmortalString& operator=(const char* const str) -        { -            if (!this->p) { -                this->p = Require(PyUnicode_InternFromString(str)); -                this->str = str; -            } -            else { -                assert(this->str == str); -            } -            return *this; -        } - -        inline operator std::string() const -        { -            return this->str; -        } - -    }; - -    class ImmortalEventName : public ImmortalString -    { -    private: -        G_NO_COPIES_OF_CLS(ImmortalEventName); -    public: -        ImmortalEventName(const char* const str) : ImmortalString(str) -        {} -    }; - -    class ImmortalException : public ImmortalObject -    { -    private: -        G_NO_COPIES_OF_CLS(ImmortalException); -    public: -        ImmortalException(const char* const name, PyObject* base=nullptr) : -            ImmortalObject(name -                           // Python 2.7 isn't const correct -                           ? Require(PyErr_NewException((char*)name, base, nullptr)) -                           : nullptr) -        {} - -        inline bool PyExceptionMatches() const -        { -            return PyErr_ExceptionMatches(this->p) > 0; -        } - -    }; - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyStr() const noexcept -    { -        if (!this->p) { -            return OwnedObject(); -        } -        return OwnedObject::consuming(PyObject_Str(reinterpret_cast<PyObject*>(this->p))); -    } - -    template<typename T, TypeChecker TC> -    inline const std::string PyObjectPointer<T, TC>::as_str() const noexcept -    { -        // NOTE: This is not Python exception safe. -        if (this->p) { -            // The Python APIs return a cached char* value that's only valid -            // as long as the original object stays around, and we're -            // about to (probably) toss it. Hence the copy to std::string. -            OwnedObject py_str = this->PyStr(); -            if (!py_str) { -                return "(nil)"; -            } -            return PyUnicode_AsUTF8(py_str.borrow()); -        } -        return "(nil)"; -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyGetAttr(const ImmortalObject& name) const noexcept -    { -        assert(this->p); -        return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast<PyObject*>(this->p), name)); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyRequireAttr(const char* const name) const -    { -        assert(this->p); -        return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name), name)); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyRequireAttr(const ImmortalString& name) const -    { -        assert(this->p); -        return OwnedObject::consuming(Require( -                   PyObject_GetAttr( -                      reinterpret_cast<PyObject*>(this->p), -                      name -                   ), -                   name -               )); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyCall(const BorrowedObject& arg) const -    { -        return this->PyCall(arg.borrow()); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyCall(PyGreenlet* arg) const -    { -        return this->PyCall(reinterpret_cast<PyObject*>(arg)); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyCall(PyObject* arg) const -    { -        assert(this->p); -        return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL)); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyCall(const BorrowedObject args, -                                                  const BorrowedObject kwargs) const -    { -        assert(this->p); -        return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs)); -    } - -    template<typename T, TypeChecker TC> -    inline OwnedObject PyObjectPointer<T, TC>::PyCall(const OwnedObject& args, -                                                  const OwnedObject& kwargs) const -    { -        assert(this->p); -        return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow())); -    } - -    G_FP_TMPL_STATIC inline void -    ListChecker(void * p) -    { -        if (!p) { -            return; -        } -        if (!PyList_Check(p)) { -            throw TypeError("Expected a list"); -        } -    } - -    class OwnedList : public OwnedReference<PyObject, ListChecker> -    { -    private: -        G_NO_ASSIGNMENT_OF_CLS(OwnedList); -    public: -        // TODO: Would like to use move. -        explicit OwnedList(const OwnedObject& other) -            : OwnedReference<PyObject, ListChecker>(other) -        { -        } - -        OwnedList& operator=(const OwnedObject& other) -        { -            if (other && PyList_Check(other.p)) { -                // Valid list. Own a new reference to it, discard the -                // reference to what we did own. -                PyObject* new_ptr = other.p; -                Py_INCREF(new_ptr); -                Py_XDECREF(this->p); -                this->p = new_ptr; -            } -            else { -                // Either the other object was NULL (an error) or it -                // wasn't a list. Either way, we're now invalidated. -                Py_XDECREF(this->p); -                this->p = nullptr; -            } -            return *this; -        } - -        inline bool empty() const -        { -            return PyList_GET_SIZE(p) == 0; -        } - -        inline Py_ssize_t size() const -        { -            return PyList_GET_SIZE(p); -        } - -        inline BorrowedObject at(const Py_ssize_t index) const -        { -            return PyList_GET_ITEM(p, index); -        } - -        inline void clear() -        { -            PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL); -        } -    }; - -    // Use this to represent the module object used at module init -    // time. -    // This could either be a borrowed (Py2) or new (Py3) reference; -    // either way, we don't want to do any memory management -    // on it here, Python itself will handle that. -    // XXX: Actually, that's not quite right. On Python 3, if an -    // exception occurs before we return to the interpreter, this will -    // leak; but all previous versions also had that problem. -    class CreatedModule : public PyObjectPointer<> -    { -    private: -        G_NO_COPIES_OF_CLS(CreatedModule); -    public: -        CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>( -            Require(PyModule_Create(&mod_def))) -        { -        } - -        // PyAddObject(): Add a reference to the object to the module. -        // On return, the reference count of the object is unchanged. -        // -        // The docs warn that PyModule_AddObject only steals the -        // reference on success, so if it fails after we've incref'd -        // or allocated, we're responsible for the decref. -        void PyAddObject(const char* name, const long new_bool) -        { -            OwnedObject p = OwnedObject::consuming(Require(PyBool_FromLong(new_bool))); -            this->PyAddObject(name, p); -        } - -        void PyAddObject(const char* name, const OwnedObject& new_object) -        { -            // The caller already owns a reference they will decref -            // when their variable goes out of scope, we still need to -            // incref/decref. -            this->PyAddObject(name, new_object.borrow()); -        } - -        void PyAddObject(const char* name, const ImmortalObject& new_object) -        { -            this->PyAddObject(name, new_object.borrow()); -        } - -        void PyAddObject(const char* name, PyTypeObject& type) -        { -            this->PyAddObject(name, reinterpret_cast<PyObject*>(&type)); -        } - -        void PyAddObject(const char* name, PyObject* new_object) -        { -            Py_INCREF(new_object); -            try { -                Require(PyModule_AddObject(this->p, name, new_object)); -            } -            catch (const PyErrOccurred&) { -                Py_DECREF(p); -                throw; -            } -        } -    }; - -    class PyErrFetchParam : public PyObjectPointer<> -    { -        // Not an owned object, because we can't be initialized with -        // one, and we only sometimes acquire ownership. -    private: -        G_NO_COPIES_OF_CLS(PyErrFetchParam); -    public: -        // To allow declaring these and passing them to -        // PyErr_Fetch we implement the empty constructor, -        // and the address operator. -        PyErrFetchParam() : PyObjectPointer<>(nullptr) -        { -        } - -        PyObject** operator&() -        { -            return &this->p; -        } - -        // This allows us to pass one directly without the &, -        // BUT it has higher precedence than the bool operator -        // if it's not explicit. -        operator PyObject**() -        { -            return &this->p; -        } - -        // We don't want to be able to pass these to Py_DECREF and -        // such so we don't have the implicit PyObject* conversion. - -        inline PyObject* relinquish_ownership() -        { -            PyObject* result = this->p; -            this->p = nullptr; -            return result; -        } - -        ~PyErrFetchParam() -        { -            Py_XDECREF(p); -        } -    }; - -    class OwnedErrPiece : public OwnedObject -    { -    private: - -    public: -        // Unlike OwnedObject, this increments the refcount. -        OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p) -        { -            this->acquire(); -        } - -        PyObject** operator&() -        { -            return &this->p; -        } - -        inline operator PyObject*() const -        { -            return this->p; -        } - -        operator PyTypeObject*() const -        { -            return reinterpret_cast<PyTypeObject*>(this->p); -        } -    }; - -    class PyErrPieces -    { -    private: -        OwnedErrPiece type; -        OwnedErrPiece instance; -        OwnedErrPiece traceback; -        bool restored; -    public: -        // Takes new references; if we're destroyed before -        // restoring the error, we drop the references. -        PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) : -            type(t), -            instance(v), -            traceback(tb), -            restored(0) -        { -            this->normalize(); -        } - -        PyErrPieces() : -            restored(0) -        { -            // PyErr_Fetch transfers ownership to us, so -            // we don't actually need to INCREF; but we *do* -            // need to DECREF if we're not restored. -            PyErrFetchParam t, v, tb; -            PyErr_Fetch(&t, &v, &tb); -            type.steal(t.relinquish_ownership()); -            instance.steal(v.relinquish_ownership()); -            traceback.steal(tb.relinquish_ownership()); -        } - -        void PyErrRestore() -        { -            // can only do this once -            assert(!this->restored); -            this->restored = true; -            PyErr_Restore( -                this->type.relinquish_ownership(), -                this->instance.relinquish_ownership(), -                this->traceback.relinquish_ownership()); -            assert(!this->type && !this->instance && !this->traceback); -        } - -    private: -        void normalize() -        { -            // First, check the traceback argument, replacing None, -            // with NULL -            if (traceback.is_None()) { -                traceback = nullptr; -            } - -            if (traceback && !PyTraceBack_Check(traceback.borrow())) { -                throw PyErrOccurred(PyExc_TypeError, -                                    "throw() third argument must be a traceback object"); -            } - -            if (PyExceptionClass_Check(type)) { -                // If we just had a type, we'll now have a type and -                // instance. -                // The type's refcount will have gone up by one -                // because of the instance and the instance will have -                // a refcount of one. Either way, we owned, and still -                // do own, exactly one reference. -                PyErr_NormalizeException(&type, &instance, &traceback); - -            } -            else if (PyExceptionInstance_Check(type)) { -                /* Raising an instance --- usually that means an -                   object that is a subclass of BaseException, but on -                   Python 2, that can also mean an arbitrary old-style -                   object. The value should be a dummy. */ -                if (instance && !instance.is_None()) { -                    throw PyErrOccurred( -                                    PyExc_TypeError, -                                    "instance exception may not have a separate value"); -                } -                /* Normalize to raise <class>, <instance> */ -                this->instance = this->type; -                this->type = PyExceptionInstance_Class(instance.borrow()); - -                /* -                  It would be tempting to do this: - -                Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow())); -                this->type = PyExceptionInstance_Class(instance.borrow()); -                assert(this->type.REFCNT() == type_count + 1); - -                But that doesn't work on Python 2 in the case of -                old-style instances: The result of Py_TYPE is going to -                be the global shared <type instance> that all -                old-style classes have, while the return of Instance_Class() -                will be the Python-level class object. The two are unrelated. -                */ -            } -            else { -                /* Not something you can raise. throw() fails. */ -                PyErr_Format(PyExc_TypeError, -                     "exceptions must be classes, or instances, not %s", -                             Py_TYPE(type.borrow())->tp_name); -                throw PyErrOccurred(); -            } -        } -    }; - -    // PyArg_Parse's O argument returns a borrowed reference. -    class PyArgParseParam : public BorrowedObject -    { -    private: -        G_NO_COPIES_OF_CLS(PyArgParseParam); -    public: -        explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p) -        { -        } - -        inline PyObject** operator&() -        { -            return &this->p; -        } -    }; - -};}; - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp deleted file mode 100644 index bd4b7ae..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef GREENLET_SLP_SWITCH_HPP -#define GREENLET_SLP_SWITCH_HPP - -#include "greenlet_compiler_compat.hpp" -#include "greenlet_refs.hpp" - -/* - * the following macros are spliced into the OS/compiler - * specific code, in order to simplify maintenance. - */ -// We can save about 10% of the time it takes to switch greenlets if -// we thread the thread state through the slp_save_state() and the -// following slp_restore_state() calls from -// slp_switch()->g_switchstack() (which already needs to access it). -// -// However: -// -// that requires changing the prototypes and implementations of the -// switching functions. If we just change the prototype of -// slp_switch() to accept the argument and update the macros, without -// changing the implementation of slp_switch(), we get crashes on -// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear); -// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit -// windows is an issue because slp_switch is written fully in assembly -// and currently ignores its argument so some code would have to be -// adjusted there to pass the argument on to the -// ``slp_save_state_asm()`` function (but interestingly, because of -// the calling convention, the extra argument is just ignored and -// things function fine, albeit slower, if we just modify -// ``slp_save_state_asm`()` to fetch the pointer to pass to the -// macro.) -// -// Our compromise is to use a *glabal*, untracked, weak, pointer -// to the necessary thread state during the process of switching only. -// This is safe because we're protected by the GIL, and if we're -// running this code, the thread isn't exiting. This also nets us a -// 10-12% speed improvement. - -static greenlet::Greenlet* volatile switching_thread_state = nullptr; - - -extern "C" { -static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref); -static void GREENLET_NOINLINE(slp_restore_state_trampoline)(); -} - - -#define SLP_SAVE_STATE(stackref, stsizediff) \ -do {                                                    \ -    assert(switching_thread_state);  \ -    stackref += STACK_MAGIC;                 \ -    if (slp_save_state_trampoline((char*)stackref))    \ -        return -1;                                     \ -    if (!switching_thread_state->active()) \ -        return 1;                                      \ -    stsizediff = switching_thread_state->stack_start() - (char*)stackref; \ -} while (0) - -#define SLP_RESTORE_STATE() slp_restore_state_trampoline() - -#define SLP_EVAL -extern "C" { -#define slp_switch GREENLET_NOINLINE(slp_switch) -#include "slp_platformselect.h" -} -#undef slp_switch - -#ifndef STACK_MAGIC -#    error \ -        "greenlet needs to be ported to this platform, or taught how to detect your compiler properly." -#endif /* !STACK_MAGIC */ - - - -#ifdef EXTERNAL_ASM -/* CCP addition: Make these functions, to be called from assembler. - * The token include file for the given platform should enable the - * EXTERNAL_ASM define so that this is included. - */ -extern "C" { -intptr_t -slp_save_state_asm(intptr_t* ref) -{ -    intptr_t diff; -    SLP_SAVE_STATE(ref, diff); -    return diff; -} - -void -slp_restore_state_asm(void) -{ -    SLP_RESTORE_STATE(); -} - -extern int slp_switch(void); -}; -#endif - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp deleted file mode 100644 index 045371f..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp +++ /dev/null @@ -1,543 +0,0 @@ -#ifndef GREENLET_THREAD_STATE_HPP -#define GREENLET_THREAD_STATE_HPP - -#include <ctime> -#include <stdexcept> - -#include "greenlet_internal.hpp" -#include "greenlet_refs.hpp" -#include "greenlet_thread_support.hpp" - -using greenlet::refs::BorrowedObject; -using greenlet::refs::BorrowedGreenlet; -using greenlet::refs::BorrowedMainGreenlet; -using greenlet::refs::OwnedMainGreenlet; -using greenlet::refs::OwnedObject; -using greenlet::refs::OwnedGreenlet; -using greenlet::refs::OwnedList; -using greenlet::refs::PyErrFetchParam; -using greenlet::refs::PyArgParseParam; -using greenlet::refs::ImmortalString; -using greenlet::refs::CreatedModule; -using greenlet::refs::PyErrPieces; -using greenlet::refs::NewReference; - -namespace greenlet { -/** - * Thread-local state of greenlets. - * - * Each native thread will get exactly one of these objects, - * automatically accessed through the best available thread-local - * mechanism the compiler supports (``thread_local`` for C++11 - * compilers or ``__thread``/``declspec(thread)`` for older GCC/clang - * or MSVC, respectively.) - * - * Previously, we kept thread-local state mostly in a bunch of - * ``static volatile`` variables in the main greenlet file.. This had - * the problem of requiring extra checks, loops, and great care - * accessing these variables if we potentially invoked any Python code - * that could release the GIL, because the state could change out from - * under us. Making the variables thread-local solves this problem. - * - * When we detected that a greenlet API accessing the current greenlet - * was invoked from a different thread than the greenlet belonged to, - * we stored a reference to the greenlet in the Python thread - * dictionary for the thread the greenlet belonged to. This could lead - * to memory leaks if the thread then exited (because of a reference - * cycle, as greenlets referred to the thread dictionary, and deleting - * non-current greenlets leaked their frame plus perhaps arguments on - * the C stack). If a thread exited while still having running - * greenlet objects (perhaps that had just switched back to the main - * greenlet), and did not invoke one of the greenlet APIs *in that - * thread, immediately before it exited, without some other thread - * then being invoked*, such a leak was guaranteed. - * - * This can be partly solved by using compiler thread-local variables - * instead of the Python thread dictionary, thus avoiding a cycle. - * - * To fully solve this problem, we need a reliable way to know that a - * thread is done and we should clean up the main greenlet. On POSIX, - * we can use the destructor function of ``pthread_key_create``, but - * there's nothing similar on Windows; a C++11 thread local object - * reliably invokes its destructor when the thread it belongs to exits - * (non-C++11 compilers offer ``__thread`` or ``declspec(thread)`` to - * create thread-local variables, but they can't hold C++ objects that - * invoke destructors; the C++11 version is the most portable solution - * I found). When the thread exits, we can drop references and - * otherwise manipulate greenlets and frames that we know can no - * longer be switched to. For compilers that don't support C++11 - * thread locals, we have a solution that uses the python thread - * dictionary, though it may not collect everything as promptly as - * other compilers do, if some other library is using the thread - * dictionary and has a cycle or extra reference. - * - * There are two small wrinkles. The first is that when the thread - * exits, it is too late to actually invoke Python APIs: the Python - * thread state is gone, and the GIL is released. To solve *this* - * problem, our destructor uses ``Py_AddPendingCall`` to transfer the - * destruction work to the main thread. (This is not an issue for the - * dictionary solution.) - * - * The second is that once the thread exits, the thread local object - * is invalid and we can't even access a pointer to it, so we can't - * pass it to ``Py_AddPendingCall``. This is handled by actually using - * a second object that's thread local (ThreadStateCreator) and having - * it dynamically allocate this object so it can live until the - * pending call runs. - */ - - - -class ThreadState { -private: -    // As of commit 08ad1dd7012b101db953f492e0021fb08634afad -    // this class needed 56 bytes in o Py_DEBUG build -    // on 64-bit macOS 11. -    // Adding the vector takes us up to 80 bytes () - -    /* Strong reference to the main greenlet */ -    OwnedMainGreenlet main_greenlet; - -    /* Strong reference to the current greenlet. */ -    OwnedGreenlet current_greenlet; - -    /* Strong reference to the trace function, if any. */ -    OwnedObject tracefunc; - -    typedef std::vector<PyGreenlet*, PythonAllocator<PyGreenlet*> > deleteme_t; -    /* A vector of raw PyGreenlet pointers representing things that need -       deleted when this thread is running. The vector owns the -       references, but you need to manually INCREF/DECREF as you use -       them. We don't use a vector<refs::OwnedGreenlet> because we -       make copy of this vector, and that would become O(n) as all the -       refcounts are incremented in the copy. -    */ -    deleteme_t deleteme; - -#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED -    void* exception_state; -#endif - -    static std::clock_t _clocks_used_doing_gc; -    static ImmortalString get_referrers_name; -    static PythonAllocator<ThreadState> allocator; - -    G_NO_COPIES_OF_CLS(ThreadState); - -public: -    static void* operator new(size_t UNUSED(count)) -    { -        return ThreadState::allocator.allocate(1); -    } - -    static void operator delete(void* ptr) -    { -        return ThreadState::allocator.deallocate(static_cast<ThreadState*>(ptr), -                                                 1); -    } - -    static void init() -    { -        ThreadState::get_referrers_name = "get_referrers"; -        ThreadState::_clocks_used_doing_gc = 0; -    } - -    ThreadState() -        : main_greenlet(OwnedMainGreenlet::consuming(green_create_main(this))), -          current_greenlet(main_greenlet) -    { -        if (!this->main_greenlet) { -            // We failed to create the main greenlet. That's bad. -            throw PyFatalError("Failed to create main greenlet"); -        } -        // The main greenlet starts with 1 refs: The returned one. We -        // then copied it to the current greenlet. -        assert(this->main_greenlet.REFCNT() == 2); - -#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED -        this->exception_state = slp_get_exception_state(); -#endif -    } - -    inline void restore_exception_state() -    { -#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED -        // It's probably important this be inlined and only call C -        // functions to avoid adding an SEH frame. -        slp_set_exception_state(this->exception_state); -#endif -    } - -    inline bool has_main_greenlet() -    { -        return !!this->main_greenlet; -    } - -    // Called from the ThreadStateCreator when we're in non-standard -    // threading mode. In that case, there is an object in the Python -    // thread state dictionary that points to us. The main greenlet -    // also traverses into us, in which case it's crucial not to -    // traverse back into the main greenlet. -    int tp_traverse(visitproc visit, void* arg, bool traverse_main=true) -    { -        if (traverse_main) { -            Py_VISIT(main_greenlet.borrow_o()); -        } -        if (traverse_main || current_greenlet != main_greenlet) { -            Py_VISIT(current_greenlet.borrow_o()); -        } -        Py_VISIT(tracefunc.borrow()); -        return 0; -    } - -    inline BorrowedMainGreenlet borrow_main_greenlet() const -    { -        assert(this->main_greenlet); -        assert(this->main_greenlet.REFCNT() >= 2); -        return this->main_greenlet; -    }; - -    inline OwnedMainGreenlet get_main_greenlet() -    { -        return this->main_greenlet; -    } - -    /** -     * In addition to returning a new reference to the currunt -     * greenlet, this performs any maintenance needed. -     */ -    inline OwnedGreenlet get_current() -    { -        /* green_dealloc() cannot delete greenlets from other threads, so -           it stores them in the thread dict; delete them now. */ -        this->clear_deleteme_list(); -        //assert(this->current_greenlet->main_greenlet == this->main_greenlet); -        //assert(this->main_greenlet->main_greenlet == this->main_greenlet); -        return this->current_greenlet; -    } - -    /** -     * As for non-const get_current(); -     */ -    inline BorrowedGreenlet borrow_current() -    { -        this->clear_deleteme_list(); -        return this->current_greenlet; -    } - -    /** -     * Does no maintenance. -     */ -    inline OwnedGreenlet get_current() const -    { -        return this->current_greenlet; -    } - -    template<typename T, refs::TypeChecker TC> -    inline bool is_current(const refs::PyObjectPointer<T, TC>& obj) const -    { -        return this->current_greenlet.borrow_o() == obj.borrow_o(); -    } - -    inline void set_current(const OwnedGreenlet& target) -    { -        this->current_greenlet = target; -    } - -private: -    /** -     * Deref and remove the greenlets from the deleteme list. Must be -     * holding the GIL. -     * -     * If *murder* is true, then we must be called from a different -     * thread than the one that these greenlets were running in. -     * In that case, if the greenlet was actually running, we destroy -     * the frame reference and otherwise make it appear dead before -     * proceeding; otherwise, we would try (and fail) to raise an -     * exception in it and wind up right back in this list. -     */ -    inline void clear_deleteme_list(const bool murder=false) -    { -        if (!this->deleteme.empty()) { -            // It's possible we could add items to this list while -            // running Python code if there's a thread switch, so we -            // need to defensively copy it before that can happen. -            deleteme_t copy = this->deleteme; -            this->deleteme.clear(); // in case things come back on the list -            for(deleteme_t::iterator it = copy.begin(), end = copy.end(); -                it != end; -                ++it ) { -                PyGreenlet* to_del = *it; -                if (murder) { -                    // Force each greenlet to appear dead; we can't raise an -                    // exception into it anymore anyway. -                    to_del->pimpl->murder_in_place(); -                } - -                // The only reference to these greenlets should be in -                // this list, decreffing them should let them be -                // deleted again, triggering calls to green_dealloc() -                // in the correct thread (if we're not murdering). -                // This may run arbitrary Python code and switch -                // threads or greenlets! -                Py_DECREF(to_del); -                if (PyErr_Occurred()) { -                    PyErr_WriteUnraisable(nullptr); -                    PyErr_Clear(); -                } -            } -        } -    } - -public: - -    /** -     * Returns a new reference, or a false object. -     */ -    inline OwnedObject get_tracefunc() const -    { -        return tracefunc; -    }; - - -    inline void set_tracefunc(BorrowedObject tracefunc) -    { -        assert(tracefunc); -        if (tracefunc == BorrowedObject(Py_None)) { -            this->tracefunc.CLEAR(); -        } -        else { -            this->tracefunc = tracefunc; -        } -    } - -    /** -     * Given a reference to a greenlet that some other thread -     * attempted to delete (has a refcount of 0) store it for later -     * deletion when the thread this state belongs to is current. -     */ -    inline void delete_when_thread_running(PyGreenlet* to_del) -    { -        Py_INCREF(to_del); -        this->deleteme.push_back(to_del); -    } - -    /** -     * Set to std::clock_t(-1) to disable. -     */ -    inline static std::clock_t& clocks_used_doing_gc() -    { -        return ThreadState::_clocks_used_doing_gc; -    } - -    ~ThreadState() -    { -        if (!PyInterpreterState_Head()) { -            // We shouldn't get here (our callers protect us) -            // but if we do, all we can do is bail early. -            return; -        } - -        // We should not have an "origin" greenlet; that only exists -        // for the temporary time during a switch, which should not -        // be in progress as the thread dies. -        //assert(!this->switching_state.origin); - -        this->tracefunc.CLEAR(); - -        // Forcibly GC as much as we can. -        this->clear_deleteme_list(true); - -        // The pending call did this. -        assert(this->main_greenlet->thread_state() == nullptr); - -        // If the main greenlet is the current greenlet, -        // then we "fell off the end" and the thread died. -        // It's possible that there is some other greenlet that -        // switched to us, leaving a reference to the main greenlet -        // on the stack, somewhere uncollectible. Try to detect that. -        if (this->current_greenlet == this->main_greenlet && this->current_greenlet) { -            assert(this->current_greenlet->is_currently_running_in_some_thread()); -            // Drop one reference we hold. -            this->current_greenlet.CLEAR(); -            assert(!this->current_greenlet); -            // Only our reference to the main greenlet should be left, -            // But hold onto the pointer in case we need to do extra cleanup. -            PyGreenlet* old_main_greenlet = this->main_greenlet.borrow(); -            Py_ssize_t cnt = this->main_greenlet.REFCNT(); -            this->main_greenlet.CLEAR(); -            if (ThreadState::_clocks_used_doing_gc != std::clock_t(-1) -                && cnt == 2 && Py_REFCNT(old_main_greenlet) == 1) { -                // Highly likely that the reference is somewhere on -                // the stack, not reachable by GC. Verify. -                // XXX: This is O(n) in the total number of objects. -                // TODO: Add a way to disable this at runtime, and -                // another way to report on it. -                std::clock_t begin = std::clock(); -                NewReference gc(PyImport_ImportModule("gc")); -                if (gc) { -                    OwnedObject get_referrers = gc.PyRequireAttr(ThreadState::get_referrers_name); -                    OwnedList refs(get_referrers.PyCall(old_main_greenlet)); -                    if (refs && refs.empty()) { -                        assert(refs.REFCNT() == 1); -                        // We found nothing! So we left a dangling -                        // reference: Probably the last thing some -                        // other greenlet did was call -                        // 'getcurrent().parent.switch()' to switch -                        // back to us. Clean it up. This will be the -                        // case on CPython 3.7 and newer, as they use -                        // an internal calling conversion that avoids -                        // creating method objects and storing them on -                        // the stack. -                        Py_DECREF(old_main_greenlet); -                    } -                    else if (refs -                             && refs.size() == 1 -                             && PyCFunction_Check(refs.at(0)) -                             && Py_REFCNT(refs.at(0)) == 2) { -                        assert(refs.REFCNT() == 1); -                        // Ok, we found a C method that refers to the -                        // main greenlet, and its only referenced -                        // twice, once in the list we just created, -                        // once from...somewhere else. If we can't -                        // find where else, then this is a leak. -                        // This happens in older versions of CPython -                        // that create a bound method object somewhere -                        // on the stack that we'll never get back to. -                        if (PyCFunction_GetFunction(refs.at(0).borrow()) == (PyCFunction)green_switch) { -                            BorrowedObject function_w = refs.at(0); -                            refs.clear(); // destroy the reference -                                          // from the list. -                            // back to one reference. Can *it* be -                            // found? -                            assert(function_w.REFCNT() == 1); -                            refs = get_referrers.PyCall(function_w); -                            if (refs && refs.empty()) { -                                // Nope, it can't be found so it won't -                                // ever be GC'd. Drop it. -                                Py_CLEAR(function_w); -                            } -                        } -                    } -                    std::clock_t end = std::clock(); -                    ThreadState::_clocks_used_doing_gc += (end - begin); -                } -            } -        } - -        // We need to make sure this greenlet appears to be dead, -        // because otherwise deallocing it would fail to raise an -        // exception in it (the thread is dead) and put it back in our -        // deleteme list. -        if (this->current_greenlet) { -            this->current_greenlet->murder_in_place(); -            this->current_greenlet.CLEAR(); -        } - -        if (this->main_greenlet) { -            // Couldn't have been the main greenlet that was running -            // when the thread exited (because we already cleared this -            // pointer if it was). This shouldn't be possible? - -            // If the main greenlet was current when the thread died (it -            // should be, right?) then we cleared its self pointer above -            // when we cleared the current greenlet's main greenlet pointer. -            // assert(this->main_greenlet->main_greenlet == this->main_greenlet -            //        || !this->main_greenlet->main_greenlet); -            // // self reference, probably gone -            // this->main_greenlet->main_greenlet.CLEAR(); - -            // This will actually go away when the ivar is destructed. -            this->main_greenlet.CLEAR(); -        } - -        if (PyErr_Occurred()) { -            PyErr_WriteUnraisable(NULL); -            PyErr_Clear(); -        } - -    } - -}; - -ImmortalString ThreadState::get_referrers_name(nullptr); -PythonAllocator<ThreadState> ThreadState::allocator; -std::clock_t ThreadState::_clocks_used_doing_gc(0); - -template<typename Destructor> -class ThreadStateCreator -{ -private: -    // Initialized to 1, and, if still 1, created on access. -    // Set to 0 on destruction. -    ThreadState* _state; -    G_NO_COPIES_OF_CLS(ThreadStateCreator); -public: - -    // Only one of these, auto created per thread -    ThreadStateCreator() : -        _state((ThreadState*)1) -    { -    } - -    ~ThreadStateCreator() -    { -        ThreadState* tmp = this->_state; -        this->_state = nullptr; -        if (tmp && tmp != (ThreadState*)1) { -            Destructor x(tmp); -        } -    } - -    inline ThreadState& state() -    { -        // The main greenlet will own this pointer when it is created, -        // which will be right after this. The plan is to give every -        // greenlet a pointer to the main greenlet for the thread it -        // runs in; if we are doing something cross-thread, we need to -        // access the pointer from the main greenlet. Deleting the -        // thread, and hence the thread-local storage, will delete the -        // state pointer in the main greenlet. -        if (this->_state == (ThreadState*)1) { -            // XXX: Assuming allocation never fails -            this->_state = new ThreadState; -            // For non-standard threading, we need to store an object -            // in the Python thread state dictionary so that it can be -            // DECREF'd when the thread ends (ideally; the dict could -            // last longer) and clean this object up. -        } -        if (!this->_state) { -            throw std::runtime_error("Accessing state after destruction."); -        } -        return *this->_state; -    } - -    operator ThreadState&() -    { -        return this->state(); -    } - -    operator ThreadState*() -    { -        return &this->state(); -    } - -    inline int tp_traverse(visitproc visit, void* arg) -    { -        if (this->_state) { -            return this->_state->tp_traverse(visit, arg); -        } -        return 0; -    } - -}; - - -// We can't use the PythonAllocator for this, because we push to it -// from the thread state destructor, which doesn't have the GIL, -// and Python's allocators can only be called with the GIL. -typedef std::vector<ThreadState*> cleanup_queue_t; - -}; // namespace greenlet - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp deleted file mode 100644 index acf39c8..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef GREENLET_THREAD_STATE_DICT_CLEANUP_HPP -#define GREENLET_THREAD_STATE_DICT_CLEANUP_HPP - -#include "greenlet_internal.hpp" -#include "greenlet_thread_state.hpp" - -#ifdef __clang__ -#    pragma clang diagnostic push -#    pragma clang diagnostic ignored "-Wmissing-field-initializers" -#endif - -#ifndef G_THREAD_STATE_DICT_CLEANUP_TYPE -// shut the compiler up if it looks at this file in isolation -#define ThreadStateCreator int -#endif - -// Define a Python object that goes in the Python thread state dict -// when the greenlet thread state is created, and which owns the -// reference to the greenlet thread local state. -// When the thread state dict is cleaned up, so too is the thread -// state. This works best if we make sure there are no circular -// references to the thread state. -typedef struct _PyGreenletCleanup { -    PyObject_HEAD -    ThreadStateCreator* thread_state_creator; -} PyGreenletCleanup; - -static void -cleanup_do_dealloc(PyGreenletCleanup* self) -{ -    ThreadStateCreator* tmp = self->thread_state_creator; -    self->thread_state_creator = nullptr; -    if (tmp) { -        delete tmp; -    } -} - -static void -cleanup_dealloc(PyGreenletCleanup* self) -{ -    PyObject_GC_UnTrack(self); -    cleanup_do_dealloc(self); -} - -static int -cleanup_clear(PyGreenletCleanup* self) -{ -    // This method is never called by our test cases. -    cleanup_do_dealloc(self); -    return 0; -} - -static int -cleanup_traverse(PyGreenletCleanup* self, visitproc visit, void* arg) -{ -    if (self->thread_state_creator) { -        return self->thread_state_creator->tp_traverse(visit, arg); -    } -    return 0; -} - -static int -cleanup_is_gc(PyGreenlet* UNUSED(self)) -{ -    return 1; -} - -static PyTypeObject PyGreenletCleanup_Type = { -    PyVarObject_HEAD_INIT(NULL, 0) -    "greenlet._greenlet.ThreadStateCleanup", -    sizeof(struct _PyGreenletCleanup), -    0,                   /* tp_itemsize */ -    /* methods */ -    (destructor)cleanup_dealloc, /* tp_dealloc */ -    0,                         /* tp_print */ -    0,                         /* tp_getattr */ -    0,                         /* tp_setattr */ -    0,                         /* tp_compare */ -    0,                         /* tp_repr */ -    0,                         /* tp_as _number*/ -    0,                         /* tp_as _sequence*/ -    0,                         /* tp_as _mapping*/ -    0,                         /* tp_hash */ -    0,                         /* tp_call */ -    0,                         /* tp_str */ -    0,                         /* tp_getattro */ -    0,                         /* tp_setattro */ -    0,                         /* tp_as_buffer*/ -    G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ -    "Internal use only",                        /* tp_doc */ -    (traverseproc)cleanup_traverse, /* tp_traverse */ -    (inquiry)cleanup_clear,         /* tp_clear */ -    0,                                  /* tp_richcompare */ -    // XXX: Don't our flags promise a weakref? -    0,                           /* tp_weaklistoffset */ -    0,                                  /* tp_iter */ -    0,                                  /* tp_iternext */ -    0,                      /* tp_methods */ -    0,                      /* tp_members */ -    0,                      /* tp_getset */ -    0,                                  /* tp_base */ -    0,                                  /* tp_dict */ -    0,                                  /* tp_descr_get */ -    0,                                  /* tp_descr_set */ -    0,         /* tp_dictoffset */ -    0,               /* tp_init */ -    PyType_GenericAlloc,                  /* tp_alloc */ -    PyType_GenericNew,                          /* tp_new */ -    PyObject_GC_Del,                   /* tp_free */ -    (inquiry)cleanup_is_gc,         /* tp_is_gc */ -}; - -#ifdef __clang__ -#    pragma clang diagnostic pop -#endif - - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp b/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp deleted file mode 100644 index 3ded7d2..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef GREENLET_THREAD_SUPPORT_HPP -#define GREENLET_THREAD_SUPPORT_HPP - -/** - * Defines various utility functions to help greenlet integrate well - * with threads. This used to be needed when we supported Python - * 2.7 on Windows, which used a very old compiler. We wrote an - * alternative implementation using Python APIs and POSIX or Windows - * APIs, but that's no longer needed. So this file is a shadow of its - * former self --- but may be needed in the future. - */ - -#include <stdexcept> -#include <thread> -#include <mutex> - -#include "greenlet_compiler_compat.hpp" - -namespace greenlet { -    typedef std::mutex Mutex; -    typedef std::lock_guard<Mutex> LockGuard; -    class LockInitError : public std::runtime_error -    { -    public: -        LockInitError(const char* what) : std::runtime_error(what) -        {}; -    }; -}; - - -#endif /* GREENLET_THREAD_SUPPORT_HPP */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/__init__.py b/venv/lib/python3.11/site-packages/greenlet/platform/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/__init__.py +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/platform/__pycache__/__init__.cpython-311.pycBinary files differ deleted file mode 100644 index a1a372f..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/__pycache__/__init__.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd b/venv/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd deleted file mode 100644 index 0928595..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd +++ /dev/null @@ -1,2 +0,0 @@ -call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64
 -ml64 /nologo /c /Fo switch_x64_masm.obj switch_x64_masm.asm
 diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h deleted file mode 100644 index 058617c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-16 Add clang support using x register naming. Fredrik Fornwall - * 13-Apr-13 Add support for strange GCC caller-save decisions - * 08-Apr-13 File creation. Michael Matz - * - * NOTES - * - * Simply save all callee saved registers - * - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REGS_TO_SAVE "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", \ -                     "x27", "x28", "x30" /* aka lr */, \ -                     "v8", "v9", "v10", "v11", \ -                     "v12", "v13", "v14", "v15" - -/* - * Recall: -   asm asm-qualifiers ( AssemblerTemplate -                 : OutputOperands -                 [ : InputOperands -                 [ : Clobbers ] ]) - - or  (if asm-qualifiers contains 'goto') - -   asm asm-qualifiers ( AssemblerTemplate -                      : OutputOperands -                      : InputOperands -                      : Clobbers -                      : GotoLabels) - - and OutputOperands are - -   [ [asmSymbolicName] ] constraint (cvariablename) - - When a name is given, refer to it as ``%[the name]``. - When not given, ``%i`` where ``i`` is the zero-based index. - - constraints starting with ``=`` means only writing; ``+`` means - reading and writing. - - This is followed by ``r`` (must be register) or ``m`` (must be memory) - and these can be combined. - - The ``cvariablename`` is actually an lvalue expression. - - In AArch65, 31 general purpose registers. If named X0... they are - 64-bit. If named W0... they are the bottom 32 bits of the - corresponding 64 bit register. - - XZR and WZR are hardcoded to 0, and ignore writes. - - Arguments are in X0..X7. C++ uses X0 for ``this``. X0 holds simple return - values (?) - - Whenever a W register is written, the top half of the X register is zeroed. - */ - -static int -slp_switch(void) -{ -	int err; -	void *fp; -        /* Windowz uses a 32-bit long on a 64-bit platform, unlike the rest of -           the world, and in theory we can be compiled with GCC/llvm on 64-bit -           windows. So we need a fixed-width type. -        */ -        int64_t *stackref, stsizediff; -        __asm__ volatile ("" : : : REGS_TO_SAVE); -	__asm__ volatile ("str x29, %0" : "=m"(fp) : : ); -        __asm__ ("mov %0, sp" : "=r" (stackref)); -        { -                SLP_SAVE_STATE(stackref, stsizediff); -                __asm__ volatile ( -                    "add sp,sp,%0\n" -                    "add x29,x29,%0\n" -                    : -                    : "r" (stsizediff) -                    ); -		SLP_RESTORE_STATE(); -		/* SLP_SAVE_STATE macro contains some return statements -		   (of -1 and 1).  It falls through only when -		   the return value of slp_save_state() is zero, which -		   is placed in x0. -		   In that case we (slp_switch) also want to return zero -		   (also in x0 of course). -		   Now, some GCC versions (seen with 4.8) think it's a -		   good idea to save/restore x0 around the call to -		   slp_restore_state(), instead of simply zeroing it -		   at the return below.  But slp_restore_state -		   writes random values to the stack slot used for this -		   save/restore (from when it once was saved above in -		   SLP_SAVE_STATE, when it was still uninitialized), so -		   "restoring" that precious zero actually makes us -		   return random values.  There are some ways to make -		   GCC not use that zero value in the normal return path -		   (e.g. making err volatile, but that costs a little -		   stack space), and the simplest is to call a function -		   that returns an unknown value (which happens to be zero), -		   so the saved/restored value is unused. - -                   Thus, this line stores a 0 into the ``err`` variable -                   (which must be held in a register for this instruction, -                    of course). The ``w`` qualifier causes the instruction -                    to use W0 instead of X0, otherwise we get a warning -                    about a value size mismatch (because err is an int, -                    and aarch64 platforms are LP64: 32-bit int, 64 bit long -                   and pointer). -                */ -           __asm__ volatile ("mov %w0, #0" : "=r" (err)); -        } -        __asm__ volatile ("ldr x29, %0" : : "m" (fp) :); -        __asm__ volatile ("" : : : REGS_TO_SAVE); -        return err; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h deleted file mode 100644 index 7e07abf..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h +++ /dev/null @@ -1,30 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "$9", "$10", "$11", "$12", "$13", "$14", "$15", \ -		     "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9" - -static int -slp_switch(void) -{ -  int ret; -  long *stackref, stsizediff; -  __asm__ volatile ("" : : : REGS_TO_SAVE); -  __asm__ volatile ("mov $30, %0" : "=r" (stackref) : ); -  { -      SLP_SAVE_STATE(stackref, stsizediff); -      __asm__ volatile ( -	  "addq $30, %0, $30\n\t" -	  : /* no outputs */ -	  : "r" (stsizediff) -	  ); -      SLP_RESTORE_STATE(); -  } -  __asm__ volatile ("" : : : REGS_TO_SAVE); -  __asm__ volatile ("mov $31, %0" : "=r" (ret) : ); -  return ret; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h deleted file mode 100644 index d470110..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 3-May-13   Ralf Schmitt  <ralf@systemexit.de> - *     Add support for strange GCC caller-save decisions - *     (ported from switch_aarch64_gcc.h) - * 18-Aug-11  Alexey Borzenkov  <snaury@gmail.com> - *      Correctly save rbp, csr and cw - * 01-Apr-04  Hye-Shik Chang    <perky@FreeBSD.org> - *      Ported from i386 to amd64. - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for spark - * 31-Avr-02  Armin Rigo         <arigo@ulb.ac.be> - *      Added ebx, esi and edi register-saves. - * 01-Mar-02  Samual M. Rushing  <rushing@ironport.com> - *      Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -/* #define STACK_MAGIC 3 */ -/* the above works fine with gcc 2.96, but 2.95.3 wants this */ -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "r12", "r13", "r14", "r15" - -static int -slp_switch(void) -{ -    int err; -    void* rbp; -    void* rbx; -    unsigned int csr; -    unsigned short cw; -    /* This used to be declared 'register', but that does nothing in -    modern compilers and is explicitly forbidden in some new -    standards. */ -    long *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("fstcw %0" : "=m" (cw)); -    __asm__ volatile ("stmxcsr %0" : "=m" (csr)); -    __asm__ volatile ("movq %%rbp, %0" : "=m" (rbp)); -    __asm__ volatile ("movq %%rbx, %0" : "=m" (rbx)); -    __asm__ ("movq %%rsp, %0" : "=g" (stackref)); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "addq %0, %%rsp\n" -            "addq %0, %%rbp\n" -            : -            : "r" (stsizediff) -            ); -        SLP_RESTORE_STATE(); -        __asm__ volatile ("xorq %%rax, %%rax" : "=a" (err)); -    } -    __asm__ volatile ("movq %0, %%rbx" : : "m" (rbx)); -    __asm__ volatile ("movq %0, %%rbp" : : "m" (rbp)); -    __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); -    __asm__ volatile ("fldcw %0" : : "m" (cw)); -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h deleted file mode 100644 index 655003a..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 14-Aug-06 File creation. Ported from Arm Thumb. Sylvain Baro - *  3-Sep-06 Commented out saving of r1-r3 (r4 already commented out) as I - *           read that these do not need to be saved.  Also added notes and - *           errors related to the frame pointer. Richard Tew. - * - * NOTES - * - *   It is not possible to detect if fp is used or not, so the supplied - *   switch function needs to support it, so that you can remove it if - *   it does not apply to you. - * - * POSSIBLE ERRORS - * - *   "fp cannot be used in asm here" - * - *   - Try commenting out "fp" in REGS_TO_SAVE. - * - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REG_SP "sp" -#define REG_SPSP "sp,sp" -#ifdef __thumb__ -#define REG_FP "r7" -#define REG_FPFP "r7,r7" -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r9", "r10", "r11", "lr" -#else -#define REG_FP "fp" -#define REG_FPFP "fp,fp" -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r8", "r9", "r10", "lr" -#endif -#if defined(__SOFTFP__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL -#elif defined(__VFP_FP__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ -                                           "d12", "d13", "d14", "d15" -#elif defined(__MAVERICK__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "mvf4", "mvf5", "mvf6", "mvf7", \ -                                           "mvf8", "mvf9", "mvf10", "mvf11", \ -                                           "mvf12", "mvf13", "mvf14", "mvf15" -#else -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "f4", "f5", "f6", "f7" -#endif - -static int -#ifdef __GNUC__ -__attribute__((optimize("no-omit-frame-pointer"))) -#endif -slp_switch(void) -{ -        void *fp; -        int *stackref, stsizediff; -        int result; -        __asm__ volatile ("" : : : REGS_TO_SAVE); -        __asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0"); -        __asm__ ("mov %0," REG_SP : "=r" (stackref)); -        { -                SLP_SAVE_STATE(stackref, stsizediff); -                __asm__ volatile ( -                    "add " REG_SPSP ",%0\n" -                    "add " REG_FPFP ",%0\n" -                    : -                    : "r" (stsizediff) -                    ); -                SLP_RESTORE_STATE(); -        } -        __asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0"); -        __asm__ volatile ("" : : : REGS_TO_SAVE); -        return result; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h deleted file mode 100644 index 9e640e1..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 31-May-15 iOS support. Ported from arm32. Proton <feisuzhu@163.com> - * - * NOTES - * - *   It is not possible to detect if fp is used or not, so the supplied - *   switch function needs to support it, so that you can remove it if - *   it does not apply to you. - * - * POSSIBLE ERRORS - * - *   "fp cannot be used in asm here" - * - *   - Try commenting out "fp" in REGS_TO_SAVE. - * - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 -#define REG_SP "sp" -#define REG_SPSP "sp,sp" -#define REG_FP "r7" -#define REG_FPFP "r7,r7" -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r10", "r11", "lr" -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ -                                           "d12", "d13", "d14", "d15" - -static int -#ifdef __GNUC__ -__attribute__((optimize("no-omit-frame-pointer"))) -#endif -slp_switch(void) -{ -        void *fp; -        int *stackref, stsizediff, result; -        __asm__ volatile ("" : : : REGS_TO_SAVE); -        __asm__ volatile ("str " REG_FP ",%0" : "=m" (fp)); -        __asm__ ("mov %0," REG_SP : "=r" (stackref)); -        { -                SLP_SAVE_STATE(stackref, stsizediff); -                __asm__ volatile ( -                    "add " REG_SPSP ",%0\n" -                    "add " REG_FPFP ",%0\n" -                    : -                    : "r" (stsizediff) -                    : REGS_TO_SAVE /* Clobber registers, force compiler to -                                    * recalculate address of void *fp from REG_SP or REG_FP */ -                ); -                SLP_RESTORE_STATE(); -        } -        __asm__ volatile ( -            "ldr " REG_FP ", %1\n\t" -            "mov %0, #0" -            : "=r" (result) -            : "m" (fp) -            : REGS_TO_SAVE /* Force compiler to restore saved registers after this */ -        ); -        return result; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm b/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm deleted file mode 100644 index 29f9c22..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm +++ /dev/null @@ -1,53 +0,0 @@ -  AREA switch_arm64_masm, CODE, READONLY; -  GLOBAL slp_switch [FUNC] -  EXTERN slp_save_state_asm -  EXTERN slp_restore_state_asm - -slp_switch     -    ; push callee saved registers to stack -    stp    x19, x20, [sp, #-16]! -    stp    x21, x22, [sp, #-16]! -    stp    x23, x24, [sp, #-16]! -    stp    x25, x26, [sp, #-16]! -    stp    x27, x28, [sp, #-16]! -    stp    x29, x30, [sp, #-16]! -    stp    d8, d9, [sp, #-16]! -    stp    d10, d11, [sp, #-16]! -    stp    d12, d13, [sp, #-16]! -    stp    d14, d15, [sp, #-16]! - -    ; call slp_save_state_asm with stack pointer -    mov x0, sp -    bl    slp_save_state_asm - -    ; early return for return value of 1 and -1 -    cmp x0, #-1 -    b.eq RETURN -    cmp x0, #1 -    b.eq RETURN - -    ; increment stack and frame pointer -    add sp, sp, x0 -    add x29, x29, x0 - -    bl slp_restore_state_asm - -    ; store return value for successful completion of routine -    mov x0, #0 - -RETURN -    ; pop registers from stack -    ldp d14, d15, [sp], #16 -    ldp d12, d13, [sp], #16 -    ldp d10, d11, [sp], #16 -    ldp d8, d9, [sp], #16 -    ldp x29, x30, [sp], #16 -    ldp x27, x28, [sp], #16 -    ldp x25, x26, [sp], #16 -    ldp x23, x24, [sp], #16 -    ldp x21, x22, [sp], #16 -    ldp x19, x20, [sp], #16 - -    ret - -    END diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.obj b/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.objBinary files differ deleted file mode 100644 index f6f220e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.obj +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h deleted file mode 100644 index 7ab7f45..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 21-Oct-21  Niyas Sait  <niyas.sait@linaro.org> - *      First version to enable win/arm64 support. - */ - -#define STACK_REFPLUS 1 -#define STACK_MAGIC 0 - -/* Use the generic support for an external assembly language slp_switch function. */ -#define EXTERNAL_ASM - -#ifdef SLP_EVAL -/* This always uses the external masm assembly file. */ -#endif
\ No newline at end of file diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h deleted file mode 100644 index ac469d3..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifdef SLP_EVAL -#define STACK_MAGIC 0 -#define REG_FP "r8" -#ifdef __CSKYABIV2__ -#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r9", "r10", "r11", "r15",\ -                             "r16", "r17", "r18", "r19", "r20", "r21", "r22",\ -                             "r23", "r24", "r25" - -#if defined (__CSKY_HARD_FLOAT__) || (__CSKY_VDSP__) -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "vr8", "vr9", "vr10", "vr11", "vr12",\ -                                           "vr13", "vr14", "vr15" -#else -#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL -#endif -#else -#define REGS_TO_SAVE "r9", "r10", "r11", "r12", "r13", "r15" -#endif - - -static int -#ifdef __GNUC__ -__attribute__((optimize("no-omit-frame-pointer"))) -#endif -slp_switch(void) -{ -        int *stackref, stsizediff; -        int result; - -        __asm__ volatile ("" : : : REGS_TO_SAVE); -        __asm__ ("mov %0, sp" : "=r" (stackref)); -        { -                SLP_SAVE_STATE(stackref, stsizediff); -                __asm__ volatile ( -                    "addu sp,%0\n" -                    "addu "REG_FP",%0\n" -                    : -                    : "r" (stsizediff) -                    ); -		 -                SLP_RESTORE_STATE(); -        } -        __asm__ volatile ("movi %0, 0" : "=r" (result)); -        __asm__ volatile ("" : : : REGS_TO_SAVE); - -        return result; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h deleted file mode 100644 index 9eaf34e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h +++ /dev/null @@ -1,31 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ -                    "s6", "s7", "s8", "fp", \ -                    "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" - -static int -slp_switch(void) -{ -    int ret; -    long *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("move %0, $sp" : "=r" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "add.d $sp, $sp, %0\n\t" -            : /* no outputs */ -            : "r" (stsizediff) -        ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("move %0, $zero" : "=r" (ret) : ); -    return ret; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h deleted file mode 100644 index da761c2..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 2014-01-06  Andreas Schwab  <schwab@linux-m68k.org> - *      File created. - */ - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ -		     "%a2", "%a3", "%a4" - -static int -slp_switch(void) -{ -  int err; -  int *stackref, stsizediff; -  void *fp, *a5; -  __asm__ volatile ("" : : : REGS_TO_SAVE); -  __asm__ volatile ("move.l %%fp, %0" : "=m"(fp)); -  __asm__ volatile ("move.l %%a5, %0" : "=m"(a5)); -  __asm__ ("move.l %%sp, %0" : "=r"(stackref)); -  { -    SLP_SAVE_STATE(stackref, stsizediff); -    __asm__ volatile ("add.l %0, %%sp; add.l %0, %%fp" : : "r"(stsizediff)); -    SLP_RESTORE_STATE(); -    __asm__ volatile ("clr.l %0" : "=g" (err)); -  } -  __asm__ volatile ("move.l %0, %%a5" : : "m"(a5)); -  __asm__ volatile ("move.l %0, %%fp" : : "m"(fp)); -  __asm__ volatile ("" : : : REGS_TO_SAVE); -  return err; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h deleted file mode 100644 index b9003e9..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 20-Sep-14 Matt Madison <madison@bliss-m.org> - *      Re-code the saving of the gp register for MIPS64. - * 05-Jan-08 Thiemo Seufer  <ths@debian.org> - *      Ported from ppc. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \ -       "$23", "$30" -static int -slp_switch(void) -{ -    int err; -    int *stackref, stsizediff; -#ifdef __mips64 -    uint64_t gpsave; -#endif -    __asm__ __volatile__ ("" : : : REGS_TO_SAVE); -#ifdef __mips64 -    __asm__ __volatile__ ("sd $28,%0" : "=m" (gpsave) : : ); -#endif -    __asm__ ("move %0, $29" : "=r" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ __volatile__ ( -#ifdef __mips64 -            "daddu $29, %0\n" -#else -            "addu $29, %0\n" -#endif -            : /* no outputs */ -            : "r" (stsizediff) -            ); -        SLP_RESTORE_STATE(); -    } -#ifdef __mips64 -    __asm__ __volatile__ ("ld $28,%0" : : "m" (gpsave) : ); -#endif -    __asm__ __volatile__ ("" : : : REGS_TO_SAVE); -    __asm__ __volatile__ ("move %0, $0" : "=r" (err)); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h deleted file mode 100644 index e7e0b87..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 16-Oct-20  Jesse Gorzinski <jgorzins@us.ibm.com> - *      Copied from Linux PPC64 implementation - * 04-Sep-18  Alexey Borzenkov  <snaury@gmail.com> - *      Workaround a gcc bug using manual save/restore of r30 - * 21-Mar-18  Tulio Magno Quites Machado Filho  <tuliom@linux.vnet.ibm.com> - *      Added r30 to the list of saved registers in order to fully comply with - *      both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this - *      register as a nonvolatile register used for local variables. - * 21-Mar-18  Laszlo Boszormenyi  <gcs@debian.org> - *      Save r2 (TOC pointer) manually. - * 10-Dec-13  Ulrich Weigand  <uweigand@de.ibm.com> - *	Support ELFv2 ABI.  Save float/vector registers. - * 09-Mar-12 Michael Ellerman <michael@ellerman.id.au> - *      64-bit implementation, copied from 32-bit. - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'r31' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 14-Jan-04  Bob Ippolito <bob@redivi.com> - *      added cr2-cr4 to the registers to be saved. - *      Open questions: Should we save FP registers? - *      What about vector registers? - *      Differences between darwin and unix? - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 04-Oct-02  Gustavo Niemeyer <niemeyer@conectiva.com> - *      Ported from MacOS version. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 29-Jun-02  Christian Tismer  <tismer@tismer.com> - *      Added register 13-29, 31 saves. The same way as - *      Armin Rigo did for the x86_unix version. - *      This seems to be now fully functional! - * 04-Mar-02  Hye-Shik Chang  <perky@fallin.lv> - *      Ported from i386. - * 31-Jul-12  Trevor Bowen    <trevorbowen@gmail.com> - *      Changed memory constraints to register only. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 6 - -#if defined(__ALTIVEC__) -#define ALTIVEC_REGS \ -       "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ -       "v28", "v29", "v30", "v31", -#else -#define ALTIVEC_REGS -#endif - -#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20",  \ -       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",  \ -       "r31",                                                    \ -       "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ -       "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ -       "fr30", "fr31", \ -       ALTIVEC_REGS \ -       "cr2", "cr3", "cr4" - -static int -slp_switch(void) -{ -    int err; -    long *stackref, stsizediff; -    void * toc; -    void * r30; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("std 2, %0" : "=m" (toc)); -    __asm__ volatile ("std 30, %0" : "=m" (r30)); -    __asm__ ("mr %0, 1" : "=r" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "mr 11, %0\n" -            "add 1, 1, 11\n" -            : /* no outputs */ -            : "r" (stsizediff) -            : "11" -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("ld 30, %0" : : "m" (r30)); -    __asm__ volatile ("ld 2, %0" : : "m" (toc)); -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("li %0, 0" : "=r" (err)); -    return err; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h deleted file mode 100644 index 3c324d0..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 04-Sep-18  Alexey Borzenkov  <snaury@gmail.com> - *      Workaround a gcc bug using manual save/restore of r30 - * 21-Mar-18  Tulio Magno Quites Machado Filho  <tuliom@linux.vnet.ibm.com> - *      Added r30 to the list of saved registers in order to fully comply with - *      both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this - *      register as a nonvolatile register used for local variables. - * 21-Mar-18  Laszlo Boszormenyi  <gcs@debian.org> - *      Save r2 (TOC pointer) manually. - * 10-Dec-13  Ulrich Weigand  <uweigand@de.ibm.com> - *	Support ELFv2 ABI.  Save float/vector registers. - * 09-Mar-12 Michael Ellerman <michael@ellerman.id.au> - *      64-bit implementation, copied from 32-bit. - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'r31' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 14-Jan-04  Bob Ippolito <bob@redivi.com> - *      added cr2-cr4 to the registers to be saved. - *      Open questions: Should we save FP registers? - *      What about vector registers? - *      Differences between darwin and unix? - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 04-Oct-02  Gustavo Niemeyer <niemeyer@conectiva.com> - *      Ported from MacOS version. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 29-Jun-02  Christian Tismer  <tismer@tismer.com> - *      Added register 13-29, 31 saves. The same way as - *      Armin Rigo did for the x86_unix version. - *      This seems to be now fully functional! - * 04-Mar-02  Hye-Shik Chang  <perky@fallin.lv> - *      Ported from i386. - * 31-Jul-12  Trevor Bowen    <trevorbowen@gmail.com> - *      Changed memory constraints to register only. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#if _CALL_ELF == 2 -#define STACK_MAGIC 4 -#else -#define STACK_MAGIC 6 -#endif - -#if defined(__ALTIVEC__) -#define ALTIVEC_REGS \ -       "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ -       "v28", "v29", "v30", "v31", -#else -#define ALTIVEC_REGS -#endif - -#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20",  \ -       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",  \ -       "r31",                                                    \ -       "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ -       "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ -       "fr30", "fr31", \ -       ALTIVEC_REGS \ -       "cr2", "cr3", "cr4" - -static int -slp_switch(void) -{ -    int err; -    long *stackref, stsizediff; -    void * toc; -    void * r30; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("std 2, %0" : "=m" (toc)); -    __asm__ volatile ("std 30, %0" : "=m" (r30)); -    __asm__ ("mr %0, 1" : "=r" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "mr 11, %0\n" -            "add 1, 1, 11\n" -            : /* no outputs */ -            : "r" (stsizediff) -            : "11" -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("ld 30, %0" : : "m" (r30)); -    __asm__ volatile ("ld 2, %0" : : "m" (toc)); -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("li %0, 0" : "=r" (err)); -    return err; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h deleted file mode 100644 index 6d93c13..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Mar-11 Floris Bruynooghe <flub@devork.be> - *      Do not add stsizediff to general purpose - *      register (GPR) 30 as this is a non-volatile and - *      unused by the PowerOpen Environment, therefore - *      this was modifying a user register instead of the - *      frame pointer (which does not seem to exist). - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'r31' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 14-Jan-04  Bob Ippolito <bob@redivi.com> - *      added cr2-cr4 to the registers to be saved. - *      Open questions: Should we save FP registers? - *      What about vector registers? - *      Differences between darwin and unix? - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 04-Oct-02  Gustavo Niemeyer <niemeyer@conectiva.com> - *      Ported from MacOS version. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 29-Jun-02  Christian Tismer  <tismer@tismer.com> - *      Added register 13-29, 31 saves. The same way as - *      Armin Rigo did for the x86_unix version. - *      This seems to be now fully functional! - * 04-Mar-02  Hye-Shik Chang  <perky@fallin.lv> - *      Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ -       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ -       "cr2", "cr3", "cr4" -static int -slp_switch(void) -{ -    int err; -    int *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ ("mr %0, 1" : "=r" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "mr 11, %0\n" -            "add 1, 1, 11\n" -            : /* no outputs */ -            : "r" (stsizediff) -            : "11" -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("li %0, 0" : "=r" (err)); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h deleted file mode 100644 index e83ad70..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'r31' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 14-Jan-04  Bob Ippolito <bob@redivi.com> - *      added cr2-cr4 to the registers to be saved. - *      Open questions: Should we save FP registers? - *      What about vector registers? - *      Differences between darwin and unix? - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 04-Oct-02  Gustavo Niemeyer <niemeyer@conectiva.com> - *      Ported from MacOS version. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 29-Jun-02  Christian Tismer  <tismer@tismer.com> - *      Added register 13-29, 31 saves. The same way as - *      Armin Rigo did for the x86_unix version. - *      This seems to be now fully functional! - * 04-Mar-02  Hye-Shik Chang  <perky@fallin.lv> - *      Ported from i386. - * 31-Jul-12  Trevor Bowen    <trevorbowen@gmail.com> - *      Changed memory constraints to register only. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ -       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ -       "cr2", "cr3", "cr4" -static int -slp_switch(void) -{ -    int err; -    int *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ ("mr %0, 1" : "=r" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "mr 11, %0\n" -            "add 1, 1, 11\n" -            "add 30, 30, 11\n" -            : /* no outputs */ -            : "r" (stsizediff) -            : "11" -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("li %0, 0" : "=r" (err)); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h deleted file mode 100644 index d6e5a03..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'r31' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 14-Jan-04  Bob Ippolito <bob@redivi.com> - *      added cr2-cr4 to the registers to be saved. - *      Open questions: Should we save FP registers? - *      What about vector registers? - *      Differences between darwin and unix? - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 29-Jun-02  Christian Tismer  <tismer@tismer.com> - *      Added register 13-29, 31 saves. The same way as - *      Armin Rigo did for the x86_unix version. - *      This seems to be now fully functional! - * 04-Mar-02  Hye-Shik Chang  <perky@fallin.lv> - *      Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ -       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ -       "cr2", "cr3", "cr4" - -static int -slp_switch(void) -{ -    int err; -    int *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ ("; asm block 2\n\tmr %0, r1" : "=g" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "; asm block 3\n" -            "\tmr r11, %0\n" -            "\tadd r1, r1, r11\n" -            "\tadd r30, r30, r11\n" -            : /* no outputs */ -            : "g" (stsizediff) -            : "r11" -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("li %0, 0" : "=r" (err)); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h deleted file mode 100644 index ca590a5..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'r31' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 14-Jan-04  Bob Ippolito <bob@redivi.com> - *      added cr2-cr4 to the registers to be saved. - *      Open questions: Should we save FP registers? - *      What about vector registers? - *      Differences between darwin and unix? - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 04-Oct-02  Gustavo Niemeyer <niemeyer@conectiva.com> - *      Ported from MacOS version. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 29-Jun-02  Christian Tismer  <tismer@tismer.com> - *      Added register 13-29, 31 saves. The same way as - *      Armin Rigo did for the x86_unix version. - *      This seems to be now fully functional! - * 04-Mar-02  Hye-Shik Chang  <perky@fallin.lv> - *      Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 3 - -/* !!!!WARNING!!!! need to add "r31" in the next line if this header file - * is meant to be compiled non-dynamically! - */ -#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ -       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ -       "cr2", "cr3", "cr4" -static int -slp_switch(void) -{ -    int err; -    int *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ ("mr %0, 1" : "=g" (stackref) : ); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "mr 11, %0\n" -            "add 1, 1, 11\n" -            "add 30, 30, 11\n" -            : /* no outputs */ -            : "g" (stsizediff) -            : "11" -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("li %0, 0" : "=r" (err)); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h deleted file mode 100644 index 24df9db..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h +++ /dev/null @@ -1,32 +0,0 @@ -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ -		     "s6", "s7", "s8", "s9", "s10", "s11", "fs0", "fs1", \ -		     "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", \ -		     "fs10", "fs11" - -static int -slp_switch(void) -{ -  int ret; -  long *stackref, stsizediff; -  __asm__ volatile ("" : : : REGS_TO_SAVE); -  __asm__ volatile ("mv %0, sp" : "=r" (stackref) : ); -  { -      SLP_SAVE_STATE(stackref, stsizediff); -      __asm__ volatile ( -	  "add sp, sp, %0\n\t" -	  : /* no outputs */ -	  : "r" (stsizediff) -	  ); -      SLP_RESTORE_STATE(); -  } -  __asm__ volatile ("" : : : REGS_TO_SAVE); -  __asm__ volatile ("mv %0, zero" : "=r" (ret) : ); -  return ret; -} - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h deleted file mode 100644 index 9199367..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 25-Jan-12  Alexey Borzenkov <snaury@gmail.com> - *      Fixed Linux/S390 port to work correctly with - *      different optimization options both on 31-bit - *      and 64-bit. Thanks to Stefan Raabe for lots - *      of testing. - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 06-Oct-02  Gustavo Niemeyer <niemeyer@conectiva.com> - *      Ported to Linux/S390. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#ifdef __s390x__ -#define STACK_MAGIC 20 /* 20 * 8 = 160 bytes of function call area */ -#else -#define STACK_MAGIC 24 /* 24 * 4 = 96 bytes of function call area */ -#endif - -/* Technically, r11-r13 also need saving, but function prolog starts -   with stm(g) and since there are so many saved registers already -   it won't be optimized, resulting in all r6-r15 being saved */ -#define REGS_TO_SAVE "r6", "r7", "r8", "r9", "r10", "r14", \ -		     "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ -		     "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15" - -static int -slp_switch(void) -{ -    int ret; -    long *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -#ifdef __s390x__ -    __asm__ volatile ("lgr %0, 15" : "=r" (stackref) : ); -#else -    __asm__ volatile ("lr %0, 15" : "=r" (stackref) : ); -#endif -    { -        SLP_SAVE_STATE(stackref, stsizediff); -/* N.B. -   r11 may be used as the frame pointer, and in that case it cannot be -   clobbered and needs offsetting just like the stack pointer (but in cases -   where frame pointer isn't used we might clobber it accidentally). What's -   scary is that r11 is 2nd (and even 1st when GOT is used) callee saved -   register that gcc would chose for surviving function calls. However, -   since r6-r10 are clobbered above, their cost for reuse is reduced, so -   gcc IRA will chose them over r11 (not seeing r11 is implicitly saved), -   making it relatively safe to offset in all cases. :) */ -        __asm__ volatile ( -#ifdef __s390x__ -            "agr 15, %0\n\t" -            "agr 11, %0" -#else -            "ar 15, %0\n\t" -            "ar 11, %0" -#endif -            : /* no outputs */ -            : "r" (stsizediff) -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("lhi %0, 0" : "=r" (ret) : ); -    return ret; -} - -#endif - -/* - * further self-processing support - */ - -/*  - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h deleted file mode 100644 index 96990c3..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 16-May-15  Alexey Borzenkov <snaury@gmail.com> - *      Move stack spilling code inside save/restore functions - * 30-Aug-13  Floris Bruynooghe <flub@devork.be> -        Clean the register windows again before returning. -        This does not clobber the PIC register as it leaves -        the current window intact and is required for multi- -        threaded code to work correctly. - * 08-Mar-11  Floris Bruynooghe <flub@devork.be> - *      No need to set return value register explicitly - *      before the stack and framepointer are adjusted - *      as none of the other registers are influenced by - *      this.  Also don't needlessly clean the windows - *      ('ta %0" :: "i" (ST_CLEAN_WINDOWS)') as that - *      clobbers the gcc PIC register (%l7). - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      added support for SunOS sparc with gcc - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - - -#define STACK_MAGIC 0 - - -#if defined(__sparcv9) -#define SLP_FLUSHW __asm__ volatile ("flushw") -#else -#define SLP_FLUSHW __asm__ volatile ("ta 3") /* ST_FLUSH_WINDOWS */ -#endif - -/* On sparc we need to spill register windows inside save/restore functions */ -#define SLP_BEFORE_SAVE_STATE() SLP_FLUSHW -#define SLP_BEFORE_RESTORE_STATE() SLP_FLUSHW - - -static int -slp_switch(void) -{ -    int err; -    int *stackref, stsizediff; - -    /* Put current stack pointer into stackref. -     * Register spilling is done in save/restore. -     */ -    __asm__ volatile ("mov %%sp, %0" : "=r" (stackref)); - -    { -        /* Thou shalt put SLP_SAVE_STATE into a local block */ -        /* Copy the current stack onto the heap */ -        SLP_SAVE_STATE(stackref, stsizediff); - -        /* Increment stack and frame pointer by stsizediff */ -        __asm__ volatile ( -            "add %0, %%sp, %%sp\n\t" -            "add %0, %%fp, %%fp" -            : : "r" (stsizediff)); - -        /* Copy new stack from it's save store on the heap */ -        SLP_RESTORE_STATE(); - -        __asm__ volatile ("mov %1, %0" : "=r" (err) : "i" (0)); -        return err; -    } -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h deleted file mode 100644 index 893369c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 17-Aug-12  Fantix King <fantix.king@gmail.com> - *      Ported from amd64. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -#define REGS_TO_SAVE "r12", "r13", "r14", "r15" - - -static int -slp_switch(void) -{ -    void* ebp; -    void* ebx; -    unsigned int csr; -    unsigned short cw; -    int err; -    int *stackref, stsizediff; -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("fstcw %0" : "=m" (cw)); -    __asm__ volatile ("stmxcsr %0" : "=m" (csr)); -    __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); -    __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); -    __asm__ ("movl %%esp, %0" : "=g" (stackref)); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "addl %0, %%esp\n" -            "addl %0, %%ebp\n" -            : -            : "r" (stsizediff) -            ); -        SLP_RESTORE_STATE(); -    } -    __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); -    __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); -    __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); -    __asm__ volatile ("fldcw %0" : : "m" (cw)); -    __asm__ volatile ("" : : : REGS_TO_SAVE); -    __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/* - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm b/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm deleted file mode 100644 index f5c72a2..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm +++ /dev/null @@ -1,111 +0,0 @@ -; -; stack switching code for MASM on x641 -; Kristjan Valur Jonsson, sept 2005 -; - - -;prototypes for our calls -slp_save_state_asm PROTO -slp_restore_state_asm PROTO - - -pushxmm MACRO reg -    sub rsp, 16 -    .allocstack 16 -    movaps [rsp], reg ; faster than movups, but we must be aligned -    ; .savexmm128 reg, offset  (don't know what offset is, no documentation) -ENDM -popxmm MACRO reg -    movaps reg, [rsp] ; faster than movups, but we must be aligned -    add rsp, 16 -ENDM - -pushreg MACRO reg -    push reg -    .pushreg reg -ENDM -popreg MACRO reg -    pop reg -ENDM - - -.code -slp_switch PROC FRAME -    ;realign stack to 16 bytes after return address push, makes the following faster -    sub rsp,8 -    .allocstack 8 - -    pushxmm xmm15 -    pushxmm xmm14 -    pushxmm xmm13 -    pushxmm xmm12 -    pushxmm xmm11 -    pushxmm xmm10 -    pushxmm xmm9 -    pushxmm xmm8 -    pushxmm xmm7 -    pushxmm xmm6 - -    pushreg r15 -    pushreg r14 -    pushreg r13 -    pushreg r12 - -    pushreg rbp -    pushreg rbx -    pushreg rdi -    pushreg rsi - -    sub rsp, 10h ;allocate the singlefunction argument (must be multiple of 16) -    .allocstack 10h -.endprolog - -    lea rcx, [rsp+10h] ;load stack base that we are saving -    call slp_save_state_asm ;pass stackpointer, return offset in eax -    cmp rax, 1 -    je EXIT1 -    cmp rax, -1 -    je EXIT2 -    ;actual stack switch: -    add rsp, rax -    call slp_restore_state_asm -    xor rax, rax ;return 0 - -EXIT: - -    add rsp, 10h -    popreg rsi -    popreg rdi -    popreg rbx -    popreg rbp - -    popreg r12 -    popreg r13 -    popreg r14 -    popreg r15 - -    popxmm xmm6 -    popxmm xmm7 -    popxmm xmm8 -    popxmm xmm9 -    popxmm xmm10 -    popxmm xmm11 -    popxmm xmm12 -    popxmm xmm13 -    popxmm xmm14 -    popxmm xmm15 - -    add rsp, 8 -    ret - -EXIT1: -    mov rax, 1 -    jmp EXIT - -EXIT2: -    sar rax, 1 -    jmp EXIT - -slp_switch ENDP - -END
\ No newline at end of file diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.obj b/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.objBinary files differ deleted file mode 100644 index 64e3e6b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.obj +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h deleted file mode 100644 index 601ea56..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 26-Sep-02  Christian Tismer  <tismer@tismer.com> - *      again as a result of virtualized stack access, - *      the compiler used less registers. Needed to - *      explicit mention registers in order to get them saved. - *      Thanks to Jeff Senn for pointing this out and help. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 01-Mar-02  Christian Tismer  <tismer@tismer.com> - *      Initial final version after lots of iterations for i386. - */ - -/* Avoid alloca redefined warning on mingw64 */ -#ifndef alloca -#define alloca _alloca -#endif - -#define STACK_REFPLUS 1 -#define STACK_MAGIC 0 - -/* Use the generic support for an external assembly language slp_switch function. */ -#define EXTERNAL_ASM - -#ifdef SLP_EVAL -/* This always uses the external masm assembly file. */ -#endif - -/* - * further self-processing support - */ - -/* we have IsBadReadPtr available, so we can peek at objects */ -/* -#define STACKLESS_SPY - -#ifdef IMPLEMENT_STACKLESSMODULE -#include "Windows.h" -#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) - -static int IS_ON_STACK(void*p) -{ -    int stackref; -    intptr_t stackbase = ((intptr_t)&stackref) & 0xfffff000; -    return (intptr_t)p >= stackbase && (intptr_t)p < stackbase + 0x00100000; -} - -#endif -*/
\ No newline at end of file diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h deleted file mode 100644 index 0f3a59f..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 26-Sep-02  Christian Tismer  <tismer@tismer.com> - *      again as a result of virtualized stack access, - *      the compiler used less registers. Needed to - *      explicit mention registers in order to get them saved. - *      Thanks to Jeff Senn for pointing this out and help. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for sparc - * 01-Mar-02  Christian Tismer  <tismer@tismer.com> - *      Initial final version after lots of iterations for i386. - */ - -#define alloca _alloca - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -#define STACK_MAGIC 0 - -/* Some magic to quell warnings and keep slp_switch() from crashing when built -   with VC90. Disable global optimizations, and the warning: frame pointer -   register 'ebp' modified by inline assembly code. - -   We used to just disable global optimizations ("g") but upstream stackless -   Python, as well as stackman, turn off all optimizations. - -References: -https://github.com/stackless-dev/stackman/blob/dbc72fe5207a2055e658c819fdeab9731dee78b9/stackman/platforms/switch_x86_msvc.h -https://github.com/stackless-dev/stackless/blob/main-slp/Stackless/platf/switch_x86_msvc.h -*/ -#define WIN32_LEAN_AND_MEAN -#include <windows.h> - -#pragma optimize("", off) /* so that autos are stored on the stack */ -#pragma warning(disable:4731) -#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ - -/** - * Most modern compilers and environments handle C++ exceptions without any - * special help from us. MSVC on 32-bit windows is an exception. There, C++ - * exceptions are dealt with using Windows' Structured Exception Handling - * (SEH). - * - * SEH is implemented as a singly linked list of <function*, prev*> nodes. The - * head of this list is stored in the Thread Information Block, which itself - * is pointed to from the FS register. It's the first field in the structure, - * or offset 0, so we can access it using assembly FS:[0], or the compiler - * intrinsics and field offset information from the headers (as we do below). - * Somewhat unusually, the tail of the list doesn't have prev == NULL, it has - * prev == 0xFFFFFFFF. - * - * SEH was designed for C, and traditionally uses the MSVC compiler - * intrinsincs __try{}/__except{}. It is also utilized for C++ exceptions by - * MSVC; there, every throw of a C++ exception raises a SEH error with the - * ExceptionCode 0xE06D7363; the SEH handler list is then traversed to - * deal with the exception. - * - * If the SEH list is corrupt, then when a C++ exception is thrown the program - * will abruptly exit with exit code 1. This does not use std::terminate(), so - * std::set_terminate() is useless to debug this. - * - * The SEH list is closely tied to the call stack; entering a function that - * uses __try{} or most C++ functions will push a new handler onto the front - * of the list. Returning from the function will remove the handler. Saving - * and restoring the head node of the SEH list (FS:[0]) per-greenlet is NOT - * ENOUGH to make SEH or exceptions work. - * - * Stack switching breaks SEH because the call stack no longer necessarily - * matches the SEH list. For example, given greenlet A that switches to - * greenlet B, at the moment of entering greenlet B, we will have any SEH - * handlers from greenlet A on the SEH list; greenlet B can then add its own - * handlers to the SEH list. When greenlet B switches back to greenlet A, - * greenlet B's handlers would still be on the SEH stack, but when switch() - * returns control to greenlet A, we have replaced the contents of the stack - * in memory, so all the address that greenlet B added to the SEH list are now - * invalid: part of the call stack has been unwound, but the SEH list was out - * of sync with the call stack. The net effect is that exception handling - * stops working. - * - * Thus, when switching greenlets, we need to be sure that the SEH list - * matches the effective call stack, "cutting out" any handlers that were - * pushed by the greenlet that switched out and which are no longer valid. - * - * The easiest way to do this is to capture the SEH list at the time the main - * greenlet for a thread is created, and, when initially starting a greenlet, - * start a new SEH list for it, which contains nothing but the handler - * established for the new greenlet itself, with the tail being the handlers - * for the main greenlet. If we then save and restore the SEH per-greenlet, - * they won't interfere with each others SEH lists. (No greenlet can unwind - * the call stack past the handlers established by the main greenlet). - * - * By observation, a new thread starts with three SEH handlers on the list. By - * the time we get around to creating the main greenlet, though, there can be - * many more, established by transient calls that lead to the creation of the - * main greenlet. Therefore, 3 is a magic constant telling us when to perform - * the initial slice. - * - * All of this can be debugged using a vectored exception handler, which - * operates independently of the SEH handler list, and is called first. - * Walking the SEH list at key points can also be helpful. - * - * References: - * https://en.wikipedia.org/wiki/Win32_Thread_Information_Block - * https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 - * https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=msvc-160 - * https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160 - * https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling - * https://docs.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler - * https://bytepointer.com/resources/pietrek_crash_course_depths_of_win32_seh.htm - */ -#define GREENLET_NEEDS_EXCEPTION_STATE_SAVED - - -typedef struct _GExceptionRegistration { -    struct _GExceptionRegistration* prev; -    void* handler_f; -} GExceptionRegistration; - -static void -slp_set_exception_state(const void *const seh_state) -{ -    // Because the stack from from which we do this is ALSO a handler, and -    // that one we want to keep, we need to relink the current SEH handler -    // frame to point to this one, cutting out the middle men, as it were. -    // -    // Entering a try block doesn't change the SEH frame, but entering a -    // function containing a try block does. -    GExceptionRegistration* current_seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); -    current_seh_state->prev = (GExceptionRegistration*)seh_state; -} - - -static GExceptionRegistration* -x86_slp_get_third_oldest_handler() -{ -    GExceptionRegistration* a = NULL; /* Closest to the top */ -    GExceptionRegistration* b = NULL; /* second */ -    GExceptionRegistration* c = NULL; -    GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); -    a = b = c = seh_state; - -    while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { -        if ((void*)seh_state->prev < (void*)100) { -            fprintf(stderr, "\tERROR: Broken SEH chain.\n"); -            return NULL; -        } -        a = b; -        b = c; -        c = seh_state; - -        seh_state = seh_state->prev; -    } -    return a ? a : (b ? b : c); -} - - -static void* -slp_get_exception_state() -{ -    // XXX: There appear to be three SEH handlers on the stack already at the -    // start of the thread. Is that a guarantee? Almost certainly not. Yet in -    // all observed cases it has been three. This is consistent with -    // faulthandler off or on, and optimizations off or on. It may not be -    // consistent with other operating system versions, though: we only have -    // CI on one or two versions (don't ask what there are). -    // In theory we could capture the number of handlers on the chain when -    // PyInit__greenlet is called: there are probably only the default -    // handlers at that point (unless we're embedded and people have used -    // __try/__except or a C++ handler)? -    return x86_slp_get_third_oldest_handler(); -} - -static int -slp_switch(void) -{ -    /* MASM syntax is typically reversed from other assemblers. -       It is usually <instruction> <destination> <source> -     */ -    int *stackref, stsizediff; -    /* store the structured exception state for this stack */ -    DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); -    __asm mov stackref, esp; -    /* modify EBX, ESI and EDI in order to get them preserved */ -    __asm mov ebx, ebx; -    __asm xchg esi, edi; -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm { -            mov     eax, stsizediff -            add     esp, eax -            add     ebp, eax -        } -        SLP_RESTORE_STATE(); -    } -    __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); -    return 0; -} - -/* re-enable ebp warning and global optimizations. */ -#pragma optimize("", on) -#pragma warning(default:4731) -#pragma warning(default:4733) /* disable warning about modifying FS[0] */ - - -#endif - -/* - * further self-processing support - */ - -/* we have IsBadReadPtr available, so we can peek at objects */ -#define STACKLESS_SPY - -#ifdef GREENLET_DEBUG - -#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) - -static int IS_ON_STACK(void*p) -{ -    int stackref; -    int stackbase = ((int)&stackref) & 0xfffff000; -    return (int)p >= stackbase && (int)p < stackbase + 0x00100000; -} - -static void -x86_slp_show_seh_chain() -{ -    GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); -    fprintf(stderr, "====== SEH Chain ======\n"); -    while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { -        fprintf(stderr, "\tSEH_chain addr: %p handler: %p prev: %p\n", -                seh_state, -                seh_state->handler_f, seh_state->prev); -        if ((void*)seh_state->prev < (void*)100) { -            fprintf(stderr, "\tERROR: Broken chain.\n"); -            break; -        } -        seh_state = seh_state->prev; -    } -    fprintf(stderr, "====== End SEH Chain ======\n"); -    fflush(NULL); -    return; -} - -//addVectoredExceptionHandler constants: -//CALL_FIRST means call this exception handler first; -//CALL_LAST means call this exception handler last -#define CALL_FIRST 1 -#define CALL_LAST 0 - -LONG WINAPI -GreenletVectorHandler(PEXCEPTION_POINTERS ExceptionInfo) -{ -    // We get one of these for every C++ exception, with code -    // E06D7363 -    // This is a special value that means "C++ exception from MSVC" -    // https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 -    // -    // Install in the module init function with: -    // AddVectoredExceptionHandler(CALL_FIRST, GreenletVectorHandler); -    PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; - -    fprintf(stderr, -            "GOT VECTORED EXCEPTION:\n" -            "\tExceptionCode   : %p\n" -            "\tExceptionFlags  : %p\n" -            "\tExceptionAddr   : %p\n" -            "\tNumberparams    : %ld\n", -            ExceptionRecord->ExceptionCode, -            ExceptionRecord->ExceptionFlags, -            ExceptionRecord->ExceptionAddress, -            ExceptionRecord->NumberParameters -            ); -    if (ExceptionRecord->ExceptionFlags & 1) { -        fprintf(stderr,  "\t\tEH_NONCONTINUABLE\n" ); -    } -    if (ExceptionRecord->ExceptionFlags & 2) { -        fprintf(stderr,  "\t\tEH_UNWINDING\n" ); -    } -    if (ExceptionRecord->ExceptionFlags & 4) { -        fprintf(stderr, "\t\tEH_EXIT_UNWIND\n" ); -    } -    if (ExceptionRecord->ExceptionFlags & 8) { -        fprintf(stderr,  "\t\tEH_STACK_INVALID\n" ); -    } -    if (ExceptionRecord->ExceptionFlags & 0x10) { -        fprintf(stderr,  "\t\tEH_NESTED_CALL\n" ); -    } -    if (ExceptionRecord->ExceptionFlags & 0x20) { -        fprintf(stderr,  "\t\tEH_TARGET_UNWIND\n" ); -    } -    if (ExceptionRecord->ExceptionFlags & 0x40) { -        fprintf(stderr,  "\t\tEH_COLLIDED_UNWIND\n" ); -    } -    fprintf(stderr, "\n"); -    fflush(NULL); -    for(DWORD i = 0; i < ExceptionRecord->NumberParameters; i++) { -        fprintf(stderr, "\t\t\tParam %ld: %lX\n", i, ExceptionRecord->ExceptionInformation[i]); -    } - -    if (ExceptionRecord->NumberParameters == 3) { -        fprintf(stderr, "\tAbout to traverse SEH chain\n"); -        // C++ Exception records have 3 params. -        x86_slp_show_seh_chain(); -    } - -    return EXCEPTION_CONTINUE_SEARCH; -} - - - - -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h b/venv/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h deleted file mode 100644 index 493fa6b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * this is the internal transfer function. - * - * HISTORY - * 3-May-13   Ralf Schmitt  <ralf@systemexit.de> - *     Add support for strange GCC caller-save decisions - *     (ported from switch_aarch64_gcc.h) - * 19-Aug-11  Alexey Borzenkov  <snaury@gmail.com> - *      Correctly save ebp, ebx and cw - * 07-Sep-05 (py-dev mailing list discussion) - *      removed 'ebx' from the register-saved.  !!!! WARNING !!!! - *      It means that this file can no longer be compiled statically! - *      It is now only suitable as part of a dynamic library! - * 24-Nov-02  Christian Tismer  <tismer@tismer.com> - *      needed to add another magic constant to insure - *      that f in slp_eval_frame(PyFrameObject *f) - *      STACK_REFPLUS will probably be 1 in most cases. - *      gets included into the saved stack area. - * 17-Sep-02  Christian Tismer  <tismer@tismer.com> - *      after virtualizing stack save/restore, the - *      stack size shrunk a bit. Needed to introduce - *      an adjustment STACK_MAGIC per platform. - * 15-Sep-02  Gerd Woetzel       <gerd.woetzel@GMD.DE> - *      slightly changed framework for spark - * 31-Avr-02  Armin Rigo         <arigo@ulb.ac.be> - *      Added ebx, esi and edi register-saves. - * 01-Mar-02  Samual M. Rushing  <rushing@ironport.com> - *      Ported from i386. - */ - -#define STACK_REFPLUS 1 - -#ifdef SLP_EVAL - -/* #define STACK_MAGIC 3 */ -/* the above works fine with gcc 2.96, but 2.95.3 wants this */ -#define STACK_MAGIC 0 - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -# define ATTR_NOCLONE __attribute__((noclone)) -#else -# define ATTR_NOCLONE -#endif - -static int -slp_switch(void) -{ -    int err; -#ifdef _WIN32 -    void *seh; -#endif -    void *ebp, *ebx; -    unsigned short cw; -    int *stackref, stsizediff; -    __asm__ volatile ("" : : : "esi", "edi"); -    __asm__ volatile ("fstcw %0" : "=m" (cw)); -    __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); -    __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); -#ifdef _WIN32 -    __asm__ volatile ( -        "movl %%fs:0x0, %%eax\n" -        "movl %%eax, %0\n" -        : "=m" (seh) -        : -        : "eax"); -#endif -    __asm__ ("movl %%esp, %0" : "=g" (stackref)); -    { -        SLP_SAVE_STATE(stackref, stsizediff); -        __asm__ volatile ( -            "addl %0, %%esp\n" -            "addl %0, %%ebp\n" -            : -            : "r" (stsizediff) -            ); -        SLP_RESTORE_STATE(); -        __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); -    } -#ifdef _WIN32 -    __asm__ volatile ( -        "movl %0, %%eax\n" -        "movl %%eax, %%fs:0x0\n" -        : -        : "m" (seh) -        : "eax"); -#endif -    __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); -    __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); -    __asm__ volatile ("fldcw %0" : : "m" (cw)); -    __asm__ volatile ("" : : : "esi", "edi"); -    return err; -} - -#endif - -/* - * further self-processing support - */ - -/*  - * if you want to add self-inspection tools, place them - * here. See the x86_msvc for the necessary defines. - * These features are highly experimental und not - * essential yet. - */ diff --git a/venv/lib/python3.11/site-packages/greenlet/slp_platformselect.h b/venv/lib/python3.11/site-packages/greenlet/slp_platformselect.h deleted file mode 100644 index c959f0f..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/slp_platformselect.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Platform Selection for Stackless Python - */ -#ifdef __cplusplus -extern "C" { -#endif - -#if   defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) && defined(_MSC_VER) -# include "platform/switch_x86_msvc.h" /* MS Visual Studio on X86 */ -#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER) || defined(__MINGW64__) -# include "platform/switch_x64_msvc.h" /* MS Visual Studio on X64 */ -#elif  defined(MS_WIN64) && defined(_M_ARM64) -# include "platform/switch_arm64_msvc.h" /* MS Visual Studio on ARM64 */ -#elif defined(__GNUC__) && defined(__amd64__) && defined(__ILP32__) -# include "platform/switch_x32_unix.h" /* gcc on amd64 with x32 ABI */ -#elif defined(__GNUC__) && defined(__amd64__) -# include "platform/switch_amd64_unix.h" /* gcc on amd64 */ -#elif defined(__GNUC__) && defined(__i386__) -# include "platform/switch_x86_unix.h" /* gcc on X86 */ -#elif defined(__GNUC__) && defined(__powerpc64__) && (defined(__linux__) || defined(__FreeBSD__)) -# include "platform/switch_ppc64_linux.h" /* gcc on PowerPC 64-bit */ -#elif defined(__GNUC__) && defined(__PPC__) && (defined(__linux__) || defined(__FreeBSD__)) -# include "platform/switch_ppc_linux.h" /* gcc on PowerPC */ -#elif defined(__GNUC__) && defined(__ppc__) && defined(__APPLE__) -# include "platform/switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ -#elif defined(__GNUC__) && defined(__powerpc64__) && defined(_AIX) -# include "platform/switch_ppc64_aix.h" /* gcc on AIX/PowerPC 64-bit */ -#elif defined(__GNUC__) && defined(_ARCH_PPC) && defined(_AIX) -# include "platform/switch_ppc_aix.h" /* gcc on AIX/PowerPC */ -#elif defined(__GNUC__) && defined(sparc) -# include "platform/switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ -#elif defined(__SUNPRO_C) && defined(sparc) && defined(sun) -# iiclude "platform/switch_sparc_sun_gcc.h" /* SunStudio on amd64 */ -#elif defined(__SUNPRO_C) && defined(__amd64__) && defined(sun) -# include "platform/switch_amd64_unix.h" /* SunStudio on amd64 */ -#elif defined(__SUNPRO_C) && defined(__i386__) && defined(sun) -# include "platform/switch_x86_unix.h" /* SunStudio on x86 */ -#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) -# include "platform/switch_s390_unix.h" /* Linux/S390 */ -#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) -# include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (64-bit) */ -#elif defined(__GNUC__) && defined(__arm__) -# ifdef __APPLE__ -#  include <TargetConditionals.h> -# endif -# if TARGET_OS_IPHONE -#  include "platform/switch_arm32_ios.h" /* iPhone OS on arm32 */ -# else -#  include "platform/switch_arm32_gcc.h" /* gcc using arm32 */ -# endif -#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) -# include "platform/switch_mips_unix.h" /* Linux/MIPS */ -#elif defined(__GNUC__) && defined(__aarch64__) -# include "platform/switch_aarch64_gcc.h" /* Aarch64 ABI */ -#elif defined(__GNUC__) && defined(__mc68000__) -# include "platform/switch_m68k_gcc.h" /* gcc on m68k */ -#elif defined(__GNUC__) && defined(__csky__) -#include "platform/switch_csky_gcc.h" /* gcc on csky */ -# elif defined(__GNUC__) && defined(__riscv) -# include "platform/switch_riscv_unix.h" /* gcc on RISC-V */ -#elif defined(__GNUC__) && defined(__alpha__) -# include "platform/switch_alpha_unix.h" /* gcc on DEC Alpha */ -#elif defined(MS_WIN32) && defined(__llvm__) && defined(__aarch64__) -# include "platform/switch_aarch64_gcc.h" /* LLVM Aarch64 ABI for Windows */ -#elif defined(__GNUC__) && defined(__loongarch64) && defined(__linux__) -# include "platform/switch_loongarch64_linux.h" /* LoongArch64 */ -#endif - -#ifdef __cplusplus -}; -#endif diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__init__.py b/venv/lib/python3.11/site-packages/greenlet/tests/__init__.py deleted file mode 100644 index e249e35..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__init__.py +++ /dev/null @@ -1,237 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlet. - -""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import sys -import unittest - -from gc import collect -from gc import get_objects -from threading import active_count as active_thread_count -from time import sleep -from time import time - -import psutil - -from greenlet import greenlet as RawGreenlet -from greenlet import getcurrent - -from greenlet._greenlet import get_pending_cleanup_count -from greenlet._greenlet import get_total_main_greenlets - -from . import leakcheck - -PY312 = sys.version_info[:2] >= (3, 12) -WIN = sys.platform.startswith("win") - -class TestCaseMetaClass(type): -    # wrap each test method with -    # a) leak checks -    def __new__(cls, classname, bases, classDict): -        # pylint and pep8 fight over what this should be called (mcs or cls). -        # pylint gets it right, but we can't scope disable pep8, so we go with -        # its convention. -        # pylint: disable=bad-mcs-classmethod-argument -        check_totalrefcount = True - -        # Python 3: must copy, we mutate the classDict. Interestingly enough, -        # it doesn't actually error out, but under 3.6 we wind up wrapping -        # and re-wrapping the same items over and over and over. -        for key, value in list(classDict.items()): -            if key.startswith('test') and callable(value): -                classDict.pop(key) -                if check_totalrefcount: -                    value = leakcheck.wrap_refcount(value) -                classDict[key] = value -        return type.__new__(cls, classname, bases, classDict) - - -class TestCase(TestCaseMetaClass( -        "NewBase", -        (unittest.TestCase,), -        {})): - -    cleanup_attempt_sleep_duration = 0.001 -    cleanup_max_sleep_seconds = 1 - -    def wait_for_pending_cleanups(self, -                                  initial_active_threads=None, -                                  initial_main_greenlets=None): -        initial_active_threads = initial_active_threads or self.threads_before_test -        initial_main_greenlets = initial_main_greenlets or self.main_greenlets_before_test -        sleep_time = self.cleanup_attempt_sleep_duration -        # NOTE: This is racy! A Python-level thread object may be dead -        # and gone, but the C thread may not yet have fired its -        # destructors and added to the queue. There's no particular -        # way to know that's about to happen. We try to watch the -        # Python threads to make sure they, at least, have gone away. -        # Counting the main greenlets, which we can easily do deterministically, -        # also helps. - -        # Always sleep at least once to let other threads run -        sleep(sleep_time) -        quit_after = time() + self.cleanup_max_sleep_seconds -        # TODO: We could add an API that calls us back when a particular main greenlet is deleted? -        # It would have to drop the GIL -        while ( -                get_pending_cleanup_count() -                or active_thread_count() > initial_active_threads -                or (not self.expect_greenlet_leak -                    and get_total_main_greenlets() > initial_main_greenlets)): -            sleep(sleep_time) -            if time() > quit_after: -                print("Time limit exceeded.") -                print("Threads: Waiting for only", initial_active_threads, -                      "-->", active_thread_count()) -                print("MGlets : Waiting for only", initial_main_greenlets, -                      "-->", get_total_main_greenlets()) -                break -        collect() - -    def count_objects(self, kind=list, exact_kind=True): -        # pylint:disable=unidiomatic-typecheck -        # Collect the garbage. -        for _ in range(3): -            collect() -        if exact_kind: -            return sum( -                1 -                for x in get_objects() -                if type(x) is kind -            ) -        # instances -        return sum( -            1 -            for x in get_objects() -            if isinstance(x, kind) -        ) - -    greenlets_before_test = 0 -    threads_before_test = 0 -    main_greenlets_before_test = 0 -    expect_greenlet_leak = False - -    def count_greenlets(self): -        """ -        Find all the greenlets and subclasses tracked by the GC. -        """ -        return self.count_objects(RawGreenlet, False) - -    def setUp(self): -        # Ensure the main greenlet exists, otherwise the first test -        # gets a false positive leak -        super().setUp() -        getcurrent() -        self.threads_before_test = active_thread_count() -        self.main_greenlets_before_test = get_total_main_greenlets() -        self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) -        self.greenlets_before_test = self.count_greenlets() - -    def tearDown(self): -        if getattr(self, 'skipTearDown', False): -            return - -        self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) -        super().tearDown() - -    def get_expected_returncodes_for_aborted_process(self): -        import signal -        # The child should be aborted in an unusual way. On POSIX -        # platforms, this is done with abort() and signal.SIGABRT, -        # which is reflected in a negative return value; however, on -        # Windows, even though we observe the child print "Fatal -        # Python error: Aborted" and in older versions of the C -        # runtime "This application has requested the Runtime to -        # terminate it in an unusual way," it always has an exit code -        # of 3. This is interesting because 3 is the error code for -        # ERROR_PATH_NOT_FOUND; BUT: the C runtime abort() function -        # also uses this code. -        # -        # If we link to the static C library on Windows, the error -        # code changes to '0xc0000409' (hex(3221226505)), which -        # apparently is STATUS_STACK_BUFFER_OVERRUN; but "What this -        # means is that nowadays when you get a -        # STATUS_STACK_BUFFER_OVERRUN, it doesn’t actually mean that -        # there is a stack buffer overrun. It just means that the -        # application decided to terminate itself with great haste." -        # -        # -        # On windows, we've also seen '0xc0000005' (hex(3221225477)). -        # That's "Access Violation" -        # -        # See -        # https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623 -        # and -        # https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN -        # and -        # https://devblogs.microsoft.com/oldnewthing/20190108-00/?p=100655 -        expected_exit = ( -            -signal.SIGABRT, -            # But beginning on Python 3.11, the faulthandler -            # that prints the C backtraces sometimes segfaults after -            # reporting the exception but before printing the stack. -            # This has only been seen on linux/gcc. -            -signal.SIGSEGV, -        ) if not WIN else ( -            3, -            0xc0000409, -            0xc0000005, -        ) -        return expected_exit - -    def get_process_uss(self): -        """ -        Return the current process's USS in bytes. - -        uss is available on Linux, macOS, Windows. Also known as -        "Unique Set Size", this is the memory which is unique to a -        process and which would be freed if the process was terminated -        right now. - -        If this is not supported by ``psutil``, this raises the -        :exc:`unittest.SkipTest` exception. -        """ -        try: -            return psutil.Process().memory_full_info().uss -        except AttributeError as e: -            raise unittest.SkipTest("uss not supported") from e - -    def run_script(self, script_name, show_output=True): -        import subprocess -        import os -        script = os.path.join( -            os.path.dirname(__file__), -            script_name, -        ) - -        try: -            return subprocess.check_output([sys.executable, script], -                                           encoding='utf-8', -                                           stderr=subprocess.STDOUT) -        except subprocess.CalledProcessError as ex: -            if show_output: -                print('-----') -                print('Failed to run script', script) -                print('~~~~~') -                print(ex.output) -                print('------') -            raise - - -    def assertScriptRaises(self, script_name, exitcodes=None): -        import subprocess -        with self.assertRaises(subprocess.CalledProcessError) as exc: -            output = self.run_script(script_name, show_output=False) -            __traceback_info__ = output -            # We're going to fail the assertion if we get here, at least -            # preserve the output in the traceback. - -        if exitcodes is None: -            exitcodes = self.get_expected_returncodes_for_aborted_process() -        self.assertIn(exc.exception.returncode, exitcodes) -        return exc.exception diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pycBinary files differ deleted file mode 100644 index 245565c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/__init__.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pycBinary files differ deleted file mode 100644 index f8ca571..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pycBinary files differ deleted file mode 100644 index 1293a2e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pycBinary files differ deleted file mode 100644 index 12af9c5..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pycBinary files differ deleted file mode 100644 index 41fa814..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pycBinary files differ deleted file mode 100644 index 73d0e65..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pycBinary files differ deleted file mode 100644 index dcdbc02..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pycBinary files differ deleted file mode 100644 index 97be12a..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pycBinary files differ deleted file mode 100644 index 7a2616e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pycBinary files differ deleted file mode 100644 index afb0e23..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pycBinary files differ deleted file mode 100644 index 3f24186..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pycBinary files differ deleted file mode 100644 index 987e490..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pycBinary files differ deleted file mode 100644 index c4edf24..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_gc.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pycBinary files differ deleted file mode 100644 index 936decb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pycBinary files differ deleted file mode 100644 index fa8ca9c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pycBinary files differ deleted file mode 100644 index 6f4f510..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pycBinary files differ deleted file mode 100644 index e40225d..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pycBinary files differ deleted file mode 100644 index 88e931a..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pycBinary files differ deleted file mode 100644 index b3f464d..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pycBinary files differ deleted file mode 100644 index 2427360..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_throw.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pycBinary files differ deleted file mode 100644 index a488241..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pycBinary files differ deleted file mode 100644 index 16d09c1..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_version.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc b/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pycBinary files differ deleted file mode 100644 index ba0b403..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-311.pyc +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.c b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.c deleted file mode 100644 index 05e81c0..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.c +++ /dev/null @@ -1,231 +0,0 @@ -/* This is a set of functions used by test_extension_interface.py to test the - * Greenlet C API. - */ - -#include "../greenlet.h" - -#ifndef Py_RETURN_NONE -#    define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif - -#define TEST_MODULE_NAME "_test_extension" - -static PyObject* -test_switch(PyObject* self, PyObject* greenlet) -{ -    PyObject* result = NULL; - -    if (greenlet == NULL || !PyGreenlet_Check(greenlet)) { -        PyErr_BadArgument(); -        return NULL; -    } - -    result = PyGreenlet_Switch((PyGreenlet*)greenlet, NULL, NULL); -    if (result == NULL) { -        if (!PyErr_Occurred()) { -            PyErr_SetString(PyExc_AssertionError, -                            "greenlet.switch() failed for some reason."); -        } -        return NULL; -    } -    Py_INCREF(result); -    return result; -} - -static PyObject* -test_switch_kwargs(PyObject* self, PyObject* args, PyObject* kwargs) -{ -    PyGreenlet* g = NULL; -    PyObject* result = NULL; - -    PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g); - -    if (g == NULL || !PyGreenlet_Check(g)) { -        PyErr_BadArgument(); -        return NULL; -    } - -    result = PyGreenlet_Switch(g, NULL, kwargs); -    if (result == NULL) { -        if (!PyErr_Occurred()) { -            PyErr_SetString(PyExc_AssertionError, -                            "greenlet.switch() failed for some reason."); -        } -        return NULL; -    } -    Py_XINCREF(result); -    return result; -} - -static PyObject* -test_getcurrent(PyObject* self) -{ -    PyGreenlet* g = PyGreenlet_GetCurrent(); -    if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) { -        PyErr_SetString(PyExc_AssertionError, -                        "getcurrent() returned an invalid greenlet"); -        Py_XDECREF(g); -        return NULL; -    } -    Py_DECREF(g); -    Py_RETURN_NONE; -} - -static PyObject* -test_setparent(PyObject* self, PyObject* arg) -{ -    PyGreenlet* current; -    PyGreenlet* greenlet = NULL; - -    if (arg == NULL || !PyGreenlet_Check(arg)) { -        PyErr_BadArgument(); -        return NULL; -    } -    if ((current = PyGreenlet_GetCurrent()) == NULL) { -        return NULL; -    } -    greenlet = (PyGreenlet*)arg; -    if (PyGreenlet_SetParent(greenlet, current)) { -        Py_DECREF(current); -        return NULL; -    } -    Py_DECREF(current); -    if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) { -        return NULL; -    } -    Py_RETURN_NONE; -} - -static PyObject* -test_new_greenlet(PyObject* self, PyObject* callable) -{ -    PyObject* result = NULL; -    PyGreenlet* greenlet = PyGreenlet_New(callable, NULL); - -    if (!greenlet) { -        return NULL; -    } - -    result = PyGreenlet_Switch(greenlet, NULL, NULL); -    Py_CLEAR(greenlet); -    if (result == NULL) { -        return NULL; -    } - -    Py_INCREF(result); -    return result; -} - -static PyObject* -test_raise_dead_greenlet(PyObject* self) -{ -    PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception."); -    return NULL; -} - -static PyObject* -test_raise_greenlet_error(PyObject* self) -{ -    PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception"); -    return NULL; -} - -static PyObject* -test_throw(PyObject* self, PyGreenlet* g) -{ -    const char msg[] = "take that sucka!"; -    PyObject* msg_obj = Py_BuildValue("s", msg); -    PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL); -    Py_DECREF(msg_obj); -    if (PyErr_Occurred()) { -        return NULL; -    } -    Py_RETURN_NONE; -} - -static PyObject* -test_throw_exact(PyObject* self, PyObject* args) -{ -    PyGreenlet* g = NULL; -    PyObject* typ = NULL; -    PyObject* val = NULL; -    PyObject* tb = NULL; - -    if (!PyArg_ParseTuple(args, "OOOO:throw", &g, &typ, &val, &tb)) { -        return NULL; -    } - -    PyGreenlet_Throw(g, typ, val, tb); -    if (PyErr_Occurred()) { -        return NULL; -    } -    Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { -    {"test_switch", -     (PyCFunction)test_switch, -     METH_O, -     "Switch to the provided greenlet sending provided arguments, and \n" -     "return the results."}, -    {"test_switch_kwargs", -     (PyCFunction)test_switch_kwargs, -     METH_VARARGS | METH_KEYWORDS, -     "Switch to the provided greenlet sending the provided keyword args."}, -    {"test_getcurrent", -     (PyCFunction)test_getcurrent, -     METH_NOARGS, -     "Test PyGreenlet_GetCurrent()"}, -    {"test_setparent", -     (PyCFunction)test_setparent, -     METH_O, -     "Se the parent of the provided greenlet and switch to it."}, -    {"test_new_greenlet", -     (PyCFunction)test_new_greenlet, -     METH_O, -     "Test PyGreenlet_New()"}, -    {"test_raise_dead_greenlet", -     (PyCFunction)test_raise_dead_greenlet, -     METH_NOARGS, -     "Just raise greenlet.GreenletExit"}, -    {"test_raise_greenlet_error", -     (PyCFunction)test_raise_greenlet_error, -     METH_NOARGS, -     "Just raise greenlet.error"}, -    {"test_throw", -     (PyCFunction)test_throw, -     METH_O, -     "Throw a ValueError at the provided greenlet"}, -    {"test_throw_exact", -     (PyCFunction)test_throw_exact, -     METH_VARARGS, -     "Throw exactly the arguments given at the provided greenlet"}, -    {NULL, NULL, 0, NULL} -}; - - -#define INITERROR return NULL - -static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, -                                       TEST_MODULE_NAME, -                                       NULL, -                                       0, -                                       test_methods, -                                       NULL, -                                       NULL, -                                       NULL, -                                       NULL}; - -PyMODINIT_FUNC -PyInit__test_extension(void) -{ -    PyObject* module = NULL; -    module = PyModule_Create(&moduledef); - -    if (module == NULL) { -        return NULL; -    } - -    PyGreenlet_Import(); -    return module; -} diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.soBinary files differ deleted file mode 100755 index 2c7fff0..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp deleted file mode 100644 index 5cbe6a7..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* This is a set of functions used to test C++ exceptions are not - * broken during greenlet switches - */ - -#include "../greenlet.h" -#include "../greenlet_compiler_compat.hpp" -#include <exception> -#include <stdexcept> - -struct exception_t { -    int depth; -    exception_t(int depth) : depth(depth) {} -}; - -/* Functions are called via pointers to prevent inlining */ -static void (*p_test_exception_throw_nonstd)(int depth); -static void (*p_test_exception_throw_std)(); -static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); - -static void -test_exception_throw_nonstd(int depth) -{ -    throw exception_t(depth); -} - -static void -test_exception_throw_std() -{ -    throw std::runtime_error("Thrown from an extension."); -} - -static PyObject* -test_exception_switch_recurse(int depth, int left) -{ -    if (left > 0) { -        return p_test_exception_switch_recurse(depth, left - 1); -    } - -    PyObject* result = NULL; -    PyGreenlet* self = PyGreenlet_GetCurrent(); -    if (self == NULL) -        return NULL; - -    try { -        if (PyGreenlet_Switch(PyGreenlet_GET_PARENT(self), NULL, NULL) == NULL) { -            Py_DECREF(self); -            return NULL; -        } -        p_test_exception_throw_nonstd(depth); -        PyErr_SetString(PyExc_RuntimeError, -                        "throwing C++ exception didn't work"); -    } -    catch (const exception_t& e) { -        if (e.depth != depth) -            PyErr_SetString(PyExc_AssertionError, "depth mismatch"); -        else -            result = PyLong_FromLong(depth); -    } -    catch (...) { -        PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); -    } - -    Py_DECREF(self); -    return result; -} - -/* test_exception_switch(int depth) - * - recurses depth times - * - switches to parent inside try/catch block - * - throws an exception that (expected to be caught in the same function) - * - verifies depth matches (exceptions shouldn't be caught in other greenlets) - */ -static PyObject* -test_exception_switch(PyObject* UNUSED(self), PyObject* args) -{ -    int depth; -    if (!PyArg_ParseTuple(args, "i", &depth)) -        return NULL; -    return p_test_exception_switch_recurse(depth, depth); -} - - -static PyObject* -py_test_exception_throw_nonstd(PyObject* self, PyObject* args) -{ -    if (!PyArg_ParseTuple(args, "")) -        return NULL; -    p_test_exception_throw_nonstd(0); -    PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); -    return NULL; -} - -static PyObject* -py_test_exception_throw_std(PyObject* self, PyObject* args) -{ -    if (!PyArg_ParseTuple(args, "")) -        return NULL; -    p_test_exception_throw_std(); -    PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); -    return NULL; -} - -static PyObject* -py_test_call(PyObject* self, PyObject* arg) -{ -    PyObject* noargs = PyTuple_New(0); -    PyObject* ret = PyObject_Call(arg, noargs, nullptr); -    Py_DECREF(noargs); -    return ret; -} - - - -/* test_exception_switch_and_do_in_g2(g2func) - * - creates new greenlet g2 to run g2func - * - switches to g2 inside try/catch block - * - verifies that no exception has been caught - * - * it is used together with test_exception_throw to verify that unhandled - * exceptions thrown in one greenlet do not propagate to other greenlet nor - * segfault the process. - */ -static PyObject* -test_exception_switch_and_do_in_g2(PyObject* self, PyObject* args) -{ -    PyObject* g2func = NULL; -    PyObject* result = NULL; - -    if (!PyArg_ParseTuple(args, "O", &g2func)) -        return NULL; -    PyGreenlet* g2 = PyGreenlet_New(g2func, NULL); -    if (!g2) { -        return NULL; -    } - -    try { -        result = PyGreenlet_Switch(g2, NULL, NULL); -        if (!result) { -            return NULL; -        } -    } -    catch (const exception_t& e) { -        /* if we are here the memory can be already corrupted and the program -         * might crash before below py-level exception might become printed. -         * -> print something to stderr to make it clear that we had entered -         *    this catch block. -         * See comments in inner_bootstrap() -         */ -#if defined(WIN32) || defined(_WIN32) -        fprintf(stderr, "C++ exception unexpectedly caught in g1\n"); -        PyErr_SetString(PyExc_AssertionError, "C++ exception unexpectedly caught in g1"); -        Py_XDECREF(result); -        return NULL; -#else -        throw; -#endif -    } - -    Py_XDECREF(result); -    Py_RETURN_NONE; -} - -static PyMethodDef test_methods[] = { -    {"test_exception_switch", -     (PyCFunction)&test_exception_switch, -     METH_VARARGS, -     "Switches to parent twice, to test exception handling and greenlet " -     "switching."}, -    {"test_exception_switch_and_do_in_g2", -     (PyCFunction)&test_exception_switch_and_do_in_g2, -     METH_VARARGS, -     "Creates new greenlet g2 to run g2func and switches to it inside try/catch " -     "block. Used together with test_exception_throw to verify that unhandled " -     "C++ exceptions thrown in a greenlet doe not corrupt memory."}, -    {"test_exception_throw_nonstd", -     (PyCFunction)&py_test_exception_throw_nonstd, -     METH_VARARGS, -     "Throws non-standard C++ exception. Calling this function directly should abort the process." -    }, -    {"test_exception_throw_std", -     (PyCFunction)&py_test_exception_throw_std, -     METH_VARARGS, -     "Throws standard C++ exception. Calling this function directly should abort the process." -    }, -    {"test_call", -     (PyCFunction)&py_test_call, -     METH_O, -     "Call the given callable. Unlike calling it directly, this creates a " -     "new C-level stack frame, which may be helpful in testing." -    }, -    {NULL, NULL, 0, NULL} -}; - - -static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, -                                       "greenlet.tests._test_extension_cpp", -                                       NULL, -                                       0, -                                       test_methods, -                                       NULL, -                                       NULL, -                                       NULL, -                                       NULL}; - -PyMODINIT_FUNC -PyInit__test_extension_cpp(void) -{ -    PyObject* module = NULL; - -    module = PyModule_Create(&moduledef); - -    if (module == NULL) { -        return NULL; -    } - -    PyGreenlet_Import(); -    if (_PyGreenlet_API == NULL) { -        return NULL; -    } - -    p_test_exception_throw_nonstd = test_exception_throw_nonstd; -    p_test_exception_throw_std = test_exception_throw_std; -    p_test_exception_switch_recurse = test_exception_switch_recurse; - -    return module; -} diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so b/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.soBinary files differ deleted file mode 100755 index 714dfa8..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so +++ /dev/null diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py deleted file mode 100644 index 6dd1492..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -""" -If we have a run callable passed to the constructor or set as an -attribute, but we don't actually use that (because ``__getattribute__`` -or the like interferes), then when we clear callable before beginning -to run, there's an opportunity for Python code to run. - -""" -import greenlet - -g = None -main = greenlet.getcurrent() - -results = [] - -class RunCallable: - -    def __del__(self): -        results.append(('RunCallable', '__del__')) -        main.switch('from RunCallable') - - -class G(greenlet.greenlet): - -    def __getattribute__(self, name): -        if name == 'run': -            results.append(('G.__getattribute__', 'run')) -            return run_func -        return object.__getattribute__(self, name) - - -def run_func(): -    results.append(('run_func', 'enter')) - - -g = G(RunCallable()) -# Try to start G. It will get to the point where it deletes -# its run callable C++ variable in inner_bootstrap. That triggers -# the __del__ method, which switches back to main before g -# actually even starts running. -x = g.switch() -results.append(('main: g.switch()', x)) -# In the C++ code, this results in g->g_switch() appearing to return, even though -# it has yet to run. -print('In main with', x, flush=True) -g.switch() -print('RESULTS', results) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py deleted file mode 100644 index fa4dc2e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Helper for testing a C++ exception throw aborts the process. - -Takes one argument, the name of the function in :mod:`_test_extension_cpp` to call. -""" -import sys -import greenlet -from greenlet.tests import _test_extension_cpp -print('fail_cpp_exception is running') - -def run_unhandled_exception_in_greenlet_aborts(): -    def _(): -        _test_extension_cpp.test_exception_switch_and_do_in_g2( -            _test_extension_cpp.test_exception_throw_nonstd -        ) -    g1 = greenlet.greenlet(_) -    g1.switch() - - -func_name = sys.argv[1] -try: -    func = getattr(_test_extension_cpp, func_name) -except AttributeError: -    if func_name == run_unhandled_exception_in_greenlet_aborts.__name__: -        func = run_unhandled_exception_in_greenlet_aborts -    elif func_name == 'run_as_greenlet_target': -        g = greenlet.greenlet(_test_extension_cpp.test_exception_throw_std) -        func = g.switch -    else: -        raise -print('raising', func, flush=True) -func() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py deleted file mode 100644 index c1a44ef..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Testing initialstub throwing an already started exception. -""" - -import greenlet - -a = None -b = None -c = None -main = greenlet.getcurrent() - -# If we switch into a dead greenlet, -# we go looking for its parents. -# if a parent is not yet started, we start it. - -results = [] - -def a_run(*args): -    #results.append('A') -    results.append(('Begin A', args)) - - -def c_run(): -    results.append('Begin C') -    b.switch('From C') -    results.append('C done') - -class A(greenlet.greenlet): pass - -class B(greenlet.greenlet): -    doing_it = False -    def __getattribute__(self, name): -        if name == 'run' and not self.doing_it: -            assert greenlet.getcurrent() is c -            self.doing_it = True -            results.append('Switch to b from B.__getattribute__ in ' -                           + type(greenlet.getcurrent()).__name__) -            b.switch() -            results.append('B.__getattribute__ back from main in ' -                           + type(greenlet.getcurrent()).__name__) -        if name == 'run': -            name = '_B_run' -        return object.__getattribute__(self, name) - -    def _B_run(self, *arg): -        results.append(('Begin B', arg)) -        results.append('_B_run switching to main') -        main.switch('From B') - -class C(greenlet.greenlet): -    pass -a = A(a_run) -b = B(parent=a) -c = C(c_run, b) - -# Start a child; while running, it will start B, -# but starting B will ALSO start B. -result = c.switch() -results.append(('main from c', result)) - -# Switch back to C, which was in the middle of switching -# already. This will throw the ``GreenletStartedWhileInPython`` -# exception, which results in parent A getting started (B is finished) -c.switch() - -results.append(('A dead?', a.dead, 'B dead?', b.dead, 'C dead?', c.dead)) - -# A and B should both be dead now. -assert a.dead -assert b.dead -assert not c.dead - -result = c.switch() -results.append(('main from c.2', result)) -# Now C is dead -assert c.dead - -print("RESULTS:", results) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py deleted file mode 100644 index 0990526..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -""" -A test helper for seeing what happens when slp_switch() -fails. -""" -# pragma: no cover - -import greenlet - - -print('fail_slp_switch is running', flush=True) - -runs = [] -def func(): -    runs.append(1) -    greenlet.getcurrent().parent.switch() -    runs.append(2) -    greenlet.getcurrent().parent.switch() -    runs.append(3) - -g = greenlet._greenlet.UnswitchableGreenlet(func) -g.switch() -assert runs == [1] -g.switch() -assert runs == [1, 2] -g.force_slp_switch_error = True - -# This should crash. -g.switch() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py deleted file mode 100644 index e151b19..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Uses a trace function to switch greenlets at unexpected times. - -In the trace function, we switch from the current greenlet to another -greenlet, which switches -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = False - -def tracefunc(*args): -    print('TRACE', *args) -    global switch_to_g2 -    if switch_to_g2: -        switch_to_g2 = False -        g2.switch() -    print('\tLEAVE TRACE', *args) - -def g1_run(): -    print('In g1_run') -    global switch_to_g2 -    switch_to_g2 = True -    from_parent = greenlet.getcurrent().parent.switch() -    print('Return to g1_run') -    print('From parent', from_parent) - -def g2_run(): -    #g1.switch() -    greenlet.getcurrent().parent.switch() - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -# This switch didn't actually finish! -# And if it did, it would raise TypeError -# because g1_run() doesn't take any arguments. -g1.switch(1) -print('Back in main') -g1.switch(2) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py deleted file mode 100644 index 1f6b66b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Like fail_switch_three_greenlets, but the call into g1_run would actually be -valid. -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = True - -results = [] - -def tracefunc(*args): -    results.append(('trace', args[0])) -    print('TRACE', *args) -    global switch_to_g2 -    if switch_to_g2: -        switch_to_g2 = False -        g2.switch('g2 from tracefunc') -    print('\tLEAVE TRACE', *args) - -def g1_run(arg): -    results.append(('g1 arg', arg)) -    print('In g1_run') -    from_parent = greenlet.getcurrent().parent.switch('from g1_run') -    results.append(('g1 from parent', from_parent)) -    return 'g1 done' - -def g2_run(arg): -    #g1.switch() -    results.append(('g2 arg', arg)) -    parent = greenlet.getcurrent().parent.switch('from g2_run') -    global switch_to_g2 -    switch_to_g2 = False -    results.append(('g2 from parent', parent)) -    return 'g2 done' - - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -x = g1.switch('g1 from main') -results.append(('main g1', x)) -print('Back in main', x) -x = g1.switch('g2 from main') -results.append(('main g2', x)) -print('back in amain again', x) -x = g1.switch('g1 from main 2') -results.append(('main g1.2', x)) -x = g2.switch() -results.append(('main g2.2', x)) -print("RESULTS:", results) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py b/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py deleted file mode 100644 index 3e52345..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Uses a trace function to switch greenlets at unexpected times. - -In the trace function, we switch from the current greenlet to another -greenlet, which switches -""" -import greenlet - -g1 = None -g2 = None - -switch_to_g2 = False - -def tracefunc(*args): -    print('TRACE', *args) -    global switch_to_g2 -    if switch_to_g2: -        switch_to_g2 = False -        g2.switch() -    print('\tLEAVE TRACE', *args) - -def g1_run(): -    print('In g1_run') -    global switch_to_g2 -    switch_to_g2 = True -    greenlet.getcurrent().parent.switch() -    print('Return to g1_run') -    print('Falling off end of g1_run') - -def g2_run(): -    g1.switch() -    print('Falling off end of g2') - -greenlet.settrace(tracefunc) - -g1 = greenlet.greenlet(g1_run) -g2 = greenlet.greenlet(g2_run) - -g1.switch() -print('Falling off end of main') -g2.switch() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/leakcheck.py b/venv/lib/python3.11/site-packages/greenlet/tests/leakcheck.py deleted file mode 100644 index a5152fb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/leakcheck.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright (c) 2018 gevent community -# Copyright (c) 2021 greenlet community -# -# This was originally part of gevent's test suite. The main author -# (Jason Madden) vendored a copy of it into greenlet. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -from __future__ import print_function - -import os -import sys -import gc - -from functools import wraps -import unittest - - -import objgraph - -# graphviz 0.18 (Nov 7 2021), available only on Python 3.6 and newer, -# has added type hints (sigh). It wants to use ``typing.Literal`` for -# some stuff, but that's only available on Python 3.9+. If that's not -# found, it creates a ``unittest.mock.MagicMock`` object and annotates -# with that. These are GC'able objects, and doing almost *anything* -# with them results in an explosion of objects. For example, trying to -# compare them for equality creates new objects. This causes our -# leakchecks to fail, with reports like: -# -# greenlet.tests.leakcheck.LeakCheckError: refcount increased by [337, 1333, 343, 430, 530, 643, 769] -# _Call          1820      +546 -# dict           4094       +76 -# MagicProxy      585       +73 -# tuple          2693       +66 -# _CallList        24        +3 -# weakref        1441        +1 -# function       5996        +1 -# type            736        +1 -# cell            592        +1 -# MagicMock         8        +1 -# -# To avoid this, we *could* filter this type of object out early. In -# principle it could leak, but we don't use mocks in greenlet, so it -# doesn't leak from us. However, a further issue is that ``MagicMock`` -# objects have subobjects that are also GC'able, like ``_Call``, and -# those create new mocks of their own too. So we'd have to filter them -# as well, and they're not public. That's OK, we can workaround the -# problem by being very careful to never compare by equality or other -# user-defined operators, only using object identity or other builtin -# functions. - -RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') -RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS -RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') -RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR -RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') -SKIP_LEAKCHECKS = RUNNING_ON_MANYLINUX or os.environ.get('GREENLET_SKIP_LEAKCHECKS') -SKIP_FAILING_LEAKCHECKS = os.environ.get('GREENLET_SKIP_FAILING_LEAKCHECKS') -ONLY_FAILING_LEAKCHECKS = os.environ.get('GREENLET_ONLY_FAILING_LEAKCHECKS') - -def ignores_leakcheck(func): -    """ -    Ignore the given object during leakchecks. - -    Can be applied to a method, in which case the method will run, but -    will not be subject to leak checks. - -    If applied to a class, the entire class will be skipped during leakchecks. This -    is intended to be used for classes that are very slow and cause problems such as -    test timeouts; typically it will be used for classes that are subclasses of a base -    class and specify variants of behaviour (such as pool sizes). -    """ -    func.ignore_leakcheck = True -    return func - -def fails_leakcheck(func): -    """ -    Mark that the function is known to leak. -    """ -    func.fails_leakcheck = True -    if SKIP_FAILING_LEAKCHECKS: -        func = unittest.skip("Skipping known failures")(func) -    return func - -class LeakCheckError(AssertionError): -    pass - -if hasattr(sys, 'getobjects'): -    # In a Python build with ``--with-trace-refs``, make objgraph -    # trace *all* the objects, not just those that are tracked by the -    # GC -    class _MockGC(object): -        def get_objects(self): -            return sys.getobjects(0) # pylint:disable=no-member -        def __getattr__(self, name): -            return getattr(gc, name) -    objgraph.gc = _MockGC() -    fails_strict_leakcheck = fails_leakcheck -else: -    def fails_strict_leakcheck(func): -        """ -        Decorator for a function that is known to fail when running -        strict (``sys.getobjects()``) leakchecks. - -        This type of leakcheck finds all objects, even those, such as -        strings, which are not tracked by the garbage collector. -        """ -        return func - -class ignores_types_in_strict_leakcheck(object): -    def __init__(self, types): -        self.types = types -    def __call__(self, func): -        func.leakcheck_ignore_types = self.types -        return func - -class _RefCountChecker(object): - -    # Some builtin things that we ignore -    # XXX: Those things were ignored by gevent, but they're important here, -    # presumably. -    IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType) - -    def __init__(self, testcase, function): -        self.testcase = testcase -        self.function = function -        self.deltas = [] -        self.peak_stats = {} -        self.ignored_types = () - -        # The very first time we are called, we have already been -        # self.setUp() by the test runner, so we don't need to do it again. -        self.needs_setUp = False - -    def _include_object_p(self, obj): -        # pylint:disable=too-many-return-statements -        # -        # See the comment block at the top. We must be careful to -        # avoid invoking user-defined operations. -        if obj is self: -            return False -        kind = type(obj) -        # ``self._include_object_p == obj`` returns NotImplemented -        # for non-function objects, which causes the interpreter -        # to try to reverse the order of arguments...which leads -        # to the explosion of mock objects. We don't want that, so we implement -        # the check manually. -        if kind == type(self._include_object_p): -            try: -                # pylint:disable=not-callable -                exact_method_equals = self._include_object_p.__eq__(obj) -            except AttributeError: -                # Python 2.7 methods may only have __cmp__, and that raises a -                # TypeError for non-method arguments -                # pylint:disable=no-member -                exact_method_equals = self._include_object_p.__cmp__(obj) == 0 - -            if exact_method_equals is not NotImplemented and exact_method_equals: -                return False - -        # Similarly, we need to check identity in our __dict__ to avoid mock explosions. -        for x in self.__dict__.values(): -            if obj is x: -                return False - - -        if kind in self.ignored_types or kind in self.IGNORED_TYPES: -            return False - -        return True - -    def _growth(self): -        return objgraph.growth(limit=None, peak_stats=self.peak_stats, -                               filter=self._include_object_p) - -    def _report_diff(self, growth): -        if not growth: -            return "<Unable to calculate growth>" - -        lines = [] -        width = max(len(name) for name, _, _ in growth) -        for name, count, delta in growth: -            lines.append('%-*s%9d %+9d' % (width, name, count, delta)) - -        diff = '\n'.join(lines) -        return diff - - -    def _run_test(self, args, kwargs): -        gc_enabled = gc.isenabled() -        gc.disable() - -        if self.needs_setUp: -            self.testcase.setUp() -            self.testcase.skipTearDown = False -        try: -            self.function(self.testcase, *args, **kwargs) -        finally: -            self.testcase.tearDown() -            self.testcase.doCleanups() -            self.testcase.skipTearDown = True -            self.needs_setUp = True -            if gc_enabled: -                gc.enable() - -    def _growth_after(self): -        # Grab post snapshot -        # pylint:disable=no-member -        if 'urlparse' in sys.modules: -            sys.modules['urlparse'].clear_cache() -        if 'urllib.parse' in sys.modules: -            sys.modules['urllib.parse'].clear_cache() - -        return self._growth() - -    def _check_deltas(self, growth): -        # Return false when we have decided there is no leak, -        # true if we should keep looping, raises an assertion -        # if we have decided there is a leak. - -        deltas = self.deltas -        if not deltas: -            # We haven't run yet, no data, keep looping -            return True - -        if gc.garbage: -            raise LeakCheckError("Generated uncollectable garbage %r" % (gc.garbage,)) - - -        # the following configurations are classified as "no leak" -        # [0, 0] -        # [x, 0, 0] -        # [... a, b, c, d]  where a+b+c+d = 0 -        # -        # the following configurations are classified as "leak" -        # [... z, z, z]  where z > 0 - -        if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): -            return False - -        if deltas[-3:] == [0, 0, 0]: -            return False - -        if len(deltas) >= 4 and sum(deltas[-4:]) == 0: -            return False - -        if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: -            diff = self._report_diff(growth) -            raise LeakCheckError('refcount increased by %r\n%s' % (deltas, diff)) - -        # OK, we don't know for sure yet. Let's search for more -        if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: -            # this is suspicious, so give a few more runs -            limit = 11 -        else: -            limit = 7 -        if len(deltas) >= limit: -            raise LeakCheckError('refcount increased by %r\n%s' -                                 % (deltas, -                                    self._report_diff(growth))) - -        # We couldn't decide yet, keep going -        return True - -    def __call__(self, args, kwargs): -        for _ in range(3): -            gc.collect() - -        expect_failure = getattr(self.function, 'fails_leakcheck', False) -        if expect_failure: -            self.testcase.expect_greenlet_leak = True -        self.ignored_types = getattr(self.function, "leakcheck_ignore_types", ()) - -        # Capture state before; the incremental will be -        # updated by each call to _growth_after -        growth = self._growth() - -        try: -            while self._check_deltas(growth): -                self._run_test(args, kwargs) - -                growth = self._growth_after() - -                self.deltas.append(sum((stat[2] for stat in growth))) -        except LeakCheckError: -            if not expect_failure: -                raise -        else: -            if expect_failure: -                raise LeakCheckError("Expected %s to leak but it did not." % (self.function,)) - -def wrap_refcount(method): -    if getattr(method, 'ignore_leakcheck', False) or SKIP_LEAKCHECKS: -        return method - -    @wraps(method) -    def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches -        if getattr(self, 'ignore_leakcheck', False): -            raise unittest.SkipTest("This class ignored during leakchecks") -        if ONLY_FAILING_LEAKCHECKS and not getattr(method, 'fails_leakcheck', False): -            raise unittest.SkipTest("Only running tests that fail leakchecks.") -        return _RefCountChecker(self, method)(args, kwargs) - -    return wrapper diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py deleted file mode 100644 index 9a16f67..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py +++ /dev/null @@ -1,310 +0,0 @@ -from __future__ import print_function - -import gc -import sys -import unittest - -from functools import partial -from unittest import skipUnless -from unittest import skipIf - -from greenlet import greenlet -from greenlet import getcurrent -from . import TestCase - - -try: -    from contextvars import Context -    from contextvars import ContextVar -    from contextvars import copy_context -    # From the documentation: -    # -    # Important: Context Variables should be created at the top module -    # level and never in closures. Context objects hold strong -    # references to context variables which prevents context variables -    # from being properly garbage collected. -    ID_VAR = ContextVar("id", default=None) -    VAR_VAR = ContextVar("var", default=None) -    ContextVar = None -except ImportError: -    Context = ContextVar = copy_context = None - -# We don't support testing if greenlet's built-in context var support is disabled. -@skipUnless(Context is not None, "ContextVar not supported") -class ContextVarsTests(TestCase): -    def _new_ctx_run(self, *args, **kwargs): -        return copy_context().run(*args, **kwargs) - -    def _increment(self, greenlet_id, callback, counts, expect): -        ctx_var = ID_VAR -        if expect is None: -            self.assertIsNone(ctx_var.get()) -        else: -            self.assertEqual(ctx_var.get(), expect) -        ctx_var.set(greenlet_id) -        for _ in range(2): -            counts[ctx_var.get()] += 1 -            callback() - -    def _test_context(self, propagate_by): -        # pylint:disable=too-many-branches -        ID_VAR.set(0) - -        callback = getcurrent().switch -        counts = dict((i, 0) for i in range(5)) - -        lets = [ -            greenlet(partial( -                partial( -                    copy_context().run, -                    self._increment -                ) if propagate_by == "run" else self._increment, -                greenlet_id=i, -                callback=callback, -                counts=counts, -                expect=( -                    i - 1 if propagate_by == "share" else -                    0 if propagate_by in ("set", "run") else None -                ) -            )) -            for i in range(1, 5) -        ] - -        for let in lets: -            if propagate_by == "set": -                let.gr_context = copy_context() -            elif propagate_by == "share": -                let.gr_context = getcurrent().gr_context - -        for i in range(2): -            counts[ID_VAR.get()] += 1 -            for let in lets: -                let.switch() - -        if propagate_by == "run": -            # Must leave each context.run() in reverse order of entry -            for let in reversed(lets): -                let.switch() -        else: -            # No context.run(), so fine to exit in any order. -            for let in lets: -                let.switch() - -        for let in lets: -            self.assertTrue(let.dead) -            # When using run(), we leave the run() as the greenlet dies, -            # and there's no context "underneath". When not using run(), -            # gr_context still reflects the context the greenlet was -            # running in. -            if propagate_by == 'run': -                self.assertIsNone(let.gr_context) -            else: -                self.assertIsNotNone(let.gr_context) - - -        if propagate_by == "share": -            self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) -        else: -            self.assertEqual(set(counts.values()), set([2])) - -    def test_context_propagated_by_context_run(self): -        self._new_ctx_run(self._test_context, "run") - -    def test_context_propagated_by_setting_attribute(self): -        self._new_ctx_run(self._test_context, "set") - -    def test_context_not_propagated(self): -        self._new_ctx_run(self._test_context, None) - -    def test_context_shared(self): -        self._new_ctx_run(self._test_context, "share") - -    def test_break_ctxvars(self): -        let1 = greenlet(copy_context().run) -        let2 = greenlet(copy_context().run) -        let1.switch(getcurrent().switch) -        let2.switch(getcurrent().switch) -        # Since let2 entered the current context and let1 exits its own, the -        # interpreter emits: -        # RuntimeError: cannot exit context: thread state references a different context object -        let1.switch() - -    def test_not_broken_if_using_attribute_instead_of_context_run(self): -        let1 = greenlet(getcurrent().switch) -        let2 = greenlet(getcurrent().switch) -        let1.gr_context = copy_context() -        let2.gr_context = copy_context() -        let1.switch() -        let2.switch() -        let1.switch() -        let2.switch() - -    def test_context_assignment_while_running(self): -        # pylint:disable=too-many-statements -        ID_VAR.set(None) - -        def target(): -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) - -            # Context is created on first use -            ID_VAR.set(1) -            self.assertIsInstance(gr.gr_context, Context) -            self.assertEqual(ID_VAR.get(), 1) -            self.assertEqual(gr.gr_context[ID_VAR], 1) - -            # Clearing the context makes it get re-created as another -            # empty context when next used -            old_context = gr.gr_context -            gr.gr_context = None  # assign None while running -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) -            ID_VAR.set(2) -            self.assertIsInstance(gr.gr_context, Context) -            self.assertEqual(ID_VAR.get(), 2) -            self.assertEqual(gr.gr_context[ID_VAR], 2) - -            new_context = gr.gr_context -            getcurrent().parent.switch((old_context, new_context)) -            # parent switches us back to old_context - -            self.assertEqual(ID_VAR.get(), 1) -            gr.gr_context = new_context  # assign non-None while running -            self.assertEqual(ID_VAR.get(), 2) - -            getcurrent().parent.switch() -            # parent switches us back to no context -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) -            gr.gr_context = old_context -            self.assertEqual(ID_VAR.get(), 1) - -            getcurrent().parent.switch() -            # parent switches us back to no context -            self.assertIsNone(ID_VAR.get()) -            self.assertIsNone(gr.gr_context) - -        gr = greenlet(target) - -        with self.assertRaisesRegex(AttributeError, "can't delete context attribute"): -            del gr.gr_context - -        self.assertIsNone(gr.gr_context) -        old_context, new_context = gr.switch() -        self.assertIs(new_context, gr.gr_context) -        self.assertEqual(old_context[ID_VAR], 1) -        self.assertEqual(new_context[ID_VAR], 2) -        self.assertEqual(new_context.run(ID_VAR.get), 2) -        gr.gr_context = old_context  # assign non-None while suspended -        gr.switch() -        self.assertIs(gr.gr_context, new_context) -        gr.gr_context = None  # assign None while suspended -        gr.switch() -        self.assertIs(gr.gr_context, old_context) -        gr.gr_context = None -        gr.switch() -        self.assertIsNone(gr.gr_context) - -        # Make sure there are no reference leaks -        gr = None -        gc.collect() -        self.assertEqual(sys.getrefcount(old_context), 2) -        self.assertEqual(sys.getrefcount(new_context), 2) - -    def test_context_assignment_different_thread(self): -        import threading -        VAR_VAR.set(None) -        ctx = Context() - -        is_running = threading.Event() -        should_suspend = threading.Event() -        did_suspend = threading.Event() -        should_exit = threading.Event() -        holder = [] - -        def greenlet_in_thread_fn(): -            VAR_VAR.set(1) -            is_running.set() -            should_suspend.wait(10) -            VAR_VAR.set(2) -            getcurrent().parent.switch() -            holder.append(VAR_VAR.get()) - -        def thread_fn(): -            gr = greenlet(greenlet_in_thread_fn) -            gr.gr_context = ctx -            holder.append(gr) -            gr.switch() -            did_suspend.set() -            should_exit.wait(10) -            gr.switch() -            del gr -            greenlet() # trigger cleanup - -        thread = threading.Thread(target=thread_fn, daemon=True) -        thread.start() -        is_running.wait(10) -        gr = holder[0] - -        # Can't access or modify context if the greenlet is running -        # in a different thread -        with self.assertRaisesRegex(ValueError, "running in a different"): -            getattr(gr, 'gr_context') -        with self.assertRaisesRegex(ValueError, "running in a different"): -            gr.gr_context = None - -        should_suspend.set() -        did_suspend.wait(10) - -        # OK to access and modify context if greenlet is suspended -        self.assertIs(gr.gr_context, ctx) -        self.assertEqual(gr.gr_context[VAR_VAR], 2) -        gr.gr_context = None - -        should_exit.set() -        thread.join(10) - -        self.assertEqual(holder, [gr, None]) - -        # Context can still be accessed/modified when greenlet is dead: -        self.assertIsNone(gr.gr_context) -        gr.gr_context = ctx -        self.assertIs(gr.gr_context, ctx) - -        # Otherwise we leak greenlets on some platforms. -        # XXX: Should be able to do this automatically -        del holder[:] -        gr = None -        thread = None - -    def test_context_assignment_wrong_type(self): -        g = greenlet() -        with self.assertRaisesRegex(TypeError, -                                    "greenlet context must be a contextvars.Context or None"): -            g.gr_context = self - - -@skipIf(Context is not None, "ContextVar supported") -class NoContextVarsTests(TestCase): -    def test_contextvars_errors(self): -        let1 = greenlet(getcurrent().switch) -        self.assertFalse(hasattr(let1, 'gr_context')) -        with self.assertRaises(AttributeError): -            getattr(let1, 'gr_context') - -        with self.assertRaises(AttributeError): -            let1.gr_context = None - -        let1.switch() - -        with self.assertRaises(AttributeError): -            getattr(let1, 'gr_context') - -        with self.assertRaises(AttributeError): -            let1.gr_context = None - -        del let1 - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_cpp.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_cpp.py deleted file mode 100644 index 2d0cc9c..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_cpp.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import subprocess -import unittest - -import greenlet -from . import _test_extension_cpp -from . import TestCase -from . import WIN - -class CPPTests(TestCase): -    def test_exception_switch(self): -        greenlets = [] -        for i in range(4): -            g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) -            g.switch(i) -            greenlets.append(g) -        for i, g in enumerate(greenlets): -            self.assertEqual(g.switch(), i) - -    def _do_test_unhandled_exception(self, target): -        import os -        import sys -        script = os.path.join( -            os.path.dirname(__file__), -            'fail_cpp_exception.py', -        ) -        args = [sys.executable, script, target.__name__ if not isinstance(target, str) else target] -        __traceback_info__ = args -        with self.assertRaises(subprocess.CalledProcessError) as exc: -            subprocess.check_output( -                args, -                encoding='utf-8', -                stderr=subprocess.STDOUT -            ) - -        ex = exc.exception -        expected_exit = self.get_expected_returncodes_for_aborted_process() -        self.assertIn(ex.returncode, expected_exit) -        self.assertIn('fail_cpp_exception is running', ex.output) -        return ex.output - - -    def test_unhandled_nonstd_exception_aborts(self): -        # verify that plain unhandled throw aborts -        self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_nonstd) - -    def test_unhandled_std_exception_aborts(self): -        # verify that plain unhandled throw aborts -        self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_std) - -    @unittest.skipIf(WIN, "XXX: This does not crash on Windows") -    # Meaning the exception is getting lost somewhere... -    def test_unhandled_std_exception_as_greenlet_function_aborts(self): -        # verify that plain unhandled throw aborts -        output = self._do_test_unhandled_exception('run_as_greenlet_target') -        self.assertIn( -            # We really expect this to be prefixed with "greenlet: Unhandled C++ exception:" -            # as added by our handler for std::exception (see TUserGreenlet.cpp), but -            # that's not correct everywhere --- our handler never runs before std::terminate -            # gets called (for example, on arm32). -            'Thrown from an extension.', -            output -        ) - -    def test_unhandled_exception_in_greenlet_aborts(self): -        # verify that unhandled throw called in greenlet aborts too -        self._do_test_unhandled_exception('run_unhandled_exception_in_greenlet_aborts') - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py deleted file mode 100644 index 34b6656..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py +++ /dev/null @@ -1,115 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import - -import sys - -import greenlet -from . import _test_extension -from . import TestCase - -# pylint:disable=c-extension-no-member - -class CAPITests(TestCase): -    def test_switch(self): -        self.assertEqual( -            50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) - -    def test_switch_kwargs(self): -        def adder(x, y): -            return x * y -        g = greenlet.greenlet(adder) -        self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) - -    def test_setparent(self): -        # pylint:disable=disallowed-name -        def foo(): -            def bar(): -                greenlet.getcurrent().parent.switch() - -                # This final switch should go back to the main greenlet, since -                # the test_setparent() function in the C extension should have -                # reparented this greenlet. -                greenlet.getcurrent().parent.switch() -                raise AssertionError("Should never have reached this code") -            child = greenlet.greenlet(bar) -            child.switch() -            greenlet.getcurrent().parent.switch(child) -            greenlet.getcurrent().parent.throw( -                AssertionError("Should never reach this code")) -        foo_child = greenlet.greenlet(foo).switch() -        self.assertEqual(None, _test_extension.test_setparent(foo_child)) - -    def test_getcurrent(self): -        _test_extension.test_getcurrent() - -    def test_new_greenlet(self): -        self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) - -    def test_raise_greenlet_dead(self): -        self.assertRaises( -            greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) - -    def test_raise_greenlet_error(self): -        self.assertRaises( -            greenlet.error, _test_extension.test_raise_greenlet_error) - -    def test_throw(self): -        seen = [] - -        def foo():         # pylint:disable=disallowed-name -            try: -                greenlet.getcurrent().parent.switch() -            except ValueError: -                seen.append(sys.exc_info()[1]) -            except greenlet.GreenletExit: -                raise AssertionError -        g = greenlet.greenlet(foo) -        g.switch() -        _test_extension.test_throw(g) -        self.assertEqual(len(seen), 1) -        self.assertTrue( -            isinstance(seen[0], ValueError), -            "ValueError was not raised in foo()") -        self.assertEqual( -            str(seen[0]), -            'take that sucka!', -            "message doesn't match") - -    def test_non_traceback_param(self): -        with self.assertRaises(TypeError) as exc: -            _test_extension.test_throw_exact( -                greenlet.getcurrent(), -                Exception, -                Exception(), -                self -            ) -        self.assertEqual(str(exc.exception), -                         "throw() third argument must be a traceback object") - -    def test_instance_of_wrong_type(self): -        with self.assertRaises(TypeError) as exc: -            _test_extension.test_throw_exact( -                greenlet.getcurrent(), -                Exception(), -                BaseException(), -                None, -            ) - -        self.assertEqual(str(exc.exception), -                         "instance exception may not have a separate value") - -    def test_not_throwable(self): -        with self.assertRaises(TypeError) as exc: -            _test_extension.test_throw_exact( -                greenlet.getcurrent(), -                "abc", -                None, -                None, -            ) -        self.assertEqual(str(exc.exception), -                         "exceptions must be classes, or instances, not str") - - -if __name__ == '__main__': -    import unittest -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_gc.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_gc.py deleted file mode 100644 index 994addb..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_gc.py +++ /dev/null @@ -1,86 +0,0 @@ -import gc - -import weakref - -import greenlet - - -from . import TestCase -from .leakcheck import fails_leakcheck -# These only work with greenlet gc support -# which is no longer optional. -assert greenlet.GREENLET_USE_GC - -class GCTests(TestCase): -    def test_dead_circular_ref(self): -        o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) -        gc.collect() -        if o() is not None: -            import sys -            print("O IS NOT NONE.", sys.getrefcount(o())) -        self.assertIsNone(o()) -        self.assertFalse(gc.garbage, gc.garbage) - -    def test_circular_greenlet(self): -        class circular_greenlet(greenlet.greenlet): -            self = None -        o = circular_greenlet() -        o.self = o -        o = weakref.ref(o) -        gc.collect() -        self.assertIsNone(o()) -        self.assertFalse(gc.garbage, gc.garbage) - -    def test_inactive_ref(self): -        class inactive_greenlet(greenlet.greenlet): -            def __init__(self): -                greenlet.greenlet.__init__(self, run=self.run) - -            def run(self): -                pass -        o = inactive_greenlet() -        o = weakref.ref(o) -        gc.collect() -        self.assertIsNone(o()) -        self.assertFalse(gc.garbage, gc.garbage) - -    @fails_leakcheck -    def test_finalizer_crash(self): -        # This test is designed to crash when active greenlets -        # are made garbage collectable, until the underlying -        # problem is resolved. How does it work: -        # - order of object creation is important -        # - array is created first, so it is moved to unreachable first -        # - we create a cycle between a greenlet and this array -        # - we create an object that participates in gc, is only -        #   referenced by a greenlet, and would corrupt gc lists -        #   on destruction, the easiest is to use an object with -        #   a finalizer -        # - because array is the first object in unreachable it is -        #   cleared first, which causes all references to greenlet -        #   to disappear and causes greenlet to be destroyed, but since -        #   it is still live it causes a switch during gc, which causes -        #   an object with finalizer to be destroyed, which causes stack -        #   corruption and then a crash - -        class object_with_finalizer(object): -            def __del__(self): -                pass -        array = [] -        parent = greenlet.getcurrent() -        def greenlet_body(): -            greenlet.getcurrent().object = object_with_finalizer() -            try: -                parent.switch() -            except greenlet.GreenletExit: -                print("Got greenlet exit!") -            finally: -                del greenlet.getcurrent().object -        g = greenlet.greenlet(greenlet_body) -        g.array = array -        array.append(g) -        g.switch() -        del array -        del g -        greenlet.getcurrent() -        gc.collect() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_generator.py deleted file mode 100644 index ca4a644..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator.py +++ /dev/null @@ -1,59 +0,0 @@ - -from greenlet import greenlet - -from . import TestCase - -class genlet(greenlet): -    parent = None -    def __init__(self, *args, **kwds): -        self.args = args -        self.kwds = kwds - -    def run(self): -        fn, = self.fn -        fn(*self.args, **self.kwds) - -    def __iter__(self): -        return self - -    def __next__(self): -        self.parent = greenlet.getcurrent() -        result = self.switch() -        if self: -            return result - -        raise StopIteration - -    next = __next__ - - -def Yield(value): -    g = greenlet.getcurrent() -    while not isinstance(g, genlet): -        if g is None: -            raise RuntimeError('yield outside a genlet') -        g = g.parent -    g.parent.switch(value) - - -def generator(func): -    class Generator(genlet): -        fn = (func,) -    return Generator - -# ____________________________________________________________ - - -class GeneratorTests(TestCase): -    def test_generator(self): -        seen = [] - -        def g(n): -            for i in range(n): -                seen.append(i) -                Yield(i) -        g = generator(g) -        for _ in range(3): -            for j in g(5): -                seen.append(j) -        self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py deleted file mode 100644 index 8d752a6..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py +++ /dev/null @@ -1,168 +0,0 @@ - -from greenlet import greenlet -from . import TestCase -from .leakcheck import fails_leakcheck - -class genlet(greenlet): -    parent = None -    def __init__(self, *args, **kwds): -        self.args = args -        self.kwds = kwds -        self.child = None - -    def run(self): -        # Note the function is packed in a tuple -        # to avoid creating a bound method for it. -        fn, = self.fn -        fn(*self.args, **self.kwds) - -    def __iter__(self): -        return self - -    def set_child(self, child): -        self.child = child - -    def __next__(self): -        if self.child: -            child = self.child -            while child.child: -                tmp = child -                child = child.child -                tmp.child = None - -            result = child.switch() -        else: -            self.parent = greenlet.getcurrent() -            result = self.switch() - -        if self: -            return result - -        raise StopIteration - -    next = __next__ - -def Yield(value, level=1): -    g = greenlet.getcurrent() - -    while level != 0: -        if not isinstance(g, genlet): -            raise RuntimeError('yield outside a genlet') -        if level > 1: -            g.parent.set_child(g) -        g = g.parent -        level -= 1 - -    g.switch(value) - - -def Genlet(func): -    class TheGenlet(genlet): -        fn = (func,) -    return TheGenlet - -# ____________________________________________________________ - - -def g1(n, seen): -    for i in range(n): -        seen.append(i + 1) -        yield i - - -def g2(n, seen): -    for i in range(n): -        seen.append(i + 1) -        Yield(i) - -g2 = Genlet(g2) - - -def nested(i): -    Yield(i) - - -def g3(n, seen): -    for i in range(n): -        seen.append(i + 1) -        nested(i) -g3 = Genlet(g3) - - -def a(n): -    if n == 0: -        return -    for ii in ax(n - 1): -        Yield(ii) -    Yield(n) -ax = Genlet(a) - - -def perms(l): -    if len(l) > 1: -        for e in l: -            # No syntactical sugar for generator expressions -            x = [Yield([e] + p) for p in perms([x for x in l if x != e])] -            assert x -    else: -        Yield(l) -perms = Genlet(perms) - - -def gr1(n): -    for ii in range(1, n): -        Yield(ii) -        Yield(ii * ii, 2) - -gr1 = Genlet(gr1) - - -def gr2(n, seen): -    for ii in gr1(n): -        seen.append(ii) - -gr2 = Genlet(gr2) - - -class NestedGeneratorTests(TestCase): -    def test_layered_genlets(self): -        seen = [] -        for ii in gr2(5, seen): -            seen.append(ii) -        self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) - -    @fails_leakcheck -    def test_permutations(self): -        gen_perms = perms(list(range(4))) -        permutations = list(gen_perms) -        self.assertEqual(len(permutations), 4 * 3 * 2 * 1) -        self.assertIn([0, 1, 2, 3], permutations) -        self.assertIn([3, 2, 1, 0], permutations) -        res = [] -        for ii in zip(perms(list(range(4))), perms(list(range(3)))): -            res.append(ii) -        self.assertEqual( -            res, -            [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), -             ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), -             ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) -        # XXX Test to make sure we are working as a generator expression - -    def test_genlet_simple(self): -        for g in g1, g2, g3: -            seen = [] -            for _ in range(3): -                for j in g(5, seen): -                    seen.append(j) -            self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) - -    def test_genlet_bad(self): -        try: -            Yield(10) -        except RuntimeError: -            pass - -    def test_nested_genlets(self): -        seen = [] -        for ii in ax(5): -            seen.append(ii) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py deleted file mode 100644 index 51849cd..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py +++ /dev/null @@ -1,1311 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import gc -import sys -import time -import threading - -from abc import ABCMeta, abstractmethod - -import greenlet -from greenlet import greenlet as RawGreenlet -from . import TestCase -from .leakcheck import fails_leakcheck - - -# We manually manage locks in many tests -# pylint:disable=consider-using-with -# pylint:disable=too-many-public-methods -# This module is quite large. -# TODO: Refactor into separate test files. For example, -# put all the regression tests that used to produce -# crashes in test_greenlet_no_crash; put tests that DO deliberately crash -# the interpreter into test_greenlet_crash. -# pylint:disable=too-many-lines - -class SomeError(Exception): -    pass - - -def fmain(seen): -    try: -        greenlet.getcurrent().parent.switch() -    except: -        seen.append(sys.exc_info()[0]) -        raise -    raise SomeError - - -def send_exception(g, exc): -    # note: send_exception(g, exc)  can be now done with  g.throw(exc). -    # the purpose of this test is to explicitly check the propagation rules. -    def crasher(exc): -        raise exc -    g1 = RawGreenlet(crasher, parent=g) -    g1.switch(exc) - - -class TestGreenlet(TestCase): - -    def _do_simple_test(self): -        lst = [] - -        def f(): -            lst.append(1) -            greenlet.getcurrent().parent.switch() -            lst.append(3) -        g = RawGreenlet(f) -        lst.append(0) -        g.switch() -        lst.append(2) -        g.switch() -        lst.append(4) -        self.assertEqual(lst, list(range(5))) - -    def test_simple(self): -        self._do_simple_test() - -    def test_switch_no_run_raises_AttributeError(self): -        g = RawGreenlet() -        with self.assertRaises(AttributeError) as exc: -            g.switch() - -        self.assertIn("run", str(exc.exception)) - -    def test_throw_no_run_raises_AttributeError(self): -        g = RawGreenlet() -        with self.assertRaises(AttributeError) as exc: -            g.throw(SomeError) - -        self.assertIn("run", str(exc.exception)) - -    def test_parent_equals_None(self): -        g = RawGreenlet(parent=None) -        self.assertIsNotNone(g) -        self.assertIs(g.parent, greenlet.getcurrent()) - -    def test_run_equals_None(self): -        g = RawGreenlet(run=None) -        self.assertIsNotNone(g) -        self.assertIsNone(g.run) - -    def test_two_children(self): -        lst = [] - -        def f(): -            lst.append(1) -            greenlet.getcurrent().parent.switch() -            lst.extend([1, 1]) -        g = RawGreenlet(f) -        h = RawGreenlet(f) -        g.switch() -        self.assertEqual(len(lst), 1) -        h.switch() -        self.assertEqual(len(lst), 2) -        h.switch() -        self.assertEqual(len(lst), 4) -        self.assertEqual(h.dead, True) -        g.switch() -        self.assertEqual(len(lst), 6) -        self.assertEqual(g.dead, True) - -    def test_two_recursive_children(self): -        lst = [] - -        def f(): -            lst.append('b') -            greenlet.getcurrent().parent.switch() - -        def g(): -            lst.append('a') -            g = RawGreenlet(f) -            g.switch() -            lst.append('c') - -        g = RawGreenlet(g) -        self.assertEqual(sys.getrefcount(g), 2) -        g.switch() -        self.assertEqual(lst, ['a', 'b', 'c']) -        # Just the one in this frame, plus the one on the stack we pass to the function -        self.assertEqual(sys.getrefcount(g), 2) - -    def test_threads(self): -        success = [] - -        def f(): -            self._do_simple_test() -            success.append(True) -        ths = [threading.Thread(target=f) for i in range(10)] -        for th in ths: -            th.start() -        for th in ths: -            th.join(10) -        self.assertEqual(len(success), len(ths)) - -    def test_exception(self): -        seen = [] -        g1 = RawGreenlet(fmain) -        g2 = RawGreenlet(fmain) -        g1.switch(seen) -        g2.switch(seen) -        g2.parent = g1 - -        self.assertEqual(seen, []) -        #with self.assertRaises(SomeError): -        #    p("***Switching back") -        #    g2.switch() -        # Creating this as a bound method can reveal bugs that -        # are hidden on newer versions of Python that avoid creating -        # bound methods for direct expressions; IOW, don't use the `with` -        # form! -        self.assertRaises(SomeError, g2.switch) -        self.assertEqual(seen, [SomeError]) - -        value = g2.switch() -        self.assertEqual(value, ()) -        self.assertEqual(seen, [SomeError]) - -        value = g2.switch(25) -        self.assertEqual(value, 25) -        self.assertEqual(seen, [SomeError]) - - -    def test_send_exception(self): -        seen = [] -        g1 = RawGreenlet(fmain) -        g1.switch(seen) -        self.assertRaises(KeyError, send_exception, g1, KeyError) -        self.assertEqual(seen, [KeyError]) - -    def test_dealloc(self): -        seen = [] -        g1 = RawGreenlet(fmain) -        g2 = RawGreenlet(fmain) -        g1.switch(seen) -        g2.switch(seen) -        self.assertEqual(seen, []) -        del g1 -        gc.collect() -        self.assertEqual(seen, [greenlet.GreenletExit]) -        del g2 -        gc.collect() -        self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) - -    def test_dealloc_catches_GreenletExit_throws_other(self): -        def run(): -            try: -                greenlet.getcurrent().parent.switch() -            except greenlet.GreenletExit: -                raise SomeError from None - -        g = RawGreenlet(run) -        g.switch() -        # Destroying the only reference to the greenlet causes it -        # to get GreenletExit; when it in turn raises, even though we're the parent -        # we don't get the exception, it just gets printed. -        # When we run on 3.8 only, we can use sys.unraisablehook -        oldstderr = sys.stderr -        try: -            from cStringIO import StringIO -        except ImportError: -            from io import StringIO -        stderr = sys.stderr = StringIO() -        try: -            del g -        finally: -            sys.stderr = oldstderr - -        v = stderr.getvalue() -        self.assertIn("Exception", v) -        self.assertIn('ignored', v) -        self.assertIn("SomeError", v) - - -    def test_dealloc_other_thread(self): -        seen = [] -        someref = [] - -        bg_glet_created_running_and_no_longer_ref_in_bg = threading.Event() -        fg_ref_released = threading.Event() -        bg_should_be_clear = threading.Event() -        ok_to_exit_bg_thread = threading.Event() - -        def f(): -            g1 = RawGreenlet(fmain) -            g1.switch(seen) -            someref.append(g1) -            del g1 -            gc.collect() - -            bg_glet_created_running_and_no_longer_ref_in_bg.set() -            fg_ref_released.wait(3) - -            RawGreenlet()   # trigger release -            bg_should_be_clear.set() -            ok_to_exit_bg_thread.wait(3) -            RawGreenlet() # One more time - -        t = threading.Thread(target=f) -        t.start() -        bg_glet_created_running_and_no_longer_ref_in_bg.wait(10) - -        self.assertEqual(seen, []) -        self.assertEqual(len(someref), 1) -        del someref[:] -        gc.collect() -        # g1 is not released immediately because it's from another thread -        self.assertEqual(seen, []) -        fg_ref_released.set() -        bg_should_be_clear.wait(3) -        try: -            self.assertEqual(seen, [greenlet.GreenletExit]) -        finally: -            ok_to_exit_bg_thread.set() -            t.join(10) -            del seen[:] -            del someref[:] - -    def test_frame(self): -        def f1(): -            f = sys._getframe(0) # pylint:disable=protected-access -            self.assertEqual(f.f_back, None) -            greenlet.getcurrent().parent.switch(f) -            return "meaning of life" -        g = RawGreenlet(f1) -        frame = g.switch() -        self.assertTrue(frame is g.gr_frame) -        self.assertTrue(g) - -        from_g = g.switch() -        self.assertFalse(g) -        self.assertEqual(from_g, 'meaning of life') -        self.assertEqual(g.gr_frame, None) - -    def test_thread_bug(self): -        def runner(x): -            g = RawGreenlet(lambda: time.sleep(x)) -            g.switch() -        t1 = threading.Thread(target=runner, args=(0.2,)) -        t2 = threading.Thread(target=runner, args=(0.3,)) -        t1.start() -        t2.start() -        t1.join(10) -        t2.join(10) - -    def test_switch_kwargs(self): -        def run(a, b): -            self.assertEqual(a, 4) -            self.assertEqual(b, 2) -            return 42 -        x = RawGreenlet(run).switch(a=4, b=2) -        self.assertEqual(x, 42) - -    def test_switch_kwargs_to_parent(self): -        def run(x): -            greenlet.getcurrent().parent.switch(x=x) -            greenlet.getcurrent().parent.switch(2, x=3) -            return x, x ** 2 -        g = RawGreenlet(run) -        self.assertEqual({'x': 3}, g.switch(3)) -        self.assertEqual(((2,), {'x': 3}), g.switch()) -        self.assertEqual((3, 9), g.switch()) - -    def test_switch_to_another_thread(self): -        data = {} -        created_event = threading.Event() -        done_event = threading.Event() - -        def run(): -            data['g'] = RawGreenlet(lambda: None) -            created_event.set() -            done_event.wait(10) -        thread = threading.Thread(target=run) -        thread.start() -        created_event.wait(10) -        with self.assertRaises(greenlet.error): -            data['g'].switch() -        done_event.set() -        thread.join(10) -        # XXX: Should handle this automatically -        data.clear() - -    def test_exc_state(self): -        def f(): -            try: -                raise ValueError('fun') -            except: # pylint:disable=bare-except -                exc_info = sys.exc_info() -                RawGreenlet(h).switch() -                self.assertEqual(exc_info, sys.exc_info()) - -        def h(): -            self.assertEqual(sys.exc_info(), (None, None, None)) - -        RawGreenlet(f).switch() - -    def test_instance_dict(self): -        def f(): -            greenlet.getcurrent().test = 42 -        def deldict(g): -            del g.__dict__ -        def setdict(g, value): -            g.__dict__ = value -        g = RawGreenlet(f) -        self.assertEqual(g.__dict__, {}) -        g.switch() -        self.assertEqual(g.test, 42) -        self.assertEqual(g.__dict__, {'test': 42}) -        g.__dict__ = g.__dict__ -        self.assertEqual(g.__dict__, {'test': 42}) -        self.assertRaises(TypeError, deldict, g) -        self.assertRaises(TypeError, setdict, g, 42) - -    def test_running_greenlet_has_no_run(self): -        has_run = [] -        def func(): -            has_run.append( -                hasattr(greenlet.getcurrent(), 'run') -            ) - -        g = RawGreenlet(func) -        g.switch() -        self.assertEqual(has_run, [False]) - -    def test_deepcopy(self): -        import copy -        self.assertRaises(TypeError, copy.copy, RawGreenlet()) -        self.assertRaises(TypeError, copy.deepcopy, RawGreenlet()) - -    def test_parent_restored_on_kill(self): -        hub = RawGreenlet(lambda: None) -        main = greenlet.getcurrent() -        result = [] -        def worker(): -            try: -                # Wait to be killed by going back to the test. -                main.switch() -            except greenlet.GreenletExit: -                # Resurrect and switch to parent -                result.append(greenlet.getcurrent().parent) -                result.append(greenlet.getcurrent()) -                hub.switch() -        g = RawGreenlet(worker, parent=hub) -        g.switch() -        # delete the only reference, thereby raising GreenletExit -        del g -        self.assertTrue(result) -        self.assertIs(result[0], main) -        self.assertIs(result[1].parent, hub) -        # Delete them, thereby breaking the cycle between the greenlet -        # and the frame, which otherwise would never be collectable -        # XXX: We should be able to automatically fix this. -        del result[:] -        hub = None -        main = None - -    def test_parent_return_failure(self): -        # No run causes AttributeError on switch -        g1 = RawGreenlet() -        # Greenlet that implicitly switches to parent -        g2 = RawGreenlet(lambda: None, parent=g1) -        # AttributeError should propagate to us, no fatal errors -        with self.assertRaises(AttributeError): -            g2.switch() - -    def test_throw_exception_not_lost(self): -        class mygreenlet(RawGreenlet): -            def __getattribute__(self, name): -                try: -                    raise Exception # pylint:disable=broad-exception-raised -                except: # pylint:disable=bare-except -                    pass -                return RawGreenlet.__getattribute__(self, name) -        g = mygreenlet(lambda: None) -        self.assertRaises(SomeError, g.throw, SomeError()) - -    @fails_leakcheck -    def _do_test_throw_to_dead_thread_doesnt_crash(self, wait_for_cleanup=False): -        result = [] -        def worker(): -            greenlet.getcurrent().parent.switch() - -        def creator(): -            g = RawGreenlet(worker) -            g.switch() -            result.append(g) -            if wait_for_cleanup: -                # Let this greenlet eventually be cleaned up. -                g.switch() -                greenlet.getcurrent() -        t = threading.Thread(target=creator) -        t.start() -        t.join(10) -        del t -        # But, depending on the operating system, the thread -        # deallocator may not actually have run yet! So we can't be -        # sure about the error message unless we wait. -        if wait_for_cleanup: -            self.wait_for_pending_cleanups() -        with self.assertRaises(greenlet.error) as exc: -            result[0].throw(SomeError) - -        if not wait_for_cleanup: -            self.assertIn( -                str(exc.exception), [ -                    "cannot switch to a different thread (which happens to have exited)", -                    "cannot switch to a different thread" -                ] -            ) -        else: -            self.assertEqual( -                str(exc.exception), -                "cannot switch to a different thread (which happens to have exited)", -            ) - -        if hasattr(result[0].gr_frame, 'clear'): -            # The frame is actually executing (it thinks), we can't clear it. -            with self.assertRaises(RuntimeError): -                result[0].gr_frame.clear() -        # Unfortunately, this doesn't actually clear the references, they're in the -        # fast local array. -        if not wait_for_cleanup: -            result[0].gr_frame.f_locals.clear() -        else: -            self.assertIsNone(result[0].gr_frame) - -        del creator -        worker = None -        del result[:] -        # XXX: we ought to be able to automatically fix this. -        # See issue 252 -        self.expect_greenlet_leak = True # direct us not to wait for it to go away - -    @fails_leakcheck -    def test_throw_to_dead_thread_doesnt_crash(self): -        self._do_test_throw_to_dead_thread_doesnt_crash() - -    def test_throw_to_dead_thread_doesnt_crash_wait(self): -        self._do_test_throw_to_dead_thread_doesnt_crash(True) - -    @fails_leakcheck -    def test_recursive_startup(self): -        class convoluted(RawGreenlet): -            def __init__(self): -                RawGreenlet.__init__(self) -                self.count = 0 -            def __getattribute__(self, name): -                if name == 'run' and self.count == 0: -                    self.count = 1 -                    self.switch(43) -                return RawGreenlet.__getattribute__(self, name) -            def run(self, value): -                while True: -                    self.parent.switch(value) -        g = convoluted() -        self.assertEqual(g.switch(42), 43) -        # Exits the running greenlet, otherwise it leaks -        # XXX: We should be able to automatically fix this -        #g.throw(greenlet.GreenletExit) -        #del g -        self.expect_greenlet_leak = True - -    def test_threaded_updatecurrent(self): -        # released when main thread should execute -        lock1 = threading.Lock() -        lock1.acquire() -        # released when another thread should execute -        lock2 = threading.Lock() -        lock2.acquire() -        class finalized(object): -            def __del__(self): -                # happens while in green_updatecurrent() in main greenlet -                # should be very careful not to accidentally call it again -                # at the same time we must make sure another thread executes -                lock2.release() -                lock1.acquire() -                # now ts_current belongs to another thread -        def deallocator(): -            greenlet.getcurrent().parent.switch() -        def fthread(): -            lock2.acquire() -            greenlet.getcurrent() -            del g[0] -            lock1.release() -            lock2.acquire() -            greenlet.getcurrent() -            lock1.release() -        main = greenlet.getcurrent() -        g = [RawGreenlet(deallocator)] -        g[0].bomb = finalized() -        g[0].switch() -        t = threading.Thread(target=fthread) -        t.start() -        # let another thread grab ts_current and deallocate g[0] -        lock2.release() -        lock1.acquire() -        # this is the corner stone -        # getcurrent() will notice that ts_current belongs to another thread -        # and start the update process, which would notice that g[0] should -        # be deallocated, and that will execute an object's finalizer. Now, -        # that object will let another thread run so it can grab ts_current -        # again, which would likely crash the interpreter if there's no -        # check for this case at the end of green_updatecurrent(). This test -        # passes if getcurrent() returns correct result, but it's likely -        # to randomly crash if it's not anyway. -        self.assertEqual(greenlet.getcurrent(), main) -        # wait for another thread to complete, just in case -        t.join(10) - -    def test_dealloc_switch_args_not_lost(self): -        seen = [] -        def worker(): -            # wait for the value -            value = greenlet.getcurrent().parent.switch() -            # delete all references to ourself -            del worker[0] -            initiator.parent = greenlet.getcurrent().parent -            # switch to main with the value, but because -            # ts_current is the last reference to us we -            # return here immediately, where we resurrect ourself. -            try: -                greenlet.getcurrent().parent.switch(value) -            finally: -                seen.append(greenlet.getcurrent()) -        def initiator(): -            return 42 # implicitly falls thru to parent - -        worker = [RawGreenlet(worker)] - -        worker[0].switch() # prime worker -        initiator = RawGreenlet(initiator, worker[0]) -        value = initiator.switch() -        self.assertTrue(seen) -        self.assertEqual(value, 42) - -    def test_tuple_subclass(self): -        # The point of this test is to see what happens when a custom -        # tuple subclass is used as an object passed directly to the C -        # function ``green_switch``; part of ``green_switch`` checks -        # the ``len()`` of the ``args`` tuple, and that can call back -        # into Python. Here, when it calls back into Python, we -        # recursively enter ``green_switch`` again. - -        # This test is really only relevant on Python 2. The builtin -        # `apply` function directly passes the given args tuple object -        # to the underlying function, whereas the Python 3 version -        # unpacks and repacks into an actual tuple. This could still -        # happen using the C API on Python 3 though. We should write a -        # builtin version of apply() ourself. -        def _apply(func, a, k): -            func(*a, **k) - -        class mytuple(tuple): -            def __len__(self): -                greenlet.getcurrent().switch() -                return tuple.__len__(self) -        args = mytuple() -        kwargs = dict(a=42) -        def switchapply(): -            _apply(greenlet.getcurrent().parent.switch, args, kwargs) -        g = RawGreenlet(switchapply) -        self.assertEqual(g.switch(), kwargs) - -    def test_abstract_subclasses(self): -        AbstractSubclass = ABCMeta( -            'AbstractSubclass', -            (RawGreenlet,), -            {'run': abstractmethod(lambda self: None)}) - -        class BadSubclass(AbstractSubclass): -            pass - -        class GoodSubclass(AbstractSubclass): -            def run(self): -                pass - -        GoodSubclass() # should not raise -        self.assertRaises(TypeError, BadSubclass) - -    def test_implicit_parent_with_threads(self): -        if not gc.isenabled(): -            return # cannot test with disabled gc -        N = gc.get_threshold()[0] -        if N < 50: -            return # cannot test with such a small N -        def attempt(): -            lock1 = threading.Lock() -            lock1.acquire() -            lock2 = threading.Lock() -            lock2.acquire() -            recycled = [False] -            def another_thread(): -                lock1.acquire() # wait for gc -                greenlet.getcurrent() # update ts_current -                lock2.release() # release gc -            t = threading.Thread(target=another_thread) -            t.start() -            class gc_callback(object): -                def __del__(self): -                    lock1.release() -                    lock2.acquire() -                    recycled[0] = True -            class garbage(object): -                def __init__(self): -                    self.cycle = self -                    self.callback = gc_callback() -            l = [] -            x = range(N*2) -            current = greenlet.getcurrent() -            g = garbage() -            for _ in x: -                g = None # lose reference to garbage -                if recycled[0]: -                    # gc callback called prematurely -                    t.join(10) -                    return False -                last = RawGreenlet() -                if recycled[0]: -                    break # yes! gc called in green_new -                l.append(last) # increase allocation counter -            else: -                # gc callback not called when expected -                gc.collect() -                if recycled[0]: -                    t.join(10) -                return False -            self.assertEqual(last.parent, current) -            for g in l: -                self.assertEqual(g.parent, current) -            return True -        for _ in range(5): -            if attempt(): -                break - -    def test_issue_245_reference_counting_subclass_no_threads(self): -        # https://github.com/python-greenlet/greenlet/issues/245 -        # Before the fix, this crashed pretty reliably on -        # Python 3.10, at least on macOS; but much less reliably on other -        # interpreters (memory layout must have changed). -        # The threaded test crashed more reliably on more interpreters. -        from greenlet import getcurrent -        from greenlet import GreenletExit - -        class Greenlet(RawGreenlet): -            pass - -        initial_refs = sys.getrefcount(Greenlet) -        # This has to be an instance variable because -        # Python 2 raises a SyntaxError if we delete a local -        # variable referenced in an inner scope. -        self.glets = [] # pylint:disable=attribute-defined-outside-init - -        def greenlet_main(): -            try: -                getcurrent().parent.switch() -            except GreenletExit: -                self.glets.append(getcurrent()) - -        # Before the -        for _ in range(10): -            Greenlet(greenlet_main).switch() - -        del self.glets -        self.assertEqual(sys.getrefcount(Greenlet), initial_refs) - -    def test_issue_245_reference_counting_subclass_threads(self): -        # https://github.com/python-greenlet/greenlet/issues/245 -        from threading import Thread -        from threading import Event - -        from greenlet import getcurrent - -        class MyGreenlet(RawGreenlet): -            pass - -        glets = [] -        ref_cleared = Event() - -        def greenlet_main(): -            getcurrent().parent.switch() - -        def thread_main(greenlet_running_event): -            mine = MyGreenlet(greenlet_main) -            glets.append(mine) -            # The greenlets being deleted must be active -            mine.switch() -            # Don't keep any reference to it in this thread -            del mine -            # Let main know we published our greenlet. -            greenlet_running_event.set() -            # Wait for main to let us know the references are -            # gone and the greenlet objects no longer reachable -            ref_cleared.wait(10) -            # The creating thread must call getcurrent() (or a few other -            # greenlet APIs) because that's when the thread-local list of dead -            # greenlets gets cleared. -            getcurrent() - -        # We start with 3 references to the subclass: -        # - This module -        # - Its __mro__ -        # - The __subclassess__ attribute of greenlet -        # - (If we call gc.get_referents(), we find four entries, including -        #   some other tuple ``(greenlet)`` that I'm not sure about but must be part -        #   of the machinery.) -        # -        # On Python 3.10 it's often enough to just run 3 threads; on Python 2.7, -        # more threads are needed, and the results are still -        # non-deterministic. Presumably the memory layouts are different -        initial_refs = sys.getrefcount(MyGreenlet) -        thread_ready_events = [] -        for _ in range( -                initial_refs + 45 -        ): -            event = Event() -            thread = Thread(target=thread_main, args=(event,)) -            thread_ready_events.append(event) -            thread.start() - - -        for done_event in thread_ready_events: -            done_event.wait(10) - - -        del glets[:] -        ref_cleared.set() -        # Let any other thread run; it will crash the interpreter -        # if not fixed (or silently corrupt memory and we possibly crash -        # later). -        self.wait_for_pending_cleanups() -        self.assertEqual(sys.getrefcount(MyGreenlet), initial_refs) - -    def test_falling_off_end_switches_to_unstarted_parent_raises_error(self): -        def no_args(): -            return 13 - -        parent_never_started = RawGreenlet(no_args) - -        def leaf(): -            return 42 - -        child = RawGreenlet(leaf, parent_never_started) - -        # Because the run function takes to arguments -        with self.assertRaises(TypeError): -            child.switch() - -    def test_falling_off_end_switches_to_unstarted_parent_works(self): -        def one_arg(x): -            return (x, 24) - -        parent_never_started = RawGreenlet(one_arg) - -        def leaf(): -            return 42 - -        child = RawGreenlet(leaf, parent_never_started) - -        result = child.switch() -        self.assertEqual(result, (42, 24)) - -    def test_switch_to_dead_greenlet_with_unstarted_perverse_parent(self): -        class Parent(RawGreenlet): -            def __getattribute__(self, name): -                if name == 'run': -                    raise SomeError - - -        parent_never_started = Parent() -        seen = [] -        child = RawGreenlet(lambda: seen.append(42), parent_never_started) -        # Because we automatically start the parent when the child is -        # finished -        with self.assertRaises(SomeError): -            child.switch() - -        self.assertEqual(seen, [42]) - -        with self.assertRaises(SomeError): -            child.switch() -        self.assertEqual(seen, [42]) - -    def test_switch_to_dead_greenlet_reparent(self): -        seen = [] -        parent_never_started = RawGreenlet(lambda: seen.append(24)) -        child = RawGreenlet(lambda: seen.append(42)) - -        child.switch() -        self.assertEqual(seen, [42]) - -        child.parent = parent_never_started -        # This actually is the same as switching to the parent. -        result = child.switch() -        self.assertIsNone(result) -        self.assertEqual(seen, [42, 24]) - -    def test_can_access_f_back_of_suspended_greenlet(self): -        # This tests our frame rewriting to work around Python 3.12+ having -        # some interpreter frames on the C stack. It will crash in the absence -        # of that logic. -        main = greenlet.getcurrent() - -        def outer(): -            inner() - -        def inner(): -            main.switch(sys._getframe(0)) - -        hub = RawGreenlet(outer) -        # start it -        hub.switch() - -        # start another greenlet to make sure we aren't relying on -        # anything in `hub` still being on the C stack -        unrelated = RawGreenlet(lambda: None) -        unrelated.switch() - -        # now it is suspended -        self.assertIsNotNone(hub.gr_frame) -        self.assertEqual(hub.gr_frame.f_code.co_name, "inner") -        self.assertIsNotNone(hub.gr_frame.f_back) -        self.assertEqual(hub.gr_frame.f_back.f_code.co_name, "outer") -        # The next line is what would crash -        self.assertIsNone(hub.gr_frame.f_back.f_back) - -    def test_get_stack_with_nested_c_calls(self): -        from functools import partial -        from . import _test_extension_cpp - -        def recurse(v): -            if v > 0: -                return v * _test_extension_cpp.test_call(partial(recurse, v - 1)) -            return greenlet.getcurrent().parent.switch() - -        gr = RawGreenlet(recurse) -        gr.switch(5) -        frame = gr.gr_frame -        for i in range(5): -            self.assertEqual(frame.f_locals["v"], i) -            frame = frame.f_back -        self.assertEqual(frame.f_locals["v"], 5) -        self.assertIsNone(frame.f_back) -        self.assertEqual(gr.switch(10), 1200)  # 1200 = 5! * 10 - -    def test_frames_always_exposed(self): -        # On Python 3.12 this will crash if we don't set the -        # gr_frames_always_exposed attribute. More background: -        # https://github.com/python-greenlet/greenlet/issues/388 -        main = greenlet.getcurrent() - -        def outer(): -            inner(sys._getframe(0)) - -        def inner(frame): -            main.switch(frame) - -        gr = RawGreenlet(outer) -        frame = gr.switch() - -        # Do something else to clobber the part of the C stack used by `gr`, -        # so we can't skate by on "it just happened to still be there" -        unrelated = RawGreenlet(lambda: None) -        unrelated.switch() - -        self.assertEqual(frame.f_code.co_name, "outer") -        # The next line crashes on 3.12 if we haven't exposed the frames. -        self.assertIsNone(frame.f_back) - - -class TestGreenletSetParentErrors(TestCase): -    def test_threaded_reparent(self): -        data = {} -        created_event = threading.Event() -        done_event = threading.Event() - -        def run(): -            data['g'] = RawGreenlet(lambda: None) -            created_event.set() -            done_event.wait(10) - -        def blank(): -            greenlet.getcurrent().parent.switch() - -        thread = threading.Thread(target=run) -        thread.start() -        created_event.wait(10) -        g = RawGreenlet(blank) -        g.switch() -        with self.assertRaises(ValueError) as exc: -            g.parent = data['g'] -        done_event.set() -        thread.join(10) - -        self.assertEqual(str(exc.exception), "parent cannot be on a different thread") - -    def test_unexpected_reparenting(self): -        another = [] -        def worker(): -            g = RawGreenlet(lambda: None) -            another.append(g) -            g.switch() -        t = threading.Thread(target=worker) -        t.start() -        t.join(10) -        # The first time we switch (running g_initialstub(), which is -        # when we look up the run attribute) we attempt to change the -        # parent to one from another thread (which also happens to be -        # dead). ``g_initialstub()`` should detect this and raise a -        # greenlet error. -        # -        # EXCEPT: With the fix for #252, this is actually detected -        # sooner, when setting the parent itself. Prior to that fix, -        # the main greenlet from the background thread kept a valid -        # value for ``run_info``, and appeared to be a valid parent -        # until we actually started the greenlet. But now that it's -        # cleared, this test is catching whether ``green_setparent`` -        # can detect the dead thread. -        # -        # Further refactoring once again changes this back to a greenlet.error -        # -        # We need to wait for the cleanup to happen, but we're -        # deliberately leaking a main greenlet here. -        self.wait_for_pending_cleanups(initial_main_greenlets=self.main_greenlets_before_test + 1) - -        class convoluted(RawGreenlet): -            def __getattribute__(self, name): -                if name == 'run': -                    self.parent = another[0] # pylint:disable=attribute-defined-outside-init -                return RawGreenlet.__getattribute__(self, name) -        g = convoluted(lambda: None) -        with self.assertRaises(greenlet.error) as exc: -            g.switch() -        self.assertEqual(str(exc.exception), -                         "cannot switch to a different thread (which happens to have exited)") -        del another[:] - -    def test_unexpected_reparenting_thread_running(self): -        # Like ``test_unexpected_reparenting``, except the background thread is -        # actually still alive. -        another = [] -        switched_to_greenlet = threading.Event() -        keep_main_alive = threading.Event() -        def worker(): -            g = RawGreenlet(lambda: None) -            another.append(g) -            g.switch() -            switched_to_greenlet.set() -            keep_main_alive.wait(10) -        class convoluted(RawGreenlet): -            def __getattribute__(self, name): -                if name == 'run': -                    self.parent = another[0] # pylint:disable=attribute-defined-outside-init -                return RawGreenlet.__getattribute__(self, name) - -        t = threading.Thread(target=worker) -        t.start() - -        switched_to_greenlet.wait(10) -        try: -            g = convoluted(lambda: None) - -            with self.assertRaises(greenlet.error) as exc: -                g.switch() -            self.assertEqual(str(exc.exception), "cannot switch to a different thread") -        finally: -            keep_main_alive.set() -            t.join(10) -            # XXX: Should handle this automatically. -            del another[:] - -    def test_cannot_delete_parent(self): -        worker = RawGreenlet(lambda: None) -        self.assertIs(worker.parent, greenlet.getcurrent()) - -        with self.assertRaises(AttributeError) as exc: -            del worker.parent -        self.assertEqual(str(exc.exception), "can't delete attribute") - -    def test_cannot_delete_parent_of_main(self): -        with self.assertRaises(AttributeError) as exc: -            del greenlet.getcurrent().parent -        self.assertEqual(str(exc.exception), "can't delete attribute") - - -    def test_main_greenlet_parent_is_none(self): -        # assuming we're in a main greenlet here. -        self.assertIsNone(greenlet.getcurrent().parent) - -    def test_set_parent_wrong_types(self): -        def bg(): -            # Go back to main. -            greenlet.getcurrent().parent.switch() - -        def check(glet): -            for p in None, 1, self, "42": -                with self.assertRaises(TypeError) as exc: -                    glet.parent = p - -                self.assertEqual( -                    str(exc.exception), -                    "GreenletChecker: Expected any type of greenlet, not " + type(p).__name__) - -        # First, not running -        g = RawGreenlet(bg) -        self.assertFalse(g) -        check(g) - -        # Then when running. -        g.switch() -        self.assertTrue(g) -        check(g) - -        # Let it finish -        g.switch() - - -    def test_trivial_cycle(self): -        glet = RawGreenlet(lambda: None) -        with self.assertRaises(ValueError) as exc: -            glet.parent = glet -        self.assertEqual(str(exc.exception), "cyclic parent chain") - -    def test_trivial_cycle_main(self): -        # This used to produce a ValueError, but we catch it earlier than that now. -        with self.assertRaises(AttributeError) as exc: -            greenlet.getcurrent().parent = greenlet.getcurrent() -        self.assertEqual(str(exc.exception), "cannot set the parent of a main greenlet") - -    def test_deeper_cycle(self): -        g1 = RawGreenlet(lambda: None) -        g2 = RawGreenlet(lambda: None) -        g3 = RawGreenlet(lambda: None) - -        g1.parent = g2 -        g2.parent = g3 -        with self.assertRaises(ValueError) as exc: -            g3.parent = g1 -        self.assertEqual(str(exc.exception), "cyclic parent chain") - - -class TestRepr(TestCase): - -    def assertEndsWith(self, got, suffix): -        self.assertTrue(got.endswith(suffix), (got, suffix)) - -    def test_main_while_running(self): -        r = repr(greenlet.getcurrent()) -        self.assertEndsWith(r, " current active started main>") - -    def test_main_in_background(self): -        main = greenlet.getcurrent() -        def run(): -            return repr(main) - -        g = RawGreenlet(run) -        r = g.switch() -        self.assertEndsWith(r, ' suspended active started main>') - -    def test_initial(self): -        r = repr(RawGreenlet()) -        self.assertEndsWith(r, ' pending>') - -    def test_main_from_other_thread(self): -        main = greenlet.getcurrent() - -        class T(threading.Thread): -            original_main = thread_main = None -            main_glet = None -            def run(self): -                self.original_main = repr(main) -                self.main_glet = greenlet.getcurrent() -                self.thread_main = repr(self.main_glet) - -        t = T() -        t.start() -        t.join(10) - -        self.assertEndsWith(t.original_main, ' suspended active started main>') -        self.assertEndsWith(t.thread_main, ' current active started main>') -        # give the machinery time to notice the death of the thread, -        # and clean it up. Note that we don't use -        # ``expect_greenlet_leak`` or wait_for_pending_cleanups, -        # because at this point we know we have an extra greenlet -        # still reachable. -        for _ in range(3): -            time.sleep(0.001) - -        # In the past, main greenlets, even from dead threads, never -        # really appear dead. We have fixed that, and we also report -        # that the thread is dead in the repr. (Do this multiple times -        # to make sure that we don't self-modify and forget our state -        # in the C++ code). -        for _ in range(3): -            self.assertTrue(t.main_glet.dead) -            r = repr(t.main_glet) -            self.assertEndsWith(r, ' (thread exited) dead>') - -    def test_dead(self): -        g = RawGreenlet(lambda: None) -        g.switch() -        self.assertEndsWith(repr(g), ' dead>') -        self.assertNotIn('suspended', repr(g)) -        self.assertNotIn('started', repr(g)) -        self.assertNotIn('active', repr(g)) - -    def test_formatting_produces_native_str(self): -        # https://github.com/python-greenlet/greenlet/issues/218 -        # %s formatting on Python 2 was producing unicode, not str. - -        g_dead = RawGreenlet(lambda: None) -        g_not_started = RawGreenlet(lambda: None) -        g_cur = greenlet.getcurrent() - -        for g in g_dead, g_not_started, g_cur: - -            self.assertIsInstance( -                '%s' % (g,), -                str -            ) -            self.assertIsInstance( -                '%r' % (g,), -                str, -            ) - - -class TestMainGreenlet(TestCase): -    # Tests some implementation details, and relies on some -    # implementation details. - -    def _check_current_is_main(self): -        # implementation detail -        assert 'main' in repr(greenlet.getcurrent()) - -        t = type(greenlet.getcurrent()) -        assert 'main' not in repr(t) -        return t - -    def test_main_greenlet_type_can_be_subclassed(self): -        main_type = self._check_current_is_main() -        subclass = type('subclass', (main_type,), {}) -        self.assertIsNotNone(subclass) - -    def test_main_greenlet_is_greenlet(self): -        self._check_current_is_main() -        self.assertIsInstance(greenlet.getcurrent(), RawGreenlet) - - - -class TestBrokenGreenlets(TestCase): -    # Tests for things that used to, or still do, terminate the interpreter. -    # This often means doing unsavory things. - -    def test_failed_to_initialstub(self): -        def func(): -            raise AssertionError("Never get here") - - -        g = greenlet._greenlet.UnswitchableGreenlet(func) -        g.force_switch_error = True - -        with self.assertRaisesRegex(SystemError, -                                    "Failed to switch stacks into a greenlet for the first time."): -            g.switch() - -    def test_failed_to_switch_into_running(self): -        runs = [] -        def func(): -            runs.append(1) -            greenlet.getcurrent().parent.switch() -            runs.append(2) -            greenlet.getcurrent().parent.switch() -            runs.append(3) # pragma: no cover - -        g = greenlet._greenlet.UnswitchableGreenlet(func) -        g.switch() -        self.assertEqual(runs, [1]) -        g.switch() -        self.assertEqual(runs, [1, 2]) -        g.force_switch_error = True - -        with self.assertRaisesRegex(SystemError, -                                    "Failed to switch stacks into a running greenlet."): -            g.switch() - -        # If we stopped here, we would fail the leakcheck, because we've left -        # the ``inner_bootstrap()`` C frame and its descendents hanging around, -        # which have a bunch of Python references. They'll never get cleaned up -        # if we don't let the greenlet finish. -        g.force_switch_error = False -        g.switch() -        self.assertEqual(runs, [1, 2, 3]) - -    def test_failed_to_slp_switch_into_running(self): -        ex = self.assertScriptRaises('fail_slp_switch.py') - -        self.assertIn('fail_slp_switch is running', ex.output) -        self.assertIn(ex.returncode, self.get_expected_returncodes_for_aborted_process()) - -    def test_reentrant_switch_two_greenlets(self): -        # Before we started capturing the arguments in g_switch_finish, this could crash. -        output = self.run_script('fail_switch_two_greenlets.py') -        self.assertIn('In g1_run', output) -        self.assertIn('TRACE', output) -        self.assertIn('LEAVE TRACE', output) -        self.assertIn('Falling off end of main', output) -        self.assertIn('Falling off end of g1_run', output) -        self.assertIn('Falling off end of g2', output) - -    def test_reentrant_switch_three_greenlets(self): -        # On debug builds of greenlet, this used to crash with an assertion error; -        # on non-debug versions, it ran fine (which it should not do!). -        # Now it always crashes correctly with a TypeError -        ex = self.assertScriptRaises('fail_switch_three_greenlets.py', exitcodes=(1,)) - -        self.assertIn('TypeError', ex.output) -        self.assertIn('positional arguments', ex.output) - -    def test_reentrant_switch_three_greenlets2(self): -        # This actually passed on debug and non-debug builds. It -        # should probably have been triggering some debug assertions -        # but it didn't. -        # -        # I think the fixes for the above test also kicked in here. -        output = self.run_script('fail_switch_three_greenlets2.py') -        self.assertIn( -            "RESULTS: [('trace', 'switch'), " -            "('trace', 'switch'), ('g2 arg', 'g2 from tracefunc'), " -            "('trace', 'switch'), ('main g1', 'from g2_run'), ('trace', 'switch'), " -            "('g1 arg', 'g1 from main'), ('trace', 'switch'), ('main g2', 'from g1_run'), " -            "('trace', 'switch'), ('g1 from parent', 'g1 from main 2'), ('trace', 'switch'), " -            "('main g1.2', 'g1 done'), ('trace', 'switch'), ('g2 from parent', ()), " -            "('trace', 'switch'), ('main g2.2', 'g2 done')]", -            output -        ) - -    def test_reentrant_switch_GreenletAlreadyStartedInPython(self): -        output = self.run_script('fail_initialstub_already_started.py') - -        self.assertIn( -            "RESULTS: ['Begin C', 'Switch to b from B.__getattribute__ in C', " -            "('Begin B', ()), '_B_run switching to main', ('main from c', 'From B'), " -            "'B.__getattribute__ back from main in C', ('Begin A', (None,)), " -            "('A dead?', True, 'B dead?', True, 'C dead?', False), " -            "'C done', ('main from c.2', None)]", -            output -        ) - -    def test_reentrant_switch_run_callable_has_del(self): -        output = self.run_script('fail_clearing_run_switches.py') -        self.assertIn( -             "RESULTS [" -            "('G.__getattribute__', 'run'), ('RunCallable', '__del__'), " -            "('main: g.switch()', 'from RunCallable'), ('run_func', 'enter')" -            "]", -            output -        ) - -if __name__ == '__main__': -    import unittest -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py deleted file mode 100644 index 8d9716e..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Tests for greenlets interacting with the CPython trash can API. - -The CPython trash can API is not designed to be re-entered from a -single thread. But this can happen using greenlets, if something -during the object deallocation process switches greenlets, and this second -greenlet then causes the trash can to get entered again. Here, we do this -very explicitly, but in other cases (like gevent) it could be arbitrarily more -complicated: for example, a weakref callback might try to acquire a lock that's -already held by another greenlet; that would allow a greenlet switch to occur. - -See https://github.com/gevent/gevent/issues/1909 - -This test is fragile and relies on details of the CPython -implementation (like most of the rest of this package): - -    - We enter the trashcan and deferred deallocation after -      ``_PyTrash_UNWIND_LEVEL`` calls. This constant, defined in -      CPython's object.c, is generally 50. That's basically how many objects are required to -      get us into the deferred deallocation situation. - -    - The test fails by hitting an ``assert()`` in object.c; if the -      build didn't enable assert, then we don't catch this. - -    - If the test fails in that way, the interpreter crashes. -""" -from __future__ import print_function, absolute_import, division - -import unittest - -class TestTrashCanReEnter(unittest.TestCase): - -    def test_it(self): -        # Try several times to trigger it, because it isn't 100% -        # reliable. -        for _ in range(10): -            self.check_it() - -    def check_it(self): # pylint:disable=too-many-statements -        import greenlet -        from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=no-name-in-module - -        main = greenlet.getcurrent() - -        assert get_tstate_trash_delete_nesting() == 0 - -        # We expect to be in deferred deallocation after this many -        # deallocations have occurred. TODO: I wish we had a better way to do -        # this --- that was before get_tstate_trash_delete_nesting; perhaps -        # we can use that API to do better? -        TRASH_UNWIND_LEVEL = 50 -        # How many objects to put in a container; it's the container that -        # queues objects for deferred deallocation. -        OBJECTS_PER_CONTAINER = 500 - -        class Dealloc: # define the class here because we alter class variables each time we run. -            """ -            An object with a ``__del__`` method. When it starts getting deallocated -            from a deferred trash can run, it switches greenlets, allocates more objects -            which then also go in the trash can. If we don't save state appropriately, -            nesting gets out of order and we can crash the interpreter. -            """ - -            #: Has our deallocation actually run and switched greenlets? -            #: When it does, this will be set to the current greenlet. This should -            #: be happening in the main greenlet, so we check that down below. -            SPAWNED = False - -            #: Has the background greenlet run? -            BG_RAN = False - -            BG_GLET = None - -            #: How many of these things have ever been allocated. -            CREATED = 0 - -            #: How many of these things have ever been deallocated. -            DESTROYED = 0 - -            #: How many were destroyed not in the main greenlet. There should always -            #: be some. -            #: If the test is broken or things change in the trashcan implementation, -            #: this may not be correct. -            DESTROYED_BG = 0 - -            def __init__(self, sequence_number): -                """ -                :param sequence_number: The ordinal of this object during -                   one particular creation run. This is used to detect (guess, really) -                   when we have entered the trash can's deferred deallocation. -                """ -                self.i = sequence_number -                Dealloc.CREATED += 1 - -            def __del__(self): -                if self.i == TRASH_UNWIND_LEVEL and not self.SPAWNED: -                    Dealloc.SPAWNED = greenlet.getcurrent() -                    other = Dealloc.BG_GLET = greenlet.greenlet(background_greenlet) -                    x = other.switch() -                    assert x == 42 -                    # It's important that we don't switch back to the greenlet, -                    # we leave it hanging there in an incomplete state. But we don't let it -                    # get collected, either. If we complete it now, while we're still -                    # in the scope of the initial trash can, things work out and we -                    # don't see the problem. We need this greenlet to complete -                    # at some point in the future, after we've exited this trash can invocation. -                    del other -                elif self.i == 40 and greenlet.getcurrent() is not main: -                    Dealloc.BG_RAN = True -                    try: -                        main.switch(42) -                    except greenlet.GreenletExit as ex: -                        # We expect this; all references to us go away -                        # while we're still running, and we need to finish deleting -                        # ourself. -                        Dealloc.BG_RAN = type(ex) -                        del ex - -                # Record the fact that we're dead last of all. This ensures that -                # we actually get returned too. -                Dealloc.DESTROYED += 1 -                if greenlet.getcurrent() is not main: -                    Dealloc.DESTROYED_BG += 1 - - -        def background_greenlet(): -            # We direct through a second function, instead of -            # directly calling ``make_some()``, so that we have complete -            # control over when these objects are destroyed: we need them -            # to be destroyed in the context of the background greenlet -            t = make_some() -            del t # Triggere deletion. - -        def make_some(): -            t = () -            i = OBJECTS_PER_CONTAINER -            while i: -                # Nest the tuples; it's the recursion that gets us -                # into trash. -                t = (Dealloc(i), t) -                i -= 1 -            return t - - -        some = make_some() -        self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER) -        self.assertEqual(Dealloc.DESTROYED, 0) - -        # If we're going to crash, it should be on the following line. -        # We only crash if ``assert()`` is enabled, of course. -        del some - -        # For non-debug builds of CPython, we won't crash. The best we can do is check -        # the nesting level explicitly. -        self.assertEqual(0, get_tstate_trash_delete_nesting()) - -        # Discard this, raising GreenletExit into where it is waiting. -        Dealloc.BG_GLET = None -        # The same nesting level maintains. -        self.assertEqual(0, get_tstate_trash_delete_nesting()) - -        # We definitely cleaned some up in the background -        self.assertGreater(Dealloc.DESTROYED_BG, 0) - -        # Make sure all the cleanups happened. -        self.assertIs(Dealloc.SPAWNED, main) -        self.assertTrue(Dealloc.BG_RAN) -        self.assertEqual(Dealloc.BG_RAN, greenlet.GreenletExit) -        self.assertEqual(Dealloc.CREATED, Dealloc.DESTROYED ) -        self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER * 2) - -        import gc -        gc.collect() - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_leaks.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_leaks.py deleted file mode 100644 index ed1fa71..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_leaks.py +++ /dev/null @@ -1,443 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Testing scenarios that may have leaked. -""" -from __future__ import print_function, absolute_import, division - -import sys -import gc - -import time -import weakref -import threading - - -import greenlet -from . import TestCase -from .leakcheck import fails_leakcheck -from .leakcheck import ignores_leakcheck -from .leakcheck import RUNNING_ON_MANYLINUX - -# pylint:disable=protected-access - -assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0 - -class HasFinalizerTracksInstances(object): -    EXTANT_INSTANCES = set() -    def __init__(self, msg): -        self.msg = sys.intern(msg) -        self.EXTANT_INSTANCES.add(id(self)) -    def __del__(self): -        self.EXTANT_INSTANCES.remove(id(self)) -    def __repr__(self): -        return "<HasFinalizerTracksInstances at 0x%x %r>" % ( -            id(self), self.msg -        ) -    @classmethod -    def reset(cls): -        cls.EXTANT_INSTANCES.clear() - - -class TestLeaks(TestCase): - -    def test_arg_refs(self): -        args = ('a', 'b', 'c') -        refcount_before = sys.getrefcount(args) -        # pylint:disable=unnecessary-lambda -        g = greenlet.greenlet( -            lambda *args: greenlet.getcurrent().parent.switch(*args)) -        for _ in range(100): -            g.switch(*args) -        self.assertEqual(sys.getrefcount(args), refcount_before) - -    def test_kwarg_refs(self): -        kwargs = {} -        # pylint:disable=unnecessary-lambda -        g = greenlet.greenlet( -            lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs)) -        for _ in range(100): -            g.switch(**kwargs) -        self.assertEqual(sys.getrefcount(kwargs), 2) - - -    @staticmethod -    def __recycle_threads(): -        # By introducing a thread that does sleep we allow other threads, -        # that have triggered their __block condition, but did not have a -        # chance to deallocate their thread state yet, to finally do so. -        # The way it works is by requiring a GIL switch (different thread), -        # which does a GIL release (sleep), which might do a GIL switch -        # to finished threads and allow them to clean up. -        def worker(): -            time.sleep(0.001) -        t = threading.Thread(target=worker) -        t.start() -        time.sleep(0.001) -        t.join(10) - -    def test_threaded_leak(self): -        gg = [] -        def worker(): -            # only main greenlet present -            gg.append(weakref.ref(greenlet.getcurrent())) -        for _ in range(2): -            t = threading.Thread(target=worker) -            t.start() -            t.join(10) -            del t -        greenlet.getcurrent() # update ts_current -        self.__recycle_threads() -        greenlet.getcurrent() # update ts_current -        gc.collect() -        greenlet.getcurrent() # update ts_current -        for g in gg: -            self.assertIsNone(g()) - -    def test_threaded_adv_leak(self): -        gg = [] -        def worker(): -            # main and additional *finished* greenlets -            ll = greenlet.getcurrent().ll = [] -            def additional(): -                ll.append(greenlet.getcurrent()) -            for _ in range(2): -                greenlet.greenlet(additional).switch() -            gg.append(weakref.ref(greenlet.getcurrent())) -        for _ in range(2): -            t = threading.Thread(target=worker) -            t.start() -            t.join(10) -            del t -        greenlet.getcurrent() # update ts_current -        self.__recycle_threads() -        greenlet.getcurrent() # update ts_current -        gc.collect() -        greenlet.getcurrent() # update ts_current -        for g in gg: -            self.assertIsNone(g()) - -    def assertClocksUsed(self): -        used = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() -        self.assertGreaterEqual(used, 0) -        # we don't lose the value -        greenlet._greenlet.enable_optional_cleanup(True) -        used2 = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() -        self.assertEqual(used, used2) -        self.assertGreater(greenlet._greenlet.CLOCKS_PER_SEC, 1) - -    def _check_issue251(self, -                        manually_collect_background=True, -                        explicit_reference_to_switch=False): -        # See https://github.com/python-greenlet/greenlet/issues/251 -        # Killing a greenlet (probably not the main one) -        # in one thread from another thread would -        # result in leaking a list (the ts_delkey list). -        # We no longer use lists to hold that stuff, though. - -        # For the test to be valid, even empty lists have to be tracked by the -        # GC - -        assert gc.is_tracked([]) -        HasFinalizerTracksInstances.reset() -        greenlet.getcurrent() -        greenlets_before = self.count_objects(greenlet.greenlet, exact_kind=False) - -        background_glet_running = threading.Event() -        background_glet_killed = threading.Event() -        background_greenlets = [] - -        # XXX: Switching this to a greenlet subclass that overrides -        # run results in all callers failing the leaktest; that -        # greenlet instance is leaked. There's a bound method for -        # run() living on the stack of the greenlet in g_initialstub, -        # and since we don't manually switch back to the background -        # greenlet to let it "fall off the end" and exit the -        # g_initialstub function, it never gets cleaned up. Making the -        # garbage collector aware of this bound method (making it an -        # attribute of the greenlet structure and traversing into it) -        # doesn't help, for some reason. -        def background_greenlet(): -            # Throw control back to the main greenlet. -            jd = HasFinalizerTracksInstances("DELETING STACK OBJECT") -            greenlet._greenlet.set_thread_local( -                'test_leaks_key', -                HasFinalizerTracksInstances("DELETING THREAD STATE")) -            # Explicitly keeping 'switch' in a local variable -            # breaks this test in all versions -            if explicit_reference_to_switch: -                s = greenlet.getcurrent().parent.switch -                s([jd]) -            else: -                greenlet.getcurrent().parent.switch([jd]) - -        bg_main_wrefs = [] - -        def background_thread(): -            glet = greenlet.greenlet(background_greenlet) -            bg_main_wrefs.append(weakref.ref(glet.parent)) - -            background_greenlets.append(glet) -            glet.switch() # Be sure it's active. -            # Control is ours again. -            del glet # Delete one reference from the thread it runs in. -            background_glet_running.set() -            background_glet_killed.wait(10) - -            # To trigger the background collection of the dead -            # greenlet, thus clearing out the contents of the list, we -            # need to run some APIs. See issue 252. -            if manually_collect_background: -                greenlet.getcurrent() - - -        t = threading.Thread(target=background_thread) -        t.start() -        background_glet_running.wait(10) -        greenlet.getcurrent() -        lists_before = self.count_objects(list, exact_kind=True) - -        assert len(background_greenlets) == 1 -        self.assertFalse(background_greenlets[0].dead) -        # Delete the last reference to the background greenlet -        # from a different thread. This puts it in the background thread's -        # ts_delkey list. -        del background_greenlets[:] -        background_glet_killed.set() - -        # Now wait for the background thread to die. -        t.join(10) -        del t -        # As part of the fix for 252, we need to cycle the ceval.c -        # interpreter loop to be sure it has had a chance to process -        # the pending call. -        self.wait_for_pending_cleanups() - -        lists_after = self.count_objects(list, exact_kind=True) -        greenlets_after = self.count_objects(greenlet.greenlet, exact_kind=False) - -        # On 2.7, we observe that lists_after is smaller than -        # lists_before. No idea what lists got cleaned up. All the -        # Python 3 versions match exactly. -        self.assertLessEqual(lists_after, lists_before) -        # On versions after 3.6, we've successfully cleaned up the -        # greenlet references thanks to the internal "vectorcall" -        # protocol; prior to that, there is a reference path through -        # the ``greenlet.switch`` method still on the stack that we -        # can't reach to clean up. The C code goes through terrific -        # lengths to clean that up. -        if not explicit_reference_to_switch \ -           and greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: -            # If cleanup was disabled, though, we may not find it. -            self.assertEqual(greenlets_after, greenlets_before) -            if manually_collect_background: -                # TODO: Figure out how to make this work! -                # The one on the stack is still leaking somehow -                # in the non-manually-collect state. -                self.assertEqual(HasFinalizerTracksInstances.EXTANT_INSTANCES, set()) -        else: -            # The explicit reference prevents us from collecting it -            # and it isn't always found by the GC either for some -            # reason. The entire frame is leaked somehow, on some -            # platforms (e.g., MacPorts builds of Python (all -            # versions!)), but not on other platforms (the linux and -            # windows builds on GitHub actions and Appveyor). So we'd -            # like to write a test that proves that the main greenlet -            # sticks around, and we can on my machine (macOS 11.6, -            # MacPorts builds of everything) but we can't write that -            # same test on other platforms. However, hopefully iteration -            # done by leakcheck will find it. -            pass - -        if greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: -            self.assertClocksUsed() - -    def test_issue251_killing_cross_thread_leaks_list(self): -        self._check_issue251() - -    def test_issue251_with_cleanup_disabled(self): -        greenlet._greenlet.enable_optional_cleanup(False) -        try: -            self._check_issue251() -        finally: -            greenlet._greenlet.enable_optional_cleanup(True) - -    @fails_leakcheck -    def test_issue251_issue252_need_to_collect_in_background(self): -        # Between greenlet 1.1.2 and the next version, this was still -        # failing because the leak of the list still exists when we -        # don't call a greenlet API before exiting the thread. The -        # proximate cause is that neither of the two greenlets from -        # the background thread are actually being destroyed, even -        # though the GC is in fact visiting both objects. It's not -        # clear where that leak is? For some reason the thread-local -        # dict holding it isn't being cleaned up. -        # -        # The leak, I think, is in the CPYthon internal function that -        # calls into green_switch(). The argument tuple is still on -        # the C stack somewhere and can't be reached? That doesn't -        # make sense, because the tuple should be collectable when -        # this object goes away. -        # -        # Note that this test sometimes spuriously passes on Linux, -        # for some reason, but I've never seen it pass on macOS. -        self._check_issue251(manually_collect_background=False) - -    @fails_leakcheck -    def test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self): -        self.expect_greenlet_leak = True -        greenlet._greenlet.enable_optional_cleanup(False) -        try: -            self._check_issue251(manually_collect_background=False) -        finally: -            greenlet._greenlet.enable_optional_cleanup(True) - -    @fails_leakcheck -    def test_issue251_issue252_explicit_reference_not_collectable(self): -        self._check_issue251( -            manually_collect_background=False, -            explicit_reference_to_switch=True) - -    UNTRACK_ATTEMPTS = 100 - -    def _only_test_some_versions(self): -        # We're only looking for this problem specifically on 3.11, -        # and this set of tests is relatively fragile, depending on -        # OS and memory management details. So we want to run it on 3.11+ -        # (obviously) but not every older 3.x version in order to reduce -        # false negatives. At the moment, those false results seem to have -        # resolved, so we are actually running this on 3.8+ -        assert sys.version_info[0] >= 3 -        if sys.version_info[:2] < (3, 8): -            self.skipTest('Only observed on 3.11') -        if RUNNING_ON_MANYLINUX: -            self.skipTest("Slow and not worth repeating here") - -    @ignores_leakcheck -    # Because we're just trying to track raw memory, not objects, and running -    # the leakcheck makes an already slow test slower. -    def test_untracked_memory_doesnt_increase(self): -        # See https://github.com/gevent/gevent/issues/1924 -        # and https://github.com/python-greenlet/greenlet/issues/328 -        self._only_test_some_versions() -        def f(): -            return 1 - -        ITER = 10000 -        def run_it(): -            for _ in range(ITER): -                greenlet.greenlet(f).switch() - -        # Establish baseline -        for _ in range(3): -            run_it() - -        # uss: (Linux, macOS, Windows): aka "Unique Set Size", this is -        # the memory which is unique to a process and which would be -        # freed if the process was terminated right now. -        uss_before = self.get_process_uss() - -        for count in range(self.UNTRACK_ATTEMPTS): -            uss_before = max(uss_before, self.get_process_uss()) -            run_it() - -            uss_after = self.get_process_uss() -            if uss_after <= uss_before and count > 1: -                break - -        self.assertLessEqual(uss_after, uss_before) - -    def _check_untracked_memory_thread(self, deallocate_in_thread=True): -        self._only_test_some_versions() -        # Like the above test, but what if there are a bunch of -        # unfinished greenlets in a thread that dies? -        # Does it matter if we deallocate in the thread or not? -        EXIT_COUNT = [0] - -        def f(): -            try: -                greenlet.getcurrent().parent.switch() -            except greenlet.GreenletExit: -                EXIT_COUNT[0] += 1 -                raise -            return 1 - -        ITER = 10000 -        def run_it(): -            glets = [] -            for _ in range(ITER): -                # Greenlet starts, switches back to us. -                # We keep a strong reference to the greenlet though so it doesn't -                # get a GreenletExit exception. -                g = greenlet.greenlet(f) -                glets.append(g) -                g.switch() - -            return glets - -        test = self - -        class ThreadFunc: -            uss_before = uss_after = 0 -            glets = () -            ITER = 2 -            def __call__(self): -                self.uss_before = test.get_process_uss() - -                for _ in range(self.ITER): -                    self.glets += tuple(run_it()) - -                for g in self.glets: -                    test.assertIn('suspended active', str(g)) -                # Drop them. -                if deallocate_in_thread: -                    self.glets = () -                self.uss_after = test.get_process_uss() - -        # Establish baseline -        uss_before = uss_after = None -        for count in range(self.UNTRACK_ATTEMPTS): -            EXIT_COUNT[0] = 0 -            thread_func = ThreadFunc() -            t = threading.Thread(target=thread_func) -            t.start() -            t.join(30) -            self.assertFalse(t.is_alive()) - -            if uss_before is None: -                uss_before = thread_func.uss_before - -            uss_before = max(uss_before, thread_func.uss_before) -            if deallocate_in_thread: -                self.assertEqual(thread_func.glets, ()) -                self.assertEqual(EXIT_COUNT[0], ITER * thread_func.ITER) - -            del thread_func # Deallocate the greenlets; but this won't raise into them -            del t -            if not deallocate_in_thread: -                self.assertEqual(EXIT_COUNT[0], 0) -            if deallocate_in_thread: -                self.wait_for_pending_cleanups() - -            uss_after = self.get_process_uss() -            # See if we achieve a non-growth state at some point. Break when we do. -            if uss_after <= uss_before and count > 1: -                break - -        self.wait_for_pending_cleanups() -        uss_after = self.get_process_uss() -        self.assertLessEqual(uss_after, uss_before, "after attempts %d" % (count,)) - -    @ignores_leakcheck -    # Because we're just trying to track raw memory, not objects, and running -    # the leakcheck makes an already slow test slower. -    def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_thread(self): -        self._check_untracked_memory_thread(deallocate_in_thread=True) - -    @ignores_leakcheck -    # Because the main greenlets from the background threads do not exit in a timely fashion, -    # we fail the object-based leakchecks. -    def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main(self): -        self._check_untracked_memory_thread(deallocate_in_thread=False) - -if __name__ == '__main__': -    __import__('unittest').main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py deleted file mode 100644 index b362bf9..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py +++ /dev/null @@ -1,19 +0,0 @@ -import greenlet -from . import TestCase - - -class Test(TestCase): - -    def test_stack_saved(self): -        main = greenlet.getcurrent() -        self.assertEqual(main._stack_saved, 0) - -        def func(): -            main.switch(main._stack_saved) - -        g = greenlet.greenlet(func) -        x = g.switch() -        self.assertGreater(x, 0) -        self.assertGreater(g._stack_saved, 0) -        g.switch() -        self.assertEqual(g._stack_saved, 0) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_throw.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_throw.py deleted file mode 100644 index f4f9a14..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_throw.py +++ /dev/null @@ -1,128 +0,0 @@ -import sys - - -from greenlet import greenlet -from . import TestCase - -def switch(*args): -    return greenlet.getcurrent().parent.switch(*args) - - -class ThrowTests(TestCase): -    def test_class(self): -        def f(): -            try: -                switch("ok") -            except RuntimeError: -                switch("ok") -                return -            switch("fail") -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw(RuntimeError) -        self.assertEqual(res, "ok") - -    def test_val(self): -        def f(): -            try: -                switch("ok") -            except RuntimeError: -                val = sys.exc_info()[1] -                if str(val) == "ciao": -                    switch("ok") -                    return -            switch("fail") - -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw(RuntimeError("ciao")) -        self.assertEqual(res, "ok") - -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw(RuntimeError, "ciao") -        self.assertEqual(res, "ok") - -    def test_kill(self): -        def f(): -            switch("ok") -            switch("fail") -        g = greenlet(f) -        res = g.switch() -        self.assertEqual(res, "ok") -        res = g.throw() -        self.assertTrue(isinstance(res, greenlet.GreenletExit)) -        self.assertTrue(g.dead) -        res = g.throw()    # immediately eaten by the already-dead greenlet -        self.assertTrue(isinstance(res, greenlet.GreenletExit)) - -    def test_throw_goes_to_original_parent(self): -        main = greenlet.getcurrent() - -        def f1(): -            try: -                main.switch("f1 ready to catch") -            except IndexError: -                return "caught" -            return "normal exit" - -        def f2(): -            main.switch("from f2") - -        g1 = greenlet(f1) -        g2 = greenlet(f2, parent=g1) -        with self.assertRaises(IndexError): -            g2.throw(IndexError) -        self.assertTrue(g2.dead) -        self.assertTrue(g1.dead) - -        g1 = greenlet(f1) -        g2 = greenlet(f2, parent=g1) -        res = g1.switch() -        self.assertEqual(res, "f1 ready to catch") -        res = g2.throw(IndexError) -        self.assertEqual(res, "caught") -        self.assertTrue(g2.dead) -        self.assertTrue(g1.dead) - -        g1 = greenlet(f1) -        g2 = greenlet(f2, parent=g1) -        res = g1.switch() -        self.assertEqual(res, "f1 ready to catch") -        res = g2.switch() -        self.assertEqual(res, "from f2") -        res = g2.throw(IndexError) -        self.assertEqual(res, "caught") -        self.assertTrue(g2.dead) -        self.assertTrue(g1.dead) - -    def test_non_traceback_param(self): -        with self.assertRaises(TypeError) as exc: -            greenlet.getcurrent().throw( -                Exception, -                Exception(), -                self -            ) -        self.assertEqual(str(exc.exception), -                         "throw() third argument must be a traceback object") - -    def test_instance_of_wrong_type(self): -        with self.assertRaises(TypeError) as exc: -            greenlet.getcurrent().throw( -                Exception(), -                BaseException() -            ) - -        self.assertEqual(str(exc.exception), -                         "instance exception may not have a separate value") - -    def test_not_throwable(self): -        with self.assertRaises(TypeError) as exc: -            greenlet.getcurrent().throw( -                "abc" -            ) -        self.assertEqual(str(exc.exception), -                         "exceptions must be classes, or instances, not str") diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_tracing.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_tracing.py deleted file mode 100644 index c044d4b..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_tracing.py +++ /dev/null @@ -1,291 +0,0 @@ -from __future__ import print_function -import sys -import greenlet -import unittest - -from . import TestCase -from . import PY312 - -# https://discuss.python.org/t/cpython-3-12-greenlet-and-tracing-profiling-how-to-not-crash-and-get-correct-results/33144/2 -DEBUG_BUILD_PY312 = ( -    PY312 and hasattr(sys, 'gettotalrefcount'), -    "Broken on debug builds of Python 3.12" -) - -class SomeError(Exception): -    pass - -class GreenletTracer(object): -    oldtrace = None - -    def __init__(self, error_on_trace=False): -        self.actions = [] -        self.error_on_trace = error_on_trace - -    def __call__(self, *args): -        self.actions.append(args) -        if self.error_on_trace: -            raise SomeError - -    def __enter__(self): -        self.oldtrace = greenlet.settrace(self) -        return self.actions - -    def __exit__(self, *args): -        greenlet.settrace(self.oldtrace) - - -class TestGreenletTracing(TestCase): -    """ -    Tests of ``greenlet.settrace()`` -    """ - -    def test_a_greenlet_tracing(self): -        main = greenlet.getcurrent() -        def dummy(): -            pass -        def dummyexc(): -            raise SomeError() - -        with GreenletTracer() as actions: -            g1 = greenlet.greenlet(dummy) -            g1.switch() -            g2 = greenlet.greenlet(dummyexc) -            self.assertRaises(SomeError, g2.switch) - -        self.assertEqual(actions, [ -            ('switch', (main, g1)), -            ('switch', (g1, main)), -            ('switch', (main, g2)), -            ('throw', (g2, main)), -        ]) - -    def test_b_exception_disables_tracing(self): -        main = greenlet.getcurrent() -        def dummy(): -            main.switch() -        g = greenlet.greenlet(dummy) -        g.switch() -        with GreenletTracer(error_on_trace=True) as actions: -            self.assertRaises(SomeError, g.switch) -            self.assertEqual(greenlet.gettrace(), None) - -        self.assertEqual(actions, [ -            ('switch', (main, g)), -        ]) - -    def test_set_same_tracer_twice(self): -        # https://github.com/python-greenlet/greenlet/issues/332 -        # Our logic in asserting that the tracefunction should -        # gain a reference was incorrect if the same tracefunction was set -        # twice. -        tracer = GreenletTracer() -        with tracer: -            greenlet.settrace(tracer) - - -class PythonTracer(object): -    oldtrace = None - -    def __init__(self): -        self.actions = [] - -    def __call__(self, frame, event, arg): -        # Record the co_name so we have an idea what function we're in. -        self.actions.append((event, frame.f_code.co_name)) - -    def __enter__(self): -        self.oldtrace = sys.setprofile(self) -        return self.actions - -    def __exit__(self, *args): -        sys.setprofile(self.oldtrace) - -def tpt_callback(): -    return 42 - -class TestPythonTracing(TestCase): -    """ -    Tests of the interaction of ``sys.settrace()`` -    with greenlet facilities. - -    NOTE: Most of this is probably CPython specific. -    """ - -    maxDiff = None - -    def test_trace_events_trivial(self): -        with PythonTracer() as actions: -            tpt_callback() -        # If we use the sys.settrace instead of setprofile, we get -        # this: - -        # self.assertEqual(actions, [ -        #     ('call', 'tpt_callback'), -        #     ('call', '__exit__'), -        # ]) - -        self.assertEqual(actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - -    def _trace_switch(self, glet): -        with PythonTracer() as actions: -            glet.switch() -        return actions - -    def _check_trace_events_func_already_set(self, glet): -        actions = self._trace_switch(glet) -        self.assertEqual(actions, [ -            ('return', '__enter__'), -            ('c_call', '_trace_switch'), -            ('call', 'run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('return', 'run'), -            ('c_return', '_trace_switch'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - -    def test_trace_events_into_greenlet_func_already_set(self): -        def run(): -            return tpt_callback() - -        self._check_trace_events_func_already_set(greenlet.greenlet(run)) - -    def test_trace_events_into_greenlet_subclass_already_set(self): -        class X(greenlet.greenlet): -            def run(self): -                return tpt_callback() -        self._check_trace_events_func_already_set(X()) - -    def _check_trace_events_from_greenlet_sets_profiler(self, g, tracer): -        g.switch() -        tpt_callback() -        tracer.__exit__() -        self.assertEqual(tracer.actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('return', 'run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - - -    def test_trace_events_from_greenlet_func_sets_profiler(self): -        tracer = PythonTracer() -        def run(): -            tracer.__enter__() -            return tpt_callback() - -        self._check_trace_events_from_greenlet_sets_profiler(greenlet.greenlet(run), -                                                             tracer) - -    def test_trace_events_from_greenlet_subclass_sets_profiler(self): -        tracer = PythonTracer() -        class X(greenlet.greenlet): -            def run(self): -                tracer.__enter__() -                return tpt_callback() - -        self._check_trace_events_from_greenlet_sets_profiler(X(), tracer) - -    @unittest.skipIf(*DEBUG_BUILD_PY312) -    def test_trace_events_multiple_greenlets_switching(self): -        tracer = PythonTracer() - -        g1 = None -        g2 = None - -        def g1_run(): -            tracer.__enter__() -            tpt_callback() -            g2.switch() -            tpt_callback() -            return 42 - -        def g2_run(): -            tpt_callback() -            tracer.__exit__() -            tpt_callback() -            g1.switch() - -        g1 = greenlet.greenlet(g1_run) -        g2 = greenlet.greenlet(g2_run) - -        x = g1.switch() -        self.assertEqual(x, 42) -        tpt_callback() # ensure not in the trace -        self.assertEqual(tracer.actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('c_call', 'g1_run'), -            ('call', 'g2_run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - -    @unittest.skipIf(*DEBUG_BUILD_PY312) -    def test_trace_events_multiple_greenlets_switching_siblings(self): -        # Like the first version, but get both greenlets running first -        # as "siblings" and then establish the tracing. -        tracer = PythonTracer() - -        g1 = None -        g2 = None - -        def g1_run(): -            greenlet.getcurrent().parent.switch() -            tracer.__enter__() -            tpt_callback() -            g2.switch() -            tpt_callback() -            return 42 - -        def g2_run(): -            greenlet.getcurrent().parent.switch() - -            tpt_callback() -            tracer.__exit__() -            tpt_callback() -            g1.switch() - -        g1 = greenlet.greenlet(g1_run) -        g2 = greenlet.greenlet(g2_run) - -        # Start g1 -        g1.switch() -        # And it immediately returns control to us. -        # Start g2 -        g2.switch() -        # Which also returns. Now kick of the real part of the -        # test. -        x = g1.switch() -        self.assertEqual(x, 42) - -        tpt_callback() # ensure not in the trace -        self.assertEqual(tracer.actions, [ -            ('return', '__enter__'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('c_call', 'g1_run'), -            ('call', 'tpt_callback'), -            ('return', 'tpt_callback'), -            ('call', '__exit__'), -            ('c_call', '__exit__'), -        ]) - - -if __name__ == '__main__': -    unittest.main() diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_version.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_version.py deleted file mode 100644 index 96c17cf..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_version.py +++ /dev/null @@ -1,41 +0,0 @@ -#! /usr/bin/env python -from __future__ import absolute_import -from __future__ import print_function - -import sys -import os -from unittest import TestCase as NonLeakingTestCase - -import greenlet - -# No reason to run this multiple times under leakchecks, -# it doesn't do anything. -class VersionTests(NonLeakingTestCase): -    def test_version(self): -        def find_dominating_file(name): -            if os.path.exists(name): -                return name - -            tried = [] -            here = os.path.abspath(os.path.dirname(__file__)) -            for i in range(10): -                up = ['..'] * i -                path = [here] + up + [name] -                fname = os.path.join(*path) -                fname = os.path.abspath(fname) -                tried.append(fname) -                if os.path.exists(fname): -                    return fname -            raise AssertionError("Could not find file " + name + "; checked " + str(tried)) - -        try: -            setup_py = find_dominating_file('setup.py') -        except AssertionError as e: -            self.skipTest("Unable to find setup.py; must be out of tree. " + str(e)) - - -        invoke_setup = "%s %s --version" % (sys.executable, setup_py) -        with os.popen(invoke_setup) as f: -            sversion = f.read().strip() - -        self.assertEqual(sversion, greenlet.__version__) diff --git a/venv/lib/python3.11/site-packages/greenlet/tests/test_weakref.py b/venv/lib/python3.11/site-packages/greenlet/tests/test_weakref.py deleted file mode 100644 index 05a38a7..0000000 --- a/venv/lib/python3.11/site-packages/greenlet/tests/test_weakref.py +++ /dev/null @@ -1,35 +0,0 @@ -import gc -import weakref - - -import greenlet -from . import TestCase - -class WeakRefTests(TestCase): -    def test_dead_weakref(self): -        def _dead_greenlet(): -            g = greenlet.greenlet(lambda: None) -            g.switch() -            return g -        o = weakref.ref(_dead_greenlet()) -        gc.collect() -        self.assertEqual(o(), None) - -    def test_inactive_weakref(self): -        o = weakref.ref(greenlet.greenlet()) -        gc.collect() -        self.assertEqual(o(), None) - -    def test_dealloc_weakref(self): -        seen = [] -        def worker(): -            try: -                greenlet.getcurrent().parent.switch() -            finally: -                seen.append(g()) -        g = greenlet.greenlet(worker) -        g.switch() -        g2 = greenlet.greenlet(lambda: None, g) -        g = weakref.ref(g2) -        g2 = None -        self.assertEqual(seen, [None]) | 
