Stop locking the world to report triggers and hits
The trigger and shape hit callbacks held m_removedPhysicsNodesMutex
while they ran, reports included. Deleting a body from such a report
reaches QPhysicsWorld::deregisterNode(), which takes the same lock, and
QMutex is not recursive, so the thread waited for itself and the
application hung. Only a delete inside the handler does that, which is
why it rarely bites: Object.destroy() and the ordinary release of a
delegate are both deferred, so it takes C++ owning the node, or a
delegate model being destroyed.
Take the lock out. 34fd69ec4c99 ("Add mutex to m_removedPhysicsNodes")
added it for threading that no longer exists: the world simulated on a
thread of its own and called fetchResults() there, so PhysX delivered
the callbacks while the QML thread deleted nodes. e05ab04b0787
("PhysicsWorld: Simulate after frame render") took that thread away, and
fetchResults(), PxController::move() and the deletion of a node have
been the same thread since. Three of the readers of the set never took
the lock anyway, cleanupRemovedNodes(), which clears it, among them.
The removed check the lock wrapped stays where it was, and only now has
anything to catch: one batch can report the same node in several pairs,
and a handler run for one pair is free to delete a node that a later
pair points at, which under the lock hung rather than returning at all.
The hit asks it before it reads enableShapeHitCallback(), which was a
read of a node whose destructor may already have run. For the same
reason the reports are guarded as they run: a trigger makes two per
body, one of them from the body, plus its own signals, and a character
controller can be deleted from the shape hit report it makes while
moving. Contact reports were never affected, being queued and emitted
from the frame.
A report that would pass a node that has just been deleted to a handler
is not made at all, so a body still inside a trigger when the trigger is
deleted is never told that it left. Document that on the signal.
Add tests/auto/deleted_node/tst_scene_changed_mid_trigger.qml, which
moves the world to another scene from a trigger report. That deregisters
every body while the callback that made the report is still running,
which is what a delete does to this end of things without waiting for
the object to be deferred to, and it hung before. Three bodies cross the
boundary together, so the pairs behind the one the move was made from
are about bodies the move took out, and only the first is reported.
Pick-to: 6.12 6.11
Change-Id: Ic5c8269013e1ababf1f39d568b9d9049962df543
Reviewed-by: Kristoffer Skau <kristoffer.skau@qt.io>