Skip to content

Commit

Permalink
Merge pull request #276 from python-greenlet/issue264
Browse files Browse the repository at this point in the history
Drop the separate PyMainGreenlet type
  • Loading branch information
jamadden committed Nov 16, 2021
2 parents c0086ea + 1353150 commit 0145f05
Show file tree
Hide file tree
Showing 8 changed files with 528 additions and 401 deletions.
477 changes: 311 additions & 166 deletions src/greenlet/greenlet.cpp

Large diffs are not rendered by default.

16 changes: 1 addition & 15 deletions src/greenlet/greenlet_allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <Python.h>
#include <memory>
#include "greenlet_compiler_compat.hpp"
// #include <iostream>


namespace greenlet
{
Expand Down Expand Up @@ -33,13 +33,6 @@ namespace greenlet

T* allocate(size_t number_objects, const void* UNUSED(hint)=0)
{
// using std::cerr;
// using std::endl;

// cerr << "Allocating " << number_objects
// << " at " << UNUSED_hint
// << " from " << typeid(this).name()
// << endl;
void* p;
if (number_objects == 1)
p = PyObject_Malloc(sizeof(T));
Expand All @@ -50,13 +43,6 @@ namespace greenlet

void deallocate(T* t, size_t n)
{
// using std::cerr;
// using std::endl;
// cerr << "Deallocating " << n
// << " at " << t
// << " of " << typeid(t).name()
// << " from " << typeid(this).name()
// << endl;
void* p = t;
if (n == 1) {
PyObject_Free(p);
Expand Down
3 changes: 0 additions & 3 deletions src/greenlet/greenlet_cpython_compat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
// based on the Python version. Write both versions of the function,
// one with the WHEN version, one with the WHEN_NOT version.
// Instantiate the template using the G_IS_PY37 macro.
// NOTE: The compiler still sees (and type checks) both versions, apparently, even when
// not instantiated? I didn't think that was how expansion worked, if
// one template is never needed.
struct GREENLET_WHEN_PY37
{
typedef GREENLET_WHEN_PY37* Yes;
Expand Down
190 changes: 124 additions & 66 deletions src/greenlet/greenlet_greenlet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,32 +284,26 @@ namespace greenlet

class ThreadState;

class UserGreenlet;
class MainGreenlet;

class Greenlet
{
private:
static greenlet::PythonAllocator<Greenlet> allocator;
G_NO_COPIES_OF_CLS(Greenlet);
private:
friend class ThreadState; // XXX: Work to remove this.
// XXX: Work to remove these.
friend class ThreadState;
friend class UserGreenlet;
friend class MainGreenlet;
protected:
ExceptionState exception_state;
SwitchingArgs switch_args;
OwnedGreenlet _parent;
PythonState python_state;
OwnedObject _run_callable;
StackState stack_state;
protected:
// The main greenlet subclass accesses `self` and `main_greenlet` once or twice.
// But see the comment where it does. This is probably
// factored wrong.
BorrowedGreenlet self;
OwnedMainGreenlet main_greenlet;
Greenlet(PyGreenlet* p, BorrowedGreenlet the_parent, const StackState& initial_state);

PythonState python_state;
Greenlet(PyGreenlet* p, const StackState& initial_state);
public:
static void* operator new(size_t UNUSED(count));
static void operator delete(void* ptr);

Greenlet(PyGreenlet* p, BorrowedGreenlet the_parent);
Greenlet(PyGreenlet* p);
virtual ~Greenlet();

template <typename IsPy37> // maybe we can use a value here?
Expand All @@ -323,6 +317,8 @@ namespace greenlet
return this->switch_args;
}

virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0;

inline intptr_t stack_saved() const G_NOEXCEPT
{
return this->stack_state.stack_saved();
Expand All @@ -338,15 +334,15 @@ namespace greenlet
return this->stack_state.stack_start();
}

OwnedObject throw_GreenletExit();
OwnedObject g_switch();
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.
*/
void murder_in_place();
virtual void murder_in_place();

/**
* Called when somebody notices we were running in a dead
Expand All @@ -371,7 +367,8 @@ namespace greenlet
inline int slp_save_state(char *const stackref) G_NOEXCEPT;

inline bool is_currently_running_in_some_thread() const;
inline bool belongs_to_thread(const ThreadState* state) const;
virtual bool belongs_to_thread(const ThreadState* state) const;

inline bool started() const
{
return this->stack_state.started();
Expand All @@ -384,53 +381,40 @@ namespace greenlet
{
return this->stack_state.main();
}
virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;

inline const OwnedGreenlet parent() const
{
return this->_parent;
}
virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0;

inline void parent(const refs::BorrowedObject new_parent);
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();
}

inline const OwnedObject& run() const
{
if (this->started() || !this->_run_callable) {
throw AttributeError("run");
}
return this->_run_callable;
}
virtual const OwnedObject& run() const = 0;
virtual void run(const refs::BorrowedObject nrun) = 0;

inline void run(const refs::BorrowedObject nrun);

int tp_traverse(visitproc visit, void* arg);
int tp_clear();
virtual int tp_traverse(visitproc visit, void* arg);
virtual int tp_clear();


class ParentIsCurrentGuard
{
private:
OwnedGreenlet oldparent;
Greenlet* greenlet;
G_NO_COPIES_OF_CLS(ParentIsCurrentGuard);
public:
ParentIsCurrentGuard(Greenlet* p, const ThreadState& thread_state);
~ParentIsCurrentGuard();
};
// 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.
inline ThreadState* thread_state() const G_NOEXCEPT;
virtual ThreadState* thread_state() const G_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 G_NOEXCEPT;
virtual bool was_running_in_dead_thread() const G_NOEXCEPT = 0;

// Return a borrowed greenlet that is the Python object
// this object represents.
virtual BorrowedGreenlet self() const G_NOEXCEPT = 0;

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.
Expand Down Expand Up @@ -482,11 +466,21 @@ namespace greenlet
// Returns the previous greenlet we just switched away from.
virtual OwnedGreenlet g_switchstack_success() G_NOEXCEPT;

virtual switchstack_result_t g_initialstub(void* mark);

private:
// 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:


void inner_bootstrap(OwnedGreenlet& origin_greenlet, OwnedObject& run) G_NOEXCEPT;
/**
Perform a stack switch into this greenlet.
Expand Down Expand Up @@ -520,32 +514,96 @@ namespace greenlet
*/
switchstack_result_t g_switchstack(void);
private:
OwnedObject g_switch_finish(const switchstack_result_t& err);
// 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;
inline void release_args();

class GreenletStartedWhileInPython : public std::runtime_error
};

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 G_NOEXCEPT;
virtual ThreadState* thread_state() const G_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 G_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:
GreenletStartedWhileInPython() : std::runtime_error("")
{}
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:
void inner_bootstrap(OwnedGreenlet& origin_greenlet, OwnedObject& run) G_NOEXCEPT;
};



class MainGreenlet : public Greenlet
{
private:
static greenlet::PythonAllocator<MainGreenlet> allocator;
refs::BorrowedMainGreenlet _self;
ThreadState* _thread_state;
G_NO_COPIES_OF_CLS(MainGreenlet);
public:
MainGreenlet(refs::BorrowedMainGreenlet::PyType*);
virtual ~MainGreenlet()
{}
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 G_NOEXCEPT;
virtual ThreadState* thread_state() const G_NOEXCEPT;
void thread_state(ThreadState*) G_NOEXCEPT;
virtual OwnedObject g_switch();
virtual BorrowedGreenlet self() const G_NOEXCEPT;
virtual int tp_traverse(visitproc visit, void* arg);
};

};
Expand Down

0 comments on commit 0145f05

Please sign in to comment.