![]() |
Qucs-S S-parameter Viewer & RF Synthesis Tools
|
#include <TThreadState.hpp>
Public Member Functions | |
| void | restore_exception_state () |
| bool | has_main_greenlet () const noexcept |
| int | tp_traverse (visitproc visit, void *arg, bool traverse_main=true) |
| BorrowedMainGreenlet | borrow_main_greenlet () const noexcept |
| OwnedMainGreenlet | get_main_greenlet () const noexcept |
| OwnedGreenlet | get_current () |
| BorrowedGreenlet | borrow_current () |
| OwnedGreenlet | get_current () const |
| template<typename T , refs::TypeChecker TC> | |
| bool | is_current (const refs::PyObjectPointer< T, TC > &obj) const |
| void | set_current (const OwnedGreenlet &target) |
| OwnedObject | get_tracefunc () const |
| void | set_tracefunc (BorrowedObject tracefunc) |
| void | delete_when_thread_running (PyGreenlet *to_del) |
Static Public Member Functions | |
| static void * | operator new (size_t UNUSED(count)) |
| static void | operator delete (void *ptr) |
| static void | init () |
| static std::clock_t | clocks_used_doing_gc () |
| static void | set_clocks_used_doing_gc (std::clock_t value) |
| static void | add_clocks_used_doing_gc (std::clock_t value) |
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.
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.
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.
|
inline |
As for non-const get_current();
|
inlinestatic |
Set to std::clock_t(-1) to disable.
|
inline |
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 |
In addition to returning a new reference to the currunt greenlet, this performs any maintenance needed.
|
inline |
Does no maintenance.
|
inline |
Returns a new reference, or a false object.