@@ -61,6 +61,11 @@ static void channel_read(channel_T *channel, int part, char *func);
6161/* Whether a redraw is needed for appending a line to a buffer. */
6262static int channel_need_redraw = FALSE;
6363
64+ /* Whether we are inside channel_parse_messages() or another situation where it
65+ * is safe to invoke callbacks. */
66+ static int safe_to_invoke_callback = 0 ;
67+
68+ static char * part_names [] = {"sock" , "out" , "err" , "in" };
6469
6570#ifdef WIN32
6671 static int
@@ -408,8 +413,15 @@ channel_free(channel_T *channel)
408413{
409414 if (!in_free_unref_items )
410415 {
411- channel_free_contents (channel );
412- channel_free_channel (channel );
416+ if (safe_to_invoke_callback == 0 )
417+ {
418+ channel -> ch_to_be_freed = TRUE;
419+ }
420+ else
421+ {
422+ channel_free_contents (channel );
423+ channel_free_channel (channel );
424+ }
413425 }
414426}
415427
@@ -449,6 +461,10 @@ free_unused_channels_contents(int copyID, int mask)
449461 int did_free = FALSE;
450462 channel_T * ch ;
451463
464+ /* This is invoked from the garbage collector, which only runs at a safe
465+ * point. */
466+ ++ safe_to_invoke_callback ;
467+
452468 for (ch = first_channel ; ch != NULL ; ch = ch -> ch_next )
453469 if (!channel_still_useful (ch )
454470 && (ch -> ch_copyID & mask ) != (copyID & mask ))
@@ -458,6 +474,8 @@ free_unused_channels_contents(int copyID, int mask)
458474 channel_free_contents (ch );
459475 did_free = TRUE;
460476 }
477+
478+ -- safe_to_invoke_callback ;
461479 return did_free ;
462480}
463481
@@ -1073,6 +1091,7 @@ channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
10731091
10741092/*
10751093 * Find a buffer matching "name" or create a new one.
1094+ * Returns NULL if there is something very wrong (error already reported).
10761095 */
10771096 static buf_T *
10781097find_buffer (char_u * name , int err )
@@ -1086,6 +1105,8 @@ find_buffer(char_u *name, int err)
10861105 {
10871106 buf = buflist_new (name == NULL || * name == NUL ? NULL : name ,
10881107 NULL , (linenr_T )0 , BLN_LISTED );
1108+ if (buf == NULL )
1109+ return NULL ;
10891110 buf_copy_options (buf , BCO_ENTER );
10901111 curbuf = buf ;
10911112#ifdef FEAT_QUICKFIX
@@ -1192,37 +1213,54 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
11921213
11931214 if ((opt -> jo_set & JO_OUT_IO ) && opt -> jo_io [PART_OUT ] == JIO_BUFFER )
11941215 {
1216+ buf_T * buf ;
1217+
11951218 /* writing output to a buffer. Default mode is NL. */
11961219 if (!(opt -> jo_set & JO_OUT_MODE ))
11971220 channel -> ch_part [PART_OUT ].ch_mode = MODE_NL ;
11981221 if (opt -> jo_set & JO_OUT_BUF )
1199- channel -> ch_part [PART_OUT ].ch_buffer =
1200- buflist_findnr (opt -> jo_io_buf [PART_OUT ]);
1222+ {
1223+ buf = buflist_findnr (opt -> jo_io_buf [PART_OUT ]);
1224+ if (buf == NULL )
1225+ EMSGN (_ (e_nobufnr ), (long )opt -> jo_io_buf [PART_OUT ]);
1226+ }
12011227 else
1202- channel -> ch_part [PART_OUT ].ch_buffer =
1203- find_buffer (opt -> jo_io_name [PART_OUT ], FALSE);
1204- ch_logs (channel , "writing out to buffer '%s'" ,
1205- (char * )channel -> ch_part [PART_OUT ].ch_buffer -> b_ffname );
1228+ {
1229+ buf = find_buffer (opt -> jo_io_name [PART_OUT ], FALSE);
1230+ }
1231+ if (buf != NULL )
1232+ {
1233+ ch_logs (channel , "writing out to buffer '%s'" ,
1234+ (char * )buf -> b_ffname );
1235+ channel -> ch_part [PART_OUT ].ch_buffer = buf ;
1236+ }
12061237 }
12071238
12081239 if ((opt -> jo_set & JO_ERR_IO ) && (opt -> jo_io [PART_ERR ] == JIO_BUFFER
12091240 || (opt -> jo_io [PART_ERR ] == JIO_OUT && (opt -> jo_set & JO_OUT_IO )
12101241 && opt -> jo_io [PART_OUT ] == JIO_BUFFER )))
12111242 {
1243+ buf_T * buf ;
1244+
12121245 /* writing err to a buffer. Default mode is NL. */
12131246 if (!(opt -> jo_set & JO_ERR_MODE ))
12141247 channel -> ch_part [PART_ERR ].ch_mode = MODE_NL ;
12151248 if (opt -> jo_io [PART_ERR ] == JIO_OUT )
1216- channel -> ch_part [PART_ERR ].ch_buffer =
1217- channel -> ch_part [PART_OUT ].ch_buffer ;
1249+ buf = channel -> ch_part [PART_OUT ].ch_buffer ;
12181250 else if (opt -> jo_set & JO_ERR_BUF )
1219- channel -> ch_part [PART_ERR ].ch_buffer =
1220- buflist_findnr (opt -> jo_io_buf [PART_ERR ]);
1251+ {
1252+ buf = buflist_findnr (opt -> jo_io_buf [PART_ERR ]);
1253+ if (buf == NULL )
1254+ EMSGN (_ (e_nobufnr ), (long )opt -> jo_io_buf [PART_ERR ]);
1255+ }
12211256 else
1222- channel -> ch_part [PART_ERR ].ch_buffer =
1223- find_buffer (opt -> jo_io_name [PART_ERR ], TRUE);
1224- ch_logs (channel , "writing err to buffer '%s'" ,
1225- (char * )channel -> ch_part [PART_ERR ].ch_buffer -> b_ffname );
1257+ buf = find_buffer (opt -> jo_io_name [PART_ERR ], TRUE);
1258+ if (buf != NULL )
1259+ {
1260+ ch_logs (channel , "writing err to buffer '%s'" ,
1261+ (char * )buf -> b_ffname );
1262+ channel -> ch_part [PART_ERR ].ch_buffer = buf ;
1263+ }
12261264 }
12271265
12281266 channel -> ch_part [PART_OUT ].ch_io = opt -> jo_io [PART_OUT ];
@@ -1392,6 +1430,29 @@ channel_write_in(channel_T *channel)
13921430 buf -> b_ml .ml_line_count - lnum + 1 );
13931431}
13941432
1433+ /*
1434+ * Handle buffer "buf" beeing freed, remove it from any channels.
1435+ */
1436+ void
1437+ channel_buffer_free (buf_T * buf )
1438+ {
1439+ channel_T * channel ;
1440+ int part ;
1441+
1442+ for (channel = first_channel ; channel != NULL ; channel = channel -> ch_next )
1443+ for (part = PART_SOCK ; part <= PART_IN ; ++ part )
1444+ {
1445+ chanpart_T * ch_part = & channel -> ch_part [part ];
1446+
1447+ if (ch_part -> ch_buffer == buf )
1448+ {
1449+ ch_logs (channel , "%s buffer has been wiped out" ,
1450+ part_names [part ]);
1451+ ch_part -> ch_buffer = NULL ;
1452+ }
1453+ }
1454+ }
1455+
13951456/*
13961457 * Write any lines waiting to be written to a channel.
13971458 */
@@ -1471,6 +1532,9 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
14711532 typval_T rettv ;
14721533 int dummy ;
14731534
1535+ if (safe_to_invoke_callback == 0 )
1536+ EMSG ("INTERNAL: Invoking callback when it is not safe" );
1537+
14741538 argv [0 ].v_type = VAR_CHANNEL ;
14751539 argv [0 ].vval .v_channel = channel ;
14761540
@@ -2803,7 +2867,8 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
28032867channel_close_on_error (channel_T * channel , char * func )
28042868{
28052869 /* Do not call emsg(), most likely the other end just exited. */
2806- ch_errors (channel , "%s(): Cannot read from channel" , func );
2870+ ch_errors (channel , "%s(): Cannot read from channel, will close it soon" ,
2871+ func );
28072872
28082873 /* Queue a "DETACH" netbeans message in the command queue in order to
28092874 * terminate the netbeans session later. Do not end the session here
@@ -2821,7 +2886,15 @@ channel_close_on_error(channel_T *channel, char *func)
28212886 (int )STRLEN (DETACH_MSG_RAW ), FALSE, "PUT " );
28222887
28232888 /* When reading from stdout is not possible, assume the other side has
2824- * died. */
2889+ * died. Don't close the channel right away, it may be the wrong moment
2890+ * to invoke callbacks. */
2891+ channel -> ch_to_be_closed = TRUE;
2892+ }
2893+
2894+ static void
2895+ channel_close_now (channel_T * channel )
2896+ {
2897+ ch_log (channel , "Closing channel because of previous read error" );
28252898 channel_close (channel , TRUE);
28262899 if (channel -> ch_nb_close_cb != NULL )
28272900 (* channel -> ch_nb_close_cb )();
@@ -3531,6 +3604,8 @@ channel_parse_messages(void)
35313604 int r ;
35323605 int part = PART_SOCK ;
35333606
3607+ ++ safe_to_invoke_callback ;
3608+
35343609 /* Only do this message when another message was given, otherwise we get
35353610 * lots of them. */
35363611 if (did_log_msg )
@@ -3540,6 +3615,21 @@ channel_parse_messages(void)
35403615 }
35413616 while (channel != NULL )
35423617 {
3618+ if (channel -> ch_to_be_closed )
3619+ {
3620+ channel -> ch_to_be_closed = FALSE;
3621+ channel_close_now (channel );
3622+ /* channel may have been freed, start over */
3623+ channel = first_channel ;
3624+ continue ;
3625+ }
3626+ if (channel -> ch_to_be_freed )
3627+ {
3628+ channel_free (channel );
3629+ /* channel has been freed, start over */
3630+ channel = first_channel ;
3631+ continue ;
3632+ }
35433633 if (channel -> ch_refcount == 0 && !channel_still_useful (channel ))
35443634 {
35453635 /* channel is no longer useful, free it */
@@ -3580,6 +3670,8 @@ channel_parse_messages(void)
35803670 redraw_after_callback ();
35813671 }
35823672
3673+ -- safe_to_invoke_callback ;
3674+
35833675 return ret ;
35843676}
35853677
0 commit comments