about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo.net>2017-07-24 14:21:28 +0200
committerMichael Woerister <michaelwoerister@posteo.net>2017-07-31 15:15:09 +0200
commitdf6be33d84f14c286689938eb2a2686315926e9f (patch)
treebffabe5e0f3821fc7d9905f36fffd679367dae75
parentbac57cf65430ce52bfa6a50e7f4db1b99c02d1cb (diff)
downloadrust-df6be33d84f14c286689938eb2a2686315926e9f.tar.gz
rust-df6be33d84f14c286689938eb2a2686315926e9f.zip
async-llvm(4): Move work coordination to separate thread in order to free up the main thread for translation.
-rw-r--r--src/librustc_trans/back/write.rs124
1 files changed, 61 insertions, 63 deletions
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index d2fc9682852..08eccd8fdf3 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -28,7 +28,6 @@ use syntax::ext::hygiene::Mark;
 use syntax_pos::MultiSpan;
 use context::{is_pie_binary, get_reloc_model};
 use jobserver::{Client, Acquired};
-use crossbeam::{scope, Scope};
 use rustc_demangle;
 
 use std::cmp;
@@ -38,8 +37,10 @@ use std::io;
 use std::io::Write;
 use std::path::{Path, PathBuf};
 use std::str;
+use std::sync::Arc;
 use std::sync::mpsc::{channel, Sender, Receiver};
 use std::slice;
+use std::thread;
 use libc::{c_uint, c_void, c_char, size_t};
 
 pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
@@ -283,13 +284,13 @@ impl ModuleConfig {
 
 /// Additional resources used by optimize_and_codegen (not module specific)
 #[derive(Clone)]
-pub struct CodegenContext<'a> {
+pub struct CodegenContext {
     // Resouces needed when running LTO
     pub time_passes: bool,
     pub lto: bool,
     pub no_landing_pads: bool,
-    pub exported_symbols: &'a ExportedSymbols,
-    pub opts: &'a config::Options,
+    pub exported_symbols: Arc<ExportedSymbols>,
+    pub opts: Arc<config::Options>,
     pub crate_types: Vec<config::CrateType>,
     pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>,
     // Handler to use for diagnostics produced during codegen.
@@ -307,18 +308,18 @@ pub struct CodegenContext<'a> {
     pub coordinator_send: Sender<Message>,
 }
 
-impl<'a> CodegenContext<'a> {
+impl CodegenContext {
     fn create_diag_handler(&self) -> Handler {
         Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
     }
 }
 
 struct HandlerFreeVars<'a> {
-    cgcx: &'a CodegenContext<'a>,
+    cgcx: &'a CodegenContext,
     diag_handler: &'a Handler,
 }
 
-unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
+unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext,
                                                msg: &'b str,
                                                cookie: c_uint) {
     cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string());
@@ -775,9 +776,8 @@ pub fn run_passes(sess: &Session,
         let num_workers = cmp::min(work_items.len() - 1, 32);
         Client::new(num_workers).expect("failed to create jobserver")
     });
