]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add new addtimer function
authorIan Lance Taylor <iant@golang.org>
Thu, 11 Apr 2019 00:56:18 +0000 (17:56 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 22 Oct 2019 18:41:00 +0000 (18:41 +0000)
When we add a timer, make sure that the network poller is initialized,
since we will use it if we have to wait for the timer to be ready.

Updates #27707

Change-Id: I0637fe646bade2cc5ce50b745712292aa9c445b1
Reviewed-on: https://go-review.googlesource.com/c/go/+/171830
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
src/runtime/netpoll.go
src/runtime/netpoll_stub.go
src/runtime/time.go

index 536dae3d4f1b228b2314003a5ec5812ec12fc464..939b27061e3e8508c4b0d0a720c06c0c46ed7477 100644 (file)
@@ -100,8 +100,13 @@ var (
 
 //go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit
 func poll_runtime_pollServerInit() {
-       netpollinit()
-       atomic.Store(&netpollInited, 1)
+       netpollGenericInit()
+}
+
+func netpollGenericInit() {
+       if atomic.Cas(&netpollInited, 0, 1) {
+               netpollinit()
+       }
 }
 
 func netpollinited() bool {
index 00c06a440b7b0d9de8acfde8fe50b24a2496d27a..ab92b0424e0a621104ac2f6bf7e856636bb6e257 100644 (file)
@@ -8,12 +8,16 @@ package runtime
 
 import "runtime/internal/atomic"
 
+var netpollInited uint32
 var netpollWaiters uint32
 
 var netpollStubLock mutex
 var netpollNote note
 var netpollBroken uint32
 
+func netpollGenericInit() {
+}
+
 func netpollBreak() {
        if atomic.Cas(&netpollBroken, 0, 1) {
                notewakeup(&netpollNote)
index b9105592a4a6115d5c7d3ec20826f62bb3d70c43..b4f1c0205e79d5f1ac1c3961ce1d0064453fb656 100644 (file)
@@ -116,6 +116,10 @@ type timersBucket struct {
 //
 // Active timers live in heaps attached to P, in the timers field.
 // Inactive timers live there too temporarily, until they are removed.
+//
+// addtimer:
+//   timerNoStatus   -> timerWaiting
+//   anything else   -> panic: invalid value
 
 // Values for the timer status field.
 const (
@@ -161,6 +165,9 @@ const (
        timerMoving
 )
 
+// maxWhen is the maximum value for timer's when field.
+const maxWhen = 1<<63 - 1
+
 // Package time APIs.
 // Godoc uses the comments in package time, not these.
 
@@ -232,12 +239,56 @@ func goroutineReady(arg interface{}, seq uintptr) {
        goready(arg.(*g), 0)
 }
 
+// addtimer adds a timer to the current P.
+// This should only be called with a newly created timer.
+// That avoids the risk of changing the when field of a timer in some P's heap,
+// which could cause the heap to become unsorted.
 func addtimer(t *timer) {
        if oldTimers {
                addtimerOld(t)
                return
        }
-       throw("new addtimer not yet implemented")
+
+       // when must never be negative; otherwise runtimer will overflow
+       // during its delta calculation and never expire other runtime timers.
+       if t.when < 0 {
+               t.when = maxWhen
+       }
+       if t.status != timerNoStatus {
+               badTimer()
+       }
+       t.status = timerWaiting
+
+       when := t.when
+
+       pp := getg().m.p.ptr()
+       lock(&pp.timersLock)
+       ok := cleantimers(pp) && doaddtimer(pp, t)
+       unlock(&pp.timersLock)
+       if !ok {
+               badTimer()
+       }
+
+       wakeNetPoller(when)
+}
+
+// doaddtimer adds t to the current P's heap.
+// It reports whether it saw no problems due to races.
+// The caller must have locked the timers for pp.
+func doaddtimer(pp *p, t *timer) bool {
+       // Timers rely on the network poller, so make sure the poller
+       // has started.
+       if netpollInited == 0 {
+               netpollGenericInit()
+       }
+
+       if t.pp != 0 {
+               throw("doaddtimer: P already set in timer")
+       }
+       t.pp.set(pp)
+       i := len(pp.timers)
+       pp.timers = append(pp.timers, t)
+       return siftupTimer(pp.timers, i)
 }
 
 func addtimerOld(t *timer) {
@@ -457,6 +508,16 @@ func timerproc(tb *timersBucket) {
        }
 }
 
+// cleantimers cleans up the head of the timer queue. This speeds up
+// programs that create and delete timers; leaving them in the heap
+// slows down addtimer. Reports whether no timer problems were found.
+// The caller must have locked the timers for pp.
+func cleantimers(pp *p) bool {
+       // TODO: write this.
+       throw("cleantimers")
+       return true
+}
+
 // moveTimers moves a slice of timers to pp. The slice has been taken
 // from a different P.
 // This is currently called when the world is stopped, but it could