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
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});
-}

Reply via email to