Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/greenlet/PyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc,
static PyObject*
mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module))
{
std::clock_t& clocks = ThreadState::clocks_used_doing_gc();
std::clock_t clocks = ThreadState::clocks_used_doing_gc();

if (clocks == std::clock_t(-1)) {
Py_RETURN_NONE;
Expand All @@ -168,15 +168,15 @@ mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag)
return nullptr;
}

std::clock_t& clocks = ThreadState::clocks_used_doing_gc();
if (is_true) {
std::clock_t clocks = ThreadState::clocks_used_doing_gc();
// If we already have a value, we don't want to lose it.
if (clocks == std::clock_t(-1)) {
clocks = 0;
ThreadState::set_clocks_used_doing_gc(0);
}
}
else {
clocks = std::clock_t(-1);
ThreadState::set_clocks_used_doing_gc(std::clock_t(-1));
}
Py_RETURN_NONE;
}
Expand Down
13 changes: 10 additions & 3 deletions src/greenlet/TMainGreenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@

#include "TGreenlet.hpp"

#ifdef Py_GIL_DISABLED
#include <atomic>
#endif


// Protected by the GIL. Incremented when we create a main greenlet,
// in a new thread, decremented when it is destroyed.
// Incremented when we create a main greenlet, in a new thread, decremented
// when it is destroyed.
#ifdef Py_GIL_DISABLED
static std::atomic<Py_ssize_t> G_TOTAL_MAIN_GREENLETS(0);
#else
// Protected by the GIL.
static Py_ssize_t G_TOTAL_MAIN_GREENLETS;
#endif

namespace greenlet {
greenlet::PythonAllocator<MainGreenlet> MainGreenlet::allocator;
Expand Down
39 changes: 35 additions & 4 deletions src/greenlet/TThreadState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <ctime>
#include <stdexcept>
#include <atomic>

#include "greenlet_internal.hpp"
#include "greenlet_refs.hpp"
Expand Down Expand Up @@ -118,7 +119,11 @@ class ThreadState {
void* exception_state;
#endif

#ifdef Py_GIL_DISABLED
static std::atomic<std::clock_t> _clocks_used_doing_gc;
#else
static std::clock_t _clocks_used_doing_gc;
#endif
static ImmortalString get_referrers_name;
static PythonAllocator<ThreadState> allocator;

Expand Down Expand Up @@ -160,7 +165,7 @@ class ThreadState {
static void init()
{
ThreadState::get_referrers_name = "get_referrers";
ThreadState::_clocks_used_doing_gc = 0;
ThreadState::set_clocks_used_doing_gc(0);
}

ThreadState()
Expand Down Expand Up @@ -349,9 +354,31 @@ class ThreadState {
/**
* Set to std::clock_t(-1) to disable.
*/
inline static std::clock_t& clocks_used_doing_gc()
inline static std::clock_t clocks_used_doing_gc()
{
#ifdef Py_GIL_DISABLED
return ThreadState::_clocks_used_doing_gc.load(std::memory_order_relaxed);
#else
return ThreadState::_clocks_used_doing_gc;
#endif
}

inline static void set_clocks_used_doing_gc(std::clock_t value)
{
#ifdef Py_GIL_DISABLED
ThreadState::_clocks_used_doing_gc.store(value, std::memory_order_relaxed);
#else
ThreadState::_clocks_used_doing_gc = value;
#endif
}

inline static void add_clocks_used_doing_gc(std::clock_t value)
{
#ifdef Py_GIL_DISABLED
ThreadState::_clocks_used_doing_gc.fetch_add(value, std::memory_order_relaxed);
#else
ThreadState::_clocks_used_doing_gc += value;
#endif
}

~ThreadState()
Expand Down Expand Up @@ -390,7 +417,7 @@ class ThreadState {
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)
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.
Expand Down Expand Up @@ -444,7 +471,7 @@ class ThreadState {
}
}
std::clock_t end = std::clock();
ThreadState::_clocks_used_doing_gc += (end - begin);
ThreadState::add_clocks_used_doing_gc(end - begin);
}
}
}
Expand Down Expand Up @@ -486,7 +513,11 @@ class ThreadState {

ImmortalString ThreadState::get_referrers_name(nullptr);
PythonAllocator<ThreadState> ThreadState::allocator;
#ifdef Py_GIL_DISABLED
std::atomic<std::clock_t> ThreadState::_clocks_used_doing_gc(0);
#else
std::clock_t ThreadState::_clocks_used_doing_gc(0);
#endif



Expand Down
3 changes: 3 additions & 0 deletions src/greenlet/greenlet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ greenlet_internal_mod_init() noexcept
// << "\n\tPyGreenlet : " << sizeof(PyGreenlet)
// << endl;

#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m.borrow(), Py_MOD_GIL_NOT_USED);
#endif
return m.borrow(); // But really it's the main reference.
}
catch (const LockInitError& e) {
Expand Down
4 changes: 4 additions & 0 deletions src/greenlet/greenlet_slp_switch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@
// running this code, the thread isn't exiting. This also nets us a
// 10-12% speed improvement.

#if Py_GIL_DISABLED
thread_local greenlet::Greenlet* switching_thread_state = nullptr;
#else
static greenlet::Greenlet* volatile switching_thread_state = nullptr;
#endif


extern "C" {
Expand Down
3 changes: 3 additions & 0 deletions src/greenlet/tests/_test_extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,8 @@ PyInit__test_extension(void)
}

PyGreenlet_Import();
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
#endif
return module;
}
3 changes: 3 additions & 0 deletions src/greenlet/tests/_test_extension_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ PyInit__test_extension_cpp(void)
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;
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
#endif

return module;
}
14 changes: 12 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[tox]
envlist =
py{37,38,39,310,311,312,313,314},py{310,311,312,313,314}-ns,docs
py{37,38,39,310,311,312,313,314},py{310,311,312,313,314}-ns,docs,py314t,tsan-314#,tsan-314t

[testenv]
commands =
python -c 'import greenlet._greenlet as G; assert G.GREENLET_USE_STANDARD_THREADING'
python -m unittest discover -v greenlet.tests
python -m unittest discover greenlet.tests
sphinx-build -b doctest -d docs/_build/doctrees-{envname} docs docs/_build/doctest-{envname}
sitepackages = False
extras =
Expand All @@ -21,3 +21,13 @@ commands =
sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest
extras = docs

[testenv:tsan-314t]
basepython = /usr/local/python-builds/tsan/bin/python3.14t
passenv =
TSAN_OPTIONS

[testenv:tsan-314]
basepython = /usr/local/python-builds/default-tsan/bin/python3.14
passenv =
TSAN_OPTIONS