1
2#[macro_use] extern crate lazy_static;
3
4use libc::{
5 mmap,
6 MAP_FAILED,
7};
8
9use std::{
10 os::unix::prelude::*,
11 ops,
12 mem,
13 ptr::{
14 self,
15 NonNull,
16 },
17 io,
18 fmt, error,
19
20 borrow::{
21 Borrow, BorrowMut,
22 }
23};
24
25mod ffi;
26use ffi::c_try;
27
28
29pub mod hugetlb;
30pub mod file;
32
33pub mod ring; use ring::buffer;
35
36mod ext; use ext::*;
37
38use hugetlb::{
39 HugePage,
40 MapHugeFlag,
41};
42
43mod uniq;
44use uniq::UniqueSlice;
45
46mod flags;
47pub use flags::*;
48
49pub mod err;
50use err::{
51 os_error,
52 opaque,
53};
54
55
56#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
57#[repr(transparent)]
58struct MappedSlice(UniqueSlice<u8>);
59
60unsafe impl Send for MappedSlice{}
61unsafe impl Sync for MappedSlice{}
62
63impl ops::Drop for MappedSlice
64{
65 #[inline]
66 fn drop(&mut self)
67 {
68 unsafe {
69 libc::munmap(self.0.as_mut_ptr() as *mut _, self.0.len());
70 }
71 }
72}
73
74#[derive(Debug, PartialEq, Eq, Hash)]
76pub struct MappedFile<T>
77{
78 file: T,
79 map: MappedSlice,
80}
81#[inline(never)]
82#[cold]
83fn _panic_invalid_address() -> !
84{
85 panic!("Invalid/unsupported address returned from mmap()")
86}
87
88pub fn get_page_size() -> usize
90{
91 use libc::c_int;
92 extern "C" {
93 fn getpagesize() -> c_int;
94 }
95 lazy_static! {
96 static ref PAGESZ: c_int = unsafe {
97 getpagesize()
98 };
99 }
100 let v: c_int = *PAGESZ;
101 v as usize
102}
103
104impl<T> MappedFile<T> {
105 #[inline]
107 pub fn inner(&self) -> &T
108 {
109 &self.file
110 }
111 #[inline]
116 pub fn inner_mut(&mut self) -> &mut T
117 {
118 &mut self.file
119 }
120
121 #[inline]
127 pub fn into_inner(self) -> T
128 {
129 drop(self.map);
130 self.file
131 }
132}
133
134impl<T: AsRawFd> MappedFile<T> {
135 pub fn try_new(file: T, len: usize, perm: Perm, flags: impl flags::MapFlags) -> Result<Self, TryNewError<T>>
146 {
147
148 const NULL: *mut libc::c_void = ptr::null_mut();
149 let fd = file.as_raw_fd();
150 let slice = match unsafe {
151 mmap(ptr::null_mut(), len, perm.get_prot(), flags.get_mmap_flags(), fd, 0)
152 } {
153 MAP_FAILED => return Err(TryNewError::wrap_last_error(file)),
154 NULL => _panic_invalid_address(),
155 ptr => unsafe {
156 UniqueSlice {
157 mem: NonNull::new_unchecked(ptr as *mut u8),
158 end: match NonNull::new((ptr as *mut u8).add(len)) {
159 Some(n) => n,
160 _ => _panic_invalid_address(),
161 },
162 }
163 },
164 };
165 Ok(Self {
166 file,
167 map: MappedSlice(slice)
168 })
169 }
170
171
172
173 pub fn shared<B: buffer::TwoBufferProvider<T>>(file: T, len: usize, flags: impl flags::MapFlags) -> (MappedFile<B>, MappedFile<B>)
191 {
192 #[cold]
193 #[inline(never)]
194 fn _panic_failed_with(error: Box<io::Error>) -> !
195 {
196 Err(error).expect("Failed to create shared mapping")
197 }
198 Self::try_shared(file, len, flags).unwrap_or_else(|e| {
199 _panic_failed_with(e.error)
200 })
201 }
202 pub fn try_shared<B: buffer::TwoBufferProvider<T>>(file: T, len: usize, flags: impl flags::MapFlags) -> Result<(MappedFile<B>, MappedFile<B>), TryNewError<T>>
217 {
218 Self::try_new_buffer_raw::<B>(file, len, None, false, flags)
219 }
220 #[inline]
222 pub(crate) fn try_new_buffer_raw<B: buffer::TwoBufferProvider<T>>(file: T, len: usize, rings: impl Into<Option<std::num::NonZeroUsize>>, allow_unsafe_writes: bool, flags: impl flags::MapFlags) -> Result<(MappedFile<B>, MappedFile<B>), TryNewError<T>>
223 {
224 const NULL: *mut libc::c_void = ptr::null_mut();
225
226 macro_rules! try_map_or {
227 ($($tt:tt)*) => {
228 match unsafe {
229 mmap($($tt)*)
230 } {
231 MAP_FAILED => Err(io::Error::last_os_error()),
232 NULL => _panic_invalid_address(),
233 ptr => Ok(unsafe {
234
235 UniqueSlice {
236 mem: NonNull::new_unchecked(ptr as *mut u8),
237 end: match NonNull::new((ptr as *mut u8).add(len)) {
238 Some(n) => n,
239 _ => _panic_invalid_address(),
240 }
241 }
242 })
243 }.map(MappedSlice)
244 };
245 }
246 macro_rules! try_map {
247 ($($tt:tt)*) => {
248 MappedSlice(match unsafe {
249 mmap($($tt)*)
250 } {
251 MAP_FAILED => return Err(TryNewError::wrap_last_error(file)),
252 NULL => _panic_invalid_address(),
253 ptr => unsafe {
254
255 UniqueSlice {
256 mem: NonNull::new_unchecked(ptr as *mut u8),
257 end: match NonNull::new((ptr as *mut u8).add(len)) {
258 Some(n) => n,
259 _ => _panic_invalid_address(),
260 }
261 }
262 }
263 })
264 };
265 }
266
267 macro_rules! unwrap {
268 ($err:expr) => {
269 match $err {
270 Ok(v) => v,
271 Err(e) => return Err(TryNewError::wrap((e, file))),
272 }
273 };
274 }
275
276 let (prot_w, prot_r) = if allow_unsafe_writes {
277 let p = Perm::ReadWrite.get_prot();
278 (p, p)
279 } else {
280 (Perm::Writeonly.get_prot(), Perm::Readonly.get_prot())
281 };
282 let (tx, rx) = match rings.into() {
285 None => {
286 let flags = flags.get_mmap_flags();
288 let mut root = try_map!(NULL, len * 2, libc::PROT_NONE, (flags & !libc::MAP_SHARED) | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, -1, 0);
289 let rawfd = file.as_raw_fd();
290
291 let rm = try_map!(root.0.as_mut_ptr().add(len) as *mut _, len, prot_r, flags | libc::MAP_FIXED, rawfd, 0); let tm = try_map!(root.0.as_mut_ptr() as *mut _, len, prot_w, flags | libc::MAP_FIXED, rawfd, 0); let tf = B::from_value(file);
295 let rf = B::from_wrapper(tf.as_wrapper());
296 (MappedFile {
297 file: tf,
298 map: tm
299 }, MappedFile {
300 file: rf,
301 map: rm,
302 })
303 },
304 Some(pages) => {
305 let full_len = unwrap!((len * 2)
307 .checked_mul(pages.get())
308 .ok_or_else(|| io::Error::new(io::ErrorKind::OutOfMemory,
309 format!("Could not map {} pages of size {len}. Value would overflow", pages.get()))));
310 let flags = flags.get_mmap_flags();
311 let mut root = try_map!(NULL, full_len, libc::PROT_NONE, libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, -1, 0);
312 let pivots = {
313 let rawfd = file.as_raw_fd();
314 let pivots: io::Result<Vec<_>> = std::iter::successors(unsafe { Some(root.0.as_mut_ptr().add(full_len - (len * 2))) }, |&x| unsafe { Some(x.sub(len * 2)) }) .take(pages.get())
316 .map(|base| {
317 let rm = try_map_or!(base.add(len) as *mut _, len, prot_r, flags | libc::MAP_FIXED,rawfd, 0 )?;
318 let tm = try_map_or!(base as *mut _, len, prot_w, flags | libc::MAP_FIXED, rawfd, 0)?;
319
320 Ok((tm, rm))
321 })
322 .collect();
323 unwrap!(pivots)
324 };
325
326 todo!("We can't carry `pivots` over to return from this function; the data is needed for unmapping the ring...");
327 todo!("The mapping we'd be using is `root`. But we need to unmap `pivots` in reverse order when the returned `MappedFile` is dropped...")
328 }
329 };
330 Ok((tx, rx))
331 }
332 #[inline]
343 pub fn new(file: T, len: usize, perm: Perm, flags: impl MapFlags) -> io::Result<Self>
344 {
345 Self::try_new(file, len, perm, flags).map_err(Into::into)
346 }
347
348 pub fn flush(&mut self, flush: Flush) -> io::Result<()>
355 {
356 use libc::msync;
357 match unsafe {
358 msync(self.map.0.as_mut_ptr() as *mut _, self.map.0.len(), flush.get_ms())
359 } {
360 0 => Ok(()),
361 _ => Err(io::Error::last_os_error())
362 }
363 }
364
365 pub fn replace_inner<U: AsRawFd>(self, other: U) -> MappedFile<U>
374 {
375 assert_eq!(self.file.as_raw_fd(), other.as_raw_fd(), "File descriptors must alias");
376 unsafe {
377 let (this, file) = self.replace_inner_unchecked(other);
378 mem::forget(file);
379 this
380 }
381 }
382
383 #[inline]
389 pub fn into_inner_synced(mut self, flush: Flush) -> T
390 {
391 self.flush(flush).expect("Failed to sync data");
392 drop(self.map);
393 self.file
394 }
395}
396
397impl<T> MappedFile<T> {
398 #[inline(always)]
399 fn raw_parts(&self) -> (*mut u8, usize)
400 {
401 (self.map.0.mem.as_ptr(), self.map.0.len())
402 }
403
404 pub fn advise(&mut self, adv: Advice, needed: Option<bool>) -> io::Result<()>
406 {
407 use libc::{
408 madvise,
409 MADV_WILLNEED,
410 MADV_DONTNEED
411 };
412 let (addr, len) = self.raw_parts();
413 match unsafe { madvise(addr as *mut _, len, adv.get_madv() | needed.map(|n| n.then(|| MADV_WILLNEED).unwrap_or(MADV_DONTNEED)).unwrap_or(0)) } {
414 0 => Ok(()),
415 _ => Err(io::Error::last_os_error())
416 }
417 }
418
419 #[inline(always)]
424 pub fn try_with_advice(mut self, adv: Advice, needed: Option<bool>) -> Result<Self, TryNewError<Self>>
425 {
426 match self.advise(adv, needed) {
427 Ok(_) => Ok(self),
428 Err(error) => Err(TryNewError {
429 error: Box::new(error),
430 value: self,
431 })
432 }
433 }
434
435 #[inline]
440 pub fn with_advice(self, adv: Advice, needed: Option<bool>) -> io::Result<Self>
441 {
442 self.try_with_advice(adv, needed).map_err(Into::into)
443 }
444
445 #[inline(always)]
453 pub unsafe fn replace_inner_unchecked<U>(self, other: U) -> (MappedFile<U>, T)
454 {
455 let MappedFile{ file, map } = self;
456 (MappedFile {
457 file: other,
458 map
459 }, file)
460 }
461
462 #[inline]
464 pub fn len(&self) -> usize
465 {
466 self.map.0.len()
467 }
468
469 #[inline]
471 pub fn as_slice(&self) -> &[u8]
472 {
473 &self.map.0[..]
474 }
475
476 #[inline]
478 pub fn as_slice_mut(&mut self) -> &mut [u8]
479 {
480 &mut self.map.0[..]
481 }
482
483 #[inline]
485 pub fn as_raw_slice(&self) -> *const [u8]
486 {
487 self.map.0.as_raw_slice()
488 }
489
490 #[inline]
492 pub fn as_raw_slice_mut(&mut self) -> *mut [u8]
493 {
494 self.map.0.as_raw_slice_mut()
495 }
496
497 #[inline]
499 pub fn is_empty(&self) -> bool
500 {
501 self.map.0.is_empty()
502 }
503}
504
505pub struct TryNewError<T: ?Sized>
509{
510 error: Box<io::Error>,
511 value: T
512}
513
514impl<T:?Sized> error::Error for TryNewError<T>
515{
516 #[inline]
517 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
518 Some(self.error.as_ref())
519 }
520}
521
522impl<T:?Sized> fmt::Display for TryNewError<T>
523{
524 #[inline]
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
526 {
527 write!(f, "error in mapping of type {}", std::any::type_name::<T>())
528 }
529}
530
531impl<T:?Sized> fmt::Debug for TryNewError<T>
532{
533 #[inline]
534 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
535 {
536 f.debug_struct("TryNewError")
537 .field("error", &self.error)
538 .finish_non_exhaustive()
539 }
540}
541
542impl<T: ?Sized> TryNewError<T>
543{
544 #[inline]
546 pub fn value(&self) -> &T
547 {
548 &self.value
549 }
550 #[inline]
552 pub fn value_mut(&mut self) -> &mut T
553 {
554 &mut self.value
555 }
556 #[inline]
558 pub fn error(&self) -> &io::Error
559 {
560 &self.error
561 }
562 #[inline]
564 pub fn into_error_box(self: Box<Self>) -> Box<io::Error>
565 {
566 self.error
567 }
568}
569
570impl<T> TryNewError<T>
571{
572 #[inline]
573 fn wrap_last_error(value: T) -> Self
574 {
575 Self {
576 error: Box::new(io::Error::last_os_error()),
577 value,
578 }
579 }
580
581 #[inline]
582 fn wrap((error, value): (impl Into<io::Error>, T)) -> Self
583 {
584 Self {
585 error: Box::new(error.into()),
586 value
587 }
588 }
589 #[inline]
591 pub fn into_inner(self) -> T
592 {
593 self.value
594 }
595
596 #[inline]
598 pub fn into_error(self) -> io::Error
599 {
600 *self.error
601 }
602 #[inline]
604 pub fn into_parts(self) -> (T, io::Error)
605 {
606 (self.value, *self.error)
607 }
608}
609
610impl<T: ?Sized> From<Box<TryNewError<T>>> for io::Error
611{
612 #[inline]
613 fn from(from: Box<TryNewError<T>>) -> Self
614 {
615 *from.error
616 }
617}
618
619impl<T> From<TryNewError<T>> for io::Error
620{
621 #[inline]
622 fn from(from: TryNewError<T>) -> Self
623 {
624 from.into_error()
625 }
626}
627
628impl<T: AsRawFd> Borrow<T> for MappedFile<T>
629{
630 #[inline]
631 fn borrow(&self) -> &T
632 {
633 &self.file
634 }
635}
636
637impl<T> Borrow<[u8]> for MappedFile<T>
638{
639 #[inline]
640 fn borrow(&self) -> &[u8]
641 {
642 self.as_slice()
643 }
644}
645
646impl<T> BorrowMut<[u8]> for MappedFile<T>
647{
648 #[inline]
649 fn borrow_mut(&mut self) -> &mut [u8]
650 {
651 self.as_slice_mut()
652 }
653}
654
655impl<T> AsRef<[u8]> for MappedFile<T>
656{
657 #[inline]
658 fn as_ref(&self) -> &[u8]
659 {
660 self.as_slice()
661 }
662}
663
664impl<T> AsMut<[u8]> for MappedFile<T>
665{
666 #[inline]
667 fn as_mut(&mut self) -> &mut [u8]
668 {
669 self.as_slice_mut()
670 }
671}
672
673impl<T> ops::Deref for MappedFile<T>
674{
675 type Target= [u8];
676 #[inline]
677 fn deref(&self) -> &Self::Target
678 {
679 self.as_slice()
680 }
681}
682impl<T> ops::DerefMut for MappedFile<T>
683{
684 #[inline]
685 fn deref_mut(&mut self) -> &mut Self::Target
686 {
687 self.as_slice_mut()
688 }
689}
690
691#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
696pub struct Anonymous;
697
698impl AsRawFd for Anonymous
699{
700 #[inline(always)]
701 fn as_raw_fd(&self) -> RawFd {
702 -1
703 }
704}
705
706