]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: update timejump function for new timers
authorIan Lance Taylor <iant@golang.org>
Thu, 11 Apr 2019 15:53:42 +0000 (08:53 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 23 Oct 2019 05:20:12 +0000 (05:20 +0000)
Since timers are now on a P, rather than having a G running timerproc,
timejump changes to return a P rather than a G.

Updates #27707

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

index edff454491f614ef1fb98aa6281b5248255cb0f6..aa0a1fa2be126eaca076ed877b6dc3df55d5450b 100644 (file)
@@ -2451,9 +2451,19 @@ stop:
                if _g_.m.spinning {
                        throw("findrunnable: netpoll with spinning")
                }
+               if faketime != 0 {
+                       // When using fake time, just poll.
+                       delta = 0
+               }
                list := netpoll(delta) // block until new work is available
                atomic.Store64(&sched.pollUntil, 0)
                atomic.Store64(&sched.lastpoll, uint64(nanotime()))
+               if faketime != 0 && list.empty() {
+                       // Using fake time and nothing is ready; stop M.
+                       // When all M's stop, checkdead will call timejump.
+                       stopm()
+                       goto top
+               }
                lock(&sched.lock)
                _p_ = pidleget()
                unlock(&sched.lock)
@@ -4422,23 +4432,44 @@ func checkdead() {
        }
 
        // Maybe jump time forward for playground.
-       gp := timejump()
-       if gp != nil {
-               casgstatus(gp, _Gwaiting, _Grunnable)
-               globrunqput(gp)
-               _p_ := pidleget()
-               if _p_ == nil {
-                       throw("checkdead: no p for timer")
+       if oldTimers {
+               gp := timejumpOld()
+               if gp != nil {
+                       casgstatus(gp, _Gwaiting, _Grunnable)
+                       globrunqput(gp)
+                       _p_ := pidleget()
+                       if _p_ == nil {
+                               throw("checkdead: no p for timer")
+                       }
+                       mp := mget()
+                       if mp == nil {
+                               // There should always be a free M since
+                               // nothing is running.
+                               throw("checkdead: no m for timer")
+                       }
+                       mp.nextp.set(_p_)
+                       notewakeup(&mp.park)
+                       return
                }
-               mp := mget()
-               if mp == nil {
-                       // There should always be a free M since
-                       // nothing is running.
-                       throw("checkdead: no m for timer")
+       } else {
+               _p_ := timejump()
+               if _p_ != nil {
+                       for pp := &sched.pidle; *pp != 0; pp = &(*pp).ptr().link {
+                               if (*pp).ptr() == _p_ {
+                                       *pp = _p_.link
+                                       break
+                               }
+                       }
+                       mp := mget()
+                       if mp == nil {
+                               // There should always be a free M since
+                               // nothing is running.
+                               throw("checkdead: no m for timer")
+                       }
+                       mp.nextp.set(_p_)
+                       notewakeup(&mp.park)
+                       return
                }
-               mp.nextp.set(_p_)
-               notewakeup(&mp.park)
-               return
        }
 
        // There are no goroutines running, so we can look at the P's.
index 3eba66bf0719e04cd8e70150f972da0e834b39e6..c0f2d0287dd64953089602091bd7b35bb959433a 100644 (file)
@@ -1125,7 +1125,66 @@ func runOneTimer(pp *p, t *timer, now int64) {
        f(arg, seq)
 }
 
-func timejump() *g {
+func timejump() *p {
+       if faketime == 0 {
+               return nil
+       }
+
+       // Nothing is running, so we can look at all the P's.
+       // Determine a timer bucket with minimum when.
+       var (
+               minT    *timer
+               minWhen int64
+               minP    *p
+       )
+       for _, pp := range allp {
+               if pp.status != _Pidle && pp.status != _Pdead {
+                       throw("non-idle P in timejump")
+               }
+               if len(pp.timers) == 0 {
+                       continue
+               }
+               c := pp.adjustTimers
+               for _, t := range pp.timers {
+                       switch s := atomic.Load(&t.status); s {
+                       case timerWaiting:
+                               if minT == nil || t.when < minWhen {
+                                       minT = t
+                                       minWhen = t.when
+                                       minP = pp
+                               }
+                       case timerModifiedEarlier, timerModifiedLater:
+                               if minT == nil || t.nextwhen < minWhen {
+                                       minT = t
+                                       minWhen = t.nextwhen
+                                       minP = pp
+                               }
+                               if s == timerModifiedEarlier {
+                                       c--
+                               }
+                       case timerRunning, timerModifying, timerMoving:
+                               badTimer()
+                       }
+                       // The timers are sorted, so we only have to check
+                       // the first timer for each P, unless there are
+                       // some timerModifiedEarlier timers. The number
+                       // of timerModifiedEarlier timers is in the adjustTimers
+                       // field, used to initialize c, above.
+                       if c == 0 {
+                               break
+                       }
+               }
+       }
+
+       if minT == nil || minWhen <= faketime {
+               return nil
+       }
+
+       faketime = minWhen
+       return minP
+}
+
+func timejumpOld() *g {
        if faketime == 0 {
                return nil
        }