mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
style: Make WorkQueue creation fallible.
Fixes bug 1290205 in bugzilla.
This commit is contained in:
parent
8a5e1b70b7
commit
4194ba063a
4 changed files with 43 additions and 15 deletions
|
@ -399,7 +399,7 @@ impl LayoutThread {
|
||||||
MediaType::Screen,
|
MediaType::Screen,
|
||||||
opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0));
|
opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0));
|
||||||
let parallel_traversal = if layout_threads != 1 {
|
let parallel_traversal = if layout_threads != 1 {
|
||||||
Some(WorkQueue::new("LayoutWorker", thread_state::LAYOUT, layout_threads))
|
WorkQueue::new("LayoutWorker", thread_state::LAYOUT, layout_threads).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,8 +18,8 @@ use deque::{self, Abort, Data, Empty, Stealer, Worker};
|
||||||
use rand::{Rng, XorShiftRng, weak_rng};
|
use rand::{Rng, XorShiftRng, weak_rng};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||||
|
use std::thread;
|
||||||
use thread_state;
|
use thread_state;
|
||||||
use util::thread::spawn_named;
|
|
||||||
|
|
||||||
/// A unit of work.
|
/// A unit of work.
|
||||||
///
|
///
|
||||||
|
@ -244,10 +244,11 @@ impl<QueueData: Sync, WorkData: Send> WorkQueue<QueueData, WorkData> {
|
||||||
/// it.
|
/// it.
|
||||||
pub fn new(thread_name: &'static str,
|
pub fn new(thread_name: &'static str,
|
||||||
state: thread_state::ThreadState,
|
state: thread_state::ThreadState,
|
||||||
thread_count: usize) -> WorkQueue<QueueData, WorkData> {
|
thread_count: usize) -> Result<WorkQueue<QueueData, WorkData>, ()> {
|
||||||
// Set up data structures.
|
// Set up data structures.
|
||||||
let (supervisor_chan, supervisor_port) = channel();
|
let (supervisor_chan, supervisor_port) = channel();
|
||||||
let (mut infos, mut threads) = (vec!(), vec!());
|
let mut infos = Vec::with_capacity(thread_count);
|
||||||
|
let mut threads = Vec::with_capacity(thread_count);
|
||||||
for i in 0..thread_count {
|
for i in 0..thread_count {
|
||||||
let (worker_chan, worker_port) = channel();
|
let (worker_chan, worker_port) = channel();
|
||||||
let (worker, thief) = deque::new();
|
let (worker, thief) = deque::new();
|
||||||
|
@ -276,21 +277,42 @@ impl<QueueData: Sync, WorkData: Send> WorkQueue<QueueData, WorkData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn threads.
|
// Spawn threads.
|
||||||
|
let mut thread_handles = vec![];
|
||||||
for (i, thread) in threads.into_iter().enumerate() {
|
for (i, thread) in threads.into_iter().enumerate() {
|
||||||
spawn_named(
|
let handle = thread::Builder::new()
|
||||||
format!("{} worker {}/{}", thread_name, i + 1, thread_count),
|
.name(format!("{} worker {}/{}", thread_name, i + 1, thread_count))
|
||||||
move || {
|
.spawn(move || {
|
||||||
thread_state::initialize(state | thread_state::IN_WORKER);
|
thread_state::initialize(state | thread_state::IN_WORKER);
|
||||||
let mut thread = thread;
|
let mut thread = thread;
|
||||||
thread.start()
|
thread.start()
|
||||||
})
|
});
|
||||||
|
match handle {
|
||||||
|
Ok(handle) => {
|
||||||
|
thread_handles.push(handle);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("Failed spawning thread: {:?}", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkQueue {
|
if thread_handles.len() != thread_count {
|
||||||
|
// At least one worker thread failed to be created, just close the
|
||||||
|
// rest of them, and return an error.
|
||||||
|
for (i, handle) in thread_handles.into_iter().enumerate() {
|
||||||
|
let _ = infos[i].chan.send(WorkerMsg::Exit);
|
||||||
|
let _ = handle.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(WorkQueue {
|
||||||
workers: infos,
|
workers: infos,
|
||||||
port: supervisor_port,
|
port: supervisor_port,
|
||||||
work_count: 0,
|
work_count: 0,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enqueues a block into the work queue.
|
/// Enqueues a block into the work queue.
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub struct PerDocumentStyleData {
|
||||||
pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
|
pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
|
||||||
|
|
||||||
// FIXME(bholley): This shouldn't be per-document.
|
// FIXME(bholley): This shouldn't be per-document.
|
||||||
pub work_queue: WorkQueue<SharedStyleContext, WorkQueueData>,
|
pub work_queue: Option<WorkQueue<SharedStyleContext, WorkQueueData>>,
|
||||||
|
|
||||||
pub num_threads: usize,
|
pub num_threads: usize,
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,11 @@ impl PerDocumentStyleData {
|
||||||
new_animations_receiver: new_anims_receiver,
|
new_animations_receiver: new_anims_receiver,
|
||||||
running_animations: Arc::new(RwLock::new(HashMap::new())),
|
running_animations: Arc::new(RwLock::new(HashMap::new())),
|
||||||
expired_animations: Arc::new(RwLock::new(HashMap::new())),
|
expired_animations: Arc::new(RwLock::new(HashMap::new())),
|
||||||
work_queue: WorkQueue::new("StyleWorker", thread_state::LAYOUT, *NUM_THREADS),
|
work_queue: if *NUM_THREADS <= 1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
WorkQueue::new("StyleWorker", thread_state::LAYOUT, *NUM_THREADS).ok()
|
||||||
|
},
|
||||||
num_threads: *NUM_THREADS,
|
num_threads: *NUM_THREADS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +95,8 @@ impl PerDocumentStyleData {
|
||||||
|
|
||||||
impl Drop for PerDocumentStyleData {
|
impl Drop for PerDocumentStyleData {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.work_queue.shutdown();
|
if let Some(ref mut queue) = self.work_queue {
|
||||||
|
queue.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,11 +103,11 @@ fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) {
|
||||||
|
|
||||||
// We ensure this is true before calling Servo_RestyleSubtree()
|
// We ensure this is true before calling Servo_RestyleSubtree()
|
||||||
debug_assert!(node.is_dirty() || node.has_dirty_descendants());
|
debug_assert!(node.is_dirty() || node.has_dirty_descendants());
|
||||||
if per_doc_data.num_threads == 1 {
|
if per_doc_data.num_threads == 1 || per_doc_data.work_queue.is_none() {
|
||||||
sequential::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context);
|
sequential::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context);
|
||||||
} else {
|
} else {
|
||||||
parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context,
|
parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context,
|
||||||
&mut per_doc_data.work_queue);
|
per_doc_data.work_queue.as_mut().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue