public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Go patch committed: copy runtime package time code from Go 1.7 runtime
@ 2016-10-15  0:29 Ian Lance Taylor
  0 siblings, 0 replies; only message in thread
From: Ian Lance Taylor @ 2016-10-15  0:29 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 518 bytes --]

This patch to the Go frontend and libgo copies the runtime package
time code from the Go 1.7 runtime.

This tweaks the frontend to fix the handling of function values for
-fgo-c-header to generate FuncVal*, not simply FuncVal.

While we're here change runtime.nanotime to use clock_gettime with
CLOCK_MONOTONIC, rather than gettimeofday.  This is what the gc
library does.  It provides nanosecond precision and a monotonic clock.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch.txt --]
[-- Type: text/plain; charset=US-ASCII; name="patch.txt", Size: 23952 bytes --]

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 241189)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@
-ec3dc927da71d15cac48a13c0fb0c1f94572d0d2
+880cb0a45590d992880fc6aabc7484e54c817eeb
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 240942)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -5928,7 +5928,7 @@ Struct_type::write_field_to_c_header(std
       break;
 
     case TYPE_FUNCTION:
-      os << "FuncVal";
+      os << "FuncVal*";
       break;
 
     case TYPE_POINTER:
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 241189)
+++ libgo/Makefile.am	(working copy)
@@ -519,7 +519,6 @@ runtime_files = \
 	reflect.c \
 	runtime1.c \
 	sigqueue.c \
-	time.c \
 	$(runtime_getncpu_file)
 
 goc2c.$(OBJEXT): runtime/goc2c.c
Index: libgo/go/runtime/stubs.go
===================================================================
--- libgo/go/runtime/stubs.go	(revision 241189)
+++ libgo/go/runtime/stubs.go	(working copy)
@@ -196,15 +196,15 @@ func getcallersp(argp unsafe.Pointer) ui
 // argp used in Defer structs when there is no argp.
 const _NoArgs = ^uintptr(0)
 
-// //go:linkname time_now time.now
-// func time_now() (sec int64, nsec int32)
+//go:linkname time_now time.now
+func time_now() (sec int64, nsec int32)
 
