@@ -7,41 +7,65 @@ use core::ops::Range;
7
7
#[ cfg( feature = "std" ) ]
8
8
use std:: { fs:: File , sync:: Arc } ;
9
9
10
- /// A simple struct consisting of a page-aligned pointer to page-aligned
11
- /// and initially-zeroed memory and a length.
12
- #[ derive( Debug ) ]
13
- pub struct Mmap {
14
- sys : mmap:: Mmap ,
10
+ /// A marker type for an [`Mmap`] where both the start address and length are a
11
+ /// multiple of the host page size.
12
+ ///
13
+ /// For more information, see the documentation on [`Mmap`].
14
+ #[ derive( Clone , Debug ) ]
15
+ pub struct AlignedLength { }
16
+
17
+ /// A type of [`Mmap`] where the start address is host page-aligned, but the
18
+ /// length is possibly not a multiple of the host page size.
19
+ ///
20
+ /// For more information, see the documentation on [`Mmap`].
21
+ #[ derive( Clone , Debug ) ]
22
+ pub struct UnalignedLength {
15
23
#[ cfg( feature = "std" ) ]
16
24
file : Option < Arc < File > > ,
17
25
}
18
26
19
- impl Mmap {
27
+ /// A platform-independent abstraction over memory-mapped data.
28
+ ///
29
+ /// The type parameter can be one of:
30
+ ///
31
+ /// * [`AlignedLength`]: Both the start address and length are page-aligned
32
+ /// (i.e. a multiple of the host page size). This is always the result of an
33
+ /// mmap backed by anonymous memory.
34
+ ///
35
+ /// * [`UnalignedLength`]: The start address is host page-aligned, but the
36
+ /// length is not necessarily page-aligned. This is usually backed by a file,
37
+ /// but can also be backed by anonymous memory.
38
+ ///
39
+ /// ## Notes
40
+ ///
41
+ /// If the length of a file is not a multiple of the host page size, [POSIX does
42
+ /// not specify any semantics][posix-mmap] for the rest of the last page. Linux
43
+ /// [does say][linux-mmap] that the rest of the page is reserved and zeroed out,
44
+ /// but for portability it's best to not assume anything about the rest of
45
+ /// memory. `UnalignedLength` achieves a type-level distinction between an mmap
46
+ /// that is backed purely by memory, and one that is possibly backed by a file.
47
+ ///
48
+ /// Currently, the OS-specific `mmap` implementations in this crate do not make
49
+ /// this this distinction -- alignment is managed at this platform-independent
50
+ /// layer. It might make sense to add this distinction to the OS-specific
51
+ /// implementations in the future.
52
+ ///
53
+ /// [posix-mmap]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html
54
+ /// [linux-mmap]: https://man7.org/linux/man-pages/man2/mmap.2.html#NOTES
55
+ #[ derive( Debug ) ]
56
+ pub struct Mmap < T > {
57
+ sys : mmap:: Mmap ,
58
+ data : T ,
59
+ }
60
+
61
+ impl Mmap < AlignedLength > {
20
62
/// Create a new `Mmap` pointing to at least `size` bytes of page-aligned
21
63
/// accessible memory.
22
64
pub fn with_at_least ( size : usize ) -> Result < Self > {
23
65
let rounded_size = crate :: runtime:: vm:: round_usize_up_to_host_pages ( size) ?;
24
66
Self :: accessible_reserved ( rounded_size, rounded_size)
25
67
}
26
68
27
- /// Creates a new `Mmap` by opening the file located at `path` and mapping
28
- /// it into memory.
29
- ///
30
- /// The memory is mapped in read-only mode for the entire file. If portions
31
- /// of the file need to be modified then the `region` crate can be use to
32
- /// alter permissions of each page.
33
- ///
34
- /// The memory mapping and the length of the file within the mapping are
35
- /// returned.
36
- #[ cfg( feature = "std" ) ]
37
- pub fn from_file ( file : Arc < File > ) -> Result < Self > {
38
- let sys = mmap:: Mmap :: from_file ( & file) ?;
39
- Ok ( Mmap {
40
- sys,
41
- file : Some ( file) ,
42
- } )
43
- }
44
-
45
69
/// Create a new `Mmap` pointing to `accessible_size` bytes of page-aligned
46
70
/// accessible memory, within a reserved mapping of `mapping_size` bytes.
47
71
/// `accessible_size` and `mapping_size` must be native page-size multiples.
@@ -58,22 +82,19 @@ impl Mmap {
58
82
if mapping_size == 0 {
59
83
Ok ( Mmap {
60
84
sys : mmap:: Mmap :: new_empty ( ) ,
61
- #[ cfg( feature = "std" ) ]
62
- file : None ,
85
+ data : AlignedLength { } ,
63
86
} )
64
87
} else if accessible_size == mapping_size {
65
88
Ok ( Mmap {
66
89
sys : mmap:: Mmap :: new ( mapping_size)
67
90
. context ( format ! ( "mmap failed to allocate {mapping_size:#x} bytes" ) ) ?,
68
- #[ cfg( feature = "std" ) ]
69
- file : None ,
91
+ data : AlignedLength { } ,
70
92
} )
71
93
} else {
72
94
let mut result = Mmap {
73
95
sys : mmap:: Mmap :: reserve ( mapping_size)
74
96
. context ( format ! ( "mmap failed to reserve {mapping_size:#x} bytes" ) ) ?,
75
- #[ cfg( feature = "std" ) ]
76
- file : None ,
97
+ data : AlignedLength { } ,
77
98
} ;
78
99
if accessible_size > 0 {
79
100
result. make_accessible ( 0 , accessible_size) . context ( format ! (
@@ -84,6 +105,20 @@ impl Mmap {
84
105
}
85
106
}
86
107
108
+ /// Converts this `Mmap` into a `Mmap<UnalignedLength>`.
109
+ ///
110
+ /// `UnalignedLength` really means "_possibly_ unaligned length", so it can
111
+ /// be freely converted over at the cost of losing the alignment guarantee.
112
+ pub fn into_unaligned ( self ) -> Mmap < UnalignedLength > {
113
+ Mmap {
114
+ sys : self . sys ,
115
+ data : UnalignedLength {
116
+ #[ cfg( feature = "std" ) ]
117
+ file : None ,
118
+ } ,
119
+ }
120
+ }
121
+
87
122
/// Make the memory starting at `start` and extending for `len` bytes
88
123
/// accessible. `start` and `len` must be native page-size multiples and
89
124
/// describe a range within `self`'s reserved memory.
@@ -101,7 +136,34 @@ impl Mmap {
101
136
102
137
self . sys . make_accessible ( start, len)
103
138
}
139
+ }
104
140
141
+ #[ cfg( feature = "std" ) ]
142
+ impl Mmap < UnalignedLength > {
143
+ /// Creates a new `Mmap` by opening the file located at `path` and mapping
144
+ /// it into memory.
145
+ ///
146
+ /// The memory is mapped in read-only mode for the entire file. If portions
147
+ /// of the file need to be modified then the `region` crate can be use to
148
+ /// alter permissions of each page.
149
+ ///
150
+ /// The memory mapping and the length of the file within the mapping are
151
+ /// returned.
152
+ pub fn from_file ( file : Arc < File > ) -> Result < Self > {
153
+ let sys = mmap:: Mmap :: from_file ( & file) ?;
154
+ Ok ( Mmap {
155
+ sys,
156
+ data : UnalignedLength { file : Some ( file) } ,
157
+ } )
158
+ }
159
+
160
+ /// Returns the underlying file that this mmap is mapping, if present.
161
+ pub fn original_file ( & self ) -> Option < & Arc < File > > {
162
+ self . data . file . as_ref ( )
163
+ }
164
+ }
165
+
166
+ impl < T > Mmap < T > {
105
167
/// Return the allocated memory as a slice of u8.
106
168
///
107
169
/// # Safety
@@ -198,15 +260,16 @@ impl Mmap {
198
260
. make_readonly ( range)
199
261
. context ( "failed to make memory readonly" )
200
262
}
201
-
202
- /// Returns the underlying file that this mmap is mapping, if present.
203
- #[ cfg( feature = "std" ) ]
204
- pub fn original_file ( & self ) -> Option < & Arc < File > > {
205
- self . file . as_ref ( )
206
- }
207
263
}
208
264
209
265
fn _assert ( ) {
210
266
fn _assert_send_sync < T : Send + Sync > ( ) { }
211
- _assert_send_sync :: < Mmap > ( ) ;
267
+ _assert_send_sync :: < Mmap < AlignedLength > > ( ) ;
268
+ _assert_send_sync :: < Mmap < UnalignedLength > > ( ) ;
269
+ }
270
+
271
+ impl From < Mmap < AlignedLength > > for Mmap < UnalignedLength > {
272
+ fn from ( mmap : Mmap < AlignedLength > ) -> Mmap < UnalignedLength > {
273
+ mmap. into_unaligned ( )
274
+ }
212
275
}
0 commit comments