mmap_linux.go

 1package platform
 2
 3import (
 4	"math/bits"
 5	"os"
 6	"sort"
 7	"strconv"
 8	"strings"
 9	"syscall"
10)
11
12const (
13	// https://man7.org/linux/man-pages/man2/mmap.2.html
14	__MAP_HUGE_SHIFT = 26
15	__MAP_HUGETLB    = 0x40000
16)
17
18var hugePagesConfigs []hugePagesConfig
19
20type hugePagesConfig struct {
21	size int
22	flag int
23}
24
25func (hpc *hugePagesConfig) match(size int) bool {
26	return (size & (hpc.size - 1)) == 0
27}
28
29func init() {
30	dirents, err := os.ReadDir("/sys/kernel/mm/hugepages/")
31	if err != nil {
32		return
33	}
34
35	for _, dirent := range dirents {
36		name := dirent.Name()
37		if !strings.HasPrefix(name, "hugepages-") {
38			continue
39		}
40		if !strings.HasSuffix(name, "kB") {
41			continue
42		}
43		n, err := strconv.ParseUint(name[10:len(name)-2], 10, 64)
44		if err != nil {
45			continue
46		}
47		if bits.OnesCount64(n) != 1 {
48			continue
49		}
50		n *= 1024
51		hugePagesConfigs = append(hugePagesConfigs, hugePagesConfig{
52			size: int(n),
53			flag: int(bits.TrailingZeros64(n)<<__MAP_HUGE_SHIFT) | __MAP_HUGETLB,
54		})
55	}
56
57	sort.Slice(hugePagesConfigs, func(i, j int) bool {
58		return hugePagesConfigs[i].size > hugePagesConfigs[j].size
59	})
60}
61
62func mmapCodeSegment(size, prot int) ([]byte, error) {
63	flags := syscall.MAP_ANON | syscall.MAP_PRIVATE
64
65	for _, hugePagesConfig := range hugePagesConfigs {
66		if hugePagesConfig.match(size) {
67			b, err := syscall.Mmap(-1, 0, size, prot, flags|hugePagesConfig.flag)
68			if err != nil {
69				continue
70			}
71			return b, nil
72		}
73	}
74
75	return syscall.Mmap(-1, 0, size, prot, flags)
76}