Skip to content

Commit ae529b5

Browse files
committed
Merge remote-tracking branch 'vim/master'
2 parents 949fc40 + de7eb0a commit ae529b5

File tree

5 files changed

+127
-18
lines changed

5 files changed

+127
-18
lines changed

src/buffer.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ free_buffer(buf_T *buf)
680680
#ifdef FEAT_RUBY
681681
ruby_buffer_free(buf);
682682
#endif
683+
#ifdef FEAT_JOB_CHANNEL
684+
channel_buffer_free(buf);
685+
#endif
683686
#ifdef FEAT_AUTOCMD
684687
aubuflocal_remove(buf);
685688
if (autocmd_busy)

src/channel.c

Lines changed: 110 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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. */
6262
static 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 *
10781097
find_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)
28032867
channel_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

src/proto/channel.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
1414
void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
1515
void channel_set_options(channel_T *channel, jobopt_T *opt);
1616
void channel_set_req_callback(channel_T *channel, int part, char_u *callback, partial_T *partial, int id);
17+
void channel_buffer_free(buf_T *buf);
1718
void channel_write_any_lines(void);
1819
void channel_write_new_lines(buf_T *buf);
1920
char_u *channel_get(channel_T *channel, int part);

src/structs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,11 @@ struct channel_S {
14191419
char *ch_hostname; /* only for socket, allocated */
14201420
int ch_port; /* only for socket */
14211421

1422+
int ch_to_be_closed; /* When TRUE reading or writing failed and
1423+
* the channel must be closed when it's safe
1424+
* to invoke callbacks. */
1425+
int ch_to_be_freed; /* When TRUE channel must be freed when it's
1426+
* safe to invoke callbacks. */
14221427
int ch_error; /* When TRUE an error was reported. Avoids
14231428
* giving pages full of error messages when
14241429
* the other side has exited, only mention the

src/version.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,14 @@ static char *(features[]) =
768768

769769
static int included_patches[] =
770770
{ /* Add new patch number below this line */
771+
/**/
772+
1829,
773+
/**/
774+
1828,
775+
/**/
776+
1827,
777+
/**/
778+
1826,
771779
/**/
772780
1825,
773781
/**/

0 commit comments

Comments
 (0)