github.com/pidato/unsafe@v0.1.4/memory/tlsf/heap_std.go (about) 1 //go:build !tinygo && !wasm && !wasi && !tinygo.wasm && (darwin || linux) 2 3 package tlsf 4 5 import ( 6 "sync" 7 "unsafe" 8 ) 9 10 func NewHeap(pages int32) *Heap { 11 return NewHeapWithConfig(pages, NewSliceArena(), GrowMin) 12 } 13 14 func NewHeapWithConfig(pages int32, pageAlloc Arena, grow GrowFactory) *Heap { 15 if pages <= 0 { 16 pages = 1 17 } 18 g := grow(pageAlloc) 19 if g == nil { 20 g = GrowMin(pageAlloc) 21 } 22 pagesAdded, start, end := g(0, pages, 0) 23 a := Bootstrap(start, end, pagesAdded, g) 24 a.arena = uintptr(unsafe.Pointer(&pageAlloc)) 25 return a 26 } 27 28 //// Scope creates an Auto free list that automatically reclaims memory 29 //// after callback finishes. 30 //func (a *Heap) Scope(fn func(a Auto)) { 31 // if fn == nil { 32 // return 33 // } 34 // auto := NewAuto(a.As, 32) 35 // defer auto.Free() 36 // fn(auto) 37 //} 38 // 39 //// Scope creates an Auto free list that automatically reclaims memory 40 //// after callback finishes. 41 //func (a *Sync) Scope(fn func(a Auto)) { 42 // if fn == nil { 43 // return 44 // } 45 // auto := NewAuto(a.AsAllocator(), 32) 46 // defer auto.Free() 47 // fn(auto) 48 //} 49 50 type SystemAllocator struct { 51 } 52 53 //// Create allocates a block of memory that fits the size provided. 54 //// The allocation IS cleared / zeroed out. 55 //func (SystemAllocator) AllocString(size uintptr) uintptr { 56 // a.Lock() 57 // defer a.Unlock() 58 // return a.a.Create(size) 59 //} 60 // 61 //// AllocZeroed allocates a block of memory that fits the size provided. 62 //// The allocation is NOT cleared / zeroed out. 63 //func (SystemAllocator) AllocZeroed(size uintptr) uintptr { 64 // a.Lock() 65 // defer a.Unlock() 66 // return a.a.AllocZeroed(size) 67 //} 68 69 type Sync struct { 70 a *Heap 71 Slot uint8 72 sync.Mutex 73 } 74 75 func (a *Heap) ToSync() *Sync { 76 return &Sync{a: a} 77 } 78 79 func (a *Sync) Stats() Stats { 80 return a.a.Stats 81 } 82 83 // Alloc allocates a block of memory that fits the size provided. 84 // The allocation IS cleared / zeroed out. 85 func (a *Sync) Alloc(size uintptr) uintptr { 86 a.Lock() 87 defer a.Unlock() 88 return a.a.Alloc(size) 89 } 90 91 // AllocZeroed allocates a block of memory that fits the size provided. 92 // The allocation is NOT cleared / zeroed out. 93 func (a *Sync) AllocZeroed(size uintptr) uintptr { 94 a.Lock() 95 defer a.Unlock() 96 return a.a.AllocZeroed(size) 97 } 98 99 // Realloc determines the best way to resize an allocation. 100 // Any extra size added is NOT cleared / zeroed out. 101 func (a *Sync) Realloc(ptr uintptr, size uintptr) uintptr { 102 a.Lock() 103 defer a.Unlock() 104 return uintptr(unsafe.Pointer(a.a.moveBlock(checkUsedBlock(ptr), uintptr(size)))) + BlockOverhead 105 } 106 107 // Free release the allocation back into the free list. 108 func (a *Sync) Free(ptr uintptr) { 109 a.Lock() 110 defer a.Unlock() 111 a.a.freeBlock(checkUsedBlock(ptr)) 112 } 113 114 //// Create allocates a block of memory that fits the size provided. 115 //// The allocation IS cleared / zeroed out. 116 //func (a *Sync) AllocString(size uintptr) Bytes { 117 // return newString(a.AsAllocator(), size) 118 //} 119 120 type GrowFactory func(arena Arena) Grow 121 122 func GrowByDouble(arena Arena) Grow { 123 return func(pagesBefore, pagesNeeded int32, minSize uintptr) (pagesAdded int32, start, end uintptr) { 124 if pagesBefore > pagesNeeded { 125 pagesAdded = pagesBefore 126 } else { 127 pagesAdded = pagesNeeded 128 } 129 start, end = arena.Alloc(uintptr(pagesAdded) * PageSize) 130 if start == 0 { 131 pagesAdded = pagesNeeded 132 start, end = arena.Alloc(uintptr(pagesAdded) * PageSize) 133 if start == 0 { 134 return 0, 0, 0 135 } 136 } 137 return 138 } 139 } 140 141 func GrowBy(pages int32, arena Arena) Grow { 142 return func(pagesBefore, pagesNeeded int32, minSize uintptr) (pagesAdded int32, start, end uintptr) { 143 if pages > pagesNeeded { 144 pagesAdded = pages 145 } else { 146 pagesAdded = pagesNeeded 147 } 148 start, end = arena.Alloc(uintptr(pagesAdded) * PageSize) 149 if start == 0 { 150 pagesAdded = pagesNeeded 151 start, end = arena.Alloc(uintptr(pagesAdded) * PageSize) 152 if start == 0 { 153 return 0, 0, 0 154 } 155 } 156 return 157 } 158 } 159 160 func GrowMin(arena Arena) Grow { 161 return func(pagesBefore, pagesNeeded int32, minSize uintptr) (int32, uintptr, uintptr) { 162 start, end := arena.Alloc(uintptr(pagesNeeded) * PageSize) 163 if start == 0 { 164 return 0, 0, 0 165 } 166 return pagesNeeded, start, end 167 } 168 }