RCU -> COW

This commit is contained in:
Brian Anderson 2012-10-10 14:30:12 -07:00
parent fca9e9fa00
commit e523a6375a
7 changed files with 21 additions and 23 deletions

View file

@ -96,7 +96,7 @@ trait StyleMethods {
impl Node : StyleMethods { impl Node : StyleMethods {
/** If none exists, creates empty layout data for the node (the reader-auxiliary /** If none exists, creates empty layout data for the node (the reader-auxiliary
* box in the RCU model) and populates it with an empty style object. * box in the COW model) and populates it with an empty style object.
*/ */
fn initialize_layout_data() -> Option<@LayoutData> { fn initialize_layout_data() -> Option<@LayoutData> {
match self.has_aux() { match self.has_aux() {
@ -141,7 +141,7 @@ impl Node : StyleMethods {
* Performs CSS selector matching on a subtree. * Performs CSS selector matching on a subtree.
* This is, importantly, the function that updates the layout data for * This is, importantly, the function that updates the layout data for
* the node (the reader-auxiliary box in the RCU model) with the * the node (the reader-auxiliary box in the COW model) with the
* computed style. * computed style.
*/ */
fn recompute_style_for_subtree(ctx: &LayoutContext, styles : &ARC<Stylesheet>) { fn recompute_style_for_subtree(ctx: &LayoutContext, styles : &ARC<Stylesheet>) {

View file

@ -1,35 +1,35 @@
#[doc(str = " #[doc(str = "
Implements the RCU DOM-sharing model. This model allows for a single writer and any number of Implements the copy-on-write DOM-sharing model. This model allows for a single writer and any number of
readers, but the writer must be able to control and manage the lifetimes of the reader(s). For readers, but the writer must be able to control and manage the lifetimes of the reader(s). For
simplicity I will describe the implementation as though there were a single reader. simplicity I will describe the implementation as though there were a single reader.
The basic idea is that every object in the RCU pool has both a reader view and a writer view. The The basic idea is that every object in the COW pool has both a reader view and a writer view. The
writer always sees the writer view, which contains the most up-to-date values. The reader uses the writer always sees the writer view, which contains the most up-to-date values. The reader uses the
reader view, which contains the values as of the point where the reader was forked. When the reader view, which contains the values as of the point where the reader was forked. When the
writer joins the reader, the reader view will be synchronized with the writer view. writer joins the reader, the reader view will be synchronized with the writer view.
Internally, the way this works is using a copy-on-write scheme. Each RCU node maintains two Internally, the way this works is using a copy-on-write scheme. Each COW node maintains two
pointers (`read_ptr` and `write_ptr`). Assuming that readers are active, when a writer wants to pointers (`read_ptr` and `write_ptr`). Assuming that readers are active, when a writer wants to
modify a node, it first copies the reader's data into a new pointer. Any writes that occur after modify a node, it first copies the reader's data into a new pointer. Any writes that occur after
that point (but before the reader is joined) will operate on this same copy. When the reader is that point (but before the reader is joined) will operate on this same copy. When the reader is
joined, any nodes which the writer modified will free the stale reader data and update the reader joined, any nodes which the writer modified will free the stale reader data and update the reader
pointer to be the same as the writer pointer. pointer to be the same as the writer pointer.
# Using the RCU APIs as a writer # Using the COW APIs as a writer
You must first create a `scope` object. The scope object manages the memory and the RCU You must first create a `scope` object. The scope object manages the memory and the COW
operations. RCU'd objects of some sendable type `T` are not referenced directly but rather through operations. COW'd objects of some sendable type `T` are not referenced directly but rather through
a `handle<T>`. To create a new RCU object, you use `scope.handle(t)` where `t` is some initial a `handle<T>`. To create a new COW object, you use `scope.handle(t)` where `t` is some initial
value of type `T`. To write to an RCU object, use `scope.write()` and to read from it use value of type `T`. To write to an COW object, use `scope.write()` and to read from it use
`scope.read()`. Be sure not to use the various `ReaderMethods`. `scope.read()`. Be sure not to use the various `ReaderMethods`.
Handles can be freely sent between tasks but the RCU scope cannot. It must stay with the writer Handles can be freely sent between tasks but the COW scope cannot. It must stay with the writer
task. You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep task. You are responsible for correctly invoking `reader_forked()` and `reader_joined()` to keep
the RCU scope abreast of when the reader is active. Failure to do so will lead to race conditions the COW scope abreast of when the reader is active. Failure to do so will lead to race conditions
or worse. or worse.
# Using the RCU APIs as a reader # Using the COW APIs as a reader
Import the `ReaderMethods` impl. When you receive a handle, you can invoke `h.read { |v| ... }` Import the `ReaderMethods` impl. When you receive a handle, you can invoke `h.read { |v| ... }`
and so forth. There is also a piece of auxiliary data that can be optionally associated with each and so forth. There is also a piece of auxiliary data that can be optionally associated with each
@ -45,7 +45,7 @@ fields.
Readers can associate a piece of auxiliary data of type `A` along with main nodes. This is Readers can associate a piece of auxiliary data of type `A` along with main nodes. This is
convenient but dangerous: it is the reader's job to ensure that this data remains live independent convenient but dangerous: it is the reader's job to ensure that this data remains live independent
of the RCU nodes themselves. of the COW nodes themselves.
")]; ")];

View file

@ -50,7 +50,7 @@ impl Node {
/* TODO: LayoutData is just a pointer, but we must circumvent the type /* TODO: LayoutData is just a pointer, but we must circumvent the type
system to actually compare the pointers. This should be fixed in system to actually compare the pointers. This should be fixed in
with a generic implementation of rcu::Handle */ with a generic implementation of cow::Handle */
impl Node : cmp::Eq { impl Node : cmp::Eq {
pure fn eq(other : &Node) -> bool unsafe { pure fn eq(other : &Node) -> bool unsafe {
let my_data : @LayoutData = @self.aux(|a| copy *a); let my_data : @LayoutData = @self.aux(|a| copy *a);
@ -122,7 +122,7 @@ fn define_bindings(compartment: &bare_compartment, doc: @Document,
} }
/** The RCU rd_aux data is a (weak) pointer to the layout data, /** The COW rd_aux data is a (weak) pointer to the layout data,
defined by this `LayoutData` enum. It contains the CSS style object defined by this `LayoutData` enum. It contains the CSS style object
as well as the primary `RenderBox`. as well as the primary `RenderBox`.
@ -132,12 +132,12 @@ enum LayoutData = {
mut flow: Option<@FlowContext> mut flow: Option<@FlowContext>
}; };
type Node = rcu::Handle<NodeData, LayoutData>; type Node = cow::Handle<NodeData, LayoutData>;
type NodeScope = rcu::Scope<NodeData, LayoutData>; type NodeScope = cow::Scope<NodeData, LayoutData>;
fn NodeScope() -> NodeScope { fn NodeScope() -> NodeScope {
rcu::Scope() cow::Scope()
} }
trait NodeScopeExtensions { trait NodeScopeExtensions {

View file

@ -12,7 +12,6 @@ use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgColor
use dl = gfx::display_list; use dl = gfx::display_list;
use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement}; use dom::element::{ElementKind, HTMLDivElement, HTMLImageElement};
use dom::node::{Element, Node, NodeData, NodeKind, NodeTree}; use dom::node::{Element, Node, NodeData, NodeKind, NodeTree};
use dom::rcu;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;
use geom::point::Point2D; use geom::point::Point2D;

View file

@ -5,7 +5,7 @@ use au::au;
use css::values::{BgColor, BgColorTransparent, Specified}; use css::values::{BgColor, BgColorTransparent, Specified};
use dl = gfx::display_list; use dl = gfx::display_list;
use dom::node::{Text, NodeScope}; use dom::node::{Text, NodeScope};
use dom::rcu::Scope; use dom::cow::Scope;
use dvec::DVec; use dvec::DVec;
use either::{Left, Right}; use either::{Left, Right};
use geom::point::Point2D; use geom::point::Point2D;

View file

@ -3,7 +3,6 @@ use core::dlist::DList;
use core::dvec::DVec; use core::dvec::DVec;
use css::values::{BoxAuto, BoxLength, Px}; use css::values::{BoxAuto, BoxLength, Px};
use dl = gfx::display_list; use dl = gfx::display_list;
use dom::rcu;
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;

View file

@ -35,7 +35,7 @@ pub mod dom {
pub mod element; pub mod element;
pub mod event; pub mod event;
pub mod node; pub mod node;
pub mod rcu; pub mod cow;
pub mod window; pub mod window;
} }