time.goc 6.65 KB
Newer Older
Russ Cox's avatar
Russ Cox committed
1 2 3 4
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

5
// Time-related runtime and pieces of package time.
Russ Cox's avatar
Russ Cox committed
6 7 8 9

package time

#include "runtime.h"
Russ Cox's avatar
Russ Cox committed
10 11 12
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
#include "arch_GOARCH.h"
13
#include "malloc.h"
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
14
#include "race.h"
Russ Cox's avatar
Russ Cox committed
15

16 17 18 19
enum {
	debug = 0,
};

20 21
static Timers timers;
static void addtimer(Timer*);
22
static void dumptimers(int8*);
23

24 25 26
// nacl fake time support. 
int64 runtime·timens;

27 28 29
// Package time APIs.
// Godoc uses the comments in package time, not these.

30
// time.now is implemented in assembly.
31

32 33 34 35 36
// runtimeNano returns the current value of the runtime clock in nanoseconds.
func runtimeNano() (ns int64) {
	ns = runtime·nanotime();
}

37 38
// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
func Sleep(ns int64) {
39
	runtime·tsleep(ns, "sleep");
40 41 42 43
}

// startTimer adds t to the timer heap.
func startTimer(t *Timer) {
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
44 45
	if(raceenabled)
		runtime·racerelease(t);
46
	runtime·addtimer(t);
47 48 49 50 51
}

// stopTimer removes t from the timer heap if it is there.
// It returns true if t was removed, false if t wasn't even there.
func stopTimer(t *Timer) (stopped bool) {
52
	stopped = runtime·deltimer(t);
53 54 55 56
}

// C runtime.

57 58 59 60 61 62 63 64 65 66
void runtime·gc_unixnanotime(int64 *now);

int64 runtime·unixnanotime(void)
{
	int64 now;

	runtime·gc_unixnanotime(&now);
	return now;
}

67 68 69 70 71 72 73 74 75 76 77 78 79
static void timerproc(void);
static void siftup(int32);
static void siftdown(int32);

// Ready the goroutine e.data.
static void
ready(int64 now, Eface e)
{
	USED(now);

	runtime·ready(e.data);
}

80 81
static FuncVal readyv = {(void(*)(void))ready};

82 83
// Put the current goroutine to sleep for ns nanoseconds.
void
84
runtime·tsleep(int64 ns, int8 *reason)
85 86 87
{
	Timer t;

88
	if(ns <= 0)
89 90 91 92
		return;

	t.when = runtime·nanotime() + ns;
	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 101
static FuncVal timerprocv = {timerproc};

102 103 104 105 106 107 108 109
void
runtime·addtimer(Timer *t)
{
	runtime·lock(&timers);
	addtimer(t);
	runtime·unlock(&timers);
}

110 111 112 113 114 115 116 117
// Add a timer to the heap and start or kick the timer proc
// if the new timer is earlier than any of the others.
static void
addtimer(Timer *t)
{
	int32 n;
	Timer **nt;

118 119 120 121 122
	// when must never be negative; otherwise timerproc will overflow
	// during its delta calculation and never expire other timers.
	if(t->when < 0)
		t->when = (1LL<<63)-1;

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	if(timers.len >= timers.cap) {
		// Grow slice.
		n = 16;
		if(n <= timers.cap)
			n = timers.cap*3 / 2;
		nt = runtime·malloc(n*sizeof nt[0]);
		runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]);
		timers.t = nt;
		timers.cap = n;
	}
	t->i = timers.len++;
	timers.t[t->i] = t;
	siftup(t->i);
	if(t->i == 0) {
		// siftup moved to top: new earliest deadline.
		if(timers.sleeping) {
			timers.sleeping = false;
			runtime·notewakeup(&timers.waitnote);
		}
		if(timers.rescheduling) {
			timers.rescheduling = false;
			runtime·ready(timers.timerproc);
		}
	}
147
	if(timers.timerproc == nil) {
148
		timers.timerproc = runtime·newproc1(&timerprocv, nil, 0, 0, addtimer);
149 150
		timers.timerproc->issystem = true;
	}
151 152
	if(debug)
		dumptimers("addtimer");
153 154 155 156 157
}

// Delete timer t from the heap.
// Do not need to update the timerproc:
// if it wakes up early, no big deal.
158 159
bool
runtime·deltimer(Timer *t)
160 161 162
{
	int32 i;

163 164 165 166 167
	// Dereference t so that any panic happens before the lock is held.
	// Discard result, because t might be moving in the heap.
	i = t->i;
	USED(i);

168 169 170 171 172 173 174 175 176 177 178
	runtime·lock(&timers);

	// t may not be registered anymore and may have
	// a bogus i (typically 0, if generated by Go).
	// Verify it before proceeding.
	i = t->i;
	if(i < 0 || i >= timers.len || timers.t[i] != t) {
		runtime·unlock(&timers);
		return false;
	}

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
179 180 181 182 183 184 185 186 187 188
	timers.len--;
	if(i == timers.len) {
		timers.t[i] = nil;
	} else {
		timers.t[i] = timers.t[timers.len];
		timers.t[timers.len] = nil;
		timers.t[i]->i = i;
		siftup(i);
		siftdown(i);
	}
189 190
	if(debug)
		dumptimers("deltimer");
191 192 193 194 195 196 197 198 199 200 201 202 203
	runtime·unlock(&timers);
	return true;
}

