github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/unsafekit/keep_alive.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package unsafekit 7 8 import ( 9 "fmt" 10 "reflect" 11 "runtime" 12 "unsafe" 13 14 "github.com/insolar/vanilla/longbits" 15 ) 16 17 func KeepAliveWhile(p unsafe.Pointer, fn func(unsafe.Pointer) uintptr) uintptr { 18 res := fn(p) 19 runtime.KeepAlive(p) 20 return res 21 } 22 23 const keepAlivePageLen = 4096/PtrSize - 4 24 25 type keepAlivePage [keepAlivePageLen]unsafe.Pointer 26 27 type KeepAliveList struct { 28 list []unsafe.Pointer 29 lastPageCount uint16 30 listOfPages bool 31 } 32 33 func (p *KeepAliveList) Reset() { 34 *p = KeepAliveList{} 35 } 36 37 func (p *KeepAliveList) Keep(v interface{}) { 38 vv := reflect.ValueOf(v) 39 switch vv.Kind() { 40 case reflect.Chan, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Slice: 41 p.keep(vv.Pointer()) 42 case reflect.String: 43 p.keepStrData(vv.String()) 44 default: 45 panic(fmt.Sprint("unsupported value", vv)) 46 } 47 runtime.KeepAlive(v) 48 } 49 50 func (p *KeepAliveList) KeepDataOf(v longbits.ByteString) { 51 p.keepStrData(string(v)) 52 runtime.KeepAlive(v) 53 } 54 55 func (p *KeepAliveList) KeepDataOfBytes(v []byte) { 56 pSlice := (*reflect.SliceHeader)(unsafe.Pointer(&v)) 57 p.keep(pSlice.Data) 58 runtime.KeepAlive(v) 59 } 60 61 func (p *KeepAliveList) keepStrData(s string) { 62 pString := (*reflect.StringHeader)(unsafe.Pointer(&s)) 63 p.keep(pString.Data) 64 } 65 66 func (p *KeepAliveList) keep(v uintptr) { 67 switch { 68 case p.listOfPages: 69 if p.lastPageCount == keepAlivePageLen { 70 break 71 } 72 73 switch { 74 case len(p.list) < 2: 75 panic("illegal state") 76 case p.lastPageCount > keepAlivePageLen: 77 panic("illegal state") 78 } 79 lastPage := (*keepAlivePage)(p.list[len(p.list)-1]) 80 lastPage[p.lastPageCount] = unsafe.Pointer(v) 81 p.lastPageCount++ 82 return 83 84 case p.lastPageCount != 0: 85 panic("illegal state") 86 87 case len(p.list) == keepAlivePageLen: 88 lastPage := new(keepAlivePage) 89 copy(lastPage[:], p.list) 90 p.list = make([]unsafe.Pointer, 1, 2) 91 p.list[0] = unsafe.Pointer(lastPage) 92 93 case len(p.list) > keepAlivePageLen: 94 panic("illegal state") 95 96 default: 97 p.list = append(p.list, unsafe.Pointer(v)) 98 return 99 } 100 101 switch { 102 case p.lastPageCount != keepAlivePageLen: 103 panic("illegal state") 104 case len(p.list) < 1: 105 panic("illegal state") 106 } 107 108 lastPage := new(keepAlivePage) 109 p.list = append(p.list, (unsafe.Pointer)(lastPage)) 110 lastPage[0] = unsafe.Pointer(p) 111 p.lastPageCount = 1 112 }