github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/runtime/time.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Time-related runtime and pieces of package time. 6 7 package runtime 8 9 import "unsafe" 10 11 // Package time knows the layout of this structure. 12 // If this struct changes, adjust ../time/sleep.go:/runtimeTimer. 13 // For GOOS=nacl, package syscall knows the layout of this structure. 14 // If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer. 15 type timer struct { 16 i int // heap index 17 18 // Timer wakes up at when, and then at when+period, ... (period > 0 only) 19 // each time calling f(arg, now) in the timer goroutine, so f must be 20 // a well-behaved function and not block. 21 when int64 22 period int64 23 f func(interface{}, uintptr) 24 arg interface{} 25 seq uintptr 26 } 27 28 var timers struct { 29 lock mutex 30 gp *g 31 created bool 32 sleeping bool 33 rescheduling bool 34 sleepUntil int64 35 waitnote note 36 t []*timer 37 } 38 39 // nacl fake time support - time in nanoseconds since 1970 40 var faketime int64 41 42 // Package time APIs. 43 // Godoc uses the comments in package time, not these. 44 45 // time.now is implemented in assembly. 46 47 // timeSleep puts the current goroutine to sleep for at least ns nanoseconds. 48 //go:linkname timeSleep time.Sleep 49 func timeSleep(ns int64) { 50 if ns <= 0 { 51 return 52 } 53 54 t := getg().timer 55 if t == nil { 56 t = new(timer) 57 getg().timer = t 58 } 59 *t = timer{} 60 t.when = nanotime() + ns 61 t.f = goroutineReady 62 t.arg = getg() 63 lock(&timers.lock) 64 addtimerLocked(t) 65 goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2) 66 } 67 68 // startTimer adds t to the timer heap. 69 //go:linkname startTimer time.startTimer 70 func startTimer(t *timer) { 71 if raceenabled { 72 racerelease(unsafe.Pointer(t)) 73 } 74 addtimer(t) 75 } 76 77 // stopTimer removes t from the timer heap if it is there. 78 // It returns true if t was removed, false if t wasn't even there. 79 //go:linkname stopTimer time.stopTimer 80 func stopTimer(t *timer) bool { 81 return deltimer(t) 82 } 83 84 // Go runtime. 85 86 // Ready the goroutine arg. 87 func goroutineReady(arg interface{}, seq uintptr) { 88 goready(arg.(*g), 0) 89 } 90 91 func addtimer(t *timer) { 92 lock(&timers.lock) 93 addtimerLocked(t) 94 unlock(&timers.lock) 95 } 96 97 // Add a timer to the heap and start or kick timerproc if the new timer is 98 // earlier than any of the others. 99 // Timers are locked. 100 func addtimerLocked(t *timer) { 101 // when must never be negative; otherwise timerproc will overflow 102 // during its delta calculation and never expire other runtime timers. 103 if t.when < 0 { 104 t.when = 1<<63 - 1 105 } 106 t.i = len(timers.t) 107 timers.t = append(timers.t, t) 108 siftupTimer(t.i) 109 if t.i == 0 { 110 // siftup moved to top: new earliest deadline. 111 if timers.sleeping { 112 timers.sleeping = false 113 notewakeup(&timers.waitnote) 114 } 115 if timers.rescheduling { 116 timers.rescheduling = false 117 goready(timers.gp, 0) 118 } 119 } 120 if !timers.created { 121 timers.created = true 122 go timerproc() 123 } 124 } 125 126 // Delete timer t from the heap. 127 // Do not need to update the timerproc: if it wakes up early, no big deal. 128 func deltimer(t *timer) bool { 129 // Dereference t so that any panic happens before the lock is held. 130 // Discard result, because t might be moving in the heap. 131 _ = t.i 132 133 lock(&timers.lock) 134 // t may not be registered anymore and may have 135 // a bogus i (typically 0, if generated by Go). 136 // Verify it before proceeding. 137 i := t.i 138 last := len(timers.t) - 1 139 if i < 0 || i > last || timers.t[i] != t { 140 unlock(&timers.lock) 141 return false 142 } 143 if i != last { 144 timers.t[i] = timers.t[last] 145 timers.t[i].i = i 146 } 147 timers.t[last] = nil 148 timers.t = timers.t[:last] 149 if i != last { 150 siftupTimer(i) 151 siftdownTimer(i) 152 } 153 unlock(&timers.lock) 154 return true 155 } 156 157 // Timerproc runs the time-driven events. 158 // It sleeps until the next event in the timers heap. 159 // If addtimer inserts a new earlier event, it wakes timerproc early. 160 func timerproc() { 161 timers.gp = getg() 162 for { 163 lock(&timers.lock) 164 timers.sleeping = false 165 now := nanotime() 166 delta := int64(-1) 167 for { 168 if len(timers.t) == 0 { 169 delta = -1 170 break 171 } 172 t := timers.t[0] 173 delta = t.when - now 174 if delta > 0 { 175 break 176 } 177 if t.period > 0 { 178 // leave in heap but adjust next time to fire 179 t.when += t.period * (1 + -delta/t.period) 180 siftdownTimer(0) 181 } else { 182 // remove from heap 183 last := len(timers.t) - 1 184 if last > 0 { 185 timers.t[0] = timers.t[last] 186 timers.t[0].i = 0 187 } 188 timers.t[last] = nil 189 timers.t = timers.t[:last] 190 if last > 0 { 191 siftdownTimer(0) 192 } 193 t.i = -1 // mark as removed 194 } 195 f := t.f 196 arg := t.arg 197 seq := t.seq 198 unlock(&timers.lock) 199 if raceenabled { 200 raceacquire(unsafe.Pointer(t)) 201 } 202 f(arg, seq) 203 lock(&timers.lock) 204 } 205 if delta < 0 || faketime > 0 { 206 // No timers left - put goroutine to sleep. 207 timers.rescheduling = true 208 goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1) 209 continue 210 } 211 // At least one timer pending. Sleep until then. 212 timers.sleeping = true 213 timers.sleepUntil = now + delta 214 noteclear(&timers.waitnote) 215 unlock(&timers.lock) 216 notetsleepg(&timers.waitnote, delta) 217 } 218 } 219 220 func timejump() *g { 221 if faketime == 0 { 222 return nil 223 } 224 225 lock(&timers.lock) 226 if !timers.created || len(timers.t) == 0 { 227 unlock(&timers.lock) 228 return nil 229 } 230 231 var gp *g 232 if faketime < timers.t[0].when { 233 faketime = timers.t[0].when 234 if timers.rescheduling { 235 timers.rescheduling = false 236 gp = timers.gp 237 } 238 } 239 unlock(&timers.lock) 240 return gp 241 } 242 243 // Heap maintenance algorithms. 244 245 func siftupTimer(i int) { 246 t := timers.t 247 when := t[i].when 248 tmp := t[i] 249 for i > 0 { 250 p := (i - 1) / 4 // parent 251 if when >= t[p].when { 252 break 253 } 254 t[i] = t[p] 255 t[i].i = i 256 t[p] = tmp 257 t[p].i = p 258 i = p 259 } 260 } 261 262 func siftdownTimer(i int) { 263 t := timers.t 264 n := len(t) 265 when := t[i].when 266 tmp := t[i] 267 for { 268 c := i*4 + 1 // left child 269 c3 := c + 2 // mid child 270 if c >= n { 271 break 272 } 273 w := t[c].when 274 if c+1 < n && t[c+1].when < w { 275 w = t[c+1].when 276 c++ 277 } 278 if c3 < n { 279 w3 := t[c3].when 280 if c3+1 < n && t[c3+1].when < w3 { 281 w3 = t[c3+1].when 282 c3++ 283 } 284 if w3 < w { 285 w = w3 286 c = c3 287 } 288 } 289 if w >= when { 290 break 291 } 292 t[i] = t[c] 293 t[i].i = i 294 t[c] = tmp 295 t[c].i = c 296 i = c 297 } 298 } 299 300 // Entry points for net, time to call nanotime. 301 302 //go:linkname poll_runtimeNano internal/poll.runtimeNano 303 func poll_runtimeNano() int64 { 304 return nanotime() 305 } 306 307 //go:linkname time_runtimeNano time.runtimeNano 308 func time_runtimeNano() int64 { 309 return nanotime() 310 } 311 312 var startNano int64 = nanotime()