11use libc:: c_int;
22
3- use std:: fs:: File ;
3+ use std:: fs:: { File , OpenOptions } ;
44use std:: io:: { self , Read , Write } ;
55use std:: mem;
66use std:: mem:: MaybeUninit ;
77use std:: os:: unix:: prelude:: * ;
8+ use std:: path:: { Path , PathBuf } ;
89use std:: process:: Command ;
910use std:: ptr;
1011use std:: sync:: { Arc , Once } ;
1112use std:: thread:: { self , Builder , JoinHandle } ;
1213use std:: time:: Duration ;
1314
1415#[ derive( Debug ) ]
15- pub struct Client {
16- read : File ,
17- write : File ,
16+ pub enum Client {
17+ /// `--jobserver-auth=R,W`
18+ Pipe { read : File , write : File } ,
19+ /// `--jobserver-auth=fifo:PATH`
20+ Fifo { file : File , path : PathBuf } ,
1821}
1922
2023#[ derive( Debug ) ]
@@ -30,16 +33,18 @@ impl Client {
3033 // wrong!
3134 const BUFFER : [ u8 ; 128 ] = [ b'|' ; 128 ] ;
3235
33- set_nonblocking ( client. write . as_raw_fd ( ) , true ) ?;
36+ let mut write = client. write ( ) ;
37+
38+ set_nonblocking ( write. as_raw_fd ( ) , true ) ?;
3439
3540 while limit > 0 {
3641 let n = limit. min ( BUFFER . len ( ) ) ;
3742
38- ( & client . write ) . write_all ( & BUFFER [ ..n] ) ?;
43+ write. write_all ( & BUFFER [ ..n] ) ?;
3944 limit -= n;
4045 }
4146
42- set_nonblocking ( client . write . as_raw_fd ( ) , false ) ?;
47+ set_nonblocking ( write. as_raw_fd ( ) , false ) ?;
4348
4449 Ok ( client)
4550 }
@@ -77,6 +82,31 @@ impl Client {
7782 }
7883
7984 pub unsafe fn open ( s : & str ) -> Option < Client > {
85+ Client :: from_fifo ( s) . or_else ( || Client :: from_pipe ( s) )
86+ }
87+
88+ /// `--jobserver-auth=fifo:PATH`
89+ fn from_fifo ( s : & str ) -> Option < Client > {
90+ let mut parts = s. splitn ( 2 , ':' ) ;
91+ if parts. next ( ) . unwrap ( ) != "fifo" {
92+ return None ;
93+ }
94+ let path = match parts. next ( ) {
95+ Some ( p) => Path :: new ( p) ,
96+ None => return None ,
97+ } ;
98+ let file = match OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( path) {
99+ Ok ( f) => f,
100+ Err ( _) => return None ,
101+ } ;
102+ Some ( Client :: Fifo {
103+ file,
104+ path : path. into ( ) ,
105+ } )
106+ }
107+
108+ /// `--jobserver-auth=R,W`
109+ unsafe fn from_pipe ( s : & str ) -> Option < Client > {
80110 let mut parts = s. splitn ( 2 , ',' ) ;
81111 let read = parts. next ( ) . unwrap ( ) ;
82112 let write = match parts. next ( ) {
@@ -110,12 +140,28 @@ impl Client {
110140 }
111141
112142 unsafe fn from_fds ( read : c_int , write : c_int ) -> Client {
113- Client {
143+ Client :: Pipe {
114144 read : File :: from_raw_fd ( read) ,
115145 write : File :: from_raw_fd ( write) ,
116146 }
117147 }
118148
149+ /// Gets the read end of our jobserver client.
150+ fn read ( & self ) -> & File {
151+ match self {
152+ Client :: Pipe { read, .. } => read,
153+ Client :: Fifo { file, .. } => file,
154+ }
155+ }
156+
157+ /// Gets the write end of our jobserver client.
158+ fn write ( & self ) -> & File {
159+ match self {
160+ Client :: Pipe { write, .. } => write,
161+ Client :: Fifo { file, .. } => file,
162+ }
163+ }
164+
119165 pub fn acquire ( & self ) -> io:: Result < Acquired > {
120166 // Ignore interrupts and keep trying if that happens
121167 loop {
@@ -150,11 +196,12 @@ impl Client {
150196 // to shut us down, so we otherwise punt all errors upwards.
151197 unsafe {
152198 let mut fd: libc:: pollfd = mem:: zeroed ( ) ;
153- fd. fd = self . read . as_raw_fd ( ) ;
199+ let mut read = self . read ( ) ;
200+ fd. fd = read. as_raw_fd ( ) ;
154201 fd. events = libc:: POLLIN ;
155202 loop {
156203 let mut buf = [ 0 ] ;
157- match ( & self . read ) . read ( & mut buf) {
204+ match read. read ( & mut buf) {
158205 Ok ( 1 ) => return Ok ( Some ( Acquired { byte : buf[ 0 ] } ) ) ,
159206 Ok ( _) => {
160207 return Err ( io:: Error :: new (
@@ -192,7 +239,7 @@ impl Client {
192239 // always quickly release a token). If that turns out to not be the
193240 // case we'll get an error anyway!
194241 let byte = data. map ( |d| d. byte ) . unwrap_or ( b'+' ) ;
195- match ( & self . write ) . write ( & [ byte] ) ? {
242+ match self . write ( ) . write ( & [ byte] ) ? {
196243 1 => Ok ( ( ) ) ,
197244 _ => Err ( io:: Error :: new (
198245 io:: ErrorKind :: Other ,
@@ -202,22 +249,31 @@ impl Client {
202249 }
203250
204251 pub fn string_arg ( & self ) -> String {
205- format ! ( "{},{}" , self . read. as_raw_fd( ) , self . write. as_raw_fd( ) )
252+ match self {
253+ Client :: Pipe { read, write } => format ! ( "{},{}" , read. as_raw_fd( ) , write. as_raw_fd( ) ) ,
254+ Client :: Fifo { path, .. } => format ! ( "fifo:{}" , path. to_str( ) . unwrap( ) ) ,
255+ }
206256 }
207257
208258 pub fn available ( & self ) -> io:: Result < usize > {
209259 let mut len = MaybeUninit :: < c_int > :: uninit ( ) ;
210- cvt ( unsafe { libc:: ioctl ( self . read . as_raw_fd ( ) , libc:: FIONREAD , len. as_mut_ptr ( ) ) } ) ?;
260+ cvt ( unsafe { libc:: ioctl ( self . read ( ) . as_raw_fd ( ) , libc:: FIONREAD , len. as_mut_ptr ( ) ) } ) ?;
211261 Ok ( unsafe { len. assume_init ( ) } as usize )
212262 }
213263
214264 pub fn configure ( & self , cmd : & mut Command ) {
265+ match self {
266+ // We `File::open`ed it when inheriting from environment,
267+ // so no need to set cloexec for fifo.
268+ Client :: Fifo { .. } => return ,
269+ Client :: Pipe { .. } => { }
270+ } ;
215271 // Here we basically just want to say that in the child process
216272 // we'll configure the read/write file descriptors to *not* be
217273 // cloexec, so they're inherited across the exec and specified as
218274 // integers through `string_arg` above.
219- let read = self . read . as_raw_fd ( ) ;
220- let write = self . write . as_raw_fd ( ) ;
275+ let read = self . read ( ) . as_raw_fd ( ) ;
276+ let write = self . write ( ) . as_raw_fd ( ) ;
221277 unsafe {
222278 cmd. pre_exec ( move || {
223279 set_cloexec ( read, false ) ?;
0 commit comments