-/*
+// For gccgo, expose this for C callers.
+//go:linkname unixnanotime runtime.unixnanotime
 func unixnanotime() int64 {
 	sec, nsec := time_now()
 	return sec*1e9 + int64(nsec)
 }
-*/
 
 // round n up to a multiple of a.  a must be a power of 2.
 func round(n, a uintptr) uintptr {
Index: libgo/go/runtime/time.go
===================================================================
--- libgo/go/runtime/time.go	(revision 0)
+++ libgo/go/runtime/time.go	(working copy)
@@ -0,0 +1,307 @@
+// 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.
+
+// Time-related runtime and pieces of package time.
+
+package runtime
+
+import "unsafe"
+
+// Export temporarily for gccgo's C code to call:
+//go:linkname addtimer runtime.addtimer
+//go:linkname deltimer runtime.deltimer
+
+// Package time knows the layout of this structure.
+// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+// For GOOS=nacl, package syscall knows the layout of this structure.
+// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
+type timer struct {
+	i int // heap index
+
+	// Timer wakes up at when, and then at when+period, ... (period > 0 only)
+	// each time calling f(arg, now) in the timer goroutine, so f must be
+	// a well-behaved function and not block.
+	when   int64
+	period int64
+	f      func(interface{}, uintptr)
+	arg    interface{}
+	seq    uintptr
+}
+
+var timers struct {
+	lock         mutex
+	gp           *g
+	created      bool
+	sleeping     bool
+	rescheduling bool
+	waitnote     note
+	t            []*timer
+}
+
+// nacl fake time support - time in nanoseconds since 1970
+var faketime int64
+
+// Package time APIs.
+// Godoc uses the comments in package time, not these.
+
+// time.now is implemented in assembly.
+
+// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
+//go:linkname timeSleep time.Sleep
+func timeSleep(ns int64) {
+	if ns <= 0 {
+		return
+	}
+
+	t := new(timer)
+	t.when = nanotime() + ns
+	t.f = goroutineReady
+	t.arg = getg()
+	lock(&timers.lock)
+	addtimerLocked(t)
+	goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
+}
+
+// startTimer adds t to the timer heap.
+//go:linkname startTimer time.startTimer
+func startTimer(t *timer) {
+	if raceenabled {
+		racerelease(unsafe.Pointer(t))
+	}
+	addtimer(t)
+}
+
+// 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.
+//go:linkname stopTimer time.stopTimer
+func stopTimer(t *timer) bool {
+	return deltimer(t)
+}
+
+// Go runtime.
+
+// Ready the goroutine arg.
+func goroutineReady(arg interface{}, seq uintptr) {
+	goready(arg.(*g), 0)
+}
+
+func addtimer(t *timer) {
+	lock(&timers.lock)
+	addtimerLocked(t)
+	unlock(&timers.lock)
+}
+
+// Add a timer to the heap and start or kick the timer proc.
+// If the new timer is earlier than any of the others.
+// Timers are locked.
+func addtimerLocked(t *timer) {
+	// when must never be negative; otherwise timerproc will overflow
+	// during its delta calculation and never expire other runtime·timers.
+	if t.when < 0 {
+		t.when = 1<<63 - 1
+	}
+	t.i = len(timers.t)
+	timers.t = append(timers.t, t)
+	siftupTimer(t.i)
+	if t.i == 0 {
+		// siftup moved to top: new earliest deadline.
+		if timers.sleeping {
+			timers.sleeping = false
+			notewakeup(&timers.waitnote)
+		}
+		if timers.rescheduling {
+			timers.rescheduling = false
+			goready(timers.gp, 0)
+		}
+	}
+	if !timers.created {
+		timers.created = true
+		go timerproc()
+	}
+}
+
+// Delete timer t from the heap.
+// Do not need to update the timerproc: if it wakes up early, no big deal.
+func deltimer(t *timer) bool {
+	// Dereference t so that any panic happens before the lock is held.
+	// Discard result, because t might be moving in the heap.
+	_ = t.i
+
+	lock(&timers.lock)
+	// 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
+	last := len(timers.t) - 1
+	if i < 0 || i > last || timers.t[i] != t {
+		unlock(&timers.lock)
+		return false
+	}
+	if i != last {
+		timers.t[i] = timers.t[last]
+		timers.t[i].i = i
+	}
+	timers.t[last] = nil
+	timers.t = timers.t[:last]
+	if i != last {
+		siftupTimer(i)
+		siftdownTimer(i)
+	}
+	unlock(&timers.lock)
+	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, addtimer1 wakes timerproc early.
+func timerproc() {
+	timers.gp = getg()
+	for {
+		lock(&timers.lock)
+		timers.sleeping = false
+		now := nanotime()
+		delta := int64(-1)
+		for {
+			if len(timers.t) == 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)
+				siftdownTimer(0)
+			} else {
+				// remove from heap
+				last := len(timers.t) - 1
+				if last > 0 {
+					timers.t[0] = timers.t[last]
+					timers.t[0].i = 0
+				}
+				timers.t[last] = nil
+				timers.t = timers.t[:last]
+				if last > 0 {
+					siftdownTimer(0)
+				}
+				t.i = -1 // mark as removed
+			}
+			f := t.f
+			arg := t.arg
+			seq := t.seq
+			unlock(&timers.lock)
+			if raceenabled {
+				raceacquire(unsafe.Pointer(t))
+			}
+			f(arg, seq)
+			lock(&timers.lock)
+		}
+		if delta < 0 || faketime > 0 {
+			// No timers left - put goroutine to sleep.
+			timers.rescheduling = true
+			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
+			continue
+		}
+		// At least one timer pending. Sleep until then.
+		timers.sleeping = true
+		noteclear(&timers.waitnote)
+		unlock(&timers.lock)
+		notetsleepg(&timers.waitnote, delta)
+	}
+}
+
+func timejump() *g {
+	if faketime == 0 {
+		return nil
+	}
+
+	lock(&timers.lock)
+	if !timers.created || len(timers.t) == 0 {
+		unlock(&timers.lock)
+		return nil
+	}
+
+	var gp *g
+	if faketime < timers.t[0].when {
+		faketime = timers.t[0].when
+		if timers.rescheduling {
+			timers.rescheduling = false
+			gp = timers.gp
+		}
+	}
+	unlock(&timers.lock)
+	return gp
+}
+
+// Heap maintenance algorithms.
+
+func siftupTimer(i int) {
+	t := timers.t
+	when := t[i].when
+	tmp := t[i]
+	for i > 0 {
+		p := (i - 1) / 4 // parent
+		if when >= t[p].when {
+			break
+		}
+		t[i] = t[p]
+		t[i].i = i
+		t[p] = tmp
+		t[p].i = p
+		i = p
+	}
+}
+
+func siftdownTimer(i int) {
+	t := timers.t
+	n := len(t)
+	when := t[i].when
+	tmp := t[i]
+	for {
+		c := i*4 + 1 // left child
+		c3 := c + 2  // mid child
+		if c >= n {
+			break
+		}
+		w := t[c].when
+		if c+1 < n && t[c+1].when < w {
+			w = t[c+1].when
+			c++
+		}
+		if c3 < n {
+			w3 := t[c3].when
+			if c3+1 < n && t[c3+1].when < w3 {
+				w3 = t[c3+1].when
+				c3++
+			}
+			if w3 < w {
+				w = w3
+				c = c3
+			}
+		}
+		if w >= when {
+			break
+		}
+		t[i] = t[c]
+		t[i].i = i
+		t[c] = tmp
+		t[c].i = c
+		i = c
+	}
+}
+
+// Entry points for net, time to call nanotime.
+
+//go:linkname net_runtimeNano net.runtimeNano
+func net_runtimeNano() int64 {
+	return nanotime()
+}
+
+//go:linkname time_runtimeNano time.runtimeNano
+func time_runtimeNano() int64 {
+	return nanotime()
+}
Index: libgo/runtime/go-nanotime.c
===================================================================
--- libgo/runtime/go-nanotime.c	(revision 240942)
+++ libgo/runtime/go-nanotime.c	(working copy)
@@ -14,8 +14,8 @@ int64 runtime_nanotime (void)
 int64
 runtime_nanotime (void)
 {
-  struct timeval tv;
+  struct timespec ts;
 
-  gettimeofday (&tv, NULL);
-  return (int64) tv.tv_sec * 1000000000 + (int64) tv.tv_usec * 1000;
+  clock_gettime (CLOCK_MONOTONIC, &ts);
+  return (int64) ts.tv_sec * 1000000000 + (int64) ts.tv_nsec;
 }
