@@ -72,7 +72,7 @@ use std::io::prelude::*;
7272use std:: mem;
7373use std:: path:: { Path , PathBuf } ;
7474use std:: str:: FromStr ;
75- use std:: sync:: { Arc , Mutex , MutexGuard , Once , OnceLock } ;
75+ use std:: sync:: { Arc , LazyLock , Mutex , MutexGuard , OnceLock } ;
7676use std:: time:: Instant ;
7777
7878use self :: ConfigValue as CV ;
@@ -239,7 +239,7 @@ pub struct GlobalContext {
239239 /// continue operating if possible.
240240 offline : bool ,
241241 /// A global static IPC control mechanism (used for managing parallel builds)
242- jobserver : Option < jobserver:: Client > ,
242+ jobserver : Option < & ' static jobserver:: Client > ,
243243 /// Cli flags of the form "-Z something" merged with config file values
244244 unstable_flags : CliUnstable ,
245245 /// Cli flags of the form "-Z something"
@@ -308,17 +308,47 @@ impl GlobalContext {
308308 ///
309309 /// This does only minimal initialization. In particular, it does not load
310310 /// any config files from disk. Those will be loaded lazily as-needed.
311- pub fn new ( shell : Shell , cwd : PathBuf , homedir : PathBuf ) -> GlobalContext {
312- static mut GLOBAL_JOBSERVER : * mut jobserver:: Client = 0 as * mut _ ;
313- static INIT : Once = Once :: new ( ) ;
314-
315- // This should be called early on in the process, so in theory the
316- // unsafety is ok here. (taken ownership of random fds)
317- INIT . call_once ( || unsafe {
318- if let Some ( client) = jobserver:: Client :: from_env ( ) {
319- GLOBAL_JOBSERVER = Box :: into_raw ( Box :: new ( client) ) ;
311+ pub fn new ( mut shell : Shell , cwd : PathBuf , homedir : PathBuf ) -> GlobalContext {
312+ static GLOBAL_JOBSERVER : LazyLock < CargoResult < Option < jobserver:: Client > > > = LazyLock :: new (
313+ || {
314+ use jobserver:: FromEnvErrorKind ;
315+ // Note that this is unsafe because it may misinterpret file descriptors
316+ // on Unix as jobserver file descriptors. We hopefully execute this near
317+ // the beginning of the process though to ensure we don't get false
318+ // positives, or in other words we try to execute this before we open
319+ // any file descriptors ourselves.
320+ let jobserver:: FromEnv { client, var } =
321+ unsafe { jobserver:: Client :: from_env_ext ( true ) } ;
322+
323+ match client {
324+ Ok ( client) => return Ok ( Some ( client) ) ,
325+ Err ( e)
326+ if matches ! (
327+ e. kind( ) ,
328+ FromEnvErrorKind :: NoEnvVar
329+ | FromEnvErrorKind :: NoJobserver
330+ | FromEnvErrorKind :: NegativeFd
331+ | FromEnvErrorKind :: Unsupported
332+ ) =>
333+ {
334+ Ok ( None )
335+ }
336+ Err ( e) => {
337+ let ( name, value) = var. unwrap ( ) ;
338+ Err ( anyhow:: anyhow!(
339+ "failed to connect to jobserver from environment variable `{name}={value:?}`: {e}"
340+ ) )
341+ }
342+ }
343+ } ,
344+ ) ;
345+ let jobserver = match & * GLOBAL_JOBSERVER {
346+ Ok ( jobserver) => jobserver. as_ref ( ) ,
347+ Err ( e) => {
348+ let _ = shell. warn ( e) ;
349+ None
320350 }
321- } ) ;
351+ } ;
322352
323353 let env = Env :: new ( ) ;
324354
@@ -342,13 +372,7 @@ impl GlobalContext {
342372 frozen : false ,
343373 locked : false ,
344374 offline : false ,
345- jobserver : unsafe {
346- if GLOBAL_JOBSERVER . is_null ( ) {
347- None
348- } else {
349- Some ( ( * GLOBAL_JOBSERVER ) . clone ( ) )
350- }
351- } ,
375+ jobserver,
352376 unstable_flags : CliUnstable :: default ( ) ,
353377 unstable_flags_cli : None ,
354378 easy : Default :: default ( ) ,
@@ -1880,7 +1904,7 @@ impl GlobalContext {
18801904 }
18811905
18821906 pub fn jobserver_from_env ( & self ) -> Option < & jobserver:: Client > {
1883- self . jobserver . as_ref ( )
1907+ self . jobserver
18841908 }
18851909
18861910 pub fn http ( & self ) -> CargoResult < & Mutex < Easy > > {
0 commit comments