Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1474)

Delta Between Two Patch Sets: src/pkg/time/sleep.go

Issue 4063043: code review 4063043: time: allow cancelling of After events. (Closed)
Left Patch Set: code review 4063043: time: allow cancelling of After events. Created 13 years, 2 months ago
Right Patch Set: code review 4063043: time: allow cancelling of After events. Created 13 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/pkg/time/sleep_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package time 5 package time
6 6
7 import ( 7 import (
8 "os" 8 "os"
9 "syscall" 9 "syscall"
10 "sync" 10 "sync"
11 "container/heap" 11 "container/heap"
12 ) 12 )
13 13
14 // The Timer type represents a single After or AfterFunc event. 14 // The Timer type represents a single event.
15 // When the Timer expires, the current time will be sent on C
16 // unless the Timer represents an AfterFunc event.
15 type Timer struct { 17 type Timer struct {
18 C <-chan int64
16 t int64 // The absolute time that the event should fire. 19 t int64 // The absolute time that the event should fire.
17 f func(int64) // The function to call when the event fires. 20 f func(int64) // The function to call when the event fires.
18 i int // The event's index inside eventHeap. 21 i int // The event's index inside eventHeap.
19 } 22 }
20 23
21 type timerHeap []*Timer 24 type timerHeap []*Timer
22 25
23 var timerMutex sync.Mutex 26 // forever is the absolute time (in ns) of an event that is forever away.
24 var timers timerHeap
25 var currentSleeper int64
26
27 const forever = 1 << 62 27 const forever = 1 << 62
28
29 // maxSleepTime is the maximum length of time that a sleeper
30 // sleeps for before checking if it is defunct.
28 const maxSleepTime = 1e9 31 const maxSleepTime = 1e9
29 32
33 var (
34 // timerMutex guards the variables inside this var group.
35 timerMutex sync.Mutex
36
37 // timers holds a binary heap of pending events, terminated with a senti nel.
38 timers timerHeap
39
40 // currentSleeper is an ever-incrementing counter which represents
41 // the current sleeper. It allows older sleepers to detect that they are
42 // defunct and exit.
43 currentSleeper int64
44 )
45
30 func init() { 46 func init() {
31 » timers.Push(&Timer{forever, nil, 0}) // sentinel 47 » timers.Push(&Timer{t: forever}) // sentinel
32 } 48 }
33 49
34 // Sleep pauses the current goroutine for at least ns nanoseconds. 50 // Sleep pauses the current goroutine for at least ns nanoseconds.
35 // Higher resolution sleeping may be provided by syscall.Nanosleep· 51 // Higher resolution sleeping may be provided by syscall.Nanosleep·
36 // on some operating systems. 52 // on some operating systems.
37 func Sleep(ns int64) os.Error { 53 func Sleep(ns int64) os.Error {
38 _, err := sleep(Nanoseconds(), ns) 54 _, err := sleep(Nanoseconds(), ns)
39 return err 55 return err
40 } 56 }
41 57
42 // sleep takes the current time and a duration, 58 // sleep takes the current time and a duration,
43 // pauses for at least ns nanoseconds, and 59 // pauses for at least ns nanoseconds, and
44 // returns the current time and an error. 60 // returns the current time and an error.
45 func sleep(t, ns int64) (int64, os.Error) { 61 func sleep(t, ns int64) (int64, os.Error) {
46 // TODO(cw): use monotonic-time once it's available 62 // TODO(cw): use monotonic-time once it's available
47 end := t + ns 63 end := t + ns
48 for t < end { 64 for t < end {
49 errno := syscall.Sleep(end - t) 65 errno := syscall.Sleep(end - t)
50 if errno != 0 && errno != syscall.EINTR { 66 if errno != 0 && errno != syscall.EINTR {
51 return 0, os.NewSyscallError("sleep", errno) 67 return 0, os.NewSyscallError("sleep", errno)
52 } 68 }
53 t = Nanoseconds() 69 t = Nanoseconds()
54 } 70 }
55 return t, nil 71 return t, nil
56 } 72 }
57 73
58 // After waits at least ns nanoseconds before sending the current time 74 // NewTimer creates a new Timer that will send
59 // on the returned channel. The returned Timer can be used to 75 // the current time on its channel after at least ns nanoseconds.
60 // prevent the send. 76 func NewTimer(ns int64) *Timer {
61 func After(ns int64) (<-chan int64, *Timer) {
62 c := make(chan int64, 1) 77 c := make(chan int64, 1)
63 e := after(ns, func(t int64) { c <- t }) 78 e := after(ns, func(t int64) { c <- t })
64 » return c, e 79 » e.C = c
80 » return e
81 }
82
83 // After waits at least ns nanoseconds before sending the current time
84 // on the returned channel.
85 // It is equivalent to NewTimer(ns).C.
86 func After(ns int64) <-chan int64 {
87 » return NewTimer(ns).C
65 } 88 }
66 89
67 // AfterFunc waits at least ns nanoseconds before calling f 90 // AfterFunc waits at least ns nanoseconds before calling f
68 // in its own goroutine. It returns a Timer that can 91 // in its own goroutine. It returns a Timer that can
69 // be used to prevent the call. 92 // be used to cancel the call using its Stop method.
70 func AfterFunc(ns int64, f func()) *Timer { 93 func AfterFunc(ns int64, f func()) *Timer {
71 return after(ns, func(_ int64) { 94 return after(ns, func(_ int64) {
72 go f() 95 go f()
73 }) 96 })
74 } 97 }
75 98
76 // Stop prevents the Timer from firing. 99 // Stop prevents the Timer from firing.
77 // It returns true if it succeeded (i.e. the 100 // It returns true if the call stops the timer, false if the timer has already
78 // timer has not already fired or been stopped). 101 // expired or stopped.
79 func (e *Timer) Stop() (ok bool) { 102 func (e *Timer) Stop() (ok bool) {
80 timerMutex.Lock() 103 timerMutex.Lock()
81 // Avoid removing the first event in the queue so that 104 // Avoid removing the first event in the queue so that
82 // we don't start a new sleeper unnecessarily. 105 // we don't start a new sleeper unnecessarily.
83 if e.i > 0 { 106 if e.i > 0 {
84 heap.Remove(timers, e.i) 107 heap.Remove(timers, e.i)
85 } 108 }
86 ok = e.f != nil 109 ok = e.f != nil
87 e.f = nil 110 e.f = nil
88 timerMutex.Unlock() 111 timerMutex.Unlock()
89 return 112 return
90 } 113 }
91 114
92 // after is the implementation of After and AfterFunc. 115 // after is the implementation of After and AfterFunc.
93 // When the current time is after ns, it calls f with the current time. 116 // When the current time is after ns, it calls f with the current time.
94 // It assumes that f will not block. 117 // It assumes that f will not block.
95 func after(ns int64, f func(int64)) (e *Timer) { 118 func after(ns int64, f func(int64)) (e *Timer) {
119 now := Nanoseconds()
96 t := Nanoseconds() + ns 120 t := Nanoseconds() + ns
97 » if t >= forever { 121 » if ns > 0 && t < now {
98 » » return &Timer{} 122 » » panic("time: time overflow")
99 } 123 }
100 timerMutex.Lock() 124 timerMutex.Lock()
101 t0 := timers[0].t 125 t0 := timers[0].t
102 » e = &Timer{t, f, -1} 126 » e = &Timer{nil, t, f, -1}
103 heap.Push(timers, e) 127 heap.Push(timers, e)
104 // Start a new sleeper if the new event is before 128 // Start a new sleeper if the new event is before
105 // the first event in the queue. If the length of time 129 // the first event in the queue. If the length of time
106 » // until the new event is more than maxSleepTime, 130 » // until the new event is at least maxSleepTime,
107 // then we're guaranteed that the sleeper will wake up 131 // then we're guaranteed that the sleeper will wake up
108 // in time to service it, so no new sleeper is needed. 132 // in time to service it, so no new sleeper is needed.
109 if t0 > t && (t0 == forever || ns < maxSleepTime) { 133 if t0 > t && (t0 == forever || ns < maxSleepTime) {
110 currentSleeper++ 134 currentSleeper++
111 go sleeper(currentSleeper) 135 go sleeper(currentSleeper)
112 } 136 }
113 timerMutex.Unlock() 137 timerMutex.Unlock()
114 return 138 return
115 } 139 }
116 140
117 // sleeper continually looks at the earliest event in the queue, waits until it happens, 141 // sleeper continually looks at the earliest event in the queue, waits until it happens,
118 // then removes any events in the queue that are due. It stops when the queue 142 // then removes any events in the queue that are due. It stops when the queue
119 // is empty, or when another sleeper has been started. 143 // is empty or when another sleeper has been started.
120 //·
121 func sleeper(sleeperId int64) { 144 func sleeper(sleeperId int64) {
122 timerMutex.Lock() 145 timerMutex.Lock()
123 e := timers[0] 146 e := timers[0]
124 t := Nanoseconds() 147 t := Nanoseconds()
125 for e.t != forever { 148 for e.t != forever {
126 » » dt := e.t - t 149 » » if dt := e.t - t; dt > 0 {
127 » » if dt > maxSleepTime { 150 » » » if dt > maxSleepTime {
128 » » » dt = maxSleepTime 151 » » » » dt = maxSleepTime
129 » » } 152 » » » }
130 » » timerMutex.Unlock() 153 » » » timerMutex.Unlock()
131 » » sleep(t, dt) 154 » » » syscall.Sleep(dt)
132 » » timerMutex.Lock() 155 » » » timerMutex.Lock()
133 » » if currentSleeper != sleeperId { 156 » » » if currentSleeper != sleeperId {
134 » » » // Another sleeper has been started, making this one red undant. 157 » » » » // Another sleeper has been started, making this one redundant.
135 » » » break 158 » » » » break
159 » » » }
136 } 160 }
137 e = timers[0] 161 e = timers[0]
138 t = Nanoseconds() 162 t = Nanoseconds()
139 for t >= e.t { 163 for t >= e.t {
140 if e.f != nil { 164 if e.f != nil {
141 e.f(t) 165 e.f(t)
142 e.f = nil 166 e.f = nil
143 } 167 }
144 heap.Pop(timers) 168 heap.Pop(timers)
145 e = timers[0] 169 e = timers[0]
(...skipping 24 matching lines...) Expand all
170 194
171 func (timerHeap) Pop() interface{} { 195 func (timerHeap) Pop() interface{} {
172 // TODO: possibly shrink array. 196 // TODO: possibly shrink array.
173 n := len(timers) - 1 197 n := len(timers) - 1
174 e := timers[n] 198 e := timers[n]
175 timers[n] = nil 199 timers[n] = nil
176 timers = timers[0:n] 200 timers = timers[0:n]
177 e.i = -1 201 e.i = -1
178 return e 202 return e
179 } 203 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b