Skip to content

Commit

Permalink
Greater safety and fewer assumptions doing cross-thread cleanup.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Sep 18, 2024
1 parent 9e8a90b commit dbf311a
Show file tree
Hide file tree
Showing 15 changed files with 158 additions and 671 deletions.
2 changes: 1 addition & 1 deletion make-manylinux
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ if [ -d /greenlet -a -d /opt/python ]; then

python -mpip install -U pip
python -mpip install -U setuptools wheel
python -mpip wheel --wheel-dir ./dist .
python -mpip wheel -v --wheel-dir ./dist .
python -mpip install -U .[test]
python -m unittest discover -v greenlet.tests
PATH="$OPATH" auditwheel repair dist/greenlet*.whl
Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/CObjects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "greenlet_internal.hpp"
#include "greenlet_refs.hpp"

#include "greenlet_thread_state.hpp"

#include "TThreadStateDestroy.cpp"

#include "PyGreenlet.hpp"
Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/PyGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The Python slot functions for TGreenlet.

#include "greenlet_refs.hpp"
#include "greenlet_slp_switch.hpp"
#include "greenlet_thread_state.hpp"

#include "greenlet_thread_support.hpp"
#include "TGreenlet.hpp"

Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/PyGreenlet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "greenlet.h"
#include "greenlet_compiler_compat.hpp"
#include "greenlet_refs.hpp"
#include "greenlet_thread_state.hpp"


using greenlet::refs::OwnedGreenlet;
using greenlet::refs::BorrowedGreenlet;
Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/PyGreenletUnswitchable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// as well.
#include "greenlet_refs.hpp"
#include "greenlet_slp_switch.hpp"
#include "greenlet_thread_state.hpp"

#include "greenlet_thread_support.hpp"
#include "TGreenlet.hpp"

Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/PyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "greenlet_internal.hpp"

#include "greenlet_thread_state.hpp"

#include "TGreenletGlobals.cpp"
#include "TMainGreenlet.cpp"
#include "TThreadStateDestroy.cpp"
Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/TGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define TGREENLET_CPP
#include "greenlet_internal.hpp"
#include "TGreenlet.hpp"
#include "greenlet_thread_state.hpp"


#include "TGreenletGlobals.cpp"
#include "TThreadStateDestroy.cpp"
Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/TGreenletGlobals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "greenlet_refs.hpp"
#include "greenlet_exceptions.hpp"
#include "greenlet_thread_support.hpp"
#include "greenlet_thread_state.hpp"
#include "greenlet_internal.hpp"

namespace greenlet {

Expand Down
2 changes: 1 addition & 1 deletion src/greenlet/TMainGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define T_MAIN_GREENLET_CPP

#include "TGreenlet.hpp"
#include "greenlet_thread_state.hpp"



// Protected by the GIL. Incremented when we create a main greenlet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,14 @@ class ThreadState {
return 0;
}

inline BorrowedMainGreenlet borrow_main_greenlet() const
inline BorrowedMainGreenlet borrow_main_greenlet() const noexcept
{
assert(this->main_greenlet);
assert(this->main_greenlet.REFCNT() >= 2);
return this->main_greenlet;
};

inline OwnedMainGreenlet get_main_greenlet()
inline OwnedMainGreenlet get_main_greenlet() const noexcept
{
return this->main_greenlet;
}
Expand Down Expand Up @@ -488,91 +488,9 @@ 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);

inline bool has_initialized_state() const
{
return this->_state != (ThreadState*)1;
}

inline bool has_state() const
{
return this->has_initialized_state() && this->_state != nullptr;
}

public:

// Only one of these, auto created per thread.
// Constructing the state constructs the MainGreenlet.
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->has_initialized_state()) {
// 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->has_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

Expand Down
Loading

0 comments on commit dbf311a

Please sign in to comment.