In #114824, I modified test_no_stale_references so that it passes in the --disable-gil build. Unfortunately, that change was not sufficient and the test may still hang once the GIL is actually disabled.
Relevant code:
|
my_object = MyObject() |
|
my_object_collected = threading.Event() |
|
my_object_callback = weakref.ref( |
|
my_object, lambda obj: my_object_collected.set()) |
|
collected = my_object_collected.wait(timeout=support.SHORT_TIMEOUT) |
The problem is due to the combination of two issues:
- Due to biased reference counting, the destructor for
my_object is usually called on the main thread asynchronously (by the eval breaker logic)
- The destructor may be called somewhere in the implementation of
my_object_collected.wait(). The my_object_collected.wait() implementation holds some of the same locks that my_object_collected.set() also needs. This can lead to deadlock if the timing is unlucky: the my_object_collected.set() call from the weakref callback tries to acquire locks already held by the current thread and deadlocks.
Linked PRs