@@ -74,27 +74,29 @@ const SpawnIOs = Vector{Any} # convenience name for readability
74
74
# handle marshalling of `Cmd` arguments from Julia to C
75
75
@noinline function _spawn_primitive (file, cmd:: Cmd , stdio:: SpawnIOs )
76
76
loop = eventloop ()
77
- iohandles = Tuple{Cint, UInt}[ # assuming little-endian layout
78
- let h = rawhandle (io)
79
- h === C_NULL ? (0x00 , UInt (0 )) :
80
- h isa OS_HANDLE ? (0x02 , UInt (cconvert (@static (Sys. iswindows () ? Ptr{Cvoid} : Cint), h))) :
81
- h isa Ptr{Cvoid} ? (0x04 , UInt (h)) :
82
- error (" invalid spawn handle $h from $io " )
83
- end
84
- for io in stdio]
85
- handle = Libc. malloc (_sizeof_uv_process)
86
- disassociate_julia_struct (handle) # ensure that data field is set to C_NULL
87
- (; exec, flags, env, dir) = cmd
88
- err = ccall (:jl_spawn , Int32,
89
- (Cstring, Ptr{Cstring}, Ptr{Cvoid}, Ptr{Cvoid},
90
- Ptr{Tuple{Cint, UInt}}, Int,
91
- UInt32, Ptr{Cstring}, Cstring, Ptr{Cvoid}),
92
- file, exec, loop, handle,
93
- iohandles, length (iohandles),
94
- flags,
95
- env === nothing ? C_NULL : env,
96
- isempty (dir) ? C_NULL : dir,
97
- @cfunction (uv_return_spawn, Cvoid, (Ptr{Cvoid}, Int64, Int32)))
77
+ GC. @preserve stdio begin
78
+ iohandles = Tuple{Cint, UInt}[ # assuming little-endian layout
79
+ let h = rawhandle (io)
80
+ h === C_NULL ? (0x00 , UInt (0 )) :
81
+ h isa OS_HANDLE ? (0x02 , UInt (cconvert (@static (Sys. iswindows () ? Ptr{Cvoid} : Cint), h))) :
82
+ h isa Ptr{Cvoid} ? (0x04 , UInt (h)) :
83
+ error (" invalid spawn handle $h from $io " )
84
+ end
85
+ for io in stdio]
86
+ handle = Libc. malloc (_sizeof_uv_process)
87
+ disassociate_julia_struct (handle) # ensure that data field is set to C_NULL
88
+ (; exec, flags, env, dir) = cmd
89
+ err = ccall (:jl_spawn , Int32,
90
+ (Cstring, Ptr{Cstring}, Ptr{Cvoid}, Ptr{Cvoid},
91
+ Ptr{Tuple{Cint, UInt}}, Int,
92
+ UInt32, Ptr{Cstring}, Cstring, Ptr{Cvoid}),
93
+ file, exec, loop, handle,
94
+ iohandles, length (iohandles),
95
+ flags,
96
+ env === nothing ? C_NULL : env,
97
+ isempty (dir) ? C_NULL : dir,
98
+ @cfunction (uv_return_spawn, Cvoid, (Ptr{Cvoid}, Int64, Int32)))
99
+ end
98
100
if err != 0
99
101
ccall (:jl_forceclose_uv , Cvoid, (Ptr{Cvoid},), handle) # will call free on handle eventually
100
102
throw (_UVError (" could not spawn " * repr (cmd), err))
@@ -210,10 +212,10 @@ function setup_stdio(stdio::PipeEndpoint, child_readable::Bool)
210
212
rd, wr = link_pipe (! child_readable, child_readable)
211
213
try
212
214
open_pipe! (stdio, child_readable ? wr : rd)
213
- catch ex
215
+ catch
214
216
close_pipe_sync (rd)
215
217
close_pipe_sync (wr)
216
- rethrow (ex )
218
+ rethrow ()
217
219
end
218
220
child = child_readable ? rd : wr
219
221
return (child, true )
@@ -252,18 +254,19 @@ function setup_stdio(stdio::FileRedirect, child_readable::Bool)
252
254
return (io, true )
253
255
end
254
256
255
- # incrementally move data between an IOBuffer and a system Pipe
257
+ # incrementally move data between an arbitrary IO and a system Pipe,
258
+ # including copying the EOF (shutdown) when finished
256
259
# TODO : probably more efficient (when valid) to use `stdio` directly as the
257
260
# PipeEndpoint buffer field in some cases
258
- function setup_stdio (stdio:: Union{IOBuffer, BufferStream} , child_readable:: Bool )
261
+ function setup_stdio (stdio:: IO , child_readable:: Bool )
259
262
parent = PipeEndpoint ()
260
263
rd, wr = link_pipe (! child_readable, child_readable)
261
264
try
262
265
open_pipe! (parent, child_readable ? wr : rd)
263
- catch ex
266
+ catch
264
267
close_pipe_sync (rd)
265
268
close_pipe_sync (wr)
266
- rethrow (ex )
269
+ rethrow ()
267
270
end
268
271
child = child_readable ? rd : wr
269
272
try
@@ -272,25 +275,19 @@ function setup_stdio(stdio::Union{IOBuffer, BufferStream}, child_readable::Bool)
272
275
@async try
273
276
write (in, out)
274
277
catch ex
275
- @warn " Process error" exception= (ex, catch_backtrace ())
278
+ @warn " Process I/O error" exception= (ex, catch_backtrace ())
276
279
finally
277
280
close (parent)
278
281
child_readable || closewrite (stdio)
279
282
end
280
283
end
281
- catch ex
284
+ catch
282
285
close_pipe_sync (child)
283
- rethrow (ex )
286
+ rethrow ()
284
287
end
285
288
return (child, true )
286
289
end
287
290
288
- function setup_stdio (io, child_readable:: Bool )
289
- # if there is no specialization,
290
- # assume that rawhandle is defined for it
291
- return (io, false )
292
- end
293
-
294
291
close_stdio (stdio:: OS_HANDLE ) = close_pipe_sync (stdio)
295
292
close_stdio (stdio) = close (stdio)
296
293
0 commit comments