}()
wg.Wait() // wait for tester goroutine to stop
}
+
+// Issue 35367.
+func TestConcurrentSetDeadline(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ const goroutines = 8
+ const conns = 10
+ const tries = 100
+
+ var c [conns]Conn
+ for i := 0; i < conns; i++ {
+ c[i], err = Dial(ln.Addr().Network(), ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c[i].Close()
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(goroutines)
+ now := time.Now()
+ for i := 0; i < goroutines; i++ {
+ go func(i int) {
+ defer wg.Done()
+ // Make the deadlines steadily earlier,
+ // to trigger runtime adjusttimers calls.
+ for j := tries; j > 0; j-- {
+ for k := 0; k < conns; k++ {
+ c[k].SetReadDeadline(now.Add(2*time.Hour + time.Duration(i*j*k)*time.Second))
+ c[k].SetWriteDeadline(now.Add(1*time.Hour + time.Duration(i*j*k)*time.Second))
+ }
+ }
+ }(i)
+ }
+ wg.Wait()
+}
badTimer()
}
moved = append(moved, t)
- if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
- badTimer()
- }
if s == timerModifiedEarlier {
if n := atomic.Xadd(&pp.adjustTimers, -1); int32(n) <= 0 {
addAdjustedTimers(pp, moved)
// back to the timer heap.
func addAdjustedTimers(pp *p, moved []*timer) {
for _, t := range moved {
- loop:
- for {
- switch s := atomic.Load(&t.status); s {
- case timerWaiting:
- // This is the normal case.
- if !doaddtimer(pp, t) {
- badTimer()
- }
- break loop
- case timerDeleted:
- // Timer has been deleted since we adjusted it.
- // This timer is already out of the heap.
- if atomic.Cas(&t.status, s, timerRemoving) {
- if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
- badTimer()
- }
- break loop
- }
- case timerModifiedEarlier, timerModifiedLater:
- // Timer has been modified again since
- // we adjusted it.
- if atomic.Cas(&t.status, s, timerMoving) {
- t.when = t.nextwhen
- if !doaddtimer(pp, t) {
- badTimer()
- }
- if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
- badTimer()
- }
- if s == timerModifiedEarlier {
- atomic.Xadd(&pp.adjustTimers, -1)
- }
- break loop
- }
- case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:
- badTimer()
- case timerModifying:
- // Wait and try again.
- osyield()
- continue
- }
+ if !doaddtimer(pp, t) {
+ badTimer()
+ }
+ if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
+ badTimer()
}
}
}