@@ -3,11 +3,13 @@ use core::ptr::NonNull;
33use std:: {
44 fs:: File ,
55 sync:: {
6- atomic:: { AtomicU32 , Ordering } ,
6+ atomic:: { AtomicU64 , Ordering } ,
77 Arc ,
88 } ,
99} ;
1010
11+ const MAGIC : u64 = 0x7368_6171_7370_7363 ; // b"shaqspsc"
12+
1113/// Calculates the minimum file size required for a queue with given capacity.
1214/// Note that file size MAY need to be increased beyond this to account for
1315/// page-size requirements.
@@ -114,11 +116,9 @@ impl<T: Sized> Producer<T> {
114116 /// All reserved positions must be fully initialized before calling `commit`.
115117 /// Pointers should be dropped before calling `commit`.
116118 pub unsafe fn reserve ( & mut self ) -> Option < NonNull < T > > {
117- // If write is >= read + buffer_size , the queue is written one iteration
119+ // If write is > read + buffer_mask , the queue is written one iteration
118120 // ahead of the consumer, and we cannot reserve more space.
119- if self . queue . cached_write . wrapping_sub ( self . queue . cached_read )
120- >= self . queue . header ( ) . buffer_size
121- {
121+ if self . queue . cached_write . wrapping_sub ( self . queue . cached_read ) > self . queue . buffer_mask {
122122 return None ;
123123 }
124124
@@ -294,10 +294,9 @@ impl<T: Sized> SharedQueue<T> {
294294 header : NonNull < SharedQueueHeader > ,
295295 ) -> Result < Self , Error > {
296296 // SAFETY: `header` is non-null and aligned properly.
297- let size = unsafe { header. as_ref ( ) . buffer_size } ;
297+ let size = unsafe { ( header. as_ref ( ) . buffer_mask as usize ) . wrapping_add ( 1 ) } ;
298298
299299 if !size. is_power_of_two ( )
300- || size == 0
301300 || SharedQueueHeader :: calculate_buffer_size_in_items :: < T > ( region. file_size ( ) ) ? != size
302301 {
303302 return Err ( Error :: InvalidBufferSize ) ;
@@ -374,10 +373,14 @@ impl<T: Sized> SharedQueue<T> {
374373/// Header in shared memory for the queue.
375374#[ repr( C ) ]
376375struct SharedQueueHeader {
376+ // Cold cache line.
377+ magic : AtomicU64 ,
378+ version : u32 ,
379+ buffer_mask : u32 ,
380+
381+ // Hot cache lines.
377382 write : CacheAlignedAtomicSize ,
378383 read : CacheAlignedAtomicSize ,
379- buffer_size : usize ,
380- version : AtomicU32 ,
381384}
382385
383386impl SharedQueueHeader {
@@ -436,8 +439,9 @@ impl SharedQueueHeader {
436439 let header = unsafe { header. as_mut ( ) } ;
437440 header. write . store ( 0 , Ordering :: Release ) ;
438441 header. read . store ( 0 , Ordering :: Release ) ;
439- header. buffer_size = buffer_size_in_items;
440- header. version . store ( VERSION , Ordering :: SeqCst ) ;
442+ header. buffer_mask = ( buffer_size_in_items - 1 ) as u32 ;
443+ header. version = VERSION ;
444+ header. magic . store ( MAGIC , Ordering :: Release ) ;
441445 }
442446
443447 fn join < T : Sized > ( file : & File ) -> Result < ( Arc < MappedRegion > , NonNull < Self > ) , Error > {
@@ -450,14 +454,18 @@ impl SharedQueueHeader {
450454 // memory is aligned to the page size, which is sufficient for the
451455 // alignment of `SharedQueueHeader`.
452456 let header = unsafe { header. as_ref ( ) } ;
453- let actual_version = header. version . load ( Ordering :: SeqCst ) ;
454- if actual_version != VERSION {
457+ if header. magic . load ( Ordering :: Acquire ) != MAGIC {
458+ return Err ( Error :: InvalidMagic ) ;
459+ }
460+ if header. version != VERSION {
455461 return Err ( Error :: InvalidVersion {
456462 expected : VERSION ,
457- actual : actual_version ,
463+ actual : header . version ,
458464 } ) ;
459465 }
460- if header. buffer_size != Self :: calculate_buffer_size_in_items :: < T > ( file_size) ? {
466+ if ( header. buffer_mask as usize ) . wrapping_add ( 1 )
467+ != Self :: calculate_buffer_size_in_items :: < T > ( file_size) ?
468+ {
461469 return Err ( Error :: InvalidBufferSize ) ;
462470 }
463471 }
0 commit comments