@@ -77,14 +77,16 @@ JL_DLLEXPORT void jl_iolock_end(void)
7777}
7878
7979
80- void jl_uv_call_close_callback (jl_value_t * val )
80+ static void jl_uv_call_close_callback (jl_value_t * val )
8181{
82- jl_value_t * args [2 ];
82+ jl_value_t * * args ;
83+ JL_GC_PUSHARGS (args , 2 ); // val is "rooted" in the finalizer list only right now
8384 args [0 ] = jl_get_global (jl_base_relative_to (((jl_datatype_t * )jl_typeof (val ))-> name -> module ),
8485 jl_symbol ("_uv_hook_close" )); // topmod(typeof(val))._uv_hook_close
8586 args [1 ] = val ;
8687 assert (args [0 ]);
8788 jl_apply (args , 2 ); // TODO: wrap in try-catch?
89+ JL_GC_POP ();
8890}
8991
9092static void jl_uv_closeHandle (uv_handle_t * handle )
@@ -105,6 +107,7 @@ static void jl_uv_closeHandle(uv_handle_t *handle)
105107 ct -> world_age = jl_atomic_load_acquire (& jl_world_counter );
106108 jl_uv_call_close_callback ((jl_value_t * )handle -> data );
107109 ct -> world_age = last_age ;
110+ return ;
108111 }
109112 if (handle == (uv_handle_t * )& signal_async )
110113 return ;
@@ -125,6 +128,10 @@ static void jl_uv_flush_close_callback(uv_write_t *req, int status)
125128 free (req );
126129 return ;
127130 }
131+ if (uv_is_closing ((uv_handle_t * )stream )) { // avoid double-close on the stream
132+ free (req );
133+ return ;
134+ }
128135 if (status == 0 && uv_is_writable (stream ) && stream -> write_queue_size != 0 ) {
129136 // new data was written, wait for it to flush too
130137 uv_buf_t buf ;
@@ -134,12 +141,10 @@ static void jl_uv_flush_close_callback(uv_write_t *req, int status)
134141 if (uv_write (req , stream , & buf , 1 , (uv_write_cb )jl_uv_flush_close_callback ) == 0 )
135142 return ; // success
136143 }
137- if (!uv_is_closing ((uv_handle_t * )stream )) { // avoid double-close on the stream
138- if (stream -> type == UV_TTY )
139- uv_tty_set_mode ((uv_tty_t * )stream , UV_TTY_MODE_NORMAL );
140- uv_close ((uv_handle_t * )stream , & jl_uv_closeHandle );
141- }
142144 free (req );
145+ if (stream -> type == UV_TTY )
146+ uv_tty_set_mode ((uv_tty_t * )stream , UV_TTY_MODE_NORMAL );
147+ uv_close ((uv_handle_t * )stream , & jl_uv_closeHandle );
143148}
144149
145150static void uv_flush_callback (uv_write_t * req , int status )
@@ -224,47 +229,42 @@ static void jl_proc_exit_cleanup_cb(uv_process_t *process, int64_t exit_status,
224229
225230JL_DLLEXPORT void jl_close_uv (uv_handle_t * handle )
226231{
232+ JL_UV_LOCK ();
227233 if (handle -> type == UV_PROCESS && ((uv_process_t * )handle )-> pid != 0 ) {
228234 // take ownership of this handle,
229235 // so we can waitpid for the resource to exit and avoid leaving zombies
230236 assert (handle -> data == NULL ); // make sure Julia has forgotten about it already
231237 ((uv_process_t * )handle )-> exit_cb = jl_proc_exit_cleanup_cb ;
232- return ;
238+ uv_unref ( handle ) ;
233239 }
234- JL_UV_LOCK ();
235- if (handle -> type == UV_FILE ) {
240+ else if (handle -> type == UV_FILE ) {
236241 uv_fs_t req ;
237242 jl_uv_file_t * fd = (jl_uv_file_t * )handle ;
238243 if ((ssize_t )fd -> file != -1 ) {
239244 uv_fs_close (handle -> loop , & req , fd -> file , NULL );
240245 fd -> file = (uv_os_fd_t )(ssize_t )- 1 ;
241246 }
242247 jl_uv_closeHandle (handle ); // synchronous (ok since the callback is known to not interact with any global state)
243- JL_UV_UNLOCK ();
244- return ;
245- }
246-
247- if (handle -> type == UV_NAMED_PIPE || handle -> type == UV_TCP || handle -> type == UV_TTY ) {
248- uv_write_t * req = (uv_write_t * )malloc_s (sizeof (uv_write_t ));
249- req -> handle = (uv_stream_t * )handle ;
250- jl_uv_flush_close_callback (req , 0 );
251- JL_UV_UNLOCK ();
252- return ;
253248 }
254-
255- // avoid double-closing the stream
256- if (!uv_is_closing (handle )) {
257- uv_close (handle , & jl_uv_closeHandle );
249+ else if (!uv_is_closing (handle )) { // avoid double-closing the stream
250+ if (handle -> type == UV_NAMED_PIPE || handle -> type == UV_TCP || handle -> type == UV_TTY ) {
251+ // flush the stream write-queue first
252+ uv_write_t * req = (uv_write_t * )malloc_s (sizeof (uv_write_t ));
253+ req -> handle = (uv_stream_t * )handle ;
254+ jl_uv_flush_close_callback (req , 0 );
255+ }
256+ else {
257+ uv_close (handle , & jl_uv_closeHandle );
258+ }
258259 }
259260 JL_UV_UNLOCK ();
260261}
261262
262263JL_DLLEXPORT void jl_forceclose_uv (uv_handle_t * handle )
263264{
264- // avoid double-closing the stream
265- if (!uv_is_closing (handle )) {
265+ if (!uv_is_closing (handle )) { // avoid double-closing the stream
266266 JL_UV_LOCK ();
267- if (!uv_is_closing (handle )) {
267+ if (!uv_is_closing (handle )) { // double-check
268268 uv_close (handle , & jl_uv_closeHandle );
269269 }
270270 JL_UV_UNLOCK ();
0 commit comments