@@ -12,13 +12,46 @@ mod mmap {
1212 FromArgs , PyObject , PyPayload , PyRef , PyResult , TryFromBorrowedObject , VirtualMachine ,
1313 } ;
1414 use crossbeam_utils:: atomic:: AtomicCell ;
15- use memmap2:: { Mmap , MmapMut , MmapOptions } ;
15+ use memmap2:: { Advice , Mmap , MmapMut , MmapOptions } ;
1616 use nix:: unistd;
1717 use std:: fs:: File ;
1818 use std:: ops:: Deref ;
1919 #[ cfg( all( unix, not( target_os = "redox" ) ) ) ]
2020 use std:: os:: unix:: io:: { FromRawFd , IntoRawFd , RawFd } ;
2121
22+ fn advice_try_from_i32 ( vm : & VirtualMachine , i : i32 ) -> PyResult < Advice > {
23+ Ok ( match i {
24+ libc:: MADV_NORMAL => Advice :: Normal ,
25+ libc:: MADV_RANDOM => Advice :: Random ,
26+ libc:: MADV_SEQUENTIAL => Advice :: Sequential ,
27+ libc:: MADV_WILLNEED => Advice :: WillNeed ,
28+ libc:: MADV_DONTNEED => Advice :: DontNeed ,
29+ #[ cfg( any( target_os = "linux" , target_os = "macos" , target_os = "ios" ) ) ]
30+ libc:: MADV_FREE => Advice :: Free ,
31+ #[ cfg( target_os = "linux" ) ]
32+ libc:: MADV_DONTFORK => Advice :: DontFork ,
33+ #[ cfg( target_os = "linux" ) ]
34+ libc:: MADV_DOFORK => Advice :: DoFork ,
35+ #[ cfg( target_os = "linux" ) ]
36+ libc:: MADV_MERGEABLE => Advice :: Mergeable ,
37+ #[ cfg( target_os = "linux" ) ]
38+ libc:: MADV_UNMERGEABLE => Advice :: Unmergeable ,
39+ #[ cfg( target_os = "linux" ) ]
40+ libc:: MADV_HUGEPAGE => Advice :: HugePage ,
41+ #[ cfg( target_os = "linux" ) ]
42+ libc:: MADV_NOHUGEPAGE => Advice :: NoHugePage ,
43+ #[ cfg( target_os = "linux" ) ]
44+ libc:: MADV_REMOVE => Advice :: Remove ,
45+ #[ cfg( target_os = "linux" ) ]
46+ libc:: MADV_DONTDUMP => Advice :: DontDump ,
47+ #[ cfg( target_os = "linux" ) ]
48+ libc:: MADV_DODUMP => Advice :: DoDump ,
49+ #[ cfg( target_os = "linux" ) ]
50+ libc:: MADV_HWPOISON => Advice :: HwPoison ,
51+ _ => return Err ( vm. new_value_error ( "Not a valid Advice value" . to_owned ( ) ) ) ,
52+ } )
53+ }
54+
2255 #[ repr( C ) ]
2356 #[ derive( PartialEq , Eq , Debug ) ]
2457 enum AccessMode {
@@ -51,12 +84,24 @@ mod mmap {
5184 #[ pyattr]
5285 use libc:: { MADV_FREE_REUSABLE , MADV_FREE_REUSE } ;
5386
87+ #[ cfg( any(
88+ target_os = "android" ,
89+ target_os = "dragonfly" ,
90+ target_os = "fuchsia" ,
91+ target_os = "freebsd" ,
92+ target_os = "linux" ,
93+ target_os = "netbsd" ,
94+ target_os = "openbsd" ,
95+ target_vendor = "apple"
96+ ) ) ]
97+ #[ pyattr]
98+ use libc:: MADV_FREE ;
99+
54100 #[ cfg( target_os = "linux" ) ]
55101 #[ pyattr]
56102 use libc:: {
57- MADV_DODUMP , MADV_DOFORK , MADV_DONTDUMP , MADV_DONTFORK , MADV_FREE , MADV_HUGEPAGE ,
58- MADV_HWPOISON , MADV_MERGEABLE , MADV_NOHUGEPAGE , MADV_REMOVE , MADV_SOFT_OFFLINE ,
59- MADV_UNMERGEABLE ,
103+ MADV_DODUMP , MADV_DOFORK , MADV_DONTDUMP , MADV_DONTFORK , MADV_HUGEPAGE , MADV_HWPOISON ,
104+ MADV_MERGEABLE , MADV_NOHUGEPAGE , MADV_REMOVE , MADV_SOFT_OFFLINE , MADV_UNMERGEABLE ,
60105 } ;
61106
62107 #[ cfg( all( target_os = "linux" , target_arch = "x86_64" , target_env = "gnu" ) ) ]
@@ -437,6 +482,39 @@ mod mmap {
437482 Ok ( ( ) )
438483 }
439484
485+ #[ allow( unused_assignments) ]
486+ #[ pymethod]
487+ fn madvise ( & self , options : AdviseOptions , vm : & VirtualMachine ) -> PyResult < ( ) > {
488+ let start = options. start . unwrap_or ( 0 ) ;
489+ let mut length = options. length . unwrap_or_else ( || self . inner_size ( ) ) ;
490+
491+ if start < 0 || start >= self . inner_size ( ) {
492+ return Err ( vm. new_value_error ( "madvise start out of bounds" . to_owned ( ) ) ) ;
493+ }
494+ if length < 0 {
495+ return Err ( vm. new_value_error ( "madvise length invalid" . to_owned ( ) ) ) ;
496+ }
497+
498+ if isize:: MAX - start < length {
499+ return Err ( vm. new_overflow_error ( "madvise length too large" . to_owned ( ) ) ) ;
500+ }
501+
502+ if start + length > self . inner_size ( ) {
503+ length = self . inner_size ( ) - start;
504+ }
505+
506+ let advice = advice_try_from_i32 ( vm, options. option ) ?;
507+
508+ //TODO: memmap2 doesn't support madvise range right now.
509+ match self . check_valid ( vm) ?. deref ( ) . as_ref ( ) . unwrap ( ) {
510+ MmapObj :: Read ( mmap) => mmap. advise ( advice) ,
511+ MmapObj :: Write ( mmap) => mmap. advise ( advice) ,
512+ }
513+ . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
514+
515+ Ok ( ( ) )
516+ }
517+
440518 #[ pymethod]
441519 fn size ( & self , vm : & VirtualMachine ) -> PyResult < PyIntRef > {
442520 let new_fd = unistd:: dup ( self . fd ) . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
0 commit comments