@@ -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,9 @@ 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- }
142- free (req );
144+ if (stream -> type == UV_TTY )
145+ uv_tty_set_mode ((uv_tty_t * )stream , UV_TTY_MODE_NORMAL );
146+ uv_close ((uv_handle_t * )stream , & jl_uv_closeHandle );
143147}
144148
145149static void uv_flush_callback (uv_write_t * req , int status )
@@ -224,47 +228,42 @@ static void jl_proc_exit_cleanup_cb(uv_process_t *process, int64_t exit_status,
224228
225229JL_DLLEXPORT void jl_close_uv (uv_handle_t * handle )
226230{
231+ JL_UV_LOCK ();
227232 if (handle -> type == UV_PROCESS && ((uv_process_t * )handle )-> pid != 0 ) {
228233 // take ownership of this handle,
229234 // so we can waitpid for the resource to exit and avoid leaving zombies
230235 assert (handle -> data == NULL ); // make sure Julia has forgotten about it already
231236 ((uv_process_t * )handle )-> exit_cb = jl_proc_exit_cleanup_cb ;
232- return ;
237+ uv_unref ( handle ) ;
233238 }
234- JL_UV_LOCK ();
235- if (handle -> type == UV_FILE ) {
239+ else if (handle -> type == UV_FILE ) {
236240 uv_fs_t req ;
237241 jl_uv_file_t * fd = (jl_uv_file_t * )handle ;
238242 if ((ssize_t )fd -> file != -1 ) {
239243 uv_fs_close (handle -> loop , & req , fd -> file , NULL );
240244 fd -> file = (uv_os_fd_t )(ssize_t )- 1 ;
241245 }
242246 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 ;
253247 }
254-
255- // avoid double-closing the stream
256- if (!uv_is_closing (handle )) {
257- uv_close (handle , & jl_uv_closeHandle );
248+ else if (!uv_is_closing (handle )) { // avoid double-closing the stream
249+ if (handle -> type == UV_NAMED_PIPE || handle -> type == UV_TCP || handle -> type == UV_TTY ) {
250+ // flush the stream write-queue first
251+ uv_write_t * req = (uv_write_t * )malloc_s (sizeof (uv_write_t ));
252+ req -> handle = (uv_stream_t * )handle ;
253+ jl_uv_flush_close_callback (req , 0 );
254+ }
255+ else {
256+ uv_close (handle , & jl_uv_closeHandle );
257+ }
258258 }
259259 JL_UV_UNLOCK ();
260260}
261261
262262JL_DLLEXPORT void jl_forceclose_uv (uv_handle_t * handle )
263263{
264- // avoid double-closing the stream
265- if (!uv_is_closing (handle )) {
264+ if (!uv_is_closing (handle )) { // avoid double-closing the stream
266265 JL_UV_LOCK ();
267- if (!uv_is_closing (handle )) {
266+ if (!uv_is_closing (handle )) { // double-check
268267 uv_close (handle , & jl_uv_closeHandle );
269268 }
270269 JL_UV_UNLOCK ();
0 commit comments