Skip to content

Commit fdd6ce4

Browse files
committed
patch 7.4.1458
Problem: When a JSON channel has a callback it may never be cleared. Solution: Do not write "DETACH" into a JS or JSON channel.
1 parent d42119f commit fdd6ce4

File tree

2 files changed

+42
-14
lines changed

2 files changed

+42
-14
lines changed

src/channel.c

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -316,20 +316,47 @@ add_channel(void)
316316
* Called when the refcount of a channel is zero.
317317
* Return TRUE if "channel" has a callback and the associated job wasn't
318318
* killed.
319-
* If the job was killed the channel is not expected to work anymore.
320-
* If there is no callback then nobody can get readahead.
321319
*/
322320
static int
323321
channel_still_useful(channel_T *channel)
324322
{
323+
int has_sock_msg;
324+
#ifdef CHANNEL_PIPES
325+
int has_out_msg;
326+
int has_err_msg;
327+
#endif
328+
329+
/* If the job was killed the channel is not expected to work anymore. */
325330
if (channel->ch_job_killed && channel->ch_job == NULL)
326331
return FALSE;
327-
return channel->ch_callback != NULL
332+
333+
/* If there is a close callback it may still need to be invoked. */
334+
if (channel->ch_close_cb != NULL)
335+
return TRUE;
336+
337+
/* If there is no callback then nobody can get readahead. If the fd is
338+
* closed and there is no readahead then the callback won't be called. */
339+
has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD
340+
|| channel->ch_part[PART_SOCK].ch_head.rq_next != NULL
341+
|| channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL;
342+
#ifdef CHANNEL_PIPES
343+
has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD
344+
|| channel->ch_part[PART_OUT].ch_head.rq_next != NULL
345+
|| channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL;
346+
has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
347+
|| channel->ch_part[PART_ERR].ch_head.rq_next != NULL
348+
|| channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
349+
#endif
350+
return (channel->ch_callback != NULL && (has_sock_msg
351+
#ifdef CHANNEL_PIPES
352+
|| has_out_msg || has_err_msg
353+
#endif
354+
))
328355
#ifdef CHANNEL_PIPES
329-
|| channel->ch_part[PART_OUT].ch_callback != NULL
330-
|| channel->ch_part[PART_ERR].ch_callback != NULL
356+
|| (channel->ch_part[PART_OUT].ch_callback != NULL && has_out_msg)
357+
|| (channel->ch_part[PART_ERR].ch_callback != NULL && has_err_msg)
331358
#endif
332-
|| channel->ch_close_cb != NULL;
359+
;
333360
}
334361

335362
/*
@@ -1497,7 +1524,7 @@ may_invoke_callback(channel_T *channel, int part)
14971524
{
14981525
if (item->cq_seq_nr == seq_nr)
14991526
{
1500-
ch_logs(channel, "Invoking one-time callback '%s'",
1527+
ch_logs(channel, "Invoking one-time callback %s",
15011528
(char *)item->cq_callback);
15021529
/* Remove the item from the list first, if the callback
15031530
* invokes ch_close() the list will be cleared. */
@@ -1558,7 +1585,7 @@ may_invoke_callback(channel_T *channel, int part)
15581585
if (callback != NULL)
15591586
{
15601587
/* invoke the channel callback */
1561-
ch_log(channel, "Invoking channel callback");
1588+
ch_logs(channel, "Invoking channel callback %s", (char *)callback);
15621589
invoke_callback(channel, callback, argv);
15631590
}
15641591
}
@@ -1758,7 +1785,6 @@ channel_free_all(void)
17581785

17591786
/* Sent when the channel is found closed when reading. */
17601787
#define DETACH_MSG_RAW "DETACH\n"
1761-
#define DETACH_MSG_JSON "\"DETACH\"\n"
17621788

17631789
/* Buffer size for reading incoming messages. */
17641790
#define MAXMSGSIZE 4096
@@ -1854,7 +1880,6 @@ channel_read(channel_T *channel, int part, char *func)
18541880
int readlen = 0;
18551881
sock_T fd;
18561882
int use_socket = FALSE;
1857-
char *msg;
18581883

18591884
fd = channel->ch_part[part].ch_fd;
18601885
if (fd == INVALID_FD)
@@ -1909,11 +1934,12 @@ channel_read(channel_T *channel, int part, char *func)
19091934
* -> ui_breakcheck
19101935
* -> gui event loop or select loop
19111936
* -> channel_read()
1937+
* Don't send "DETACH" for a JS or JSON channel.
19121938
*/
1913-
msg = channel->ch_part[part].ch_mode == MODE_RAW
1914-
|| channel->ch_part[part].ch_mode == MODE_NL
1915-
? DETACH_MSG_RAW : DETACH_MSG_JSON;
1916-
channel_save(channel, part, (char_u *)msg, (int)STRLEN(msg));
1939+
if (channel->ch_part[part].ch_mode == MODE_RAW
1940+
|| channel->ch_part[part].ch_mode == MODE_NL)
1941+
channel_save(channel, part, (char_u *)DETACH_MSG_RAW,
1942+
(int)STRLEN(DETACH_MSG_RAW));
19171943

19181944
/* TODO: When reading from stdout is not possible, should we try to
19191945
* keep stdin and stderr open? Probably not, assume the other side

src/version.c

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

744744
static int included_patches[] =
745745
{ /* Add new patch number below this line */
746+
/**/
747+
1458,
746748
/**/
747749
1457,
748750
/**/

0 commit comments

Comments
 (0)