diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 05a983b274d0..4cf5a435da71 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -399,7 +399,7 @@ impl LayoutThread { MediaType::Screen, opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0)); 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 { None }; diff --git a/components/style/workqueue.rs b/components/style/workqueue.rs index 8202b5c322eb..fc4f66ea1201 100644 --- a/components/style/workqueue.rs +++ b/components/style/workqueue.rs @@ -18,8 +18,8 @@ use deque::{self, Abort, Data, Empty, Stealer, Worker}; use rand::{Rng, XorShiftRng, weak_rng}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::{Receiver, Sender, channel}; +use std::thread; use thread_state; -use util::thread::spawn_named; /// A unit of work. /// @@ -244,10 +244,11 @@ impl WorkQueue { /// it. pub fn new(thread_name: &'static str, state: thread_state::ThreadState, - thread_count: usize) -> WorkQueue { + thread_count: usize) -> Result, ()> { // Set up data structures. 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 { let (worker_chan, worker_port) = channel(); let (worker, thief) = deque::new(); @@ -276,21 +277,42 @@ impl WorkQueue { } // Spawn threads. + let mut thread_handles = vec![]; for (i, thread) in threads.into_iter().enumerate() { - spawn_named( - format!("{} worker {}/{}", thread_name, i + 1, thread_count), - move || { + let handle = thread::Builder::new() + .name(format!("{} worker {}/{}", thread_name, i + 1, thread_count)) + .spawn(move || { thread_state::initialize(state | thread_state::IN_WORKER); let mut thread = thread; thread.start() - }) + }); + match handle { + Ok(handle) => { + thread_handles.push(handle); + } + Err(err) => { + warn!("Failed spawning thread: {:?}", err); + break; + } + } + } + + 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(()); } - WorkQueue { + Ok(WorkQueue { workers: infos, port: supervisor_port, work_count: 0, - } + }) } /// Enqueues a block into the work queue. diff --git a/ports/geckolib/data.rs b/ports/geckolib/data.rs index 836090bbbe5a..d1abe67f9bdc 100644 --- a/ports/geckolib/data.rs +++ b/ports/geckolib/data.rs @@ -38,7 +38,7 @@ pub struct PerDocumentStyleData { pub expired_animations: Arc>>>, // FIXME(bholley): This shouldn't be per-document. - pub work_queue: WorkQueue, + pub work_queue: Option>, pub num_threads: usize, } @@ -68,7 +68,11 @@ impl PerDocumentStyleData { new_animations_receiver: new_anims_receiver, running_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, } } @@ -91,6 +95,8 @@ impl PerDocumentStyleData { impl Drop for PerDocumentStyleData { fn drop(&mut self) { - self.work_queue.shutdown(); + if let Some(ref mut queue) = self.work_queue { + queue.shutdown(); + } } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 14f2a3547c8e..ae682ac72e06 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -103,11 +103,11 @@ fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) { // We ensure this is true before calling Servo_RestyleSubtree() 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::(node, &shared_style_context); } else { parallel::traverse_dom::(node, &shared_style_context, - &mut per_doc_data.work_queue); + per_doc_data.work_queue.as_mut().unwrap()); } }