diff options
author | Eliza Weisman <eliza@buoyant.io> | 2020-04-03 15:45:29 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-03 15:45:29 -0700 |
commit | 1121a8eb23f6f0edd9f41cdc08331d40e18105ee (patch) | |
tree | e2420ae1dd6504ab1f4fb313aefa5a96a7dff12e /tokio/src/sync/rwlock.rs | |
parent | 6fa40b6e2060b253dd32df326440fa6196763412 (diff) |
sync: ensure Mutex, RwLock, and Semaphore futures are Send + Sync (#2375)
Previously, the `Mutex::lock`, `RwLock::{read, write}`, and
`Semaphore::acquire` futures in `tokio::sync` implemented `Send + Sync`
automatically. This was by virtue of being implemented using a `poll_fn`
that only closed over `Send + Sync` types. However, this broke in
PR #2325, which rewrote those types using the new `batch_semaphore`.
Now, they await an `Acquire` future, which contains a `Waiter`, which
internally contains an `UnsafeCell`, and thus does not implement `Sync`.
Since removing previously implemented traits breaks existing code, this
inadvertantly caused a breaking change. There were tests ensuring that
the `Mutex`, `RwLock`, and `Semaphore` types themselves were `Send +
Sync`, but no tests that the _futures they return_ implemented those
traits.
I've fixed this by adding an explicit impl of `Sync` for the
`batch_semaphore::Acquire` future. Since the `Waiter` type held by this
struct is only accessed when borrowed mutably, it is safe for it to
implement `Sync`.
Additionally, I've added to the bounds checks for the effected
`tokio::sync` types to ensure that returned futures continue to
implement `Send + Sync` in the future.
Diffstat (limited to 'tokio/src/sync/rwlock.rs')
-rw-r--r-- | tokio/src/sync/rwlock.rs | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/tokio/src/sync/rwlock.rs b/tokio/src/sync/rwlock.rs index 7cce69a5..0f7991a5 100644 --- a/tokio/src/sync/rwlock.rs +++ b/tokio/src/sync/rwlock.rs @@ -133,6 +133,9 @@ fn bounds() { fn check_send<T: Send>() {} fn check_sync<T: Sync>() {} fn check_unpin<T: Unpin>() {} + // This has to take a value, since the async fn's return type is unnameable. + fn check_send_sync_val<T: Send + Sync>(_t: T) {} + check_send::<RwLock<u32>>(); check_sync::<RwLock<u32>>(); check_unpin::<RwLock<u32>>(); @@ -142,6 +145,10 @@ fn bounds() { check_sync::<RwLockWriteGuard<'_, u32>>(); check_unpin::<RwLockWriteGuard<'_, u32>>(); + + let rwlock = RwLock::new(0); + check_send_sync_val(rwlock.read()); + check_send_sync_val(rwlock.write()); } // As long as T: Send + Sync, it's fine to send and share RwLock<T> between threads. |