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