1const MemoryMap = @This();
2
3const builtin = @import("builtin");
4const native_os = builtin.os.tag;
5const is_windows = native_os == .windows;
6
7const std = @import("../../std.zig");
8const Io = std.Io;
9const File = Io.File;
10const Allocator = std.mem.Allocator;
11
12file: File,
13/// Byte index inside `file` where `memory` starts. Page-aligned.
14offset: u64,
15/// Memory that may or may not remain consistent with file contents. Use `read`
16/// and `write` to ensure synchronization points. Length has no alignment
17/// requirement.
18memory: []align(std.heap.page_size_min) u8,
19/// Tells whether it is memory-mapped or file operations. On Windows this also
20/// has a section handle.
21section: ?Section,
22
23pub const Section = if (is_windows) std.os.windows.HANDLE else void;
24
25pub const CreateError = error{
26 /// One of the following:
27 /// * The `File.Kind` is not `file`.
28 /// * The file is not open for reading and read access protections enabled.
29 /// * The file is not open for writing and write access protections enabled.
30 AccessDenied,
31 /// The `prot` argument asks for `PROT_EXEC` but the mapped area belongs to a file on
32 /// a filesystem that was mounted no-exec.
33 PermissionDenied,
34 LockedMemoryLimitExceeded,
35 ProcessFdQuotaExceeded,
36 SystemFdQuotaExceeded,
37} || Allocator.Error || File.ReadPositionalError;
38
39pub const CreateOptions = struct {
40 /// Size of the mapping, in bytes. If this is longer than the file size,
41 /// `memory` beyond the file end will be filled with zeroes and it is
42 /// unspecified whether, after calling `write`, the file length will be
43 /// set to `len` or remain unchanged.
44 ///
45 /// This value has no minimum alignment requirement, but may gain
46 /// efficiency benefits from being a multiple of `File.Stat.block_size`.
47 len: usize,
48 /// When this has read set to false, bytes that are not modified before a
49 /// sync may have the original file contents, or may be set to zero.
50 protection: std.process.MemoryProtection = .{ .read = true, .write = true },
51 /// If set to `true`, allows bytes observed before calling `read` to be
52 /// undefined, and bytes unwritten before calling `write` to write
53 /// undefined memory to the file.
54 undefined_contents: bool = false,
55 /// Prefault the pages. If this option is unsupported, it is silently
56 /// ignored. Aside from custom Io implementations, this option is only
57 /// supported on Linux.
58 populate: bool = true,
59 /// Asserted to be a multiple of page size which can be obtained via
60 /// `std.heap.pageSize`.
61 offset: u64 = 0,
62};
63
64/// To release the resources associated with the returned `MemoryMap`, call
65/// `destroy`.
66pub fn create(io: Io, file: File, options: CreateOptions) CreateError!MemoryMap {
67 return io.vtable.fileMemoryMapCreate(io.userdata, file, options);
68}
69
70/// If `write` is not called before this function, changes to `memory` may or may
71/// not be synchronized to `file`.
72pub fn destroy(mm: *MemoryMap, io: Io) void {
73 io.vtable.fileMemoryMapDestroy(io.userdata, mm);
74}
75
76pub const SetLengthError = error{
77 /// Changing the mapping length could not be done atomically. Caller must
78 /// use `destroy` and `create` to resize the mapping.
79 OperationUnsupported,
80 /// One of the following:
81 /// * The `File.Kind` is not `file`.
82 /// * The file is not open for reading and read access protections enabled.
83 /// * The file is not open for writing and write access protections enabled.
84 AccessDenied,
85 /// The `prot` argument asks for `PROT_EXEC` but the mapped area belongs to a file on
86 /// a filesystem that was mounted no-exec.
87 PermissionDenied,
88 LockedMemoryLimitExceeded,
89 ProcessFdQuotaExceeded,
90 SystemFdQuotaExceeded,
91} || Allocator.Error || File.SetLengthError;
92
93/// Change the size of the mapping. This does not sync the contents. The size
94/// of the file after calling this is unspecified until `write` is called.
95///
96/// May change the pointer address of `memory`.
97pub fn setLength(mm: *MemoryMap, io: Io, new_len: usize) SetLengthError!void {
98 return io.vtable.fileMemoryMapSetLength(io.userdata, mm, new_len);
99}
100
101/// Synchronizes the contents of `memory` from `file`.
102pub fn read(mm: *MemoryMap, io: Io) File.ReadPositionalError!void {
103 return io.vtable.fileMemoryMapRead(io.userdata, mm);
104}
105
106/// Synchronizes the contents of `memory` to `file`.
107///
108/// If `memory.len` is greater than file size, the bytes beyond the end of the
109/// file may be dropped, or they may be written, extending the size of the
110/// file.
111pub fn write(mm: *MemoryMap, io: Io) File.WritePositionalError!void {
112 return io.vtable.fileMemoryMapWrite(io.userdata, mm);
113}