rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/runtime/mfixalloc.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Fixed-size object allocator.  Returned memory is not zeroed.
     6  //
     7  // See malloc.go for overview.
     8  
     9  package runtime
    10  
    11  import "unsafe"
    12  
    13  // FixAlloc is a simple free-list allocator for fixed size objects.
    14  // Malloc uses a FixAlloc wrapped around sysAlloc to manages its
    15  // MCache and MSpan objects.
    16  //
    17  // Memory returned by FixAlloc_Alloc is not zeroed.
    18  // The caller is responsible for locking around FixAlloc calls.
    19  // Callers can keep state in the object but the first word is
    20  // smashed by freeing and reallocating.
    21  type fixalloc struct {
    22  	size   uintptr
    23  	first  unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned
    24  	arg    unsafe.Pointer
    25  	list   *mlink
    26  	chunk  *byte
    27  	nchunk uint32
    28  	inuse  uintptr // in-use bytes now
    29  	stat   *uint64
    30  }
    31  
    32  // A generic linked list of blocks.  (Typically the block is bigger than sizeof(MLink).)
    33  // Since assignments to mlink.next will result in a write barrier being preformed
    34  // this can not be used by some of the internal GC structures. For example when
    35  // the sweeper is placing an unmarked object on the free list it does not want the
    36  // write barrier to be called since that could result in the object being reachable.
    37  type mlink struct {
    38  	next *mlink
    39  }
    40  
    41  // Initialize f to allocate objects of the given size,
    42  // using the allocator to obtain chunks of memory.
    43  func fixAlloc_Init(f *fixalloc, size uintptr, first func(unsafe.Pointer, unsafe.Pointer), arg unsafe.Pointer, stat *uint64) {
    44  	f.size = size
    45  	f.first = *(*unsafe.Pointer)(unsafe.Pointer(&first))
    46  	f.arg = arg
    47  	f.list = nil
    48  	f.chunk = nil
    49  	f.nchunk = 0
    50  	f.inuse = 0
    51  	f.stat = stat
    52  }
    53  
    54  func fixAlloc_Alloc(f *fixalloc) unsafe.Pointer {
    55  	if f.size == 0 {
    56  		print("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n")
    57  		throw("runtime: internal error")
    58  	}
    59  
    60  	if f.list != nil {
    61  		v := unsafe.Pointer(f.list)
    62  		f.list = f.list.next
    63  		f.inuse += f.size
    64  		return v
    65  	}
    66  	if uintptr(f.nchunk) < f.size {
    67  		f.chunk = (*uint8)(persistentalloc(_FixAllocChunk, 0, f.stat))
    68  		f.nchunk = _FixAllocChunk
    69  	}
    70  
    71  	v := (unsafe.Pointer)(f.chunk)
    72  	if f.first != nil {
    73  		fn := *(*func(unsafe.Pointer, unsafe.Pointer))(unsafe.Pointer(&f.first))
    74  		fn(f.arg, v)
    75  	}
    76  	f.chunk = (*byte)(add(unsafe.Pointer(f.chunk), f.size))
    77  	f.nchunk -= uint32(f.size)
    78  	f.inuse += f.size
    79  	return v
    80  }
    81  
    82  func fixAlloc_Free(f *fixalloc, p unsafe.Pointer) {
    83  	f.inuse -= f.size
    84  	v := (*mlink)(p)
    85  	v.next = f.list
    86  	f.list = v
    87  }