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