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  }