github.com/lightlus/netstack@v1.2.0/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  	"time"
    19  
    20  	"github.com/lightlus/netstack/sleep"
    21  )
    22  
    23  type timerState int
    24  
    25  const (
    26  	timerStateDisabled timerState = iota
    27  	timerStateEnabled
    28  	timerStateOrphaned
    29  )
    30  
    31  // timer is a timer implementation that reduces the interactions with the
    32  // runtime timer infrastructure by letting timers run (and potentially
    33  // eventually expire) even if they are stopped. It makes it cheaper to
    34  // disable/reenable timers at the expense of spurious wakes. This is useful for
    35  // cases when the same timer is disabled/reenabled repeatedly with relatively
    36  // long timeouts farther into the future.
    37  //
    38  // TCP retransmit timers benefit from this because they the timeouts are long
    39  // (currently at least 200ms), and get disabled when acks are received, and
    40  // reenabled when new pending segments are sent.
    41  //
    42  // It is advantageous to avoid interacting with the runtime because it acquires
    43  // a global mutex and performs O(log n) operations, where n is the global number
    44  // of timers, whenever a timer is enabled or disabled, and may make a syscall.
    45  //
    46  // This struct is thread-compatible.
    47  type timer struct {
    48  	// state is the current state of the timer, it can be one of the
    49  	// following values:
    50  	//     disabled - the timer is disabled.
    51  	//     orphaned - the timer is disabled, but the runtime timer is
    52  	//                enabled, which means that it will evetually cause a
    53  	//                spurious wake (unless it gets enabled again before
    54  	//                then).
    55  	//     enabled  - the timer is enabled, but the runtime timer may be set
    56  	//                to an earlier expiration time due to a previous
    57  	//                orphaned state.
    58  	state timerState
    59  
    60  	// target is the expiration time of the current timer. It is only
    61  	// meaningful in the enabled state.
    62  	target time.Time
    63  
    64  	// runtimeTarget is the expiration time of the runtime timer. It is
    65  	// meaningful in the enabled and orphaned states.
    66  	runtimeTarget time.Time
    67  
    68  	// timer is the runtime timer used to wait on.
    69  	timer *time.Timer
    70  }
    71  
    72  // init initializes the timer. Once it expires, it the given waker will be
    73  // asserted.
    74  func (t *timer) init(w *sleep.Waker) {
    75  	t.state = timerStateDisabled
    76  
    77  	// Initialize a runtime timer that will assert the waker, then
    78  	// immediately stop it.
    79  	t.timer = time.AfterFunc(time.Hour, func() {
    80  		w.Assert()
    81  	})
    82  	t.timer.Stop()
    83  }
    84  
    85  // cleanup frees all resources associated with the timer.
    86  func (t *timer) cleanup() {
    87  	t.timer.Stop()
    88  }
    89  
    90  // checkExpiration checks if the given timer has actually expired, it should be
    91  // called whenever a sleeper wakes up due to the waker being asserted, and is
    92  // used to check if it's a supurious wake (due to a previously orphaned timer)
    93  // or a legitimate one.
    94  func (t *timer) checkExpiration() bool {
    95  	// Transition to fully disabled state if we're just consuming an
    96  	// orphaned timer.
    97  	if t.state == timerStateOrphaned {
    98  		t.state = timerStateDisabled
    99  		return false
   100  	}
   101  
   102  	// The timer is enabled, but it may have expired early. Check if that's
   103  	// the case, and if so, reset the runtime timer to the correct time.
   104  	now := time.Now()
   105  	if now.Before(t.target) {
   106  		t.runtimeTarget = t.target
   107  		t.timer.Reset(t.target.Sub(now))
   108  		return false
   109  	}
   110  
   111  	// The timer has actually expired, disable it for now and inform the
   112  	// caller.
   113  	t.state = timerStateDisabled
   114  	return true
   115  }
   116  
   117  // disable disables the timer, leaving it in an orphaned state if it wasn't
   118  // already disabled.
   119  func (t *timer) disable() {
   120  	if t.state != timerStateDisabled {
   121  		t.state = timerStateOrphaned
   122  	}
   123  }
   124  
   125  // enabled returns true if the timer is currently enabled, false otherwise.
   126  func (t *timer) enabled() bool {
   127  	return t.state == timerStateEnabled
   128  }
   129  
   130  // enable enables the timer, programming the runtime timer if necessary.
   131  func (t *timer) enable(d time.Duration) {
   132  	t.target = time.Now().Add(d)
   133  
   134  	// Check if we need to set the runtime timer.
   135  	if t.state == timerStateDisabled || t.target.Before(t.runtimeTarget) {
   136  		t.runtimeTarget = t.target
   137  		t.timer.Reset(d)
   138  	}
   139  
   140  	t.state = timerStateEnabled
   141  }