mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 01:13:23 +00:00
Don't copy on write if this is the only reference
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
f13e5d12c1
commit
bec2c97637
@ -241,7 +241,14 @@ impl VmMapping {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_shared {
|
// If the forked child or parent immediately unmaps the page after
|
||||||
|
// the fork without accessing it, we are the only reference to the
|
||||||
|
// frame. We can directly map the frame as writable without
|
||||||
|
// copying. In this case, the reference count of the frame is 2 (
|
||||||
|
// one for the mapping and one for the frame handle itself).
|
||||||
|
let only_reference = frame.reference_count() == 2;
|
||||||
|
|
||||||
|
if self.is_shared || only_reference {
|
||||||
cursor.protect(PAGE_SIZE, |p| p.flags |= PageFlags::W);
|
cursor.protect(PAGE_SIZE, |p| p.flags |= PageFlags::W);
|
||||||
} else {
|
} else {
|
||||||
let new_frame = duplicate_frame(&frame)?;
|
let new_frame = duplicate_frame(&frame)?;
|
||||||
|
@ -80,6 +80,21 @@ impl Frame {
|
|||||||
core::ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.size());
|
core::ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the reference count of the frame.
|
||||||
|
///
|
||||||
|
/// It returns the number of all references to the page, including all the
|
||||||
|
/// existing page handles ([`Frame`]) and all the mappings in the page
|
||||||
|
/// table that points to the page.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The function is safe to call, but using it requires extra care. The
|
||||||
|
/// reference count can be changed by other threads at any time including
|
||||||
|
/// potentially between calling this method and acting on the result.
|
||||||
|
pub fn reference_count(&self) -> u32 {
|
||||||
|
self.page.reference_count()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Page<FrameMeta>> for Frame {
|
impl From<Page<FrameMeta>> for Frame {
|
||||||
|
@ -164,6 +164,21 @@ impl<M: PageMeta> Page<M> {
|
|||||||
unsafe { &*(self.ptr as *const M) }
|
unsafe { &*(self.ptr as *const M) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the reference count of the page.
|
||||||
|
///
|
||||||
|
/// It returns the number of all references to the page, including all the
|
||||||
|
/// existing page handles ([`Page`], [`DynPage`]), and all the mappings in the
|
||||||
|
/// page table that points to the page.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The function is safe to call, but using it requires extra care. The
|
||||||
|
/// reference count can be changed by other threads at any time including
|
||||||
|
/// potentially between calling this method and acting on the result.
|
||||||
|
pub fn reference_count(&self) -> u32 {
|
||||||
|
self.ref_count().load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
fn ref_count(&self) -> &AtomicU32 {
|
fn ref_count(&self) -> &AtomicU32 {
|
||||||
unsafe { &(*self.ptr).ref_count }
|
unsafe { &(*self.ptr).ref_count }
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user