Index: libgo/runtime/malloc.h
===================================================================
--- libgo/runtime/malloc.h	(revision 241189)
+++ libgo/runtime/malloc.h	(working copy)
@@ -543,5 +543,4 @@ int32	runtime_setgcpercent(int32);
 
 struct Workbuf;
 void	runtime_proc_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
-void	runtime_time_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
 void	runtime_netpoll_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
Index: libgo/runtime/mgc0.c
===================================================================
--- libgo/runtime/mgc0.c	(revision 241189)
+++ libgo/runtime/mgc0.c	(working copy)
@@ -1277,7 +1277,6 @@ markroot(ParFor *desc, uint32 i)
 		enqueue1(&wbuf, (Obj){(byte*)&runtime_allp, sizeof runtime_allp, 0});
 		enqueue1(&wbuf, (Obj){(byte*)&work, sizeof work, 0});
 		runtime_proc_scan(&wbuf, enqueue1);
-		runtime_time_scan(&wbuf, enqueue1);
 		runtime_netpoll_scan(&wbuf, enqueue1);
 		break;
 
Index: libgo/runtime/netpoll.goc
===================================================================
--- libgo/runtime/netpoll.goc	(revision 241124)
+++ libgo/runtime/netpoll.goc	(working copy)
@@ -89,11 +89,6 @@ static FuncVal deadlineFn	= {(void(*)(vo
 static FuncVal readDeadlineFn	= {(void(*)(void))readDeadline};
 static FuncVal writeDeadlineFn	= {(void(*)(void))writeDeadline};
 
-// runtimeNano returns the current value of the runtime clock in nanoseconds.
-func runtimeNano() (ns int64) {
-	ns = runtime_nanotime();
-}
-
 func runtime_pollServerInit() {
 	runtime_netpollinit();
 }
@@ -176,13 +171,13 @@ func runtime_pollSetDeadline(pd *PollDes
 	}
 	pd->seq++;  // invalidate current timers
 	// Reset current timers.
-	if(pd->rt.fv) {
+	if(pd->rt.f) {
 		runtime_deltimer(&pd->rt);
-		pd->rt.fv = nil;
+		pd->rt.f = nil;
 	}
-	if(pd->wt.fv) {
+	if(pd->wt.f) {
 		runtime_deltimer(&pd->wt);
-		pd->wt.fv = nil;
+		pd->wt.f = nil;
 	}
 	// Setup new timers.
 	if(d != 0 && d <= runtime_nanotime())
@@ -192,7 +187,7 @@ func runtime_pollSetDeadline(pd *PollDes
 	if(mode == 'w' || mode == 'r'+'w')
 		pd->wd = d;
 	if(pd->rd > 0 && pd->rd == pd->wd) {
-		pd->rt.fv = &deadlineFn;
+		pd->rt.f = &deadlineFn;
 		pd->rt.when = pd->rd;
 		// Copy current seq into the timer arg.
 		// Timer func will check the seq against current descriptor seq,
@@ -203,7 +198,7 @@ func runtime_pollSetDeadline(pd *PollDes
 		runtime_addtimer(&pd->rt);
 	} else {
 		if(pd->rd > 0) {
-			pd->rt.fv = &readDeadlineFn;
+			pd->rt.f = &readDeadlineFn;
 			pd->rt.when = pd->rd;
 			pd->rt.arg.type = nil; // should be *pollDesc type descriptor.
 			pd->rt.arg.data = pd;
@@ -211,7 +206,7 @@ func runtime_pollSetDeadline(pd *PollDes
 			runtime_addtimer(&pd->rt);
 		}
 		if(pd->wd > 0) {
-			pd->wt.fv = &writeDeadlineFn;
+			pd->wt.f = &writeDeadlineFn;
 			pd->wt.when = pd->wd;
 			pd->wt.arg.type = nil; // should be *pollDesc type descriptor.
 			pd->wt.arg.data = pd;
@@ -244,13 +239,13 @@ func runtime_pollUnblock(pd *PollDesc) {
 	runtime_atomicstorep(&rg, nil);  // full memory barrier between store to closing and read of rg/wg in netpollunblock
 	rg = netpollunblock(pd, 'r', false);
 	wg = netpollunblock(pd, 'w', false);
-	if(pd->rt.fv) {
+	if(pd->rt.f) {
 		runtime_deltimer(&pd->rt);
-		pd->rt.fv = nil;
+		pd->rt.f = nil;
 	}
-	if(pd->wt.fv) {
+	if(pd->wt.f) {
 		runtime_deltimer(&pd->wt);
-		pd->wt.fv = nil;
+		pd->wt.f = nil;
 	}
 	runtime_unlock(pd);
 	if(rg)
@@ -408,17 +403,17 @@ deadlineimpl(Eface arg, uintptr seq, boo
 		return;
 	}
 	if(read) {
-		if(pd->rd <= 0 || pd->rt.fv == nil)
+		if(pd->rd <= 0 || pd->rt.f == nil)
 			runtime_throw("deadlineimpl: inconsistent read deadline");
 		pd->rd = -1;
-		runtime_atomicstorep(&pd->rt.fv, nil);  // full memory barrier between store to rd and load of rg in netpollunblock
+		runtime_atomicstorep(&pd->rt.f, nil);  // full memory barrier between store to rd and load of rg in netpollunblock
 		rg = netpollunblock(pd, 'r', false);
 	}
 	if(write) {
-		if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
+		if(pd->wd <= 0 || (pd->wt.f == nil && !read))
 			runtime_throw("deadlineimpl: inconsistent write deadline");
 		pd->wd = -1;
-		runtime_atomicstorep(&pd->wt.fv, nil);  // full memory barrier between store to wd and load of wg in netpollunblock
+		runtime_atomicstorep(&pd->wt.f, nil);  // full memory barrier between store to wd and load of wg in netpollunblock
 		wg = netpollunblock(pd, 'w', false);
 	}
 	runtime_unlock(pd);
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h	(revision 241189)
+++ libgo/runtime/runtime.h	(working copy)
@@ -66,8 +66,7 @@ typedef	struct	SigTab		SigTab;
 typedef	struct	mcache		MCache;
 typedef struct	FixAlloc	FixAlloc;
 typedef	struct	hchan		Hchan;
-typedef	struct	Timers		Timers;
-typedef	struct	Timer		Timer;
+typedef	struct	timer		Timer;
 typedef	struct	gcstats		GCStats;
 typedef	struct	LFNode		LFNode;
 typedef	struct	ParFor		ParFor;
@@ -181,36 +180,6 @@ enum {
 };
 #endif
 
-struct	Timers
-{
-	Lock;
-	G	*timerproc;
-	bool		sleeping;
-	bool		rescheduling;
-	Note	waitnote;
-	Timer	**t;
-	int32	len;
-	int32	cap;
-};
-
-// Package time knows the layout of this structure.
-// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
-// For GOOS=nacl, package syscall knows the layout of this structure.
-// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
-struct	Timer
-{
-	intgo	i;	// heap index
-
-	// Timer wakes up at when, and then at when+period, ... (period > 0 only)
-	// each time calling f(now, arg) in the timer goroutine, so f must be
-	// a well-behaved function and not block.
-	int64	when;
-	int64	period;
-	FuncVal	*fv;
-	Eface	arg;
-	uintptr	seq;
-};
-
 // Lock-free stack node.
 struct LFNode
 {
@@ -403,7 +372,8 @@ bool	__go_sigsend(int32 sig);
 int32	runtime_callers(int32, Location*, int32, bool keep_callers);
 int64	runtime_nanotime(void)	// monotonic time
   __asm__(GOSYM_PREFIX "runtime.nanotime");
-int64	runtime_unixnanotime(void); // real time, can skip
+int64	runtime_unixnanotime(void) // real time, can skip
+  __asm__ (GOSYM_PREFIX "runtime.unixnanotime");
 void	runtime_dopanic(int32) __attribute__ ((noreturn));
 void	runtime_startpanic(void);
 void	runtime_freezetheworld(void);
@@ -422,8 +392,10 @@ int64	runtime_tickspersecond(void)
      __asm__ (GOSYM_PREFIX "runtime.tickspersecond");
 void	runtime_blockevent(int64, int32);
 extern int64 runtime_blockprofilerate;
-void	runtime_addtimer(Timer*);
-bool	runtime_deltimer(Timer*);
+void	runtime_addtimer(Timer*)
+  __asm__ (GOSYM_PREFIX "runtime.addtimer");
+bool	runtime_deltimer(Timer*)
+  __asm__ (GOSYM_PREFIX "runtime.deltimer");
 G*	runtime_netpoll(bool);
 void	runtime_netpollinit(void);
 int32	runtime_netpollopen(uintptr, PollDesc*);
Index: libgo/runtime/time.goc
===================================================================
--- libgo/runtime/time.goc	(revision 240942)
+++ libgo/runtime/time.goc	(working copy)
@@ -1,353 +0,0 @@
-// 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.
-
-// Time-related runtime and pieces of package time.
-
-package time
-
-#include <sys/time.h>
-
-#include "runtime.h"
-#include "defs.h"
-#include "arch.h"
-#include "malloc.h"
-
-enum {
-	debug = 0,
-};
-
-static Timers timers;
-static void addtimer(Timer*);
-static void dumptimers(const char*);
-
-// nacl fake time support. 
-int64 runtime_timens;
-
-// Package time APIs.
-// Godoc uses the comments in package time, not these.
-
-// time.now is implemented in assembly.
-
-// runtimeNano returns the current value of the runtime clock in nanoseconds.
-func runtimeNano() (ns int64) {
-	ns = runtime_nanotime();
-}
-
-// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
-func Sleep(ns int64) {
-	runtime_tsleep(ns, "sleep");
-}
-
-// startTimer adds t to the timer heap.
-func startTimer(t *Timer) {
-	runtime_addtimer(t);
-}
-
-// 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) {
-	stopped = runtime_deltimer(t);
-}
-
-// C runtime.
-
-int64 runtime_unixnanotime(void)
-{
-	struct time_now_ret r;
-
-	r = now();
-	return r.sec*1000000000 + r.nsec;
-}
-
-static void timerproc(void*);
-static void siftup(int32);
-static void siftdown(int32);
-
-// Ready the goroutine e.data.
-static void
-ready(Eface e, uintptr seq)
-{
-	USED(seq);
-
-	runtime_ready(e.__object);
-}
-
-static FuncVal readyv = {(void(*)(void))ready};
-
-// Put the current goroutine to sleep for ns nanoseconds.
-void
-runtime_tsleep(int64 ns, const char *reason)
-{
-	G* g;
-	Timer t;
-
-	g = runtime_g();
-
-	if(ns <= 0)
-		return;
-
-	t.when = runtime_nanotime() + ns;
-	t.period = 0;
-	t.fv = &readyv;
-	t.arg.__object = g;
-	t.seq = 0;
-	runtime_lock(&timers);
-	addtimer(&t);
-	runtime_parkunlock(&timers, reason);
-}
-
-void
-runtime_addtimer(Timer *t)
-{
-	runtime_lock(&timers);
-	addtimer(t);
-	runtime_unlock(&timers);
-}
-
-// 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;
-
-	// when must never be negative; otherwise timerproc will overflow
-	// during its delta calculation and never expire other timers.
-	if(t->when < 0)
-		t->when = (int64)((1ULL<<63)-1);
-
-	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]);
-		runtime_free(timers.t);
-		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);
-		}
-	}
-	if(timers.timerproc == nil) {
-		timers.timerproc = __go_go(timerproc, nil);
-		timers.timerproc->issystem = true;
-	}
-	if(debug)
-		dumptimers("addtimer");
-}
-
-// Used to force a dereference before the lock is acquired.
-static int32 gi;
-
-// Delete timer t from the heap.
-// Do not need to update the timerproc:
-// if it wakes up early, no big deal.
-bool
-runtime_deltimer(Timer *t)
-{
-	int32 i;
-
-	// 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;
-	gi = i;
-
-	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;
-	}
-
-	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);
-	}
-	if(debug)
-		dumptimers("deltimer");
-	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* dummy __attribute__ ((unused)))
-{
-	int64 delta, now;
-	Timer *t;
-	FuncVal *fv;
-	void (*f)(Eface, uintptr);
-	Eface arg;
-	uintptr seq;
-
-	for(;;) {
-		runtime_lock(&timers);
-		timers.sleeping = false;
-		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
-			}
-			fv = t->fv;
-			f = (void*)t->fv->fn;
-			arg = t->arg;
-			seq = t->seq;
-			runtime_unlock(&timers);
-			__builtin_call_with_static_chain(f(arg, seq), fv);
-
-			// clear f and arg to avoid leak while sleeping for next timer
-			f = nil;
-			USED(f);
-			arg.__type_descriptor = nil;
-			arg.__object = nil;
-			USED(&arg);
-
-			runtime_lock(&timers);
-		}
-		if(delta < 0) {
-			// No timers left - put goroutine to sleep.
-			timers.rescheduling = true;
-			runtime_g()->isbackground = true;
-			runtime_parkunlock(&timers, "timer goroutine (idle)");
-			runtime_g()->isbackground = false;
-			continue;
-		}
-		// At least one timer pending.  Sleep until then.
-		timers.sleeping = true;
-		runtime_noteclear(&timers.waitnote);
-		runtime_unlock(&timers);
-		runtime_notetsleepg(&timers.waitnote, delta);
-	}
-}
-
-// heap maintenance algorithms.
-
-static void
-siftup(int32 i)
-{
-	int32 p;
-	int64 when;
-	Timer **t, *tmp;
-
-	t = timers.t;
-	when = t[i]->when;
-	tmp = t[i];
-	while(i > 0) {
-		p = (i-1)/4;  // parent
-		if(when >= t[p]->when)
-			break;
-		t[i] = t[p];
-		t[i]->i = i;
-		t[p] = tmp;
-		tmp->i = p;
-		i = p;
-	}
-}
-
-static void
-siftdown(int32 i)
-{
-	int32 c, c3, len;
-	int64 when, w, w3;
-	Timer **t, *tmp;
-
-	t = timers.t;
-	len = timers.len;
-	when = t[i]->when;
-	tmp = t[i];
-	for(;;) {
-		c = i*4 + 1;  // left child
-		c3 = c + 2;  // mid child
-		if(c >= len) {
-			break;
-		}
-		w = t[c]->when;
-		if(c+1 < len && t[c+1]->when < w) {
-			w = t[c+1]->when;
-			c++;
-		}
-		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)
-			break;
-		t[i] = t[c];
-		t[i]->i = i;
-		t[c] = tmp;
-		tmp->i = c;
-		i = c;
-	}
-}
-
-static void
-dumptimers(const char *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");
-}
-
-void
-runtime_time_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
-{
-	enqueue1(wbufp, (Obj){(byte*)&timers, sizeof timers, 0});
-}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-10-15  0:29 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-15  0:29 Go patch committed: copy runtime package time code from Go 1.7 runtime Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).