From: Ian Lance Taylor <iant@golang.org>
To: gcc-patches <gcc-patches@gcc.gnu.org>,
"gofrontend-dev@googlegroups.com"
<gofrontend-dev@googlegroups.com>
Subject: Go patch committed: copy runtime package time code from Go 1.7 runtime
Date: Sat, 15 Oct 2016 00:29:00 -0000 [thread overview]
Message-ID: <CAOyqgcUStJaTRxgXxApOog+Lf6n-yAqRib+JnRE4kt8P8EVjkA@mail.gmail.com> (raw)
[-- 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});
-}
reply other threads:[~2016-10-15 0:29 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAOyqgcUStJaTRxgXxApOog+Lf6n-yAqRib+JnRE4kt8P8EVjkA@mail.gmail.com \
--to=iant@golang.org \
--cc=gcc-patches@gcc.gnu.org \
--cc=gofrontend-dev@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).