@@ -60,8 +60,13 @@ use crate::table::{Table, TableElementType};
6060use crate :: vmcontext:: { VMCallerCheckedAnyfunc , VMContext } ;
6161use crate :: TrapReason ;
6262use anyhow:: Result ;
63+ use parking_lot_core:: {
64+ park, unpark_all, unpark_one, ParkResult , DEFAULT_PARK_TOKEN , DEFAULT_UNPARK_TOKEN ,
65+ } ;
6366use std:: mem;
6467use std:: ptr:: { self , NonNull } ;
68+ use std:: sync:: atomic:: { AtomicU32 , AtomicU64 , Ordering } ;
69+ use std:: time:: { Duration , Instant } ;
6570use wasmtime_environ:: {
6671 DataIndex , ElemIndex , FuncIndex , GlobalIndex , MemoryIndex , TableIndex , TrapCode ,
6772} ;
@@ -435,49 +440,122 @@ unsafe fn memory_atomic_notify(
435440 vmctx : * mut VMContext ,
436441 memory_index : u32 ,
437442 addr : u64 ,
438- _count : u32 ,
443+ count : u32 ,
439444) -> Result < u32 , TrapReason > {
440445 let memory = MemoryIndex :: from_u32 ( memory_index) ;
441446 let instance = ( * vmctx) . instance ( ) ;
442- validate_atomic_addr ( instance, memory, addr, 4 , 4 ) ?;
443- Err (
444- anyhow:: anyhow!( "unimplemented: wasm atomics (fn memory_atomic_notify) unsupported" , )
445- . into ( ) ,
446- )
447+ let addr = validate_atomic_addr ( instance, memory, addr, 4 , 4 ) ?;
448+ if count == 0 {
449+ return Ok ( 0 ) ;
450+ }
451+
452+ let unparked_threads = if count == u32:: MAX {
453+ // SAFETY: `addr` is a valid pointer into the given memory and unique to parking_lot_core.
454+ unsafe { unpark_all ( addr as _ , DEFAULT_UNPARK_TOKEN ) }
455+ } else {
456+ let mut num = 0 ;
457+ for _ in 0 ..count {
458+ // SAFETY: `addr` is a valid pointer into the given memory and unique to parking_lot_core.
459+ let num_t = unsafe { unpark_one ( addr as _ , |_| DEFAULT_UNPARK_TOKEN ) . unparked_threads } ;
460+
461+ if num_t == 0 {
462+ break ;
463+ }
464+
465+ num += num_t;
466+ }
467+ num
468+ } ;
469+
470+ u32:: try_from ( unparked_threads) . map_err ( |e| TrapReason :: user_with_backtrace ( e. into ( ) ) )
447471}
448472
449473// Implementation of `memory.atomic.wait32` for locally defined memories.
450474unsafe fn memory_atomic_wait32 (
451475 vmctx : * mut VMContext ,
452476 memory_index : u32 ,
453477 addr : u64 ,
454- _expected : u32 ,
455- _timeout : u64 ,
478+ expected : u32 ,
479+ timeout : u64 ,
456480) -> Result < u32 , TrapReason > {
481+ // convert to absolute timestamp as soon as possible
482+ let wait_until = ( timeout > 0 )
483+ . then ( || {
484+ Instant :: now ( )
485+ . checked_add ( Duration :: from_nanos ( timeout) )
486+ . ok_or_else ( || {
487+ TrapReason :: user_with_backtrace ( anyhow:: anyhow!(
488+ "overflow when adding timeout to current time"
489+ ) )
490+ } )
491+ } )
492+ . transpose ( ) ?;
493+
457494 let memory = MemoryIndex :: from_u32 ( memory_index) ;
458495 let instance = ( * vmctx) . instance ( ) ;
459- validate_atomic_addr ( instance, memory, addr, 4 , 4 ) ?;
460- Err (
461- anyhow:: anyhow!( "unimplemented: wasm atomics (fn memory_atomic_wait32) unsupported" , )
462- . into ( ) ,
463- )
496+ let addr = validate_atomic_addr ( instance, memory, addr, 4 , 4 ) ?;
497+
498+ // SAFETY: `addr` was validated by `validate_atomic_addr` above.
499+ let atomic = unsafe { & * ( addr as * const AtomicU32 ) } ;
500+ // SAFETY: `addr` is a valid pointer into the given memory and unique to parking_lot_core.
501+ match unsafe {
502+ park (
503+ addr as usize ,
504+ || atomic. load ( Ordering :: SeqCst ) == expected,
505+ || { } ,
506+ |_, _| { } ,
507+ DEFAULT_PARK_TOKEN ,
508+ wait_until,
509+ )
510+ } {
511+ ParkResult :: Unparked ( _) => return Ok ( 0 ) ,
512+ ParkResult :: Invalid => return Ok ( 1 ) ,
513+ ParkResult :: TimedOut => return Ok ( 2 ) ,
514+ }
464515}
465516
466517// Implementation of `memory.atomic.wait64` for locally defined memories.
467518unsafe fn memory_atomic_wait64 (
468519 vmctx : * mut VMContext ,
469520 memory_index : u32 ,
470521 addr : u64 ,
471- _expected : u64 ,
472- _timeout : u64 ,
522+ expected : u64 ,
523+ timeout : u64 ,
473524) -> Result < u32 , TrapReason > {
525+ // convert to absolute timestamp as soon as possible
526+ let wait_until = ( timeout > 0 )
527+ . then ( || {
528+ Instant :: now ( )
529+ . checked_add ( Duration :: from_nanos ( timeout) )
530+ . ok_or_else ( || {
531+ TrapReason :: user_with_backtrace ( anyhow:: anyhow!(
532+ "overflow when adding timeout to current time"
533+ ) )
534+ } )
535+ } )
536+ . transpose ( ) ?;
537+
474538 let memory = MemoryIndex :: from_u32 ( memory_index) ;
475539 let instance = ( * vmctx) . instance ( ) ;
476- validate_atomic_addr ( instance, memory, addr, 8 , 8 ) ?;
477- Err (
478- anyhow:: anyhow!( "unimplemented: wasm atomics (fn memory_atomic_wait64) unsupported" , )
479- . into ( ) ,
480- )
540+ let addr = validate_atomic_addr ( instance, memory, addr, 8 , 8 ) ?;
541+
542+ // SAFETY: `addr` was validated by `validate_atomic_addr` above.
543+ let atomic = unsafe { & * ( addr as * const AtomicU64 ) } ;
544+ // SAFETY: `addr` is a valid pointer into the given memory and unique to parking_lot_core.
545+ match unsafe {
546+ park (
547+ addr as usize ,
548+ || atomic. load ( Ordering :: SeqCst ) == expected,
549+ || { } ,
550+ |_, _| { } ,
551+ DEFAULT_PARK_TOKEN ,
552+ wait_until,
553+ )
554+ } {
555+ ParkResult :: Unparked ( _) => return Ok ( 0 ) ,
556+ ParkResult :: Invalid => return Ok ( 1 ) ,
557+ ParkResult :: TimedOut => return Ok ( 2 ) ,
558+ }
481559}
482560
483561macro_rules! ensure {
@@ -498,17 +576,19 @@ unsafe fn validate_atomic_addr(
498576 addr : u64 ,
499577 access_size : u64 ,
500578 access_alignment : u64 ,
501- ) -> Result < ( ) , TrapCode > {
579+ ) -> Result < * mut u8 , TrapCode > {
502580 debug_assert ! ( access_alignment. is_power_of_two( ) ) ;
503581 ensure ! ( addr % access_alignment == 0 , TrapCode :: HeapMisaligned ) ;
504582
505- let length = u64:: try_from ( instance. get_memory ( memory) . current_length ( ) ) . unwrap ( ) ;
583+ let mem = instance. get_memory ( memory) ;
584+
585+ let length = u64:: try_from ( mem. current_length ( ) ) . unwrap ( ) ;
506586 ensure ! (
507587 addr. saturating_add( access_size) < length,
508588 TrapCode :: HeapOutOfBounds
509589 ) ;
510590
511- Ok ( ( ) )
591+ Ok ( mem . base . add ( addr as usize ) )
512592}
513593
514594// Hook for when an instance runs out of fuel.
0 commit comments