Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify event pipe before releasing NativeActivity resources #134

Merged
merged 1 commit into from
Mar 24, 2021

Conversation

maciejgodek
Copy link
Contributor

@maciejgodek maciejgodek commented Mar 21, 2021

Currently, some NativeActivity callbacks (on_native_window_destroyed, on_input_queue_destroyed):
(1) acquire a write lock on a static handle to the resource that is about to be destroyed, (2) drop the handle, (3) dispatch an asynchronous Event to the user on a UNIX pipe notifying of the release, (4) immediately return from the callback.

This is incorrect according to ANativeActivityCallbacks docs. If the user is holding on to a read lock on the handle (as they should), there will be a deadlock. If the user does not have a read lock on the handle, there is a race condition, since Android may free the resource before the user cleans up all the objects derived from that resource (e.g. EGLSurface from NativeWindow).

In order to prevent races, ndk_glue should (1) notify users of upcoming resource release, so they can correctly clean up derived objects, and only then (2) acquire a write lock on the handle, (3) drop the handle, (4) return from the callback.

Closes #117

ndk-glue/src/lib.rs Outdated Show resolved Hide resolved
@MarijnS95
Copy link
Member

MarijnS95 commented Mar 22, 2021

To be ever so slightly more specific, could you mention in the commit message that acquiring a writelock in step (2) assumes the user holds a readlock on the resource to be destroyed (INPUT_QUEUE or NATIVE_WINDOW) that it should only release after cleaning up dependent resources like surfaces/swapchains and the like?

maciejgodek added a commit to maciejgodek/winit that referenced this pull request Mar 23, 2021
In order to ensure validity of the raw pointers to Android's `ANativeWindow`
handed out by `Window::raw_window_handle()`, the `EventLoop` will hold on
to a read lock on the `NativeWindow` returned by `ndk_glue::native_window()`
between receiving the `WindowCreated` event and the matching `WindowDestroyed`
event from `ndk-glue`'s event pipe.

Note that this commit depends on recent fixes to `ndk-glue`, specifically
this PR rust-mobile/ndk#134. Previous
versions of `ndk-glue` will cause this code to deadlock due to a concurrency
bug.
maciejgodek added a commit to maciejgodek/winit that referenced this pull request Mar 23, 2021
In order to ensure validity of the raw pointers to Android's `ANativeWindow`
handed out by `Window::raw_window_handle()`, the `EventLoop` will hold on
to a read lock on the `NativeWindow` returned by `ndk_glue::native_window()`
between receiving the `WindowCreated` event and the matching `WindowDestroyed`
event from `ndk-glue`'s event pipe.

Note that this commit depends on recent fixes to `ndk-glue`, specifically
this PR rust-mobile/ndk#134. Previous
versions of `ndk-glue` will cause this code to deadlock due to a concurrency
bug.
The design of ndk-glue seems to imply that the user of a `NativeActivity`
resource, e.g. `NativeWindow` obtained from `ndk_glue::native_window()`, should
hold a read lock on the resource as long as they are using it.

Therefore, ndk-glue's `NativeActivity` callbacks related to resource release
should: (1) notify the user of upcoming resource release, (2) acquire a write
lock on the handle, waiting for all read locks to be dropped, (3) drop the
handle, (4) return from the callback.  This allows the user to react and correctly
release various objects derived from the resource (e.g. swapchains/surfaces
from `NativeWindow`) before it goes away. Currently, the order is 2-3-1-4, which
can lead to a deadlock (if the user holds on to a read guard) or a race condition
(if they drop the read guard early).

This commit fixes the order.
@maciejgodek
Copy link
Contributor Author

Ok, I think I fixed it. :) Apologies for the repeated force pushes, I can't focus today.

@MarijnS95 MarijnS95 requested a review from dvc94ch March 23, 2021 23:54
Copy link
Member

@MarijnS95 MarijnS95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit description is completely on point, I couldn't have worded it better, thanks!

Assigning this for final review to @dvc94ch since he originally discussed this with you in #117.

Copy link
Contributor

@dvc94ch dvc94ch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@dvc94ch dvc94ch merged commit ca87ad8 into rust-mobile:master Mar 24, 2021
MarijnS95 added a commit that referenced this pull request Aug 7, 2021
This completes #134 by applying the same pointer-equality check in
`on_input_queue_destroyed` to `on_window_destroyed`, and documents when
the user should hold on to or release any of the `RWLock`s to ensure
proper lifetimes for dependencies like surfaces in graphics APIs.
msiglreith pushed a commit that referenced this pull request Aug 7, 2021
…ity (#174)

This completes #134 by applying the same pointer-equality check in
`on_input_queue_destroyed` to `on_window_destroyed`, and documents when
the user should hold on to or release any of the `RWLock`s to ensure
proper lifetimes for dependencies like surfaces in graphics APIs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ndk-glue does not handle NativeWindow lifecycle correctly
3 participants