// Timerproc runs the time-driven events.
// It sleeps until the next event in the timers heap.
// If addtimer inserts a new earlier event, addtimer
// wakes timerproc early.
static void
timerproc(void)
{
	int64 delta, now;
	Timer *t;
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
204 205
	void (*f)(int64, Eface);
	Eface arg;
206 207 208

	for(;;) {
		runtime·lock(&timers);
209
		timers.sleeping = false;
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
		now = runtime·nanotime();
		for(;;) {
			if(timers.len == 0) {
				delta = -1;
				break;
			}
			t = timers.t[0];
			delta = t->when - now;
			if(delta > 0)
				break;
			if(t->period > 0) {
				// leave in heap but adjust next time to fire
				t->when += t->period * (1 + -delta/t->period);
				siftdown(0);
			} else {
				// remove from heap
				timers.t[0] = timers.t[--timers.len];
				timers.t[0]->i = 0;
				siftdown(0);
				t->i = -1;  // mark as removed
			}
231
			f = (void*)t->fv->fn;
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
232 233
			arg = t->arg;
			runtime·unlock(&timers);
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
234 235
			if(raceenabled)
				runtime·raceacquire(t);
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
236
			f(now, arg);
237 238 239 240 241 242 243 244

			// clear f and arg to avoid leak while sleeping for next timer
			f = nil;
			USED(f);
			arg.type = nil;
			arg.data = nil;
			USED(&arg);

Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
245
			runtime·lock(&timers);
246 247 248 249
		}
		if(delta < 0) {
			// No timers left - put goroutine to sleep.
			timers.rescheduling = true;
250
			g->isbackground = true;
251
			runtime·parkunlock(&timers, "timer goroutine (idle)");
252
			g->isbackground = false;
253 254 255 256 257 258
			continue;
		}
		// At least one timer pending.  Sleep until then.
		timers.sleeping = true;
		runtime·noteclear(&timers.waitnote);
		runtime·unlock(&timers);
259
		runtime·notetsleepg(&timers.waitnote, delta);
260 261 262 263 264 265 266 267 268
	}
}

// heap maintenance algorithms.

static void
siftup(int32 i)
{
	int32 p;
Sokolov Yura's avatar
Sokolov Yura committed
269
	int64 when;
270 271 272
	Timer **t, *tmp;

	t = timers.t;
Sokolov Yura's avatar
Sokolov Yura committed
273 274
	when = t[i]->when;
	tmp = t[i];
275
	while(i > 0) {
Sokolov Yura's avatar
Sokolov Yura committed
276 277
		p = (i-1)/4;  // parent
		if(when >= t[p]->when)
278 279 280
			break;
		t[i] = t[p];
		t[i]->i = i;
Sokolov Yura's avatar
Sokolov Yura committed
281 282
		t[p] = tmp;
		tmp->i = p;
283 284 285 286 287 288 289
		i = p;
	}
}

static void
siftdown(int32 i)
{
Sokolov Yura's avatar
Sokolov Yura committed
290 291
	int32 c, c3, len;
	int64 when, w, w3;
292 293 294 295
	Timer **t, *tmp;

	t = timers.t;
	len = timers.len;
Sokolov Yura's avatar
Sokolov Yura committed
296 297
	when = t[i]->when;
	tmp = t[i];
298
	for(;;) {
Sokolov Yura's avatar
Sokolov Yura committed
299 300
		c = i*4 + 1;  // left child
		c3 = c + 2;  // mid child
301 302 303
		if(c >= len) {
			break;
		}
Sokolov Yura's avatar
Sokolov Yura committed
304 305 306
		w = t[c]->when;
		if(c+1 < len && t[c+1]->when < w) {
			w = t[c+1]->when;
307
			c++;
Sokolov Yura's avatar
Sokolov Yura committed
308 309 310 311 312 313 314 315 316 317 318 319 320
		}
		if(c3 < len) {
			w3 = t[c3]->when;
			if(c3+1 < len && t[c3+1]->when < w3) {
				w3 = t[c3+1]->when;
				c3++;
			}
			if(w3 < w) {
				w = w3;
				c = c3;
			}
		}
		if(w >= when)
321 322 323
			break;
		t[i] = t[c];
		t[i]->i = i;
Sokolov Yura's avatar
Sokolov Yura committed
324 325
		t[c] = tmp;
		tmp->i = c;
326 327 328
		i = c;
	}
}
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343

static void
dumptimers(int8 *msg)
{
	Timer *t;
	int32 i;

	runtime·printf("timers: %s\n", msg);
	for(i = 0; i < timers.len; i++) {
		t = timers.t[i];
		runtime·printf("\t%d\t%p:\ti %d when %D period %D fn %p\n",
				i, t, t->i, t->when, t->period, t->fv->fn);
	}
	runtime·printf("\n");
}