@@ -800,9 +800,12 @@ pub fn park() {
800
800
match thread. inner . state . compare_exchange ( EMPTY , PARKED , SeqCst , SeqCst ) {
801
801
Ok ( _) => { }
802
802
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`.
806
809
let old = thread. inner . state . swap ( EMPTY , SeqCst ) ;
807
810
assert_eq ! ( old, NOTIFIED , "park state changed unexpectedly" ) ;
808
811
return ;
@@ -893,9 +896,7 @@ pub fn park_timeout(dur: Duration) {
893
896
match thread. inner . state . compare_exchange ( EMPTY , PARKED , SeqCst , SeqCst ) {
894
897
Ok ( _) => { }
895
898
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`.
899
900
let old = thread. inner . state . swap ( EMPTY , SeqCst ) ;
900
901
assert_eq ! ( old, NOTIFIED , "park state changed unexpectedly" ) ;
901
902
return ;
@@ -1066,8 +1067,12 @@ impl Thread {
1066
1067
/// [park]: fn.park.html
1067
1068
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1068
1069
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.
1071
1076
match self . inner . state . swap ( NOTIFIED , SeqCst ) {
1072
1077
EMPTY => return , // no one was waiting
1073
1078
NOTIFIED => return , // already unparked
0 commit comments