Skip to content

Commit

Permalink
Clean up initialization/creation of greenlets.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Sep 16, 2024
1 parent 6105b1a commit 9216e63
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 58 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
3.1.1 (unreleased)
==================

- Fix crashes on 32-bit PPC Linux.
- Fix crashes on 32-bit PPC Linux. Note that there is no CI for this,
and support is best effort; there may be other issues lurking.
See `issue 422
<https://github.com/python-greenlet/greenlet/issues/422>`_.
- Remove unnecessary logging sometimes during interpreter shutdown.
Expand Down
16 changes: 0 additions & 16 deletions src/greenlet/PyGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,6 @@ using greenlet::BrokenGreenlet;
using greenlet::ThreadState;
using greenlet::PythonState;

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;
}


static PyGreenlet*
Expand Down
1 change: 0 additions & 1 deletion src/greenlet/PyGreenlet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ using greenlet::refs::PyErrPieces;


// XXX: These doesn't really belong here, it's not a Python slot.
static PyGreenlet* green_create_main(greenlet::ThreadState* state);
static OwnedObject internal_green_throw(BorrowedGreenlet self, PyErrPieces& err_pieces);

static PyGreenlet* green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds));
Expand Down
18 changes: 9 additions & 9 deletions src/greenlet/TGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@
namespace greenlet {

Greenlet::Greenlet(PyGreenlet* p)
: Greenlet(p, StackState())
{
p ->pimpl = this;
}

Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack)
: _self(p), stack_state(initial_stack)
{
assert(p->pimpl == nullptr);
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;
this->_self->pimpl = nullptr;
}

bool
Expand Down
11 changes: 7 additions & 4 deletions src/greenlet/TGreenlet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ namespace greenlet
{
private:
G_NO_COPIES_OF_CLS(Greenlet);
PyGreenlet* const _self;
private:
// XXX: Work to remove these.
friend class ThreadState;
Expand All @@ -331,6 +332,8 @@ namespace greenlet
PythonState python_state;
Greenlet(PyGreenlet* p, const StackState& initial_state);
public:
// This constructor takes ownership of the PyGreenlet, by
// setting ``p->pimpl = this;``.
Greenlet(PyGreenlet* p);
virtual ~Greenlet();

Expand Down Expand Up @@ -461,7 +464,10 @@ namespace greenlet

// Return a borrowed greenlet that is the Python object
// this object represents.
virtual BorrowedGreenlet self() const noexcept = 0;
inline BorrowedGreenlet self() const noexcept
{
return BorrowedGreenlet(this->_self);
}

// For testing. If this returns true, we should pretend that
// slp_switch() failed.
Expand Down Expand Up @@ -645,7 +651,6 @@ class TracingGuard
{
private:
static greenlet::PythonAllocator<UserGreenlet> allocator;
BorrowedGreenlet _self;
OwnedMainGreenlet _main_greenlet;
OwnedObject _run_callable;
OwnedGreenlet _parent;
Expand Down Expand Up @@ -674,7 +679,6 @@ class TracingGuard

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);
Expand Down Expand Up @@ -748,7 +752,6 @@ class TracingGuard
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);
};

Expand Down
6 changes: 0 additions & 6 deletions src/greenlet/TMainGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,6 @@ MainGreenlet::thread_state(ThreadState* t) noexcept
this->_thread_state = t;
}

BorrowedGreenlet
MainGreenlet::self() const noexcept
{
return BorrowedGreenlet(this->_self.borrow());
}


const BorrowedMainGreenlet
MainGreenlet::main_greenlet() const
Expand Down
12 changes: 2 additions & 10 deletions src/greenlet/TUserGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ void UserGreenlet::operator delete(void* ptr)
UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent)
: Greenlet(p), _parent(the_parent)
{
this->_self = p;
}

UserGreenlet::~UserGreenlet()
Expand All @@ -50,13 +49,6 @@ UserGreenlet::~UserGreenlet()
this->tp_clear();
}

BorrowedGreenlet
UserGreenlet::self() const noexcept
{
return this->_self;
}



const BorrowedMainGreenlet
UserGreenlet::main_greenlet() const
Expand Down Expand Up @@ -240,7 +232,7 @@ UserGreenlet::g_initialstub(void* mark)
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);
run = this->self().PyRequireAttr(mod_globs->str_run);
/* restore saved exception */
saved.PyErrRestore();

Expand Down Expand Up @@ -600,7 +592,7 @@ UserGreenlet::parent(const BorrowedObject raw_new_parent)
// throw
// TypeError!
for (BorrowedGreenlet p = new_parent; p; p = p->parent()) {
if (p == this->_self) {
if (p == this->self()) {
throw ValueError("cyclic parent chain");
}
main_greenlet_of_new_parent = p->main_greenlet();
Expand Down
3 changes: 1 addition & 2 deletions src/greenlet/greenlet_internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ greenlet::refs::MainGreenletExactChecker(void *p)
// 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;
Greenlet* g = static_cast<PyGreenlet*>(p)->pimpl;
if (g->main()) {
return;
}
Expand Down Expand Up @@ -88,7 +88,6 @@ 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);

Expand Down
42 changes: 33 additions & 9 deletions src/greenlet/greenlet_thread_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ class ThreadState {

G_NO_COPIES_OF_CLS(ThreadState);


// Allocates a main greenlet for the thread state. If this fails,
// exits the process. Called only during constructing a ThreadState.
MainGreenlet* alloc_main()
{
PyGreenlet* gmain;

/* create the main greenlet for this thread */
gmain = reinterpret_cast<PyGreenlet*>(PyType_GenericAlloc(&PyGreenlet_Type, 0));
if (gmain == NULL) {
throw PyFatalError("alloc_main failed to alloc"); //exits the process
}

MainGreenlet* const main = new MainGreenlet(gmain, this);

assert(Py_REFCNT(gmain) == 1);
assert(gmain->pimpl == main);
return main;
}


public:
static void* operator new(size_t UNUSED(count))
{
Expand All @@ -143,20 +164,23 @@ class ThreadState {
}

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

// XXX: Potentially dangerous, exposing a not fully
// constructed object.
MainGreenlet* const main = this->alloc_main();
this->main_greenlet = OwnedMainGreenlet::consuming(
main->self()
);
assert(this->main_greenlet);
this->current_greenlet = main->self();
// The main greenlet starts with 1 refs: The returned one. We
// then copied it to the current greenlet.
assert(this->main_greenlet.REFCNT() == 2);
}

inline void restore_exception_state()
Expand Down

0 comments on commit 9216e63

Please sign in to comment.