cubefs
86 строк · 2.0 Кб
1package clock2
3import (4"context"5"fmt"6"sync"7"time"8)
9
10func (m *Mock) WithTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {11return m.WithDeadline(parent, m.Now().Add(timeout))12}
13
14func (m *Mock) WithDeadline(parent context.Context, deadline time.Time) (context.Context, context.CancelFunc) {15if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {16// The current deadline is already sooner than the new one.17return context.WithCancel(parent)18}19ctx := &timerCtx{clock: m, parent: parent, deadline: deadline, done: make(chan struct{})}20propagateCancel(parent, ctx)21dur := m.Until(deadline)22if dur <= 0 {23ctx.cancel(context.DeadlineExceeded) // deadline has already passed24return ctx, func() {}25}26ctx.Lock()27defer ctx.Unlock()28if ctx.err == nil {29ctx.timer = m.AfterFunc(dur, func() {30ctx.cancel(context.DeadlineExceeded)31})32}33return ctx, func() { ctx.cancel(context.Canceled) }34}
35
36// propagateCancel arranges for child to be canceled when parent is.
37func propagateCancel(parent context.Context, child *timerCtx) {38if parent.Done() == nil {39return // parent is never canceled40}41go func() {42select {43case <-parent.Done():44child.cancel(parent.Err())45case <-child.Done():46}47}()48}
49
50type timerCtx struct {51sync.Mutex52
53clock Clock
54parent context.Context55deadline time.Time56done chan struct{}57
58err error59timer *Timer60}
61
62func (c *timerCtx) cancel(err error) {63c.Lock()64defer c.Unlock()65if c.err != nil {66return // already canceled67}68c.err = err69close(c.done)70if c.timer != nil {71c.timer.Stop()72c.timer = nil73}74}
75
76func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true }77
78func (c *timerCtx) Done() <-chan struct{} { return c.done }79
80func (c *timerCtx) Err() error { return c.err }81
82func (c *timerCtx) Value(key interface{}) interface{} { return c.parent.Value(key) }83
84func (c *timerCtx) String() string {85return fmt.Sprintf("clock.WithDeadline(%s [%s])", c.deadline, c.deadline.Sub(c.clock.Now()))86}
87