]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_data_structures/src/jobserver.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_data_structures / src / jobserver.rs
1 pub use jobserver_crate::Client;
2
3 use jobserver_crate::{FromEnv, FromEnvErrorKind};
4
5 use std::sync::{LazyLock, OnceLock};
6
7 // We can only call `from_env_ext` once per process
8
9 // We stick this in a global because there could be multiple rustc instances
10 // in this process, and the jobserver is per-process.
11 static GLOBAL_CLIENT: LazyLock<Result<Client, String>> = LazyLock::new(|| {
12 // Note that this is unsafe because it may misinterpret file descriptors
13 // on Unix as jobserver file descriptors. We hopefully execute this near
14 // the beginning of the process though to ensure we don't get false
15 // positives, or in other words we try to execute this before we open
16 // any file descriptors ourselves.
17 let FromEnv { client, var } = unsafe { Client::from_env_ext(true) };
18
19 let error = match client {
20 Ok(client) => return Ok(client),
21 Err(e) => e,
22 };
23
24 if matches!(
25 error.kind(),
26 FromEnvErrorKind::NoEnvVar | FromEnvErrorKind::NoJobserver | FromEnvErrorKind::Unsupported
27 ) {
28 return Ok(default_client());
29 }
30
31 // Environment specifies jobserver, but it looks incorrect.
32 // Safety: `error.kind()` should be `NoEnvVar` if `var == None`.
33 let (name, value) = var.unwrap();
34 Err(format!(
35 "failed to connect to jobserver from environment variable `{name}={:?}`: {error}",
36 value
37 ))
38 });
39
40 // Create a new jobserver if there's no inherited one.
41 fn default_client() -> Client {
42 // Pick a "reasonable maximum" capping out at 32
43 // so we don't take everything down by hogging the process run queue.
44 // The fixed number is used to have deterministic compilation across machines.
45 let client = Client::new(32).expect("failed to create jobserver");
46
47 // Acquire a token for the main thread which we can release later
48 client.acquire_raw().ok();
49
50 client
51 }
52
53 static GLOBAL_CLIENT_CHECKED: OnceLock<Client> = OnceLock::new();
54
55 pub fn initialize_checked(report_warning: impl FnOnce(&'static str)) {
56 let client_checked = match &*GLOBAL_CLIENT {
57 Ok(client) => client.clone(),
58 Err(e) => {
59 report_warning(e);
60 default_client()
61 }
62 };
63 GLOBAL_CLIENT_CHECKED.set(client_checked).ok();
64 }
65
66 const ACCESS_ERROR: &str = "jobserver check should have been called earlier";
67
68 pub fn client() -> Client {
69 GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).clone()
70 }
71
72 pub fn acquire_thread() {
73 GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).acquire_raw().ok();
74 }
75
76 pub fn release_thread() {
77 GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).release_raw().ok();
78 }