Landin library reference discuss source

platform/posix/memory.ldn

1--  Memory the system maps for the process: anonymous, zeroed, readable
2--  and writable pages, given back, grown where they are and, on Linux,
3--  moved; and the page size.
4
5import platform/libc
6import platform/linux
7
8--- Map `length` bytes of fresh, zeroed memory that this process alone may
9--- read and write, POSIX's anonymous private `mmap`: its first byte, which
10--- is aligned to a page, or the errno, `enomem` when the system has no
11--- room.
12public link(symbol: "_landin_posix_map") map:
13    (length: usize) -> (base: ptr mut u8) ! errno =
14    base = try system_map(length)
15end map
16
17--- Give back the `length` bytes mapped at `base`, POSIX's `munmap`.
18public link(symbol: "_landin_posix_unmap") unmap:
19    (base: ptr mut u8, length: usize) -> none ! errno =
20    try system_unmap(base, length)
21end unmap
22
23--- Make the `length` bytes `map` mapped at `base` `new_length` bytes long,
24--- at least `length`, where they are: the pages after them must be free,
25--- or it fails with `enomem` and the mapping is as it was.  Linux's
26--- `mremap` without `MREMAP_MAYMOVE`.  Darwin and FreeBSD have no `mremap`:
27--- there the pages after the mapping are asked for, and kept only when the
28--- system puts them there.  A shorter `new_length` fails with `einval`;
29--- give a mapping's tail back with `unmap`.
30public link(symbol: "_landin_posix_extend") extend:
31    (base: ptr mut u8, length: usize, new_length: usize) -> none ! errno =
32    fail einval when new_length < length
33    return when new_length == length
34    try system_extend(base, length, new_length)
35end extend
36
37--- Make the `length` bytes `map` mapped at `base` `new_length` bytes long,
38--- at least `length`, and return where they now are: in place, as `extend`
39--- does, or else at an address with room, the pages moved rather than their
40--- bytes copied, which is Linux's `mremap` with `MREMAP_MAYMOVE`.  Darwin
41--- and FreeBSD cannot move a mapping, so there it is `extend`.  A failure
42--- leaves the mapping as it was; a shorter `new_length` fails with
43--- `einval`.
44public link(symbol: "_landin_posix_remap") remap:
45    (base: ptr mut u8, length: usize, new_length: usize)
46    -> (moved: ptr mut u8) ! errno =
47    fail einval when new_length < length
48    moved = ptr(usize(base))
49    return when new_length == length
50    moved = try system_remap(base, length, new_length)
51end remap
52
53--- The size of the system's pages in bytes, which `map` aligns to: 16 KiB
54--- on Darwin arm64 and 4 KiB on the others.  On Linux it is what the
55--- kernel told a static executable's entry or, under `--link=libc`, what
56--- the auxiliary vector after C `main`'s `envp` says, and 4096 when no
57--- vector was found.
58public link(symbol: "_landin_posix_page_size") page_size:
59    () -> (bytes: usize) =
60    bytes = system_page_size()
61end page_size
62
63--  The system's own calls beneath the facility above: Linux's system
64--  calls through platform/linux, and the C library through
65--  platform/libc on Darwin and FreeBSD, whose system interface it is.
66
67fixed if compiler.os == linux then
68    system_map: (length: usize) -> (base: ptr mut u8) ! errno =
69        result: i64 = linux.mmap(0, length, linux.prot_read | linux.prot_write,
70                                 linux.map_private | linux.map_anonymous, -1,
71                                 0)
72        fail errno_of(i32(-result)) when result < 0
73        base = ptr(usize(result))
74    end system_map
75
76    system_unmap: (base: ptr mut u8, length: usize) -> none ! errno =
77        result: i32 = linux.munmap(usize(base), length)
78        fail errno_of(-result) when result < 0
79    end system_unmap
80
81    system_extend: (base: ptr mut u8, length: usize, new_length: usize)
82                   -> none ! errno =
83        result: i64 = linux.mremap(usize(base), length, new_length, 0)
84        fail errno_of(i32(-result)) when result < 0
85    end system_extend
86
87    system_remap: (base: ptr mut u8, length: usize, new_length: usize)
88                  -> (moved: ptr mut u8) ! errno =
89        result: i64 = linux.mremap(usize(base), length, new_length,
90                                   linux.mremap_maymove)
91        fail errno_of(i32(-result)) when result < 0
92        moved = ptr(usize(result))
93    end system_remap
94
95    system_page_size: () -> (bytes: usize) =
96        bytes = linux.page_size()
97    end system_page_size
98elsif compiler.os == darwin or compiler.os == freebsd then
99    system_map: (length: usize) -> (base: ptr mut u8) ! errno =
100        result: usize = libc.mmap(0, length, libc.prot_read | libc.prot_write,
101                                  libc.map_private | libc.map_anonymous, -1,
102                                  0)
103        fail failure() when result == libc.map_failed
104        base = ptr(result)
105    end system_map
106
107    system_unmap: (base: ptr mut u8, length: usize) -> none ! errno =
108        fail failure() when libc.munmap(usize(base), length) <> 0
109    end system_unmap
110
111    --  The pages after the mapping, asked for at its end without
112    --  `MAP_FIXED`, which would replace whatever is mapped there: a system
113    --  that puts them elsewhere has none free there, and they are given
114    --  back.
115    system_extend: (base: ptr mut u8, length: usize, new_length: usize)
116                   -> none ! errno =
117        wanted: usize = usize(base) + length
118        extra: usize = new_length - length
119        result: usize = libc.mmap(wanted, extra,
120                                  libc.prot_read | libc.prot_write,
121                                  libc.map_private | libc.map_anonymous, -1,
122                                  0)
123        fail failure() when result == libc.map_failed
124        if result <> wanted then
125            _ = libc.munmap(result, extra)
126            fail enomem
127        end if
128    end system_extend
129
130    --  A mapping cannot move here, so it grows where it is or not at all.
131    system_remap: (base: ptr mut u8, length: usize, new_length: usize)
132                  -> (moved: ptr mut u8) ! errno =
133        try system_extend(base, length, new_length)
134        moved = ptr(usize(base))
135    end system_remap
136
137    system_page_size: () -> (bytes: usize) =
138        bytes = usize(libc.getpagesize())
139    end system_page_size
140end if