Just holding the lock while calling Observer::surface_exists but that can lead to deadlocks. Indeed CursorController installs an observer, in which it's surface_exists handler calls back into the scene.
Taking a copy of the list of surfaces and then releasing a lock can lead to calling Observer::surface_removed before Observer::surface_exists which could lead to the observer having stale and/or invalid Surface pointers around leading to other subtle runtime failures.
Maybe a secondary lock that serializes add_observer and surface_removed is enough.
Just holding the lock while calling Observer: :surface_ exists but that can lead to deadlocks. Indeed CursorController installs an observer, in which it's surface_exists handler calls back into the scene.
Taking a copy of the list of surfaces and then releasing a lock can lead to calling Observer: :surface_ removed before Observer: :surface_ exists which could lead to the observer having stale and/or invalid Surface pointers around leading to other subtle runtime failures.
Maybe a secondary lock that serializes add_observer and surface_removed is enough.