<p dir="auto">I saw two common usage patterns of Timer.Reset:</p>
<p dir="auto">First is ensuring that a sequence of events happens in a timely fashion:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="timeout := time.NewTimer(T)
for {
  if !timeout.Reset(T) {
    &lt;-timeout.C
  }
  select {
  case &lt;- ...: ...
  case &lt;-timeout.C: ...
  }
}"><pre class="notranslate"><span class="pl-s1">timeout</span> <span class="pl-c1">:=</span> <span class="pl-s1">time</span>.<span class="pl-en">NewTimer</span>(<span class="pl-s1">T</span>)
<span class="pl-k">for</span> {
  <span class="pl-k">if</span> <span class="pl-c1">!</span><span class="pl-s1">timeout</span>.<span class="pl-en">Reset</span>(<span class="pl-s1">T</span>) {
    <span class="pl-c1">&lt;-</span><span class="pl-s1">timeout</span>.<span class="pl-c1">C</span>
  }
  <span class="pl-k">select</span> {
  <span class="pl-k">case</span> <span class="pl-c1">&lt;-</span> <span class="pl-c1">...</span>: <span class="pl-c1">...</span>
  <span class="pl-k">case</span> <span class="pl-c1">&lt;-</span><span class="pl-s1">timeout</span>.<span class="pl-c1">C</span>: <span class="pl-c1">...</span>
  }
}</pre></div>
<p dir="auto">Second is connection timeout with an ability to change the timeout:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="timeout := time.NewTimer(T)

// goroutine 1
for {
  select {
  case &lt;- ...: ...
  case &lt;-timeout.C: ...
  }
}

// goroutine 2
  if !timeout.Reset(T2) {
    &lt;-timeout.C
  }"><pre class="notranslate"><span class="pl-s1">timeout</span> <span class="pl-c1">:=</span> <span class="pl-s1">time</span>.<span class="pl-en">NewTimer</span>(<span class="pl-s1">T</span>)

<span class="pl-c">// goroutine 1</span>
<span class="pl-k">for</span> {
  <span class="pl-k">select</span> {
  <span class="pl-k">case</span> <span class="pl-c1">&lt;-</span> <span class="pl-c1">...</span>: <span class="pl-c1">...</span>
  <span class="pl-k">case</span> <span class="pl-c1">&lt;-</span><span class="pl-s1">timeout</span>.<span class="pl-c1">C</span>: <span class="pl-c1">...</span>
  }
}

<span class="pl-c">// goroutine 2</span>
  <span class="pl-k">if</span> <span class="pl-c1">!</span><span class="pl-s1">timeout</span>.<span class="pl-en">Reset</span>(<span class="pl-s1">T2</span>) {
    <span class="pl-c1">&lt;-</span><span class="pl-s1">timeout</span>.<span class="pl-c1">C</span>
  }</pre></div>
