inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/tcpip/transport/tcp/timer.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tcp
    16  
    17  import (
    18  	"math"
    19  	"time"
    20  
    21  	"inet.af/netstack/sleep"
    22  	"inet.af/netstack/tcpip"
    23  )
    24  
    25  type timerState int
    26  
    27  const (
    28  	// The timer is disabled.
    29  	timerStateDisabled timerState = iota
    30  	// The timer is enabled, but the clock timer may be set to an earlier
    31  	// expiration time due to a previous orphaned state.
    32  	timerStateEnabled
    33  	// The timer is disabled, but the clock timer is enabled, which means that
    34  	// it will cause a spurious wakeup unless the timer is enabled before the
    35  	// clock timer fires.
    36  	timerStateOrphaned
    37  )
    38  
    39  // timer is a timer implementation that reduces the interactions with the
    40  // clock timer infrastructure by letting timers run (and potentially
    41  // eventually expire) even if they are stopped. It makes it cheaper to
    42  // disable/reenable timers at the expense of spurious wakes. This is useful for
    43  // cases when the same timer is disabled/reenabled repeatedly with relatively
    44  // long timeouts farther into the future.
    45  //
    46  // TCP retransmit timers benefit from this because they the timeouts are long
    47  // (currently at least 200ms), and get disabled when acks are received, and
    48  // reenabled when new pending segments are sent.
    49  //
    50  // It is advantageous to avoid interacting with the clock because it acquires
    51  // a global mutex and performs O(log n) operations, where n is the global number
    52  // of timers, whenever a timer is enabled or disabled, and may make a syscall.
    53  //
    54  // This struct is thread-compatible.
    55  type timer struct {
    56  	state timerState
    57  
    58  	clock tcpip.Clock
    59  
    60  	// target is the expiration time of the current timer. It is only
    61  	// meaningful in the enabled state.
    62  	target tcpip.MonotonicTime
    63  
    64  	// clockTarget is the expiration time of the clock timer. It is
    65  	// meaningful in the enabled and orphaned states.
    66  	clockTarget tcpip.MonotonicTime
    67  
    68  	// timer is the clock timer used to wait on.
    69  	timer tcpip.Timer
    70  }
    71  
    72  // init initializes the timer. Once it expires, it the given waker will be
    73  // asserted.
    74  func (t *timer) init(clock tcpip.Clock, w *sleep.Waker) {
    75  	t.state = timerStateDisabled
    76  	t.clock = clock
    77  
    78  	// Initialize a clock timer that will assert the waker, then
    79  	// immediately stop it.
    80  	t.timer = t.clock.AfterFunc(math.MaxInt64, func() {
    81  		w.Assert()
    82  	})
    83  	t.timer.Stop()
    84  }
    85  
    86  // cleanup frees all resources associated with the timer.
    87  func (t *timer) cleanup() {
    88  	if t.timer == nil {
    89  		// No cleanup needed.
    90  		return
    91  	}
    92  	t.timer.Stop()
    93  	*t = timer{}
    94  }
    95  
    96  // checkExpiration checks if the given timer has actually expired, it should be
    97  // called whenever a sleeper wakes up due to the waker being asserted, and is
    98  // used to check if it's a supurious wake (due to a previously orphaned timer)
    99  // or a legitimate one.
   100  func (t *timer) checkExpiration() bool {
   101  	// Transition to fully disabled state if we're just consuming an
   102  	// orphaned timer.
   103  	if t.state == timerStateOrphaned {
   104  		t.state = timerStateDisabled
   105  		return false
   106  	}
   107  
   108  	// The timer is enabled, but it may have expired early. Check if that's
   109  	// the case, and if so, reset the runtime timer to the correct time.
   110  	now := t.clock.NowMonotonic()
   111  	if now.Before(t.target) {
   112  		t.clockTarget = t.target
   113  		t.timer.Reset(t.target.Sub(now))
   114  		return false
   115  	}
   116  
   117  	// The timer has actually expired, disable it for now and inform the
   118  	// caller.
   119  	t.state = timerStateDisabled
   120  	return true
   121  }
   122  
   123  // disable disables the timer, leaving it in an orphaned state if it wasn't
   124  // already disabled.
   125  func (t *timer) disable() {
   126  	if t.state != timerStateDisabled {
   127  		t.state = timerStateOrphaned
   128  	}
   129  }
   130  
   131  // enabled returns true if the timer is currently enabled, false otherwise.
   132  func (t *timer) enabled() bool {
   133  	return t.state == timerStateEnabled
   134  }
   135  
   136  // enable enables the timer, programming the runtime timer if necessary.
   137  func (t *timer) enable(d time.Duration) {
   138  	t.target = t.clock.NowMonotonic().Add(d)
   139  
   140  	// Check if we need to set the runtime timer.
   141  	if t.state == timerStateDisabled || t.target.Before(t.clockTarget) {
   142  		t.clockTarget = t.target
   143  		t.timer.Reset(d)
   144  	}
   145  
   146  	t.state = timerStateEnabled
   147  }