blob: ffe75905263165f898030a2b8a4a7e077577dded [file] [log] [blame]
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +04001// 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
7package runtime
8
9import "unsafe"
10
11// Package time knows the layout of this structure.
Dmitriy Vyukov91a670d2014-09-04 10:04:04 +040012// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040013// For GOOS=nacl, package syscall knows the layout of this structure.
14// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
15type 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
Dmitriy Vyukov91a670d2014-09-04 10:04:04 +040023 f func(interface{}, uintptr)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040024 arg interface{}
Dmitriy Vyukov91a670d2014-09-04 10:04:04 +040025 seq uintptr
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040026}
27
28var timers struct {
Russ Cox8ecb9a72014-08-27 23:32:49 -040029 lock mutex
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040030 gp *g
31 created bool
32 sleeping bool
33 rescheduling bool
34 waitnote note
35 t []*timer
36}
37
Shenghou Ma2fe94822014-10-27 20:35:15 -040038// nacl fake time support - time in nanoseconds since 1970
39var faketime int64
Dmitriy Vyukov21a4bde2014-08-25 23:24:18 +040040
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040041// Package time APIs.
42// Godoc uses the comments in package time, not these.
43
44// time.now is implemented in assembly.
45
Russ Cox7a524a12014-12-22 13:27:53 -050046// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
47//go:linkname timeSleep time.Sleep
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040048func timeSleep(ns int64) {
49 if ns <= 0 {
50 return
51 }
52
53 t := new(timer)
Russ Coxd21638b2014-08-27 21:59:49 -040054 t.when = nanotime() + ns
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040055 t.f = goroutineReady
56 t.arg = getg()
Russ Cox8ecb9a72014-08-27 23:32:49 -040057 lock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040058 addtimerLocked(t)
Dmitry Vyukov919fd242015-02-21 21:01:40 +030059 goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040060}
61
62// startTimer adds t to the timer heap.
Russ Cox7a524a12014-12-22 13:27:53 -050063//go:linkname startTimer time.startTimer
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040064func 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.
Russ Cox7a524a12014-12-22 13:27:53 -050073//go:linkname stopTimer time.stopTimer
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040074func stopTimer(t *timer) bool {
75 return deltimer(t)
76}
77
78// Go runtime.
79
80// Ready the goroutine arg.
Dmitriy Vyukov91a670d2014-09-04 10:04:04 +040081func goroutineReady(arg interface{}, seq uintptr) {
Dmitry Vyukov919fd242015-02-21 21:01:40 +030082 goready(arg.(*g), 0)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040083}
84
85func addtimer(t *timer) {
Russ Cox8ecb9a72014-08-27 23:32:49 -040086 lock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040087 addtimerLocked(t)
Russ Cox8ecb9a72014-08-27 23:32:49 -040088 unlock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +040089}
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.
94func 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
Russ Coxd21638b2014-08-27 21:59:49 -0400107 notewakeup(&timers.waitnote)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400108 }
109 if timers.rescheduling {
110 timers.rescheduling = false
Dmitry Vyukov919fd242015-02-21 21:01:40 +0300111 goready(timers.gp, 0)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400112 }
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.
122func 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
Russ Cox8ecb9a72014-08-27 23:32:49 -0400127 lock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400128 // 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 {
Russ Cox8ecb9a72014-08-27 23:32:49 -0400134 unlock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400135 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 }
Russ Cox8ecb9a72014-08-27 23:32:49 -0400147 unlock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400148 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.
154func timerproc() {
155 timers.gp = getg()
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400156 for {
Russ Cox8ecb9a72014-08-27 23:32:49 -0400157 lock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400158 timers.sleeping = false
Russ Coxd21638b2014-08-27 21:59:49 -0400159 now := nanotime()
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400160 delta := int64(-1)
161 for {
162 if len(timers.t) == 0 {
163 delta = -1
164 break
165 }
166 t := timers.t[0]
167 delta = t.when - now
168 if delta > 0 {
169 break
170 }
171 if t.period > 0 {
172 // leave in heap but adjust next time to fire
173 t.when += t.period * (1 + -delta/t.period)
174 siftdownTimer(0)
175 } else {
176 // remove from heap
177 last := len(timers.t) - 1
178 if last > 0 {
179 timers.t[0] = timers.t[last]
180 timers.t[0].i = 0
181 }
182 timers.t[last] = nil
183 timers.t = timers.t[:last]
184 if last > 0 {
185 siftdownTimer(0)
186 }
187 t.i = -1 // mark as removed
188 }
189 f := t.f
190 arg := t.arg
Dmitriy Vyukov91a670d2014-09-04 10:04:04 +0400191 seq := t.seq
Russ Cox8ecb9a72014-08-27 23:32:49 -0400192 unlock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400193 if raceenabled {
194 raceacquire(unsafe.Pointer(t))
195 }
Dmitriy Vyukov91a670d2014-09-04 10:04:04 +0400196 f(arg, seq)
Russ Cox8ecb9a72014-08-27 23:32:49 -0400197 lock(&timers.lock)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400198 }
Shenghou Ma2fe94822014-10-27 20:35:15 -0400199 if delta < 0 || faketime > 0 {
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400200 // No timers left - put goroutine to sleep.
201 timers.rescheduling = true
Dmitry Vyukov919fd242015-02-21 21:01:40 +0300202 goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400203 continue
204 }
205 // At least one timer pending. Sleep until then.
206 timers.sleeping = true
Russ Coxd21638b2014-08-27 21:59:49 -0400207 noteclear(&timers.waitnote)
Russ Cox8ecb9a72014-08-27 23:32:49 -0400208 unlock(&timers.lock)
Russ Coxd21638b2014-08-27 21:59:49 -0400209 notetsleepg(&timers.waitnote, delta)
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400210 }
211}
212
Shenghou Ma2fe94822014-10-27 20:35:15 -0400213func timejump() *g {
214 if faketime == 0 {
215 return nil
216 }
217
218 lock(&timers.lock)
219 if !timers.created || len(timers.t) == 0 {
220 unlock(&timers.lock)
221 return nil
222 }
223
224 var gp *g
225 if faketime < timers.t[0].when {
226 faketime = timers.t[0].when
227 if timers.rescheduling {
228 timers.rescheduling = false
229 gp = timers.gp
230 }
231 }
232 unlock(&timers.lock)
233 return gp
234}
235
Dmitriy Vyukov9601aba2014-08-25 20:25:22 +0400236// Heap maintenance algorithms.
237
238func siftupTimer(i int) {
239 t := timers.t
240 when := t[i].when
241 tmp := t[i]
242 for i > 0 {
243 p := (i - 1) / 4 // parent
244 if when >= t[p].when {
245 break
246 }
247 t[i] = t[p]
248 t[i].i = i
249 t[p] = tmp
250 t[p].i = p
251 i = p
252 }
253}
254
255func siftdownTimer(i int) {
256 t := timers.t
257 n := len(t)
258 when := t[i].when
259 tmp := t[i]
260 for {
261 c := i*4 + 1 // left child
262 c3 := c + 2 // mid child
263 if c >= n {
264 break
265 }
266 w := t[c].when
267 if c+1 < n && t[c+1].when < w {
268 w = t[c+1].when
269 c++
270 }
271 if c3 < n {
272 w3 := t[c3].when
273 if c3+1 < n && t[c3+1].when < w3 {
274 w3 = t[c3+1].when
275 c3++
276 }
277 if w3 < w {
278 w = w3
279 c = c3
280 }
281 }
282 if w >= when {
283 break
284 }
285 t[i] = t[c]
286 t[i].i = i
287 t[c] = tmp
288 t[c].i = c
289 i = c
290 }
291}
Russ Cox7a524a12014-12-22 13:27:53 -0500292
293// Entry points for net, time to call nanotime.
294
295//go:linkname net_runtimeNano net.runtimeNano
296func net_runtimeNano() int64 {
297 return nanotime()
298}
299
300//go:linkname time_runtimeNano time.runtimeNano
301func time_runtimeNano() int64 {
302 return nanotime()
303}