go.temporal.io/server@v1.23.0/common/clock/context.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package clock 26 27 import ( 28 "context" 29 "sync" 30 "time" 31 ) 32 33 type ctxWithDeadline struct { 34 context.Context 35 deadline time.Time 36 timer Timer 37 once sync.Once 38 done chan struct{} 39 err error 40 } 41 42 func (ctx *ctxWithDeadline) Deadline() (deadline time.Time, ok bool) { 43 return ctx.deadline, true 44 } 45 46 func (ctx *ctxWithDeadline) Done() <-chan struct{} { 47 return ctx.done 48 } 49 50 func (ctx *ctxWithDeadline) Err() error { 51 select { 52 case <-ctx.done: 53 return ctx.err 54 default: 55 return nil 56 } 57 } 58 59 func (ctx *ctxWithDeadline) deadlineExceeded() { 60 ctx.once.Do(func() { 61 ctx.err = context.DeadlineExceeded 62 close(ctx.done) 63 }) 64 } 65 66 func (ctx *ctxWithDeadline) cancel() { 67 ctx.once.Do(func() { 68 ctx.timer.Stop() 69 ctx.err = context.Canceled 70 close(ctx.done) 71 }) 72 } 73 74 func ContextWithDeadline( 75 ctx context.Context, 76 deadline time.Time, 77 timeSource TimeSource, 78 ) (context.Context, context.CancelFunc) { 79 ctxd := &ctxWithDeadline{ 80 Context: ctx, 81 deadline: deadline, 82 done: make(chan struct{}), 83 } 84 timer := timeSource.AfterFunc(deadline.Sub(timeSource.Now()), ctxd.deadlineExceeded) 85 ctxd.timer = timer 86 return ctxd, ctxd.cancel 87 } 88 89 func ContextWithTimeout( 90 ctx context.Context, 91 timeout time.Duration, 92 timeSource TimeSource, 93 ) (context.Context, context.CancelFunc) { 94 return ContextWithDeadline(ctx, timeSource.Now().Add(timeout), timeSource) 95 }