Skip to content

Commit c3cef0b

Browse files
runtime: keep adjusted timers in timerMoving status until moved
Before this CL adjustTimers left timers being moved in an inconsistent state: status timerWaiting but not on a P. Simplify the code by leaving the timers in timerMoving status until they are actually moved. Other functions (deltimer, modtimer) will wait until the move is complete before changing anything on the timer. This does leave timers in timerMoving state for longer, but still not all that long. Fixes #35367 Change-Id: I31851002fb4053bd6914139125b4c82a68bf6fb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/205418 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent a9c0cc6 commit c3cef0b

File tree

2 files changed

+45
-44
lines changed

2 files changed

+45
-44
lines changed

src/net/timeout_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -1033,3 +1033,43 @@ func TestReadWriteDeadlineRace(t *testing.T) {
10331033
}()
10341034
wg.Wait() // wait for tester goroutine to stop
10351035
}
1036+
1037+
// Issue 35367.
1038+
func TestConcurrentSetDeadline(t *testing.T) {
1039+
ln, err := newLocalListener("tcp")
1040+
if err != nil {
1041+
t.Fatal(err)
1042+
}
1043+
defer ln.Close()
1044+
1045+
const goroutines = 8
1046+
const conns = 10
1047+
const tries = 100
1048+
1049+
var c [conns]Conn
1050+
for i := 0; i < conns; i++ {
1051+
c[i], err = Dial(ln.Addr().Network(), ln.Addr().String())
1052+
if err != nil {
1053+
t.Fatal(err)
1054+
}
1055+
defer c[i].Close()
1056+
}
1057+
1058+
var wg sync.WaitGroup
1059+
wg.Add(goroutines)
1060+
now := time.Now()
1061+
for i := 0; i < goroutines; i++ {
1062+
go func(i int) {
1063+
defer wg.Done()
1064+
// Make the deadlines steadily earlier,
1065+
// to trigger runtime adjusttimers calls.
1066+
for j := tries; j > 0; j-- {
1067+
for k := 0; k < conns; k++ {
1068+
c[k].SetReadDeadline(now.Add(2*time.Hour + time.Duration(i*j*k)*time.Second))
1069+
c[k].SetWriteDeadline(now.Add(1*time.Hour + time.Duration(i*j*k)*time.Second))
1070+
}
1071+
}
1072+
}(i)
1073+
}
1074+
wg.Wait()
1075+
}

src/runtime/time.go

+5-44
Original file line numberDiff line numberDiff line change
@@ -947,9 +947,6 @@ func adjusttimers(pp *p) {
947947
badTimer()
948948
}
949949
moved = append(moved, t)
950-
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
951-
badTimer()
952-
}
953950
if s == timerModifiedEarlier {
954951
if n := atomic.Xadd(&pp.adjustTimers, -1); int32(n) <= 0 {
955952
addAdjustedTimers(pp, moved)
@@ -979,47 +976,11 @@ func adjusttimers(pp *p) {
979976
// back to the timer heap.
980977
func addAdjustedTimers(pp *p, moved []*timer) {
981978
for _, t := range moved {
982-
loop:
983-
for {
984-
switch s := atomic.Load(&t.status); s {
985-
case timerWaiting:
986-
// This is the normal case.
987-
if !doaddtimer(pp, t) {
988-
badTimer()
989-
}
990-
break loop
991-
case timerDeleted:
992-
// Timer has been deleted since we adjusted it.
993-
// This timer is already out of the heap.
994-
if atomic.Cas(&t.status, s, timerRemoving) {
995-
if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
996-
badTimer()
997-
}
998-
break loop
999-
}
1000-
case timerModifiedEarlier, timerModifiedLater:
1001-
// Timer has been modified again since
1002-
// we adjusted it.
1003-
if atomic.Cas(&t.status, s, timerMoving) {
1004-
t.when = t.nextwhen
1005-
if !doaddtimer(pp, t) {
1006-
badTimer()
1007-
}
1008-
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
1009-
badTimer()
1010-
}
1011-
if s == timerModifiedEarlier {
1012-
atomic.Xadd(&pp.adjustTimers, -1)
1013-
}
1014-
break loop
1015-
}
1016-
case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:
1017-
badTimer()
1018-
case timerModifying:
1019-
// Wait and try again.
1020-
osyield()
1021-
continue
1022-
}
979+
if !doaddtimer(pp, t) {
980+
badTimer()
981+
}
982+
if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
983+
badTimer()
1023984
}
1024985
}
1025986
}

0 commit comments

Comments
 (0)