@@ -800,9 +800,12 @@ pub fn park() {
800800 match thread. inner . state . compare_exchange ( EMPTY , PARKED , SeqCst , SeqCst ) {
801801 Ok ( _) => { }
802802 Err ( NOTIFIED ) => {
803- // We must read again here, even though we know it will be NOTIFY,
804- // to synchronize with an write in `unpark` that occurred since we
805- // last read.
803+ // We must read here, even though we know it will be `NOTIFIED`.
804+ // This is because `unpark` may have been called again since we read
805+ // `NOTIFIED` in the `compare_exchange` above. We must perform an
806+ // acquire operation that synchronizes with that `unpark` to observe
807+ // any writes it made before the call to unpark. To do that we must
808+ // read from the write it made to `state`.
806809 let old = thread. inner . state . swap ( EMPTY , SeqCst ) ;
807810 assert_eq ! ( old, NOTIFIED , "park state changed unexpectedly" ) ;
808811 return ;
@@ -893,9 +896,7 @@ pub fn park_timeout(dur: Duration) {
893896 match thread. inner . state . compare_exchange ( EMPTY , PARKED , SeqCst , SeqCst ) {
894897 Ok ( _) => { }
895898 Err ( NOTIFIED ) => {
896- // We must read again here, even though we know it will be NOTIFY,
897- // to synchronize with an write in `unpark` that occurred since we
898- // last read.
899+ // We must read again here, see `park`.
899900 let old = thread. inner . state . swap ( EMPTY , SeqCst ) ;
900901 assert_eq ! ( old, NOTIFIED , "park state changed unexpectedly" ) ;
901902 return ;
@@ -1066,8 +1067,12 @@ impl Thread {
10661067 /// [park]: fn.park.html
10671068 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
10681069 pub fn unpark ( & self ) {
1069- // We must unconditionally write NOTIFIED here to
1070- // synchronize with a read in `park`.
1070+ // To ensure the unparked thread will observe any writes we made
1071+ // before this call, we must perform a release operation that `park`
1072+ // can synchronize with. To do that we must write `NOTIFIED` even if
1073+ // `state` is already `NOTIFIED`. That is why this must be a swap
1074+ // rather than a compare-and-swap that returns if it reads `NOTIFIED`
1075+ // on failure.
10711076 match self . inner . state . swap ( NOTIFIED , SeqCst ) {
10721077 EMPTY => return , // no one was waiting
10731078 NOTIFIED => return , // already unparked
0 commit comments