-    scope(|scope| {
-        execute_work(sess, work_items, client, &trans.exported_symbols, scope);
-    });
+
+    execute_work(sess, work_items, client, trans.exported_symbols.clone());
 
     // If in incr. comp. mode, preserve the `.o` files for potential re-use
     for mtrans in modules.iter() {
@@ -1052,11 +1052,10 @@ pub struct Diagnostic {
     lvl: Level,
 }
 
-fn execute_work<'a>(sess: &'a Session,
-                    mut work_items: Vec<WorkItem>,
-                    jobserver: Client,
-                    exported_symbols: &'a ExportedSymbols,
-                    scope: &Scope<'a>) {
+fn execute_work(sess: &Session,
+                mut work_items: Vec<WorkItem>,
+                jobserver: Client,
+                exported_symbols: Arc<ExportedSymbols>) {
     let (tx, rx) = channel();
     let tx2 = tx.clone();
 
@@ -1092,7 +1091,7 @@ fn execute_work<'a>(sess: &'a Session,
         each_linked_rlib_for_lto: each_linked_rlib_for_lto,
         lto: sess.lto(),
         no_landing_pads: sess.no_landing_pads(),
-        opts: &sess.opts,
+        opts: Arc::new(sess.opts.clone()),
         time_passes: sess.time_passes(),
         exported_symbols: exported_symbols,
         plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
@@ -1158,68 +1157,67 @@ fn execute_work<'a>(sess: &'a Session,
     // Before that work finishes, however, we may acquire a token. In that case
     // we actually wastefully acquired the token, so we relinquish it back to
     // the jobserver.
-    let mut tokens = Vec::new();
-    let mut running = 0;
-    while work_items.len() > 0 || running > 0 {
-
-        // Spin up what work we can, only doing this while we've got available
-        // parallelism slots and work left to spawn.
-        while work_items.len() > 0 && running < tokens.len() + 1 {
-            let item = work_items.pop().unwrap();
-            let worker_index = work_items.len();
-
-            let cgcx = CodegenContext {
-                worker: worker_index,
-                .. cgcx.clone()
-            };
 
-            spawn_work(cgcx,
-                       scope,
-                       item);
-            running += 1;
-        }
+    thread::spawn(move || {
+        let mut tokens = Vec::new();
+        let mut running = 0;
+        while work_items.len() > 0 || running > 0 {
 
-        // Relinquish accidentally acquired extra tokens
-        tokens.truncate(running.saturating_sub(1));
+            // Spin up what work we can, only doing this while we've got available
+            // parallelism slots and work left to spawn.
+            while work_items.len() > 0 && running < tokens.len() + 1 {
+                let item = work_items.pop().unwrap();
+                let worker_index = work_items.len();
 
-        match rx.recv().unwrap() {
-            // Save the token locally and the next turn of the loop will use
-            // this to spawn a new unit of work, or it may get dropped
-            // immediately if we have no more work to spawn.
-            Message::Token(token) => {
-                tokens.push(token.expect("failed to acquire jobserver token"));
-            }
+                let cgcx = CodegenContext {
+                    worker: worker_index,
+                    .. cgcx.clone()
+                };
 
-            // If a thread exits successfully then we drop a token associated
-            // with that worker and update our `running` count. We may later
-            // re-acquire a token to continue running more work. We may also not
-            // actually drop a token here if the worker was running with an
-            // "ephemeral token"
-            //
-            // Note that if the thread failed that means it panicked, so we
-            // abort immediately.
-            Message::Done { success: true } => {
-                drop(tokens.pop());
-                running -= 1;
+                spawn_work(cgcx, item);
+                running += 1;
             }
-            Message::Done { success: false } => {
-                shared_emitter.fatal("aborting due to worker thread panic".to_string());
+
+            // Relinquish accidentally acquired extra tokens
+            tokens.truncate(running.saturating_sub(1));
+
+            match rx.recv().unwrap() {
+                // Save the token locally and the next turn of the loop will use
+                // this to spawn a new unit of work, or it may get dropped
+                // immediately if we have no more work to spawn.
+                Message::Token(token) => {
+                    tokens.push(token.expect("failed to acquire jobserver token"));
+                }
+
+                // If a thread exits successfully then we drop a token associated
+                // with that worker and update our `running` count. We may later
+                // re-acquire a token to continue running more work. We may also not
+                // actually drop a token here if the worker was running with an
+                // "ephemeral token"
+                //
+                // Note that if the thread failed that means it panicked, so we
+                // abort immediately.
+                Message::Done { success: true } => {
+                    drop(tokens.pop());
+                    running -= 1;
+                }
+                Message::Done { success: false } => {
+                    shared_emitter.fatal("aborting due to worker thread panic".to_string());
+                }
             }
         }
+    }).join().unwrap();
 
-        shared_emitter_main.check(sess);
-    }
+    shared_emitter_main.check(sess);
 
     // Just in case, check this on the way out.
     sess.diagnostic().abort_if_errors();
 }
 
-fn spawn_work<'a>(cgcx: CodegenContext<'a>,
-                  scope: &Scope<'a>,
-                  work: WorkItem) {
+fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
     let depth = time_depth();
 
-    scope.spawn(move || {
+    thread::spawn(move || {
         set_time_depth(depth);
 
         // Set up a destructor which will fire off a message that we're done as