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