@@ -88,6 +88,36 @@ macro_rules! rmw {
8888 } } ;
8989}
9090
91+ // Atomic store that is serialized against the emulated PSRAM RMWs.
92+ //
93+ // A naturally aligned store is itself atomic on these CPUs (only the
94+ // read-modify-write instruction misbehaves on PSRAM), but it must take the
95+ // same critical section as the RMW path. Otherwise, on the dual-core
96+ // ESP32 / ESP32-S3, a plain store on one core could land between the read
97+ // and write of an in-progress RMW on the other core and be lost.
98+ //
99+ // When the `critical-section` feature is disabled, RMWs on PSRAM panic, so no
100+ // store-vs-RMW race can occur and a plain native store stays correct.
101+ macro_rules! store {
102+ ( $self: ident, $val: ident, $order: ident) => { {
103+ #[ cfg( feature = "critical-section" ) ]
104+ {
105+ let p: * mut _ = $self. as_ptr( ) ;
106+ if in_psram( p) {
107+ critical_section:: with( |_cs| {
108+ // SAFETY: inside a critical section we have exclusive
109+ // access to `p`, which is valid and aligned because it
110+ // came from `&self`. The store is serialized with the
111+ // RMW path, which takes the same critical section.
112+ unsafe { core:: ptr:: write_volatile( p, $val) }
113+ } ) ;
114+ return ;
115+ }
116+ }
117+ $self. inner. store( $val, $order) ;
118+ } } ;
119+ }
120+
91121// ---------------------------------------------------------------------------
92122// AtomicPtr
93123
@@ -113,13 +143,16 @@ impl<T> AtomicPtr<T> {
113143 #[ cfg_attr( any( debug_assertions, miri) , track_caller) ]
114144 pub ( crate ) fn load ( & self , order : Ordering ) -> * mut T {
115145 crate :: utils:: assert_load_ordering ( order) ;
146+ // No critical section needed: A naturally aligned load always
147+ // observes a complete value written by a store or by the RMW
148+ // path's single `write_volatile`.
116149 self . inner . load ( order)
117150 }
118151 #[ inline]
119152 #[ cfg_attr( any( debug_assertions, miri) , track_caller) ]
120153 pub ( crate ) fn store ( & self , ptr : * mut T , order : Ordering ) {
121154 crate :: utils:: assert_store_ordering ( order) ;
122- self . inner . store ( ptr, order) ;
155+ store ! ( self , ptr, order) ;
123156 }
124157
125158 #[ inline]
@@ -363,13 +396,16 @@ macro_rules! atomic_int {
363396 #[ cfg_attr( any( debug_assertions, miri) , track_caller) ]
364397 pub ( crate ) fn load( & self , order: Ordering ) -> $int_type {
365398 crate :: utils:: assert_load_ordering( order) ;
399+ // No critical section needed: A naturally aligned load always
400+ // observes a complete value written by a store or by the RMW
401+ // path's single `write_volatile`.
366402 self . inner. load( order)
367403 }
368404 #[ inline]
369405 #[ cfg_attr( any( debug_assertions, miri) , track_caller) ]
370406 pub ( crate ) fn store( & self , val: $int_type, order: Ordering ) {
371407 crate :: utils:: assert_store_ordering( order) ;
372- self . inner . store( val, order) ;
408+ store! ( self , val, order) ;
373409 }
374410
375411 #[ inline]
0 commit comments