Patch 8.1.0350
Problem:    Vim may block on ch_sendraw() when the job is sending data back to
            Vim, which isn't read yet. (Nate Bosch)
Solution:   Add the "noblock" option to job_start(). (closes #2548)
Files:      src/channel.c, src/structs.h, src/testdir/test_channel.vim,
            runtime/doc/channel.txt


*** ../vim-8.1.0349/src/channel.c       2018-08-09 22:15:30.042856715 +0200
--- src/channel.c       2018-09-06 16:08:40.193230860 +0200
***************
*** 1180,1185 ****
--- 1180,1186 ----
        channel->ch_part[PART_OUT].ch_mode = opt->jo_out_mode;
      if (opt->jo_set & JO_ERR_MODE)
        channel->ch_part[PART_ERR].ch_mode = opt->jo_err_mode;
+     channel->ch_nonblock = opt->jo_noblock;
  
      if (opt->jo_set & JO_TIMEOUT)
        for (part = PART_SOCK; part < PART_COUNT; ++part)
***************
*** 3677,3683 ****
  channel_set_nonblock(channel_T *channel, ch_part_T part)
  {
      chanpart_T *ch_part = &channel->ch_part[part];
!     int fd = ch_part->ch_fd;
  
      if (fd != INVALID_FD)
      {
--- 3678,3684 ----
  channel_set_nonblock(channel_T *channel, ch_part_T part)
  {
      chanpart_T *ch_part = &channel->ch_part[part];
!     int               fd = ch_part->ch_fd;
  
      if (fd != INVALID_FD)
      {
***************
*** 3722,3727 ****
--- 3723,3731 ----
        return FAIL;
      }
  
+     if (channel->ch_nonblock && !ch_part->ch_nonblocking)
+       channel_set_nonblock(channel, part);
+ 
      if (ch_log_active())
      {
        ch_log_lead("SEND ", channel, part);
***************
*** 4553,4558 ****
--- 4557,4568 ----
                                                                      == FAIL)
                    return FAIL;
            }
+           else if (STRCMP(hi->hi_key, "noblock") == 0)
+           {
+               if (!(supported & JO_MODE))
+                   break;
+               opt->jo_noblock = get_tv_number(item);
+           }
            else if (STRCMP(hi->hi_key, "in_io") == 0
                    || STRCMP(hi->hi_key, "out_io") == 0
                    || STRCMP(hi->hi_key, "err_io") == 0)
*** ../vim-8.1.0349/src/structs.h       2018-06-30 18:27:59.897025143 +0200
--- src/structs.h       2018-09-06 15:30:31.063357009 +0200
***************
*** 1651,1656 ****
--- 1651,1657 ----
      partial_T *ch_close_partial;
      int               ch_drop_never;
      int               ch_keep_open;   /* do not close on read error */
+     int               ch_nonblock;
  
      job_T     *ch_job;        /* Job that uses this channel; this does not
                                 * count as a reference to avoid a circular
***************
*** 1729,1734 ****
--- 1730,1736 ----
      ch_mode_T jo_in_mode;
      ch_mode_T jo_out_mode;
      ch_mode_T jo_err_mode;
+     int               jo_noblock;
  
      job_io_T  jo_io[4];       /* PART_OUT, PART_ERR, PART_IN */
      char_u    jo_io_name_buf[4][NUMBUFLEN];
*** ../vim-8.1.0349/src/testdir/test_channel.vim        2018-04-28 
21:07:37.000000000 +0200
--- src/testdir/test_channel.vim        2018-09-06 16:05:43.771212320 +0200
***************
*** 47,54 ****
--- 47,57 ----
  func Ch_communicate(port)
    " Avoid dropping messages, since we don't use a callback here.
    let s:chopt.drop = 'never'
+   " Also add the noblock flag to try it out.
+   let s:chopt.noblock = 1
    let handle = ch_open('localhost:' . a:port, s:chopt)
    unlet s:chopt.drop
+   unlet s:chopt.noblock
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 451,458 ****
    call ch_log('Test_raw_pipe()')
    " Add a dummy close callback to avoid that messages are dropped when calling
    " ch_canread().
    let job = job_start(s:python . " test_channel_pipe.py",
!       \ {'mode': 'raw', 'drop': 'never'})
    call assert_equal(v:t_job, type(job))
    call assert_equal("run", job_status(job))
  
--- 454,462 ----
    call ch_log('Test_raw_pipe()')
    " Add a dummy close callback to avoid that messages are dropped when calling
    " ch_canread().
+   " Also test the non-blocking option.
    let job = job_start(s:python . " test_channel_pipe.py",
!       \ {'mode': 'raw', 'drop': 'never', 'noblock': 1})
    call assert_equal(v:t_job, type(job))
    call assert_equal("run", job_status(job))
  
***************
*** 1349,1354 ****
--- 1353,1386 ----
  endfunc
  
  """"""""""
+ 
+ function ExitCbWipe(job, status)
+   exe g:wipe_buf 'bw!'
+ endfunction
+ 
+ " This caused a crash, because messages were handled while peeking for a
+ " character.
+ func Test_exit_cb_wipes_buf()
+   if !has('timers')
+     return
+   endif
+   set cursorline lazyredraw
+   call test_override('redraw_flag', 1)
+   new
+   let g:wipe_buf = bufnr('')
+ 
+   let job = job_start(['true'], {'exit_cb': 'ExitCbWipe'})
+   let timer = timer_start(300, {-> feedkeys("\<Esc>", 'nt')}, {'repeat': 5})
+   call feedkeys(repeat('g', 1000) . 'o', 'ntx!')
+   call WaitForAssert({-> assert_equal("dead", job_status(job))})
+   call timer_stop(timer)
+ 
+   set nocursorline nolazyredraw
+   unlet g:wipe_buf
+   call test_override('ALL', 0)
+ endfunc
+ 
+ """"""""""
  
  let g:Ch_unletResponse = ''
  func s:UnletHandler(handle, msg)
*** ../vim-8.1.0349/runtime/doc/channel.txt     2018-06-03 14:42:17.824505143 
+0200
--- runtime/doc/channel.txt     2018-09-06 16:14:07.501586039 +0200
***************
*** 163,168 ****
--- 163,171 ----
                                The "close_cb" is also considered for this.
                    "never"     All messages will be kept.
  
+                                                       *channel-noblock*
+ "noblock"     Same effect as |job-noblock|.  Only matters for writing.
+ 
                                                        *waittime*
  "waittime"    The time to wait for the connection to be made in
                milliseconds.  A negative number waits forever.
***************
*** 594,599 ****
--- 597,613 ----
                        Note: when writing to a file or buffer and when
                        reading from a buffer NL mode is used by default.
  
+                                               *job-noblock*
+ "noblock": 1          When writing use a non-blocking write call.  This
+                       avoids getting stuck if Vim should handle other
+                       messages in between, e.g. when a job sends back data
+                       to Vim.  It implies that when `ch_sendraw()` returns
+                       not all data may have been written yet.
+                       This option was added in patch 8.1.0350, test with: >
+                               if has("patch-8.1.350")
+                                 let options['noblock'] = 1
+                               endif
+ <
                                                *job-callback*
  "callback": handler   Callback for something to read on any part of the
                        channel.
*** ../vim-8.1.0349/src/version.c       2018-09-06 13:14:39.148722497 +0200
--- src/version.c       2018-09-06 16:25:42.981907095 +0200
***************
*** 796,797 ****
--- 796,799 ----
  {   /* Add new patch number below this line */
+ /**/
+     350,
  /**/

-- 
I have a drinking problem -- I can't afford it.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui