fn map_unaccessed_pages(
    tracker: &SigsegvMemoryTracker,
    page_map: &PageMap,
    page_protection_flags: ProtFlags,
    faulting_page: PageIndex,
    min_prefetch_range: Range<PageIndex>,
    max_prefetch_range: Range<PageIndex>,
) -> Range<PageIndex> {
    assert!(min_prefetch_range.contains(&faulting_page));
    assert!(max_prefetch_range.contains(&faulting_page));

    let memory_region = page_map.get_memory_region(faulting_page);
    match memory_region {
        MemoryRegion::Zeros(page_map_range) | MemoryRegion::BackedByFile(page_map_range, _) => {
            assert!(page_map_range.contains(&faulting_page));
            let mprotect_range = range_intersection(&max_prefetch_range, &page_map_range);
            let start_addr = tracker.page_start_addr_from(mprotect_range.start);
            unsafe {
                mprotect(
                    start_addr,
                    range_size_in_bytes(&mprotect_range),
                    page_protection_flags,
                )
                .unwrap()
            };
            mprotect_range
        }

        MemoryRegion::BackedByPage(contents) => {
            let prefetch_range = range_intersection(
                &range_from_count(faulting_page, MAX_PAGES_TO_COPY),
                &min_prefetch_range,
            );

            // Get the largest contiguous memory region backed by pages.
            let mut pages: [Option<&PageBytes>; MAX_PAGES_TO_COPY] = [None; MAX_PAGES_TO_COPY];
            pages[0] = Some(contents);
            let mut count = 1;
            while count < range_count(&prefetch_range) {
                match page_map.get_memory_region(PageIndex::new(faulting_page.get() + count as u64))
                {
                    MemoryRegion::Zeros(_) | MemoryRegion::BackedByFile(_, _) => {
                        break;
                    }
                    MemoryRegion::BackedByPage(contents) => {
                        pages[count] = Some(contents);
                    }
                }
                count += 1;
            }

            let mprotect_range = range_from_count(faulting_page, count);
            let page_start_addr = tracker.page_start_addr_from(mprotect_range.start);

            // Make the page writable because we are going to copy bytes.
            unsafe {
                mprotect(
                    page_start_addr,
                    range_size_in_bytes(&mprotect_range),
                    ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
                )
                .unwrap()
            };

            // Copy the contents of the pages.
            for (index, page) in pages.iter().enumerate() {
                if let Some(contents) = *page {
                    assert!(index < count);
                    unsafe {
                        std::ptr::copy_nonoverlapping(
                            contents.as_ptr(),
                            (page_start_addr as *mut u8).add(index * PAGE_SIZE),
                            PAGE_SIZE,
                        )
                    };
                }
            }

            if !page_protection_flags.contains(ProtFlags::PROT_WRITE) {
                // Make the page read-only to intercept the future write accesses.
                // TODO(EXC-447): This `mprotect` call is the main performance bottleneck
                // for messages that need to track dirty pages. It causes expensive TLB flushes
                // because it reduces the protection flags from Read/Write to Read.
                // There are two ways to eliminate this call:
                // 1) Implement an mmap allocator for `PageDelta` pages so that we can mmap it.
                // 2) Track all accessed pages and after execution filter dirty pages by
                //    comparing the page contents.
                unsafe {
                    mprotect(
                        page_start_addr,
                        range_size_in_bytes(&mprotect_range),
                        ProtFlags::PROT_READ,
                    )
                    .unwrap()
                };
            }
            mprotect_range
        }
    }
}
// Sets up page mapping for the given `faulting_page` and its subsequent pages
// using the backing memory from the given `page_map`. The range of mapped pages
// depends on the type of the backing memory. If it is cheap to map then the
// largest range specified by `max_prefetch_range` is used. If it involves
// copying then the smallest range specified by `min_prefetch_range` is used.
// The function is allowed to map less pages than specified by the ranges.
Sets up page mapping for the given `faulting_page` and its subsequent pages
using the backing memory from the given `page_map`. The range of mapped pages
depends on the type of the backing memory. If it is cheap to map then the
largest range specified by `max_prefetch_range` is used. If it involves
copying then the smallest range specified by `min_prefetch_range` is used.
The function is allowed to map less pages than specified by the ranges.
Sets up page mapping for the given ` faulting_page ` and its subsequent pages using the backing memory from the given ` page_map ` . The range of mapped pages depends on the type of the backing memory . If it is cheap to map then the largest range specified by ` max_prefetch_range ` is used . If it involves copying then the smallest range specified by ` min_prefetch_range ` is used . The function is allowed to map less pages than specified by the ranges .
fn map_unaccessed_pages(
    tracker: &SigsegvMemoryTracker,
    page_map: &PageMap,
    page_protection_flags: ProtFlags,
    faulting_page: PageIndex,
    min_prefetch_range: Range<PageIndex>,
    max_prefetch_range: Range<PageIndex>,
) -> Range<PageIndex> {
    assert!(min_prefetch_range.contains(&faulting_page));
    assert!(max_prefetch_range.contains(&faulting_page));
    let memory_region = page_map.get_memory_region(faulting_page);
    match memory_region {
        MemoryRegion::Zeros(page_map_range) | MemoryRegion::BackedByFile(page_map_range, _) => {
            assert!(page_map_range.contains(&faulting_page));
            let mprotect_range = range_intersection(&max_prefetch_range, &page_map_range);
            let start_addr = tracker.page_start_addr_from(mprotect_range.start);
            unsafe {
                mprotect(
                    start_addr,
                    range_size_in_bytes(&mprotect_range),
                    page_protection_flags,
                )
                .unwrap()
            };
            mprotect_range
        }
        MemoryRegion::BackedByPage(contents) => {
            let prefetch_range = range_intersection(
                &range_from_count(faulting_page, MAX_PAGES_TO_COPY),
                &min_prefetch_range,
            );
            // Get the largest contiguous memory region backed by pages.
            let mut pages: [Option<&PageBytes>; MAX_PAGES_TO_COPY] = [None; MAX_PAGES_TO_COPY];
            pages[0] = Some(contents);
            let mut count = 1;
            while count < range_count(&prefetch_range) {
                match page_map.get_memory_region(PageIndex::new(faulting_page.get() + count as u64))
                {
                    MemoryRegion::Zeros(_) | MemoryRegion::BackedByFile(_, _) => {
                        break;
                    }
                    MemoryRegion::BackedByPage(contents) => {
                        pages[count] = Some(contents);
                    }
                }
                count += 1;
            }
            let mprotect_range = range_from_count(faulting_page, count);
            let page_start_addr = tracker.page_start_addr_from(mprotect_range.start);
            // Make the page writable because we are going to copy bytes.
            unsafe {
                mprotect(
                    page_start_addr,
                    range_size_in_bytes(&mprotect_range),
                    ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
                )
                .unwrap()
            };
            // Copy the contents of the pages.
            for (index, page) in pages.iter().enumerate() {
                if let Some(contents) = *page {
                    assert!(index < count);
                    unsafe {
                        std::ptr::copy_nonoverlapping(
                            contents.as_ptr(),
                            (page_start_addr as *mut u8).add(index * PAGE_SIZE),
                            PAGE_SIZE,
                        )
                    };
                }
            }
            if !page_protection_flags.contains(ProtFlags::PROT_WRITE) {
                // Make the page read-only to intercept the future write accesses.
                // TODO(EXC-447): This `mprotect` call is the main performance bottleneck
                // for messages that need to track dirty pages. It causes expensive TLB flushes
                // because it reduces the protection flags from Read/Write to Read.
                // There are two ways to eliminate this call:
                // 1) Implement an mmap allocator for `PageDelta` pages so that we can mmap it.
                // 2) Track all accessed pages and after execution filter dirty pages by
                //    comparing the page contents.
                unsafe {
                    mprotect(
                        page_start_addr,
                        range_size_in_bytes(&mprotect_range),
                        ProtFlags::PROT_READ,
                    )
                    .unwrap()
                };
            }
            mprotect_range
        }
    }
}
fn map_unaccessed_pages ( tracker : & SigsegvMemoryTracker , page_map : & PageMap , page_protection_flags : ProtFlags , faulting_page : PageIndex , min_prefetch_range : Range < PageIndex > , max_prefetch_range : Range < PageIndex > , ) -> Range < PageIndex > { assert ! ( min_prefetch_range contains ( faulting_page ) ) ; assert ! ( max_prefetch_range contains ( faulting_page ) ) ; let memory_region = page_map . get_memory_region ( faulting_page ) ; match memory_region { MemoryRegion :: Zeros ( page_map_range ) | MemoryRegion :: BackedByFile ( page_map_range , _ ) => { assert ! ( page_map_range contains ( faulting_page ) ) ; let mprotect_range = range_intersection ( & max_prefetch_range , & page_map_range ) ; let start_addr = tracker . page_start_addr_from ( mprotect_range . start ) ; unsafe { mprotect ( start_addr , range_size_in_bytes ( & mprotect_range ) , page_protection_flags , ) . unwrap ( ) } ; mprotect_range } MemoryRegion :: BackedByPage ( contents ) => { let prefetch_range = range_intersection ( & range_from_count ( faulting_page , MAX_PAGES_TO_COPY ) , & min_prefetch_range , ) ; // Get the largest contiguous memory region backed by pages. let mut pages : [ Option < & PageBytes > ; MAX_PAGES_TO_COPY ] = [ None ; MAX_PAGES_TO_COPY ] ; pages [ 0 ] = Some ( contents ) ; let mut count = 1 ; while count < range_count ( & prefetch_range ) { match page_map . get_memory_region ( PageIndex :: new ( faulting_page . get ( ) + count as u64 ) ) { MemoryRegion :: Zeros ( _ ) | MemoryRegion :: BackedByFile ( _ , _ ) => { break ; } MemoryRegion :: BackedByPage ( contents ) => { pages [ count ] = Some ( contents ) ; } } count += 1 ; } let mprotect_range = range_from_count ( faulting_page , count ) ; let page_start_addr = tracker . page_start_addr_from ( mprotect_range . start ) ; // Make the page writable because we are going to copy bytes. unsafe { mprotect ( page_start_addr , range_size_in_bytes ( & mprotect_range ) , ProtFlags :: PROT_READ | ProtFlags :: PROT_WRITE , ) . unwrap ( ) } ; // Copy the contents of the pages. for ( index , page ) in pages . iter ( ) . enumerate ( ) { if let Some ( contents ) = * page { assert ! ( index count ) ; unsafe { std :: ptr :: copy_nonoverlapping ( contents . as_ptr ( ) , ( page_start_addr as * mut u8 ) . add ( index * PAGE_SIZE ) , PAGE_SIZE , ) } ; } } if ! page_protection_flags . contains ( ProtFlags :: PROT_WRITE ) { // Make the page read-only to intercept the future write accesses. // TODO(EXC-447): This `mprotect` call is the main performance bottleneck // for messages that need to track dirty pages. It causes expensive TLB flushes // because it reduces the protection flags from Read/Write to Read. // There are two ways to eliminate this call: // 1) Implement an mmap allocator for `PageDelta` pages so that we can mmap it. // 2) Track all accessed pages and after execution filter dirty pages by //    comparing the page contents. unsafe { mprotect ( page_start_addr , range_size_in_bytes ( & mprotect_range ) , ProtFlags :: PROT_READ , ) . unwrap ( ) } ; } mprotect_range } } }
Sets up page mapping for the given `faulting_page` and its subsequent pages
using the backing memory from the given `page_map`.
Sets up page mapping for the given ` faulting_page ` and its subsequent pages using the backing memory from the given ` page_map ` .
tracker
&SigsegvMemoryTracker
page_map
&PageMap
page_protection_flags
ProtFlags
faulting_page
PageIndex
min_prefetch_range
Range<PageIndex>
max_prefetch_range
Range<PageIndex>
tracker
&SigsegvMemoryTracker
page_map
&PageMap
page_protection_flags
ProtFlags
faulting_page
PageIndex
min_prefetch_range
Range<PageIndex>
max_prefetch_range
Range<PageIndex>