2013-05-24 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgo / runtime / time.goc
blob9a5cbdfed3b8a3b4db7128ce6249f6bc74e52978
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 time
9 #include "runtime.h"
10 #include "defs.h"
11 #include "arch.h"
12 #include "malloc.h"
13 #include "race.h"
15 static Timers timers;
16 static void addtimer(Timer*);
17 static bool deltimer(Timer*);
19 // Package time APIs.
20 // Godoc uses the comments in package time, not these.
22 // time.now is implemented in assembly.
24 // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
25 func Sleep(ns int64) {
26         runtime_tsleep(ns, "sleep");
29 // startTimer adds t to the timer heap.
30 func startTimer(t *Timer) {
31         if(raceenabled)
32                 runtime_racerelease(t);
33         runtime_lock(&timers);
34         addtimer(t);
35         runtime_unlock(&timers);
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);
44 // C runtime.
46 static void timerproc(void*);
47 static void siftup(int32);
48 static void siftdown(int32);
50 // Ready the goroutine e.data.
51 static void
52 ready(int64 now, Eface e)
54         USED(now);
56         runtime_ready(e.__object);
59 // Put the current goroutine to sleep for ns nanoseconds.
60 void
61 runtime_tsleep(int64 ns, const char *reason)
63         G* g;
64         Timer t;
66         g = runtime_g();
68         if(ns <= 0)
69                 return;
71         t.when = runtime_nanotime() + ns;
72         t.period = 0;
73         t.f = ready;
74         t.arg.__object = g;
75         runtime_lock(&timers);
76         addtimer(&t);
77         runtime_park(runtime_unlock, &timers, reason);
80 // Add a timer to the heap and start or kick the timer proc
81 // if the new timer is earlier than any of the others.
82 static void
83 addtimer(Timer *t)
85         int32 n;
86         Timer **nt;
88         if(timers.len >= timers.cap) {
89                 // Grow slice.
90                 n = 16;
91                 if(n <= timers.cap)
92                         n = timers.cap*3 / 2;
93                 nt = runtime_malloc(n*sizeof nt[0]);
94                 runtime_memmove(nt, timers.t, timers.len*sizeof nt[0]);
95                 runtime_free(timers.t);
96                 timers.t = nt;
97                 timers.cap = n;
98         }
99         t->i = timers.len++;
100         timers.t[t->i] = t;
101         siftup(t->i);
102         if(t->i == 0) {
103                 // siftup moved to top: new earliest deadline.
104                 if(timers.sleeping) {
105                         timers.sleeping = false;
106                         runtime_notewakeup(&timers.waitnote);
107                 }
108                 if(timers.rescheduling) {
109                         timers.rescheduling = false;
110                         runtime_ready(timers.timerproc);
111                 }
112         }
113         if(timers.timerproc == nil) {
114                 timers.timerproc = __go_go(timerproc, nil);
115                 timers.timerproc->issystem = true;
116         }
119 // Delete timer t from the heap.
120 // Do not need to update the timerproc:
121 // if it wakes up early, no big deal.
122 static bool
123 deltimer(Timer *t)
125         int32 i;
127         runtime_lock(&timers);
129         // t may not be registered anymore and may have
130         // a bogus i (typically 0, if generated by Go).
131         // Verify it before proceeding.
132         i = t->i;
133         if(i < 0 || i >= timers.len || timers.t[i] != t) {
134                 runtime_unlock(&timers);
135                 return false;
136         }
138         timers.len--;
139         if(i == timers.len) {
140                 timers.t[i] = nil;
141         } else {
142                 timers.t[i] = timers.t[timers.len];
143                 timers.t[timers.len] = nil;
144                 timers.t[i]->i = i;
145                 siftup(i);
146                 siftdown(i);
147         }
148         runtime_unlock(&timers);
149         return true;
152 // Timerproc runs the time-driven events.
153 // It sleeps until the next event in the timers heap.
154 // If addtimer inserts a new earlier event, addtimer
155 // wakes timerproc early.
156 static void
157 timerproc(void* dummy __attribute__ ((unused)))
159         int64 delta, now;
160         Timer *t;
161         void (*f)(int64, Eface);
162         Eface arg;
164         for(;;) {
165                 runtime_lock(&timers);
166                 now = runtime_nanotime();
167                 for(;;) {
168                         if(timers.len == 0) {
169                                 delta = -1;
170                                 break;
171                         }
172                         t = timers.t[0];
173                         delta = t->when - now;
174                         if(delta > 0)
175                                 break;
176                         if(t->period > 0) {
177                                 // leave in heap but adjust next time to fire
178                                 t->when += t->period * (1 + -delta/t->period);
179                                 siftdown(0);
180                         } else {
181                                 // remove from heap
182                                 timers.t[0] = timers.t[--timers.len];
183                                 timers.t[0]->i = 0;
184                                 siftdown(0);
185                                 t->i = -1;  // mark as removed
186                         }
187                         f = t->f;
188                         arg = t->arg;
189                         runtime_unlock(&timers);
190                         if(raceenabled)
191                                 runtime_raceacquire(t);
192                         f(now, arg);
193                         runtime_lock(&timers);
194                 }
195                 if(delta < 0) {
196                         // No timers left - put goroutine to sleep.
197                         timers.rescheduling = true;
198                         runtime_park(runtime_unlock, &timers, "timer goroutine (idle)");
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         }
211 // heap maintenance algorithms.
213 static void
214 siftup(int32 i)
216         int32 p;
217         Timer **t, *tmp;
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         }
233 static void
234 siftdown(int32 i)
236         int32 c, len;
237         Timer **t, *tmp;
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         }
259 void
260 runtime_time_scan(void (*addroot)(Obj))
262         addroot((Obj){(byte*)&timers, sizeof timers, 0});