patch 7.4.1422 v7.4.1422
authorBram Moolenaar <Bram@vim.org>
Fri, 26 Feb 2016 10:17:46 +0000 (11:17 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 26 Feb 2016 10:17:46 +0000 (11:17 +0100)
Problem:    Error when reading fails uses wrong errno.  Keeping channel open
            after job stops results in test failing.
Solution:   Move the error up.  Add ch_job_killed.

src/channel.c
src/eval.c
src/structs.h
src/version.c

index 4a2b20c442ca334245a6c39c1643e1069bcbc695..03dbdc30175ecba4612b6a6c5f4b2ec08d953532 100644 (file)
@@ -307,11 +307,14 @@ add_channel(void)
 }
 
 /*
- * Return TRUE if "channel" has a callback.
+ * Return TRUE if "channel" has a callback and the associated job wasn't
+ * killed.
  */
     static int
-channel_has_callback(channel_T *channel)
+channel_still_useful(channel_T *channel)
 {
+    if (channel->ch_job_killed && channel->ch_job == NULL)
+       return FALSE;
     return channel->ch_callback != NULL
 #ifdef CHANNEL_PIPES
            || channel->ch_part[PART_OUT].ch_callback != NULL
@@ -322,12 +325,13 @@ channel_has_callback(channel_T *channel)
 
 /*
  * Close a channel and free all its resources if there is no further action
- * possible, there is no callback to be invoked.
+ * possible, there is no callback to be invoked or the associated job was
+ * killed.
  */
     void
 channel_may_free(channel_T *channel)
 {
-    if (!channel_has_callback(channel))
+    if (!channel_still_useful(channel))
        channel_free(channel);
 }
 
@@ -1774,6 +1778,12 @@ channel_read(channel_T *channel, int part, char *func)
         *                      -> channel_read()
         */
        ch_errors(channel, "%s(): Cannot read", func);
+       if (len < 0)
+       {
+           ch_error(channel, "channel_read(): cannot read from channel");
+           PERROR(_("E896: read from channel"));
+       }
+
        msg = channel->ch_part[part].ch_mode == MODE_RAW
                                  || channel->ch_part[part].ch_mode == MODE_NL
                    ? DETACH_MSG_RAW : DETACH_MSG_JSON;
@@ -1785,12 +1795,6 @@ channel_read(channel_T *channel, int part, char *func)
        channel_close(channel, TRUE);
        if (channel->ch_nb_close_cb != NULL)
            (*channel->ch_nb_close_cb)();
-
-       if (len < 0)
-       {
-           ch_error(channel, "channel_read(): cannot read from channel");
-           PERROR(_("E896: read from channel"));
-       }
     }
 
 #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
@@ -2174,7 +2178,7 @@ channel_parse_messages(void)
 
     while (channel != NULL)
     {
-       if (channel->ch_refcount == 0 && !channel_has_callback(channel))
+       if (channel->ch_refcount == 0 && !channel_still_useful(channel))
        {
            /* channel is no longer useful, free it */
            channel_free(channel);
index 0db6cfac535ebb3290782be25d8eea53789a07c5..f9e85178bf3d34835259b97373bc3e06d0b550e7 100644 (file)
@@ -7770,8 +7770,11 @@ job_free(job_T *job)
 # ifdef FEAT_CHANNEL
     if (job->jv_channel != NULL)
     {
-       /* The channel doesn't count as a references for the job, we need to
-        * NULL the reference when the job is freed. */
+       /* The link from the channel to the job doesn't count as a reference,
+        * thus don't decrement the refcount of the job.  The reference from
+        * the job to the channel does count the refrence, decrement it and
+        * NULL the reference.  We don't set ch_job_killed, unreferencing the
+        * job doesn't mean it stops running. */
        job->jv_channel->ch_job = NULL;
        channel_unref(job->jv_channel);
     }
@@ -15161,7 +15164,14 @@ f_job_stop(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
        if (mch_stop_job(job, arg) == FAIL)
            rettv->vval.v_number = 0;
        else
+       {
            rettv->vval.v_number = 1;
+           /* Assume that "hup" does not kill the job. */
+           if (job->jv_channel != NULL && STRCMP(arg, "hup") != 0)
+               job->jv_channel->ch_job_killed = TRUE;
+       }
+       /* We don't try freeing the job, obviously the caller still has a
+        * reference to it. */
     }
 }
 #endif
index 5f70c732b6637aa83c7ac2cb5e1bc7472c5f3000..c0339de81c207bdced3fc80cde4b5459372dd1e7 100644 (file)
@@ -1373,6 +1373,8 @@ struct channel_S {
     job_T      *ch_job;        /* Job that uses this channel; this does not
                                 * count as a reference to avoid a circular
                                 * reference. */
+    int                ch_job_killed;  /* TRUE when there was a job and it was killed
+                                * or we know it died. */
 
     int                ch_refcount;    /* reference count */
 };
index 42200012a4420633eba2dc3a35b05b2c4c12e3c0..08c8c1a8ed244ad0df3d9ccb99b0c85c1f2657cd 100644 (file)
@@ -748,6 +748,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1422,
 /**/
     1421,
 /**/