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