github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/sleep/sleep_unsafe.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build go1.11 16 // +build !go1.14 17 18 // Check go:linkname function signatures when updating Go version. 19 20 // Package sleep allows goroutines to efficiently sleep on multiple sources of 21 // notifications (wakers). It offers O(1) complexity, which is different from 22 // multi-channel selects which have O(n) complexity (where n is the number of 23 // channels) and a considerable constant factor. 24 // 25 // It is similar to edge-triggered epoll waits, where the user registers each 26 // object of interest once, and then can repeatedly wait on all of them. 27 // 28 // A Waker object is used to wake a sleeping goroutine (G) up, or prevent it 29 // from going to sleep next. A Sleeper object is used to receive notifications 30 // from wakers, and if no notifications are available, to optionally sleep until 31 // one becomes available. 32 // 33 // A Waker can be associated with at most one Sleeper, but a Sleeper can be 34 // associated with multiple Wakers. A Sleeper has a list of asserted (ready) 35 // wakers; when Fetch() is called repeatedly, elements from this list are 36 // returned until the list becomes empty in which case the goroutine goes to 37 // sleep. When Assert() is called on a Waker, it adds itself to the Sleeper's 38 // asserted list and wakes the G up from its sleep if needed. 39 // 40 // Sleeper objects are expected to be used as follows, with just one goroutine 41 // executing this code: 42 // 43 // // One time set-up. 44 // s := sleep.Sleeper{} 45 // s.AddWaker(&w1, constant1) 46 // s.AddWaker(&w2, constant2) 47 // 48 // // Called repeatedly. 49 // for { 50 // switch id, _ := s.Fetch(true); id { 51 // case constant1: 52 // // Do work triggered by w1 being asserted. 53 // case constant2: 54 // // Do work triggered by w2 being asserted. 55 // } 56 // } 57 // 58 // And Waker objects are expected to call w.Assert() when they want the sleeper 59 // to wake up and perform work. 60 // 61 // The notifications are edge-triggered, which means that if a Waker calls 62 // Assert() several times before the sleeper has the chance to wake up, it will 63 // only be notified once and should perform all pending work (alternatively, it 64 // can also call Assert() on the waker, to ensure that it will wake up again). 65 // 66 // The "unsafeness" here is in the casts to/from unsafe.Pointer, which is safe 67 // when only one type is used for each unsafe.Pointer (which is the case here), 68 // we should just make sure that this remains the case in the future. The usage 69 // of unsafe package could be confined to sharedWaker and sharedSleeper types 70 // that would hold pointers in atomic.Pointers, but the go compiler currently 71 // can't optimize these as well (it won't inline their method calls), which 72 // reduces performance. 73 package sleep 74 75 import ( 76 "sync/atomic" 77 "unsafe" 78 ) 79 80 const ( 81 // preparingG is stored in sleepers to indicate that they're preparing 82 // to sleep. 83 preparingG = 1 84 ) 85 86 var ( 87 // assertedSleeper is a sentinel sleeper. A pointer to it is stored in 88 // wakers that are asserted. 89 assertedSleeper Sleeper 90 ) 91 92 //go:linkname gopark runtime.gopark 93 func gopark(unlockf func(uintptr, *uintptr) bool, wg *uintptr, reason uint8, traceEv byte, traceskip int) 94 95 //go:linkname goready runtime.goready 96 func goready(g uintptr, traceskip int) 97 98 // Sleeper allows a goroutine to sleep and receive wake up notifications from 99 // Wakers in an efficient way. 100 // 101 // This is similar to edge-triggered epoll in that wakers are added to the 102 // sleeper once and the sleeper can then repeatedly sleep in O(1) time while 103 // waiting on all wakers. 104 // 105 // None of the methods in a Sleeper can be called concurrently. Wakers that have 106 // been added to a sleeper A can only be added to another sleeper after A.Done() 107 // returns. These restrictions allow this to be implemented lock-free. 108 // 109 // This struct is thread-compatible. 110 type Sleeper struct { 111 // sharedList is a "stack" of asserted wakers. They atomically add 112 // themselves to the front of this list as they become asserted. 113 sharedList unsafe.Pointer 114 115 // localList is a list of asserted wakers that is only accessible to the 116 // waiter, and thus doesn't have to be accessed atomically. When 117 // fetching more wakers, the waiter will first go through this list, and 118 // only when it's empty will it atomically fetch wakers from 119 // sharedList. 120 localList *Waker 121 122 // allWakers is a list with all wakers that have been added to this 123 // sleeper. It is used during cleanup to remove associations. 124 allWakers *Waker 125 126 // waitingG holds the G that is sleeping, if any. It is used by wakers 127 // to determine which G, if any, they should wake. 128 waitingG uintptr 129 } 130 131 // AddWaker associates the given waker to the sleeper. id is the value to be 132 // returned when the sleeper is woken by the given waker. 133 func (s *Sleeper) AddWaker(w *Waker, id int) { 134 // Add the waker to the list of all wakers. 135 w.allWakersNext = s.allWakers 136 s.allWakers = w 137 w.id = id 138 139 // Try to associate the waker with the sleeper. If it's already 140 // asserted, we simply enqueue it in the "ready" list. 141 for { 142 p := (*Sleeper)(atomic.LoadPointer(&w.s)) 143 if p == &assertedSleeper { 144 s.enqueueAssertedWaker(w) 145 return 146 } 147 148 if atomic.CompareAndSwapPointer(&w.s, usleeper(p), usleeper(s)) { 149 return 150 } 151 } 152 } 153 154 // nextWaker returns the next waker in the notification list, blocking if 155 // needed. 156 func (s *Sleeper) nextWaker(block bool) *Waker { 157 // Attempt to replenish the local list if it's currently empty. 158 if s.localList == nil { 159 for atomic.LoadPointer(&s.sharedList) == nil { 160 // Fail request if caller requested that we 161 // don't block. 162 if !block { 163 return nil 164 } 165 166 // Indicate to wakers that we're about to sleep, 167 // this allows them to abort the wait by setting 168 // waitingG back to zero (which we'll notice 169 // before committing the sleep). 170 atomic.StoreUintptr(&s.waitingG, preparingG) 171 172 // Check if something was queued while we were 173 // preparing to sleep. We need this interleaving 174 // to avoid missing wake ups. 175 if atomic.LoadPointer(&s.sharedList) != nil { 176 atomic.StoreUintptr(&s.waitingG, 0) 177 break 178 } 179 180 // Try to commit the sleep and report it to the 181 // tracer as a select. 182 // 183 // gopark puts the caller to sleep and calls 184 // commitSleep to decide whether to immediately 185 // wake the caller up or to leave it sleeping. 186 const traceEvGoBlockSelect = 24 187 // See:runtime2.go in the go runtime package for 188 // the values to pass as the waitReason here. 189 const waitReasonSelect = 9 190 gopark(commitSleep, &s.waitingG, waitReasonSelect, traceEvGoBlockSelect, 0) 191 } 192 193 // Pull the shared list out and reverse it in the local 194 // list. Given that wakers push themselves in reverse 195 // order, we fix things here. 196 v := (*Waker)(atomic.SwapPointer(&s.sharedList, nil)) 197 for v != nil { 198 cur := v 199 v = v.next 200 201 cur.next = s.localList 202 s.localList = cur 203 } 204 } 205 206 // Remove the waker in the front of the list. 207 w := s.localList 208 s.localList = w.next 209 210 return w 211 } 212 213 // Fetch fetches the next wake-up notification. If a notification is immediately 214 // available, it is returned right away. Otherwise, the behavior depends on the 215 // value of 'block': if true, the current goroutine blocks until a notification 216 // arrives, then returns it; if false, returns 'ok' as false. 217 // 218 // When 'ok' is true, the value of 'id' corresponds to the id associated with 219 // the waker; when 'ok' is false, 'id' is undefined. 220 // 221 // N.B. This method is *not* thread-safe. Only one goroutine at a time is 222 // allowed to call this method. 223 func (s *Sleeper) Fetch(block bool) (id int, ok bool) { 224 for { 225 w := s.nextWaker(block) 226 if w == nil { 227 return -1, false 228 } 229 230 // Reassociate the waker with the sleeper. If the waker was 231 // still asserted we can return it, otherwise try the next one. 232 old := (*Sleeper)(atomic.SwapPointer(&w.s, usleeper(s))) 233 if old == &assertedSleeper { 234 return w.id, true 235 } 236 } 237 } 238 239 // Done is used to indicate that the caller won't use this Sleeper anymore. It 240 // removes the association with all wakers so that they can be safely reused 241 // by another sleeper after Done() returns. 242 func (s *Sleeper) Done() { 243 // Remove all associations that we can, and build a list of the ones 244 // we could not. An association can be removed right away from waker w 245 // if w.s has a pointer to the sleeper, that is, the waker is not 246 // asserted yet. By atomically switching w.s to nil, we guarantee that 247 // subsequent calls to Assert() on the waker will not result in it being 248 // queued to this sleeper. 249 var pending *Waker 250 w := s.allWakers 251 for w != nil { 252 next := w.allWakersNext 253 for { 254 t := atomic.LoadPointer(&w.s) 255 if t != usleeper(s) { 256 w.allWakersNext = pending 257 pending = w 258 break 259 } 260 261 if atomic.CompareAndSwapPointer(&w.s, t, nil) { 262 break 263 } 264 } 265 w = next 266 } 267 268 // The associations that we could not remove are either asserted, or in 269 // the process of being asserted, or have been asserted and cleared 270 // before being pulled from the sleeper lists. We must wait for them all 271 // to make it to the sleeper lists, so that we know that the wakers 272 // won't do any more work towards waking this sleeper up. 273 for pending != nil { 274 pulled := s.nextWaker(true) 275 276 // Remove the waker we just pulled from the list of associated 277 // wakers. 278 prev := &pending 279 for w := *prev; w != nil; w = *prev { 280 if pulled == w { 281 *prev = w.allWakersNext 282 break 283 } 284 prev = &w.allWakersNext 285 } 286 } 287 s.allWakers = nil 288 } 289 290 // enqueueAssertedWaker enqueues an asserted waker to the "ready" circular list 291 // of wakers that want to notify the sleeper. 292 func (s *Sleeper) enqueueAssertedWaker(w *Waker) { 293 // Add the new waker to the front of the list. 294 for { 295 v := (*Waker)(atomic.LoadPointer(&s.sharedList)) 296 w.next = v 297 if atomic.CompareAndSwapPointer(&s.sharedList, uwaker(v), uwaker(w)) { 298 break 299 } 300 } 301 302 for { 303 // Nothing to do if there isn't a G waiting. 304 g := atomic.LoadUintptr(&s.waitingG) 305 if g == 0 { 306 return 307 } 308 309 // Signal to the sleeper that a waker has been asserted. 310 if atomic.CompareAndSwapUintptr(&s.waitingG, g, 0) { 311 if g != preparingG { 312 // We managed to get a G. Wake it up. 313 goready(g, 0) 314 } 315 } 316 } 317 } 318 319 // Waker represents a source of wake-up notifications to be sent to sleepers. A 320 // waker can be associated with at most one sleeper at a time, and at any given 321 // time is either in asserted or non-asserted state. 322 // 323 // Once asserted, the waker remains so until it is manually cleared or a sleeper 324 // consumes its assertion (i.e., a sleeper wakes up or is prevented from going 325 // to sleep due to the waker). 326 // 327 // This struct is thread-safe, that is, its methods can be called concurrently 328 // by multiple goroutines. 329 type Waker struct { 330 // s is the sleeper that this waker can wake up. Only one sleeper at a 331 // time is allowed. This field can have three classes of values: 332 // nil -- the waker is not asserted: it either is not associated with 333 // a sleeper, or is queued to a sleeper due to being previously 334 // asserted. This is the zero value. 335 // &assertedSleeper -- the waker is asserted. 336 // otherwise -- the waker is not asserted, and is associated with the 337 // given sleeper. Once it transitions to asserted state, the 338 // associated sleeper will be woken. 339 s unsafe.Pointer 340 341 // next is used to form a linked list of asserted wakers in a sleeper. 342 next *Waker 343 344 // allWakersNext is used to form a linked list of all wakers associated 345 // to a given sleeper. 346 allWakersNext *Waker 347 348 // id is the value to be returned to sleepers when they wake up due to 349 // this waker being asserted. 350 id int 351 } 352 353 // Assert moves the waker to an asserted state, if it isn't asserted yet. When 354 // asserted, the waker will cause its matching sleeper to wake up. 355 func (w *Waker) Assert() { 356 // Nothing to do if the waker is already asserted. This check allows us 357 // to complete this case (already asserted) without any interlocked 358 // operations on x86. 359 if atomic.LoadPointer(&w.s) == usleeper(&assertedSleeper) { 360 return 361 } 362 363 // Mark the waker as asserted, and wake up a sleeper if there is one. 364 switch s := (*Sleeper)(atomic.SwapPointer(&w.s, usleeper(&assertedSleeper))); s { 365 case nil: 366 case &assertedSleeper: 367 default: 368 s.enqueueAssertedWaker(w) 369 } 370 } 371 372 // Clear moves the waker to then non-asserted state and returns whether it was 373 // asserted before being cleared. 374 // 375 // N.B. The waker isn't removed from the "ready" list of a sleeper (if it 376 // happens to be in one), but the sleeper will notice that it is not asserted 377 // anymore and won't return it to the caller. 378 func (w *Waker) Clear() bool { 379 // Nothing to do if the waker is not asserted. This check allows us to 380 // complete this case (already not asserted) without any interlocked 381 // operations on x86. 382 if atomic.LoadPointer(&w.s) != usleeper(&assertedSleeper) { 383 return false 384 } 385 386 // Try to store nil in the sleeper, which indicates that the waker is 387 // not asserted. 388 return atomic.CompareAndSwapPointer(&w.s, usleeper(&assertedSleeper), nil) 389 } 390 391 // IsAsserted returns whether the waker is currently asserted (i.e., if it's 392 // currently in a state that would cause its matching sleeper to wake up). 393 func (w *Waker) IsAsserted() bool { 394 return (*Sleeper)(atomic.LoadPointer(&w.s)) == &assertedSleeper 395 } 396 397 func usleeper(s *Sleeper) unsafe.Pointer { 398 return unsafe.Pointer(s) 399 } 400 401 func uwaker(w *Waker) unsafe.Pointer { 402 return unsafe.Pointer(w) 403 }