11use crate :: io:: { self , BorrowedCursor , IoSlice , IoSliceMut } ;
22use crate :: ops:: Neg ;
33use crate :: os:: windows:: prelude:: * ;
4+ use crate :: sync:: atomic:: Atomic ;
5+ use crate :: sync:: atomic:: Ordering :: Relaxed ;
46use crate :: sys:: handle:: Handle ;
57use crate :: sys:: { FromInner , IntoInner , api, c} ;
68use crate :: { mem, ptr} ;
@@ -70,10 +72,19 @@ pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) ->
7072 let mut object_attributes = c:: OBJECT_ATTRIBUTES :: default ( ) ;
7173 object_attributes. Length = size_of :: < c:: OBJECT_ATTRIBUTES > ( ) as u32 ;
7274
73- // Open a handle to the pipe filesystem (`\??\PIPE\`).
74- // This will be used when creating a new annon pipe.
75- let pipe_fs = {
76- let path = api:: unicode_str!( r"\??\PIPE\" ) ;
75+ // Open a handle to the pipe filesystem (`\Device\NamedPipe\`).
76+ // This will be used when creating a new anonymous pipe.
77+ //
78+ // We cache the handle once so we can reuse it without needing to reopen it each time.
79+ // NOTE: this means the handle may appear to be leaked but that's fine because
80+ // it's only one handle and the OS will clean it up when the process exits.
81+ static PIPE_FS : Atomic < c:: HANDLE > = Atomic :: < c:: HANDLE > :: new ( ptr:: null_mut ( ) ) ;
82+ let pipe_fs = if let handle = PIPE_FS . load ( Relaxed )
83+ && !handle. is_null ( )
84+ {
85+ handle
86+ } else {
87+ let path = api:: unicode_str!( r"\Device\NamedPipe\" ) ;
7788 object_attributes. ObjectName = path. as_ptr ( ) ;
7889 let mut pipe_fs = ptr:: null_mut ( ) ;
7990 let status = c:: NtOpenFile (
@@ -85,7 +96,13 @@ pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) ->
8596 c:: FILE_SYNCHRONOUS_IO_NONALERT , // synchronous access
8697 ) ;
8798 if c:: nt_success ( status) {
88- Handle :: from_raw_handle ( pipe_fs)
99+ match PIPE_FS . compare_exchange ( ptr:: null_mut ( ) , pipe_fs, Relaxed , Relaxed ) {
100+ Ok ( _) => pipe_fs,
101+ Err ( existing) => {
102+ c:: CloseHandle ( pipe_fs) ;
103+ existing
104+ }
105+ }
89106 } else {
90107 return Err ( io:: Error :: from_raw_os_error ( c:: RtlNtStatusToDosError ( status) as i32 ) ) ;
91108 }
@@ -104,7 +121,7 @@ pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) ->
104121 let ours = {
105122 // Use the pipe filesystem as the root directory.
106123 // With no name provided, an anonymous pipe will be created.
107- object_attributes. RootDirectory = pipe_fs. as_raw_handle ( ) ;
124+ object_attributes. RootDirectory = pipe_fs;
108125
109126 // A negative timeout value is a relative time (rather than an absolute time).
110127 // The time is given in 100's of nanoseconds so this is 50 milliseconds.
0 commit comments