-
Notifications
You must be signed in to change notification settings - Fork 0
/
impl_1.21.go
51 lines (41 loc) · 1.24 KB
/
impl_1.21.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//go:build go1.21 && !go1.23
// +build go1.21,!go1.23
package cancelContext
import (
"context"
"reflect"
"runtime"
"sync/atomic"
"github.com/szmcdull/go-forceexport"
)
// A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx.
type canceler interface {
cancel(removeFromParent bool, err, cause error)
Done() <-chan struct{}
}
var (
propagateCancel func(cancelCtx uintptr, parent context.Context, child canceler)
)
func init() {
f := runtime.Func{}
_ = &f
if err := forceexport.GetFunc(&propagateCancel, `context.(*cancelCtx).propagateCancel`); err != nil {
panic(err)
}
}
func (me *CancelCtx) cancel(removeFromParent bool, err, cause error) {
if atomic.CompareAndSwapInt32(&me.isDone, 0, 1) {
me.cancelFunc()
}
}
// NewLinkedCancelCtx creates a new context that links with all parents.
// When any parent is done, the new context is canceled automatically.
func (parent *CancelCtx) NewLinkedCancelCtx(otherParents ...context.Context) *CancelCtx {
withCancel := NewCancelCtx(parent)
p := reflect.ValueOf(withCancel.Context).Pointer()
for _, c := range otherParents {
propagateCancel(p, c, withCancel)
}
return withCancel
}