blob: ad9f3aac564055c594fb408b2fff8eeae5380953 [file] [log] [blame]
Russ Coxf4373312011-11-03 17:35:28 -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
Russ Cox3b860262011-11-09 15:17:05 -05005// Time-related runtime and pieces of package time.
Russ Coxf4373312011-11-03 17:35:28 -04006
7package time
8
9#include "runtime.h"
Russ Cox3b860262011-11-09 15:17:05 -050010#include "defs.h"
11#include "os.h"
12#include "arch.h"
13#include "malloc.h"
Russ Coxf4373312011-11-03 17:35:28 -040014
Russ Cox3b860262011-11-09 15:17:05 -050015static Timers timers;
16static void addtimer(Timer*);
17static bool deltimer(Timer*);
18
19// Package time APIs.
20// Godoc uses the comments in package time, not these.
21
22// Nanoseconds returns the current time in nanoseconds.
Russ Coxf4373312011-11-03 17:35:28 -040023func Nanoseconds() (ret int64) {
24 ret = runtime·nanotime();
25}
Russ Cox3b860262011-11-09 15:17:05 -050026
27// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
28func Sleep(ns int64) {
29 g->status = Gwaiting;
30 g->waitreason = "sleep";
31 runtime·tsleep(ns);
32}
33
34// startTimer adds t to the timer heap.
35func startTimer(t *Timer) {
36 addtimer(t);
37}
38
39// stopTimer removes t from the timer heap if it is there.
40// It returns true if t was removed, false if t wasn't even there.
41func stopTimer(t *Timer) (stopped bool) {
42 stopped = deltimer(t);
43}
44
45// C runtime.
46
47static void timerproc(void);
48static void siftup(int32);
49static void siftdown(int32);
50
51// Ready the goroutine e.data.
52static void
53ready(int64 now, Eface e)
54{
55 USED(now);
56
57 runtime·ready(e.data);
58}
59
60// Put the current goroutine to sleep for ns nanoseconds.
61// The caller must have set g->status and g->waitreason.
62void
63runtime·tsleep(int64 ns)
64{
65 Timer t;
66
67 if(ns <= 0)
68 return;
69
70 t.when = runtime·nanotime() + ns;
71 t.period = 0;
72 t.f = ready;
73 t.arg.data = g;
74 addtimer(&t);
75 runtime·gosched();
76}
77
78// Add a timer to the heap and start or kick the timer proc
79// if the new timer is earlier than any of the others.
80static void
81addtimer(Timer *t)
82{
83 int32 n;
84 Timer **nt;
85
86 runtime·lock(&timers);
87 if(timers.len >= timers.cap) {
88 // Grow slice.
89 n = 16;
90 if(n <= timers.cap)
91 n = timers.cap*3 / 2;
92 nt = runtime·malloc(n*sizeof nt[0]);
93 runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]);
94 runtime·free(timers.t);
95 timers.t = nt;
96 timers.cap = n;
97 }
98 t->i = timers.len++;
99 timers.t[t->i] = t;
100 siftup(t->i);
101 if(t->i == 0) {
102 // siftup moved to top: new earliest deadline.
103 if(timers.sleeping) {
104 timers.sleeping = false;
105 runtime·notewakeup(&timers.waitnote);
106 }
107 if(timers.rescheduling) {
108 timers.rescheduling = false;
109 runtime·ready(timers.timerproc);
110 }
111 }
112 if(timers.timerproc == nil)
113 timers.timerproc = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer);
114 runtime·unlock(&timers);
115}
116
117// Delete timer t from the heap.
118// Do not need to update the timerproc:
119// if it wakes up early, no big deal.
120static bool
121deltimer(Timer *t)
122{
123 int32 i;
124
125 runtime·lock(&timers);
126
127 // t may not be registered anymore and may have
128 // a bogus i (typically 0, if generated by Go).
129 // Verify it before proceeding.
130 i = t->i;
131 if(i < 0 || i >= timers.len || timers.t[i] != t) {
132 runtime·unlock(&timers);
133 return false;
134 }
135
Dmitriy Vyukova899a462011-11-25 14:13:10 +0300136 timers.len--;
137 if(i == timers.len) {
138 timers.t[i] = nil;
139 } else {
140 timers.t[i] = timers.t[timers.len];
141 timers.t[timers.len] = nil;
142 timers.t[i]->i = i;
143 siftup(i);
144 siftdown(i);
145 }
Russ Cox3b860262011-11-09 15:17:05 -0500146 runtime·unlock(&timers);
147 return true;
148}
149
150// Timerproc runs the time-driven events.
151// It sleeps until the next event in the timers heap.
152// If addtimer inserts a new earlier event, addtimer
153// wakes timerproc early.
154static void
155timerproc(void)
156{
157 int64 delta, now;
158 Timer *t;
Dmitriy Vyukovdc6726b2011-11-14 21:59:48 +0300159 void (*f)(int64, Eface);
160 Eface arg;
Russ Cox3b860262011-11-09 15:17:05 -0500161
162 for(;;) {
163 runtime·lock(&timers);
164 now = runtime·nanotime();
165 for(;;) {
166 if(timers.len == 0) {
167 delta = -1;
168 break;
169 }
170 t = timers.t[0];
171 delta = t->when - now;
172 if(delta > 0)
173 break;
174 if(t->period > 0) {
175 // leave in heap but adjust next time to fire
176 t->when += t->period * (1 + -delta/t->period);
177 siftdown(0);
178 } else {
179 // remove from heap
180 timers.t[0] = timers.t[--timers.len];
181 timers.t[0]->i = 0;
182 siftdown(0);
183 t->i = -1; // mark as removed
184 }
Dmitriy Vyukovdc6726b2011-11-14 21:59:48 +0300185 f = t->f;
186 arg = t->arg;
187 runtime·unlock(&timers);
188 f(now, arg);
189 runtime·lock(&timers);
Russ Cox3b860262011-11-09 15:17:05 -0500190 }
191 if(delta < 0) {
192 // No timers left - put goroutine to sleep.
193 timers.rescheduling = true;
194 g->status = Gwaiting;
195 g->waitreason = "timer goroutine (idle)";
196 runtime·unlock(&timers);
197 runtime·gosched();
198 continue;
199 }
200 // At least one timer pending. Sleep until then.
201 timers.sleeping = true;
202 runtime·noteclear(&timers.waitnote);
203 runtime·unlock(&timers);
204 runtime·entersyscall();
205 runtime·notetsleep(&timers.waitnote, delta);
206 runtime·exitsyscall();
207 }
208}
209
210// heap maintenance algorithms.
211
212static void
213siftup(int32 i)
214{
215 int32 p;
216 Timer **t, *tmp;
217
218 t = timers.t;
219 while(i > 0) {
220 p = (i-1)/2; // parent
221 if(t[i]->when >= t[p]->when)
222 break;
223 tmp = t[i];
224 t[i] = t[p];
225 t[p] = tmp;
226 t[i]->i = i;
227 t[p]->i = p;
228 i = p;
229 }
230}
231
232static void
233siftdown(int32 i)
234{
235 int32 c, len;
236 Timer **t, *tmp;
237
238 t = timers.t;
239 len = timers.len;
240 for(;;) {
241 c = i*2 + 1; // left child
242 if(c >= len) {
243 break;
244 }
245 if(c+1 < len && t[c+1]->when < t[c]->when)
246 c++;
247 if(t[c]->when >= t[i]->when)
248 break;
249 tmp = t[i];
250 t[i] = t[c];
251 t[c] = tmp;
252 t[i]->i = i;
253 t[c]->i = c;
254 i = c;
255 }
256}