Skip to content

Commit

Permalink
Rename + Send/Sync tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Cassy343 committed Jul 25, 2022
1 parent 0048118 commit 119a2f2
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 10 deletions.
10 changes: 5 additions & 5 deletions src/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,20 +145,20 @@ count to 0 and then `unpark` the writing thread.
## The Write Algorithm
The write algorithm is split into two parts: `synchronize` + start write, and `finish_write`. When
The write algorithm is split into two parts: `synchronize` + start write, and `publish`. When
a new write guard is created, `start_write` is called, and when that guard is dropped
`finish_write` is called.
`publish` is called.
`synchronize` + start write:
1. If there are no residual readers, we are done.
2. If there are residual readers, then park as described above.
3. Once unblocked, obtain a reference to the writable map.
4. Apply changes from previous write.
After these steps but before `finish_write`, the changes to the writable map are made and stored in
After these steps but before `publish`, the changes to the writable map are made and stored in
the operation log.
`finish_write`:
`publish`:
1. Acquire the lock on the refcount array.
2. Swap out the value of the field storing the writable map with the old map.
3. Call `swap_maps` on each refcount in the array, and (non-atomically) accumulate a sum of the
Expand All @@ -171,7 +171,7 @@ the operation log.
Note that read handles are not swapped to the new map at the same time, this is done one-by-one.
An important invariant of this algorithm is that `residual == 0` whenever `finish_write` is called.
An important invariant of this algorithm is that `residual == 0` whenever `publish` is called.
That way, either the writing thread will see `residual == 0` after swapping all the maps, or one
of the residual readers will see `residual & isize::MAX == 1` as the old value when it performs its
atomic decrement. In either case, this provides a definite signal that there are no more readers
Expand Down
15 changes: 11 additions & 4 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,15 @@ pub struct Core<K, V, S = DefaultHashBuilder> {
writer_thread: UnsafeCell<Option<Thread>>,
writer_map: Cell<MapIndex>,
maps: OwnedMapAccess<K, V, S>,
// TODO: figure out if core can implement send or sync
_not_send_sync: PhantomData<*const u8>,
_not_sync: PhantomData<*const u8>,
}

unsafe impl<K, V, S> Send for Core<K, V, S>
where
Alias<K>: Send,
Alias<V>: Send,
S: Send,
{
}

impl<K, V, S> Core<K, V, S>
Expand All @@ -59,7 +66,7 @@ where
writer_thread: UnsafeCell::new(None),
writer_map: Cell::new(MapIndex::Second),
maps: OwnedMapAccess::new(maps),
_not_send_sync: PhantomData,
_not_sync: PhantomData,
});

let write_handle = unsafe { WriteHandle::new(Arc::clone(&me)) };
Expand Down Expand Up @@ -154,7 +161,7 @@ impl<K, V, S> Core<K, V, S> {
}

#[inline]
pub unsafe fn finish_write(&self) {
pub unsafe fn publish(&self) {
debug_assert_eq!(self.residual.load(Ordering::Relaxed), 0);

fence(Ordering::Release);
Expand Down
2 changes: 2 additions & 0 deletions src/core/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ impl<K, V, S> SharedMapAccess<K, V, S> {
let maps = unsafe { self.maps.as_ref() };
&maps[map_index as usize]
}
}

impl<K, V, S> Clone for SharedMapAccess<K, V, S> {
fn clone(&self) -> Self {
Self { maps: self.maps }
}
Expand Down
73 changes: 73 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,76 @@ pub(crate) struct BuilderArgs<S> {
pub h1: S,
pub h2: S,
}

/// ```compile_fail
/// fn assert_send<T: Send>() {}
/// use flashmap::*;
/// assert_send::<Evicted<'_, (), ()>>();
/// ```
///
/// ```compile_fail
/// fn assert_send<T: Send>() {}
/// use flashmap::*;
/// assert_send::<Alias<std::cell::Cell<()>>>();
/// ```
#[allow(dead_code)]
struct NotSendTypes;

/// ```compile_fail
/// fn assert_sync<T: Sync>() {}
/// use flashmap::*;
/// assert_sync::<Evicted<'_, (), ()>>();
/// ```
///
/// ```compile_fail
/// fn assert_sync<T: Sync>() {}
/// use flashmap::*;
/// assert_sync::<Alias<std::sync::MutexGuard<'_, ()>>>();
/// ```
#[allow(dead_code)]
struct NotSyncTypes;

#[cfg(test)]
mod tests {
use super::*;
use std::{collections::hash_map::DefaultHasher, marker::PhantomData};

fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}

#[derive(PartialEq, Eq, Hash)]
struct SendOnly(PhantomData<*const u8>);

unsafe impl Send for SendOnly {}

#[derive(PartialEq, Eq, Hash)]
struct SyncOnly(PhantomData<*const u8>);

unsafe impl Sync for SyncOnly {}

#[derive(PartialEq, Eq, Hash)]
struct SendSync;

impl BuildHasher for SendSync {
type Hasher = DefaultHasher;

fn build_hasher(&self) -> Self::Hasher {
unimplemented!()
}
}

#[test]
fn send_types() {
assert_send::<ReadHandle<SendSync, SendSync, SendSync>>();
assert_send::<WriteHandle<SendSync, SendSync, SendSync>>();
assert_send::<View<ReadGuard<'_, SendSync, SendSync, SendSync>>>();
assert_send::<Leaked<SendOnly>>();
}

#[test]
fn sync_types() {
assert_sync::<ReadHandle<SendSync, SendSync, SendSync>>();
assert_sync::<View<ReadGuard<'_, SendSync, SendSync, SendSync>>>();
assert_sync::<Leaked<SyncOnly>>();
}
}
5 changes: 4 additions & 1 deletion src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ where
S: BuildHasher,
{
fn drop(&mut self) {
unsafe { self.handle.core.finish_write() };
unsafe { self.handle.core.publish() };
}
}

Expand Down Expand Up @@ -567,6 +567,9 @@ pub struct Leaked<V> {
handle_uid: WriterUid,
}

unsafe impl<V> Send for Leaked<V> where V: Send {}
unsafe impl<V> Sync for Leaked<V> where V: Sync {}

impl<V> Leaked<V> {
/// Consumes this leaked value, providing the inner aliased value. Note that the aliased value
/// must be manually dropped via `Alias::`[`drop`](crate::Alias::drop), or converted into an
Expand Down

0 comments on commit 119a2f2

Please sign in to comment.