<p dir="auto">There are several things that can go wrong here depending on timings:</p>
<ol dir="auto">
<li>Reset returns false; one element is already in the channel (the old one); timer goroutine sends another (corresponding to the new timeout), it is discarded since the channel is full; now we drain the channel to read out the old value; as the result timeout will never happen as the new value was discarded.</li>
<li>Reset returns false; one element is already in the channel (the old one); timer goroutine sends another (corresponding to the new timeout), it is discarded since the channel is full; goroutine 1 reads out from the channel; goroutine 2 hangs forever trying to drain the channel.</li>
</ol>
<p dir="auto">I've found several cases of this bug in our internal codebase, one even with a TODO by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/bradfitz/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/bradfitz">@bradfitz</a> describing this race.</p>
<p dir="auto">Timer.Reset does the following:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="func (t *Timer) Reset(d Duration) bool {
    if t.r.f == nil {
        panic(&quot;time: Reset called on uninitialized Timer&quot;)
    }
    w := when(d)
    active := stopTimer(&amp;t.r)
    t.r.when = w
    startTimer(&amp;t.r)
    return active
}"><pre class="notranslate"><span class="pl-k">func</span> (<span class="pl-s1">t</span> <span class="pl-c1">*</span><span class="pl-smi">Timer</span>) <span class="pl-en">Reset</span>(<span class="pl-s1">d</span> <span class="pl-smi">Duration</span>) <span class="pl-smi">bool</span> {
    <span class="pl-k">if</span> <span class="pl-s1">t</span>.<span class="pl-c1">r</span>.<span class="pl-c1">f</span> <span class="pl-c1">==</span> <span class="pl-c1">nil</span> {
        <span class="pl-en">panic</span>(<span class="pl-s">"time: Reset called on uninitialized Timer"</span>)
    }
    <span class="pl-s1">w</span> <span class="pl-c1">:=</span> <span class="pl-en">when</span>(<span class="pl-s1">d</span>)
    <span class="pl-s1">active</span> <span class="pl-c1">:=</span> <span class="pl-en">stopTimer</span>(<span class="pl-c1">&amp;</span><span class="pl-s1">t</span>.<span class="pl-c1">r</span>)
    <span class="pl-s1">t</span>.<span class="pl-c1">r</span>.<span class="pl-c1">when</span> <span class="pl-c1">=</span> <span class="pl-s1">w</span>
    <span class="pl-en">startTimer</span>(<span class="pl-c1">&amp;</span><span class="pl-s1">t</span>.<span class="pl-c1">r</span>)
    <span class="pl-k">return</span> <span class="pl-s1">active</span>
}</pre></div>
<p dir="auto">What would be possible to use correctly is:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="func (t *Timer) Reset2(d Duration) bool {
    if t.r.f == nil {
        panic(&quot;time: Reset called on uninitialized Timer&quot;)
    }
    w := when(d)
    active := stopTimer(&amp;t.r)
        if !active {
                &lt;-t.C
        }
    t.r.when = w
    startTimer(&amp;t.r)
    return active
}"><pre class="notranslate"><span class="pl-k">func</span> (<span class="pl-s1">t</span> <span class="pl-c1">*</span><span class="pl-smi">Timer</span>) <span class="pl-en">Reset2</span>(<span class="pl-s1">d</span> <span class="pl-smi">Duration</span>) <span class="pl-smi">bool</span> {
    <span class="pl-k">if</span> <span class="pl-s1">t</span>.<span class="pl-c1">r</span>.<span class="pl-c1">f</span> <span class="pl-c1">==</span> <span class="pl-c1">nil</span> {
        <span class="pl-en">panic</span>(<span class="pl-s">"time: Reset called on uninitialized Timer"</span>)
    }
    <span class="pl-s1">w</span> <span class="pl-c1">:=</span> <span class="pl-en">when</span>(<span class="pl-s1">d</span>)
    <span class="pl-s1">active</span> <span class="pl-c1">:=</span> <span class="pl-en">stopTimer</span>(<span class="pl-c1">&amp;</span><span class="pl-s1">t</span>.<span class="pl-c1">r</span>)
        <span class="pl-k">if</span> <span class="pl-c1">!</span><span class="pl-s1">active</span> {
                <span class="pl-c1">&lt;-</span><span class="pl-s1">t</span>.<span class="pl-c1">C</span>
        }
    <span class="pl-s1">t</span>.<span class="pl-c1">r</span>.<span class="pl-c1">when</span> <span class="pl-c1">=</span> <span class="pl-s1">w</span>
    <span class="pl-en">startTimer</span>(<span class="pl-c1">&amp;</span><span class="pl-s1">t</span>.<span class="pl-c1">r</span>)
    <span class="pl-k">return</span> <span class="pl-s1">active</span>
}</pre></div>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/rsc/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/rsc">@rsc</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Sajmani/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Sajmani">@Sajmani</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/aclements/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/aclements">@aclements</a></p>
<p dir="auto">A common idiom is to keep a single timer and extend its<br>
use by calling Timer.Reset.</p>
<p dir="auto">From a naive reading of the documentation, these two<br>
lines are equivalent except for saving some garbage:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="t.Reset(x)

t := time.NewTimer(x)"><pre class="notranslate"><code class="notranslate">t.Reset(x)

t := time.NewTimer(x)
</code></pre></div>
<p dir="auto">Unfortunately t.C is buffered, so if the timer has just expired,<br>
the newly reset timer can actually trigger immediately.</p>
<p dir="auto">The safe way to do it might be someting like:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="t.Stop()
select {
case &lt;-t.C:
default:
}
t.Reset(x)"><pre class="notranslate"><code class="notranslate">t.Stop()
select {
case &lt;-t.C:
default:
}
t.Reset(x)
</code></pre></div>
<p dir="auto">but this is cumbersome. Perhaps we could change Reset to do this<br>
as a matter of course.</p>