LEFT | RIGHT |
(no file at all) | |
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 time | |
8 | |
9 #include "runtime.h" | |
10 #include "defs_GOOS_GOARCH.h" | |
11 #include "os_GOOS.h" | |
12 #include "arch_GOARCH.h" | |
13 #include "malloc.h" | |
14 #include "race.h" | |
15 | |
16 enum { | |
17 debug = 0, | |
18 }; | |
19 | |
20 static Timers timers; | |
21 static void addtimer(Timer*); | |
22 static void dumptimers(int8*); | |
23 | |
24 // nacl fake time support.· | |
25 int64 runtime·timens; | |
26 | |
27 // Package time APIs. | |
28 // Godoc uses the comments in package time, not these. | |
29 | |
30 // time.now is implemented in assembly. | |
31 | |
32 // runtimeNano returns the current value of the runtime clock in nanoseconds. | |
33 func runtimeNano() (ns int64) { | |
34 ns = runtime·nanotime(); | |
35 } | |
36 | |
37 // Sleep puts the current goroutine to sleep for at least ns nanoseconds. | |
38 func Sleep(ns int64) { | |
39 runtime·tsleep(ns, "sleep"); | |
40 } | |
41 | |
42 // startTimer adds t to the timer heap. | |
43 func startTimer(t *Timer) { | |
44 if(raceenabled) | |
45 runtime·racerelease(t); | |
46 runtime·addtimer(t); | |
47 } | |
48 | |
49 // stopTimer removes t from the timer heap if it is there. | |
50 // It returns true if t was removed, false if t wasn't even there. | |
51 func stopTimer(t *Timer) (stopped bool) { | |
52 stopped = runtime·deltimer(t); | |
53 } | |
54 | |
55 // C runtime. | |
56 | |
57 void runtime·gc_unixnanotime(int64 *now); | |
58 | |
59 int64 runtime·unixnanotime(void) | |
60 { | |
61 int64 now; | |
62 | |
63 runtime·gc_unixnanotime(&now); | |
64 return now; | |
65 } | |
66 | |
67 static void timerproc(void); | |
68 static void siftup(int32); | |
69 static void siftdown(int32); | |
70 | |
71 // Ready the goroutine e.data. | |
72 static void | |
73 ready(int64 now, Eface e) | |
74 { | |
75 USED(now); | |
76 | |
77 runtime·ready(e.data); | |
78 } | |
79 | |
80 static FuncVal readyv = {(void(*)(void))ready}; | |
81 | |
82 // Put the current goroutine to sleep for ns nanoseconds. | |
83 void | |
84 runtime·tsleep(int64 ns, int8 *reason) | |
85 { | |
86 Timer t; | |
87 | |
88 if(ns <= 0) | |
89 return; | |
90 | |
91 t.when = runtime·nanotime() + ns; | |
92 t.period = 0; | |
93 t.fv = &readyv; | |
94 t.arg.data = g; | |
95 runtime·lock(&timers); | |
96 addtimer(&t); | |
97 runtime·parkunlock(&timers, reason); | |
98 } | |
99 | |
100 static FuncVal timerprocv = {timerproc}; | |
101 | |
102 void | |
103 runtime·addtimer(Timer *t) | |
104 { | |
105 runtime·lock(&timers); | |
106 addtimer(t); | |
107 runtime·unlock(&timers); | |
108 } | |
109 | |
110 // Add a timer to the heap and start or kick the timer proc | |
111 // if the new timer is earlier than any of the others. | |
112 static void | |
113 addtimer(Timer *t) | |
114 { | |
115 int32 n; | |
116 Timer **nt; | |
117 | |
118 // when must never be negative; otherwise timerproc will overflow | |
119 // during its delta calculation and never expire other timers. | |
120 if(t->when < 0) | |
121 t->when = (1LL<<63)-1; | |
122 | |
123 if(timers.len >= timers.cap) { | |
124 // Grow slice. | |
125 n = 16; | |
126 if(n <= timers.cap) | |
127 n = timers.cap*3 / 2; | |
128 nt = runtime·malloc(n*sizeof nt[0]); | |
129 runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]); | |
130 timers.t = nt; | |
131 timers.cap = n; | |
132 } | |
133 t->i = timers.len++; | |
134 timers.t[t->i] = t; | |
135 siftup(t->i); | |
136 if(t->i == 0) { | |
137 // siftup moved to top: new earliest deadline. | |
138 if(timers.sleeping) { | |
139 timers.sleeping = false; | |
140 runtime·notewakeup(&timers.waitnote); | |
141 } | |
142 if(timers.rescheduling) { | |
143 timers.rescheduling = false; | |
144 runtime·ready(timers.timerproc); | |
145 } | |
146 } | |
147 if(timers.timerproc == nil) { | |
148 timers.timerproc = runtime·newproc1(&timerprocv, nil, 0, 0, addt
imer); | |
149 timers.timerproc->issystem = true; | |
150 } | |
151 if(debug) | |
152 dumptimers("addtimer"); | |
153 } | |
154 | |
155 // Delete timer t from the heap. | |
156 // Do not need to update the timerproc: | |
157 // if it wakes up early, no big deal. | |
158 bool | |
159 runtime·deltimer(Timer *t) | |
160 { | |
161 int32 i; | |
162 | |
163 // Dereference t so that any panic happens before the lock is held. | |
164 // Discard result, because t might be moving in the heap. | |
165 i = t->i; | |
166 USED(i); | |
167 | |
168 runtime·lock(&timers); | |
169 | |
170 // t may not be registered anymore and may have | |
171 // a bogus i (typically 0, if generated by Go). | |
172 // Verify it before proceeding. | |
173 i = t->i; | |
174 if(i < 0 || i >= timers.len || timers.t[i] != t) { | |
175 runtime·unlock(&timers); | |
176 return false; | |
177 } | |
178 | |
179 timers.len--; | |
180 if(i == timers.len) { | |
181 timers.t[i] = nil; | |
182 } else { | |
183 timers.t[i] = timers.t[timers.len]; | |
184 timers.t[timers.len] = nil; | |
185 timers.t[i]->i = i; | |
186 siftup(i); | |
187 siftdown(i); | |
188 } | |
189 if(debug) | |
190 dumptimers("deltimer"); | |
191 runtime·unlock(&timers); | |
192 return true; | |
193 } | |
194 | |
195 // Timerproc runs the time-driven events. | |
196 // It sleeps until the next event in the timers heap. | |
197 // If addtimer inserts a new earlier event, addtimer | |
198 // wakes timerproc early. | |
199 static void | |
200 timerproc(void) | |
201 { | |
202 int64 delta, now; | |
203 Timer *t; | |
204 void (*f)(int64, Eface); | |
205 Eface arg; | |
206 | |
207 for(;;) { | |
208 runtime·lock(&timers); | |
209 timers.sleeping = false; | |
210 now = runtime·nanotime(); | |
211 for(;;) { | |
212 if(timers.len == 0) { | |
213 delta = -1; | |
214 break; | |
215 } | |
216 t = timers.t[0]; | |
217 delta = t->when - now; | |
218 if(delta > 0) | |
219 break; | |
220 if(t->period > 0) { | |
221 // leave in heap but adjust next time to fire | |
222 t->when += t->period * (1 + -delta/t->period); | |
223 siftdown(0); | |
224 } else { | |
225 // remove from heap | |
226 timers.t[0] = timers.t[--timers.len]; | |
227 timers.t[0]->i = 0; | |
228 siftdown(0); | |
229 t->i = -1; // mark as removed | |
230 } | |
231 f = (void*)t->fv->fn; | |
232 arg = t->arg; | |
233 runtime·unlock(&timers); | |
234 if(raceenabled) | |
235 runtime·raceacquire(t); | |
236 f(now, arg); | |
237 | |
238 // clear f and arg to avoid leak while sleeping for next
timer | |
239 f = nil; | |
240 USED(f); | |
241 arg.type = nil; | |
242 arg.data = nil; | |
243 USED(&arg); | |
244 | |
245 runtime·lock(&timers); | |
246 } | |
247 if(delta < 0) { | |
248 // No timers left - put goroutine to sleep. | |
249 timers.rescheduling = true; | |
250 g->isbackground = true; | |
251 runtime·parkunlock(&timers, "timer goroutine (idle)"); | |
252 g->isbackground = false; | |
253 continue; | |
254 } | |
255 // At least one timer pending. Sleep until then. | |
256 timers.sleeping = true; | |
257 runtime·noteclear(&timers.waitnote); | |
258 runtime·unlock(&timers); | |
259 runtime·notetsleepg(&timers.waitnote, delta); | |
260 } | |
261 } | |
262 | |
263 // heap maintenance algorithms. | |
264 | |
265 static void | |
266 siftup(int32 i) | |
267 { | |
268 int32 p; | |
269 int64 when; | |
270 Timer **t, *tmp; | |
271 | |
272 t = timers.t; | |
273 when = t[i]->when; | |
274 tmp = t[i]; | |
275 while(i > 0) { | |
276 p = (i-1)/4; // parent | |
277 if(when >= t[p]->when) | |
278 break; | |
279 t[i] = t[p]; | |
280 t[i]->i = i; | |
281 t[p] = tmp; | |
282 tmp->i = p; | |
283 i = p; | |
284 } | |
285 } | |
286 | |
287 static void | |
288 siftdown(int32 i) | |
289 { | |
290 int32 c, c3, len; | |
291 int64 when, w, w3; | |
292 Timer **t, *tmp; | |
293 | |
294 t = timers.t; | |
295 len = timers.len; | |
296 when = t[i]->when; | |
297 tmp = t[i]; | |
298 for(;;) { | |
299 c = i*4 + 1; // left child | |
300 c3 = c + 2; // mid child | |
301 if(c >= len) { | |
302 break; | |
303 } | |
304 w = t[c]->when; | |
305 if(c+1 < len && t[c+1]->when < w) { | |
306 w = t[c+1]->when; | |
307 c++; | |
308 } | |
309 if(c3 < len) { | |
310 w3 = t[c3]->when; | |
311 if(c3+1 < len && t[c3+1]->when < w3) { | |
312 w3 = t[c3+1]->when; | |
313 c3++; | |
314 } | |
315 if(w3 < w) { | |
316 w = w3; | |
317 c = c3; | |
318 } | |
319 } | |
320 if(w >= when) | |
321 break; | |
322 t[i] = t[c]; | |
323 t[i]->i = i; | |
324 t[c] = tmp; | |
325 tmp->i = c; | |
326 i = c; | |
327 } | |
328 } | |
329 | |
330 static void | |
331 dumptimers(int8 *msg) | |
332 { | |
333 Timer *t; | |
334 int32 i; | |
335 | |
336 runtime·printf("timers: %s\n", msg); | |
337 for(i = 0; i < timers.len; i++) { | |
338 t = timers.t[i]; | |
339 runtime·printf("\t%d\t%p:\ti %d when %D period %D fn %p\n", | |
340 i, t, t->i, t->when, t->period, t->fv->fn); | |
341 } | |
342 runtime·printf("\n"); | |
343 } | |
LEFT | RIGHT |