github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/lightning/manual/manual.go (about) 1 // Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package manual 6 7 // #include <stdlib.h> 8 import "C" 9 import "unsafe" 10 11 // The go:linkname directives provides backdoor access to private functions in 12 // the runtime. Below we're accessing the throw function. 13 14 //go:linkname throw runtime.throw 15 func throw(s string) 16 17 // TODO(peter): Rather than relying an C malloc/free, we could fork the Go 18 // runtime page allocator and allocate large chunks of memory using mmap or 19 // similar. 20 21 const ( 22 // MaxArrayLen is a safe maximum length for slices on this architecture. 23 MaxArrayLen = 1<<31 - 1 24 ) 25 26 // New allocates a slice of size n. The returned slice is from manually managed 27 // memory and MUST be released by calling Free. Failure to do so will result in 28 // a memory leak. 29 func New(n int) []byte { 30 if n == 0 { 31 return make([]byte, 0) 32 } 33 // We need to be conscious of the Cgo pointer passing rules: 34 // 35 // https://golang.org/cmd/cgo/#hdr-Passing_pointers 36 // 37 // ... 38 // Note: the current implementation has a bug. While Go code is permitted 39 // to write nil or a C pointer (but not a Go pointer) to C memory, the 40 // current implementation may sometimes cause a runtime error if the 41 // contents of the C memory appear to be a Go pointer. Therefore, avoid 42 // passing uninitialized C memory to Go code if the Go code is going to 43 // store pointer values in it. Zero out the memory in C before passing it 44 // to Go. 45 ptr := C.calloc(C.size_t(n), 1) 46 if ptr == nil { 47 // NB: throw is like panic, except it guarantees the process will be 48 // terminated. The call below is exactly what the Go runtime invokes when 49 // it cannot allocate memory. 50 throw("out of memory") 51 } 52 // Interpret the C pointer as a pointer to a Go array, then slice. 53 return (*[MaxArrayLen]byte)(unsafe.Pointer(ptr))[:n:n] 54 } 55 56 // Free frees the specified slice. 57 func Free(b []byte) { 58 if cap(b) != 0 { 59 if len(b) == 0 { 60 b = b[:cap(b)] 61 } 62 ptr := unsafe.Pointer(&b[0]) 63 C.free(ptr) 64 } 65 }