Auto merge of #6547 - Ms2ger:workqueue-reference, r=pcwalton

Borrow the QueueData for WorkQueue::run.

This allows us to get rid of the raw pointers and unsafe dereferencing in
the parallel layout implementation.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6547)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-07-06 08:29:17 -06:00
commit a3821bf240
4 changed files with 46 additions and 47 deletions

View file

@ -129,9 +129,7 @@ pub struct SharedLayoutContext {
pub goal: ReflowGoal, pub goal: ReflowGoal,
} }
pub struct SharedLayoutContextWrapper(pub *const SharedLayoutContext); unsafe impl Send for SharedLayoutContext {}
unsafe impl Send for SharedLayoutContextWrapper {}
pub struct LayoutContext<'a> { pub struct LayoutContext<'a> {
pub shared: &'a SharedLayoutContext, pub shared: &'a SharedLayoutContext,

View file

@ -9,7 +9,7 @@
use animation; use animation;
use construct::ConstructionResult; use construct::ConstructionResult;
use context::{SharedLayoutContext, SharedLayoutContextWrapper, heap_size_of_local_context}; use context::{SharedLayoutContext, heap_size_of_local_context};
use css::node_style::StyledNode; use css::node_style::StyledNode;
use data::LayoutDataWrapper; use data::LayoutDataWrapper;
use display_list_builder::ToGfxColor; use display_list_builder::ToGfxColor;
@ -108,7 +108,7 @@ pub struct LayoutTaskData {
pub stylist: Box<Stylist>, pub stylist: Box<Stylist>,
/// The workers that we use for parallel operation. /// The workers that we use for parallel operation.
pub parallel_traversal: Option<WorkQueue<SharedLayoutContextWrapper, WorkQueueData>>, pub parallel_traversal: Option<WorkQueue<SharedLayoutContext, WorkQueueData>>,
/// The dirty rect. Used during display list construction. /// The dirty rect. Used during display list construction.
pub dirty: Rect<Au>, pub dirty: Rect<Au>,

View file

@ -8,7 +8,7 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
use context::{LayoutContext, SharedLayoutContextWrapper, SharedLayoutContext}; use context::{LayoutContext, SharedLayoutContext};
use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
use flow; use flow;
use flow_ref::FlowRef; use flow_ref::FlowRef;
@ -88,29 +88,29 @@ pub type UnsafeFlowList = (Box<Vec<UnsafeLayoutNode>>, usize);
pub type ChunkedDomTraversalFunction = pub type ChunkedDomTraversalFunction =
extern "Rust" fn(UnsafeLayoutNodeList, extern "Rust" fn(UnsafeLayoutNodeList,
&mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>); &mut WorkerProxy<SharedLayoutContext,UnsafeLayoutNodeList>);
pub type DomTraversalFunction = pub type DomTraversalFunction =
extern "Rust" fn(UnsafeLayoutNode, extern "Rust" fn(UnsafeLayoutNode,
&mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>); &mut WorkerProxy<SharedLayoutContext,UnsafeLayoutNodeList>);
pub type ChunkedFlowTraversalFunction = pub type ChunkedFlowTraversalFunction =
extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>); extern "Rust" fn(UnsafeFlowList, &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>);
pub type FlowTraversalFunction = pub type FlowTraversalFunction =
extern "Rust" fn(UnsafeFlow, &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>); extern "Rust" fn(UnsafeFlow, &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>);
/// A parallel top-down DOM traversal. /// A parallel top-down DOM traversal.
pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { pub trait ParallelPreorderDomTraversal : PreorderDomTraversal {
fn run_parallel(&self, fn run_parallel(&self,
nodes: UnsafeLayoutNodeList, nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>); proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeLayoutNodeList>);
#[inline(always)] #[inline(always)]
fn run_parallel_helper( fn run_parallel_helper(
&self, &self,
unsafe_nodes: UnsafeLayoutNodeList, unsafe_nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>, proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeLayoutNodeList>,
top_down_func: ChunkedDomTraversalFunction, top_down_func: ChunkedDomTraversalFunction,
bottom_up_func: DomTraversalFunction) { bottom_up_func: DomTraversalFunction) {
let mut discovered_child_nodes = Vec::new(); let mut discovered_child_nodes = Vec::new();
@ -169,7 +169,7 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
/// fetch-and-subtract the parent's children count. /// fetch-and-subtract the parent's children count.
fn run_parallel(&self, fn run_parallel(&self,
mut unsafe_node: UnsafeLayoutNode, mut unsafe_node: UnsafeLayoutNode,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeLayoutNodeList>) { proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeLayoutNodeList>) {
loop { loop {
// Get a real layout node. // Get a real layout node.
let node: LayoutNode = unsafe { let node: LayoutNode = unsafe {
@ -179,7 +179,7 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
// Perform the appropriate operation. // Perform the appropriate operation.
self.process(node); self.process(node);
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let parent = match node.layout_parent_node(layout_context.shared) { let parent = match node.layout_parent_node(layout_context.shared) {
@ -239,7 +239,7 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
/// fetch-and-subtract the parent's children count. /// fetch-and-subtract the parent's children count.
fn run_parallel(&self, fn run_parallel(&self,
mut unsafe_flow: UnsafeFlow, mut unsafe_flow: UnsafeFlow,
_: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) { _: &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>) {
loop { loop {
unsafe { unsafe {
// Get a real flow. // Get a real flow.
@ -285,14 +285,14 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
fn run_parallel(&self, fn run_parallel(&self,
unsafe_flows: UnsafeFlowList, unsafe_flows: UnsafeFlowList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>); proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>);
fn should_record_thread_ids(&self) -> bool; fn should_record_thread_ids(&self) -> bool;
#[inline(always)] #[inline(always)]
fn run_parallel_helper(&self, fn run_parallel_helper(&self,
unsafe_flows: UnsafeFlowList, unsafe_flows: UnsafeFlowList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>, proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>,
top_down_func: ChunkedFlowTraversalFunction, top_down_func: ChunkedFlowTraversalFunction,
bottom_up_func: FlowTraversalFunction) { bottom_up_func: FlowTraversalFunction) {
let mut discovered_child_flows = Vec::new(); let mut discovered_child_flows = Vec::new();
@ -338,7 +338,7 @@ impl<'a> ParallelPostorderFlowTraversal for BubbleISizes<'a> {}
impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> { impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
fn run_parallel(&self, fn run_parallel(&self,
unsafe_flows: UnsafeFlowList, unsafe_flows: UnsafeFlowList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) { proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>) {
self.run_parallel_helper(unsafe_flows, self.run_parallel_helper(unsafe_flows,
proxy, proxy,
assign_inline_sizes, assign_inline_sizes,
@ -355,7 +355,7 @@ impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {}
impl<'a> ParallelPreorderFlowTraversal for ComputeAbsolutePositions<'a> { impl<'a> ParallelPreorderFlowTraversal for ComputeAbsolutePositions<'a> {
fn run_parallel(&self, fn run_parallel(&self,
unsafe_flows: UnsafeFlowList, unsafe_flows: UnsafeFlowList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlowList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>) {
self.run_parallel_helper(unsafe_flows, self.run_parallel_helper(unsafe_flows,
proxy, proxy,
compute_absolute_positions, compute_absolute_positions,
@ -374,14 +374,14 @@ impl<'a> ParallelPostorderDomTraversal for ConstructFlows<'a> {}
impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> { impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> {
fn run_parallel(&self, fn run_parallel(&self,
unsafe_nodes: UnsafeLayoutNodeList, unsafe_nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNodeList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
self.run_parallel_helper(unsafe_nodes, proxy, recalc_style, construct_flows) self.run_parallel_helper(unsafe_nodes, proxy, recalc_style, construct_flows)
} }
} }
fn recalc_style(unsafe_nodes: UnsafeLayoutNodeList, fn recalc_style(unsafe_nodes: UnsafeLayoutNodeList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNodeList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let recalc_style_for_node_traversal = RecalcStyleForNode { let recalc_style_for_node_traversal = RecalcStyleForNode {
layout_context: &layout_context, layout_context: &layout_context,
@ -390,8 +390,8 @@ fn recalc_style(unsafe_nodes: UnsafeLayoutNodeList,
} }
fn construct_flows(unsafe_node: UnsafeLayoutNode, fn construct_flows(unsafe_node: UnsafeLayoutNode,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeLayoutNodeList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let construct_flows_traversal = ConstructFlows { let construct_flows_traversal = ConstructFlows {
layout_context: &layout_context, layout_context: &layout_context,
@ -400,8 +400,8 @@ fn construct_flows(unsafe_node: UnsafeLayoutNode,
} }
fn assign_inline_sizes(unsafe_flows: UnsafeFlowList, fn assign_inline_sizes(unsafe_flows: UnsafeFlowList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) { proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let assign_inline_sizes_traversal = AssignISizes { let assign_inline_sizes_traversal = AssignISizes {
layout_context: &layout_context, layout_context: &layout_context,
@ -411,8 +411,8 @@ fn assign_inline_sizes(unsafe_flows: UnsafeFlowList,
fn assign_block_sizes_and_store_overflow( fn assign_block_sizes_and_store_overflow(
unsafe_flow: UnsafeFlow, unsafe_flow: UnsafeFlow,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper,UnsafeFlowList>) { proxy: &mut WorkerProxy<SharedLayoutContext,UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let assign_block_sizes_traversal = AssignBSizesAndStoreOverflow { let assign_block_sizes_traversal = AssignBSizesAndStoreOverflow {
layout_context: &layout_context, layout_context: &layout_context,
@ -422,8 +422,8 @@ fn assign_block_sizes_and_store_overflow(
fn compute_absolute_positions( fn compute_absolute_positions(
unsafe_flows: UnsafeFlowList, unsafe_flows: UnsafeFlowList,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlowList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let compute_absolute_positions_traversal = ComputeAbsolutePositions { let compute_absolute_positions_traversal = ComputeAbsolutePositions {
layout_context: &layout_context, layout_context: &layout_context,
@ -432,8 +432,8 @@ fn compute_absolute_positions(
} }
fn build_display_list(unsafe_flow: UnsafeFlow, fn build_display_list(unsafe_flow: UnsafeFlow,
proxy: &mut WorkerProxy<SharedLayoutContextWrapper, UnsafeFlowList>) { proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeFlowList>) {
let shared_layout_context = unsafe { &*(proxy.user_data().0) }; let shared_layout_context = proxy.user_data();
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let build_display_list_traversal = BuildDisplayList { let build_display_list_traversal = BuildDisplayList {
@ -444,20 +444,20 @@ fn build_display_list(unsafe_flow: UnsafeFlow,
} }
fn run_queue_with_custom_work_data_type<To,F>( fn run_queue_with_custom_work_data_type<To,F>(
queue: &mut WorkQueue<SharedLayoutContextWrapper, WorkQueueData>, queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>,
callback: F, callback: F,
shared_layout_context: &SharedLayoutContext) shared_layout_context: &SharedLayoutContext)
where To: 'static + Send, F: FnOnce(&mut WorkQueue<SharedLayoutContextWrapper,To>) { where To: 'static + Send, F: FnOnce(&mut WorkQueue<SharedLayoutContext,To>) {
let queue: &mut WorkQueue<SharedLayoutContextWrapper,To> = unsafe { let queue: &mut WorkQueue<SharedLayoutContext,To> = unsafe {
mem::transmute(queue) mem::transmute(queue)
}; };
callback(queue); callback(queue);
queue.run(SharedLayoutContextWrapper(shared_layout_context as *const _)); queue.run(shared_layout_context);
} }
pub fn traverse_dom_preorder(root: LayoutNode, pub fn traverse_dom_preorder(root: LayoutNode,
shared_layout_context: &SharedLayoutContext, shared_layout_context: &SharedLayoutContext,
queue: &mut WorkQueue<SharedLayoutContextWrapper, WorkQueueData>) { queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>) {
run_queue_with_custom_work_data_type(queue, |queue| { run_queue_with_custom_work_data_type(queue, |queue| {
queue.push(WorkUnit { queue.push(WorkUnit {
fun: recalc_style, fun: recalc_style,
@ -471,7 +471,7 @@ pub fn traverse_flow_tree_preorder(
profiler_metadata: ProfilerMetadata, profiler_metadata: ProfilerMetadata,
time_profiler_chan: time::ProfilerChan, time_profiler_chan: time::ProfilerChan,
shared_layout_context: &SharedLayoutContext, shared_layout_context: &SharedLayoutContext,
queue: &mut WorkQueue<SharedLayoutContextWrapper, WorkQueueData>) { queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>) {
if opts::get().bubble_inline_sizes_separately { if opts::get().bubble_inline_sizes_separately {
let layout_context = LayoutContext::new(shared_layout_context); let layout_context = LayoutContext::new(shared_layout_context);
let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context }; let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
@ -494,7 +494,7 @@ pub fn build_display_list_for_subtree(
profiler_metadata: ProfilerMetadata, profiler_metadata: ProfilerMetadata,
time_profiler_chan: time::ProfilerChan, time_profiler_chan: time::ProfilerChan,
shared_layout_context: &SharedLayoutContext, shared_layout_context: &SharedLayoutContext,
queue: &mut WorkQueue<SharedLayoutContextWrapper, WorkQueueData>) { queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>) {
run_queue_with_custom_work_data_type(queue, |queue| { run_queue_with_custom_work_data_type(queue, |queue| {
profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata, profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata,
time_profiler_chan, || { time_profiler_chan, || {

View file

@ -169,7 +169,10 @@ impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
let mut proxy = WorkerProxy { let mut proxy = WorkerProxy {
worker: &mut deque, worker: &mut deque,
ref_count: ref_count, ref_count: ref_count,
queue_data: queue_data, // queue_data is kept alive in the stack frame of
// WorkQueue::run until we send the
// SupervisorMsg::ReturnDeque message below.
queue_data: unsafe { &*queue_data },
worker_index: self.index as u8, worker_index: self.index as u8,
}; };
(work_unit.fun)(work_unit.data, &mut proxy); (work_unit.fun)(work_unit.data, &mut proxy);
@ -193,7 +196,7 @@ impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> { pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>, worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
ref_count: *mut AtomicUsize, ref_count: *mut AtomicUsize,
queue_data: *const QueueData, queue_data: &'a QueueData,
worker_index: u8, worker_index: u8,
} }
@ -209,10 +212,8 @@ impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData
/// Retrieves the queue user data. /// Retrieves the queue user data.
#[inline] #[inline]
pub fn user_data<'b>(&'b self) -> &'b QueueData { pub fn user_data(&self) -> &'a QueueData {
unsafe { self.queue_data
mem::transmute(self.queue_data)
}
} }
/// Retrieves the index of the worker. /// Retrieves the index of the worker.
@ -302,13 +303,13 @@ impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
} }
/// Synchronously runs all the enqueued tasks and waits for them to complete. /// Synchronously runs all the enqueued tasks and waits for them to complete.
pub fn run(&mut self, data: QueueData) { pub fn run(&mut self, data: &QueueData) {
// Tell the workers to start. // Tell the workers to start.
let mut work_count = AtomicUsize::new(self.work_count); let mut work_count = AtomicUsize::new(self.work_count);
for worker in self.workers.iter_mut() { for worker in self.workers.iter_mut() {
worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(), worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
&mut work_count, &mut work_count,
&data)).unwrap() data)).unwrap()
} }
// Wait for the work to finish. // Wait for the work to finish.