Closed vfdev-5 closed 1 month ago
I think the easiest approach might be to use a different mutex for the exception translators than for the rest of the internals. Other than initialization and finalization, I think the accesses for exception translators and the rest of internals are separate
The alternative is to unlock before calling exception translators, but to do that safely I think you may need to copy the list of translators.
Thanks @colesbury let me check these approaches!
I tried another alternative doing the following, checking whether the mutex is already locked and lock it only if unlocked:
// Wrapper around PyMutex to provide BasicLockable semantics
class pymutex {
PyMutex mutex;
public:
pymutex() : mutex({}) {}
void lock() { PyMutex_Lock(&mutex); }
void unlock() { PyMutex_Unlock(&mutex); }
bool has_lock() { return mutex._bits == 1; }
};
#ifdef Py_GIL_DISABLED
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<pymutex> lock((internals).mutex, std::defer_lock); if ((internals).mutex.has_lock()) { lock.lock(); }
#else
# define PYBIND11_LOCK_INTERNALS(internals)
#endif
What do you think?
That looks like it would skip locking the mutex if it's held by another thread, which would not be safe. But also, your sample code only locks the mutex if it's already locked, so I don't think it will ever get locked.
Required prerequisites
What version (or hash if on master) of pybind11 are you using?
2.13.5 and from source
Problem description
I have a program stuck when retranslating local exception with custom data class using CPython with free-threading mode enabled.
This is due to
internals.mutex
being in the locked state when the callback is running. When using custom data,all_type_info_get_cache
method is called internally which also tries to lockinternals.mutex
.See the repro code below
Reproducible example code
C++ test1.cpp
Python code:
exceptions1.py
Run:
Output:
Is this a regression? Put the last known working version here if it is.
Not a regression