2015-05-29 François Dumont fdumont@gcc.gnu.org>
[official-gcc.git] / libgo / go / runtime / time.go
blob11862c7e23520fe9e31ad1690ee0b36c98948832
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.
5 // Time-related runtime and pieces of package time.
7 package runtime
9 import "unsafe"
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
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
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
38 // nacl fake time support - time in nanoseconds since 1970
39 var faketime int64
41 // Package time APIs.
42 // Godoc uses the comments in package time, not these.
44 // time.now is implemented in assembly.
46 // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
47 func timeSleep(ns int64) {
48 if ns <= 0 {
49 return
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")
61 // startTimer adds t to the timer heap.
62 func startTimer(t *timer) {
63 if raceenabled {
64 racerelease(unsafe.Pointer(t))
66 addtimer(t)
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)
75 // Go runtime.
77 // Ready the goroutine arg.
78 func goroutineReady(arg interface{}, seq uintptr) {
79 goready(arg.(*g))
82 func addtimer(t *timer) {
83 lock(&timers.lock)
84 addtimerLocked(t)
85 unlock(&timers.lock)
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
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)
106 if timers.rescheduling {
107 timers.rescheduling = false
108 goready(timers.gp)
111 if !timers.created {
112 timers.created = true
113 go timerproc()
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
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
134 if i != last {
135 timers.t[i] = timers.t[last]
136 timers.t[i].i = i
138 timers.t[last] = nil
139 timers.t = timers.t[:last]
140 if i != last {
141 siftupTimer(i)
142 siftdownTimer(i)
144 unlock(&timers.lock)
145 return true
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
164 t := timers.t[0]
165 delta = t.when - now
166 if delta > 0 {
167 break
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
180 timers.t[last] = nil
181 timers.t = timers.t[:last]
182 if last > 0 {
183 siftdownTimer(0)
185 t.i = -1 // mark as removed
187 f := t.f
188 arg := t.arg
189 seq := t.seq
190 unlock(&timers.lock)
191 if raceenabled {
192 raceacquire(unsafe.Pointer(t))
194 f(arg, seq)
195 lock(&timers.lock)
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
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)
211 func timejump() *g {
212 if faketime == 0 {
213 return nil
216 lock(&timers.lock)
217 if !timers.created || len(timers.t) == 0 {
218 unlock(&timers.lock)
219 return nil
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
230 unlock(&timers.lock)
231 return gp
234 // Heap maintenance algorithms.
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
245 t[i] = t[p]
246 t[i].i = i
247 t[p] = tmp
248 t[p].i = p
249 i = p
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
264 w := t[c].when
265 if c+1 < n && t[c+1].when < w {
266 w = t[c+1].when
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++
275 if w3 < w {
276 w = w3
277 c = c3
280 if w >= when {
281 break
283 t[i] = t[c]
284 t[i].i = i
285 t[c] = tmp
286 t[c].i = c
287 i = c