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

Use GILProtected for capsule caching? #263

Open
SimonSapin opened this issue Jul 6, 2021 · 2 comments · May be fixed by #268
Open

Use GILProtected for capsule caching? #263

SimonSapin opened this issue Jul 6, 2021 · 2 comments · May be fixed by #268

Comments

@SimonSapin
Copy link
Contributor

SimonSapin commented Jul 6, 2021

The py_capsule and py_capsule_fn macros generate code that cache the pointer obtained from a capsule in a static mut item, with a std::sync::Once in a second static item for thread-safety.

Although the synchronization cost of Once is small, it seems unnecessary here since code touching this is always holding the GIL. Could this cache be implemented with a single static item of type cpython::GILProtected<std::cell::Cell<_>> instead?

@markbt
Copy link
Collaborator

markbt commented Aug 11, 2021

This is probably a question for @gracinet.

SimonSapin added a commit to SimonSapin/rust-cpython that referenced this issue Aug 12, 2021
The `py_capsule!` and `py_capsule_fn!` macros generate `retrieve` functions
that cache their results for subsequent calls.

Prior to this commit, caching is done with a generated unsafe `static mut`
item whose access is made thread-safe by a `std::sync::Once` on the side.
However this synchronization is unnecessary since `retreive` takes a
`Python<'_>` parameter that indicates that the GIL is held.

This changes the cache to use safe `static` item instead, with `GILProtected`
for synchronization-free thread-safety and `OnceCell` for interior mutability.
As a bonus, this removes the need for cache-related `unsafe` code in
generated `retrieve` functions.

This adds a dependency to the `once_cell` crate, which can be removed when
`OnceCell` becomes stable in the standard library:
rust-lang/rust#74465

Alternatively `OnceCell` could be replaced with `UnsafeCell` plus some
`unsafe` code, effectively inlining the core of the logic of `OnceCell`.
`RefCell` might work too.

Fixes dgrunwald#263
@SimonSapin
Copy link
Contributor Author

I’ve submitted #268. Cell turned out not to be enough, this uses OnceCell instead. The fact that no cache-related unsafe code is needed anymore reinforces my belief that this approach is sound.

SimonSapin added a commit to SimonSapin/rust-cpython that referenced this issue Aug 12, 2021
The `py_capsule!` and `py_capsule_fn!` macros generate `retrieve` functions
that cache their results for subsequent calls.

Prior to this commit, caching is done with a generated unsafe `static mut`
item whose access is made thread-safe by a `std::sync::Once` on the side.
However this synchronization is unnecessary since `retreive` takes a
`Python<'_>` parameter that indicates that the GIL is held.

This changes the cache to use safe `static` item instead, with `GILProtected`
for synchronization-free thread-safety and `OnceCell` for interior mutability.
As a bonus, this removes the need for cache-related `unsafe` code in
generated `retrieve` functions.

This adds a dependency to the `once_cell` crate, which can be removed when
`OnceCell` becomes stable in the standard library:
rust-lang/rust#74465

Alternatively `OnceCell` could be replaced with `UnsafeCell` plus some
`unsafe` code, effectively inlining the core of the logic of `OnceCell`.

Fixes dgrunwald#263
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 a pull request may close this issue.

2 participants