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