]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.5118: MS-Windows: sending a message to another Vim may hang v8.2.5118
authorK.Takata <kentkt@csc.jp>
Fri, 17 Jun 2022 19:05:40 +0000 (20:05 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 17 Jun 2022 19:05:40 +0000 (20:05 +0100)
Problem:    MS-Windows: sending a message to another Vim may hang if that Vim
            is halted.
Solution:   Add a timeout to serverSendToVim(). (Ken Takata, closes #10585)

runtime/pack/dist/opt/editexisting/plugin/editexisting.vim
src/os_mswin.c
src/version.c

index d9877a0591628287fb7f273a8123c9c56457f9da..5eda29047d5b7dd8e55595bfd1a9a2fb9715bbab 100644 (file)
@@ -1,6 +1,6 @@
 " Vim Plugin:  Edit the file with an existing Vim if possible
 " Maintainer:  Bram Moolenaar
-" Last Change: 2016 Mar 28
+" Last Change: 2022 Jun 17
 
 " To use add ":packadd! editexisting" in your vimrc file.
 
@@ -35,32 +35,36 @@ func s:EditElsewhere(filename)
     endif
 
     " Check if this server is editing our file.
-    if remote_expr(servername, "bufloaded('" . fname_esc . "')")
-      " Yes, bring it to the foreground.
-      if has("win32")
-       call remote_foreground(servername)
-      endif
-      call remote_expr(servername, "foreground()")
+    try
+      if remote_expr(servername, "bufloaded('" . fname_esc . "')")
+       " Yes, bring it to the foreground.
+       if has("win32")
+         call remote_foreground(servername)
+       endif
+       call remote_expr(servername, "foreground()")
 
-      if remote_expr(servername, "exists('*EditExisting')")
-       " Make sure the file is visible in a window (not hidden).
-       " If v:swapcommand exists and is set, send it to the server.
-       if exists("v:swapcommand")
-         let c = substitute(v:swapcommand, "'", "''", "g")
-         call remote_expr(servername, "EditExisting('" . fname_esc . "', '" . c . "')")
-       else
-         call remote_expr(servername, "EditExisting('" . fname_esc . "', '')")
+       if remote_expr(servername, "exists('*EditExisting')")
+         " Make sure the file is visible in a window (not hidden).
+         " If v:swapcommand exists and is set, send it to the server.
+         if exists("v:swapcommand")
+           let c = substitute(v:swapcommand, "'", "''", "g")
+           call remote_expr(servername, "EditExisting('" . fname_esc . "', '" . c . "')")
+         else
+           call remote_expr(servername, "EditExisting('" . fname_esc . "', '')")
+         endif
        endif
-      endif
 
-      if !(has('vim_starting') && has('gui_running') && has('gui_win32'))
-       " Tell the user what is happening.  Not when the GUI is starting
-       " though, it would result in a message box.
-       echomsg "File is being edited by " . servername
-       sleep 2
+       if !(has('vim_starting') && has('gui_running') && has('gui_win32'))
+         " Tell the user what is happening.  Not when the GUI is starting
+         " though, it would result in a message box.
+         echomsg "File is being edited by " . servername
+         sleep 2
+       endif
+       return 'q'
       endif
-      return 'q'
-    endif
+    catch /^Vim\%((\a\+)\)\=:E241:/
+      " Unable to send to this server, ignore it.
+    endtry
   endwhile
   return ''
 endfunc
index 448b2bf29c7ffdec3442831b447e62470946f1cb..256da045800e88d38e95004506247465b0521fb8 100644 (file)
@@ -1971,6 +1971,10 @@ HWND message_window = 0;     // window that's handling messages
 # define VIM_CLASSNAME      "VIM_MESSAGES"
 # define VIM_CLASSNAME_LEN  (sizeof(VIM_CLASSNAME) - 1)
 
+// Timeout for sending a message to another Vim instance.  Normally this works
+// instantly, but it may hang when the other Vim instance is halted.
+# define SENDMESSAGE_TIMEOUT   (5 * 1000)
+
 // Communication is via WM_COPYDATA messages. The message type is sent in
 // the dwData parameter. Types are defined here.
 # define COPYDATA_KEYS         0
@@ -1992,9 +1996,9 @@ static char_u     *client_enc = NULL;
 
 /*
  * Tell the other side what encoding we are using.
- * Errors are ignored.
+ * Return -1 if timeout happens.  Other errors are ignored.
  */
-    static void
+    static int
 serverSendEnc(HWND target)
 {
     COPYDATASTRUCT data;
@@ -2002,8 +2006,11 @@ serverSendEnc(HWND target)
     data.dwData = COPYDATA_ENCODING;
     data.cbData = (DWORD)STRLEN(p_enc) + 1;
     data.lpData = p_enc;
-    (void)SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
-                                                            (LPARAM)(&data));
+    if (SendMessageTimeout(target, WM_COPYDATA,
+           (WPARAM)message_window, (LPARAM)&data,
+           SMTO_ABORTIFHUNG, SENDMESSAGE_TIMEOUT, NULL) == 0)
+       return -1;
+    return 0;
 }
 
 /*
@@ -2061,6 +2068,7 @@ Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
        COPYDATASTRUCT  reply;
        char_u          *res;
        int             retval;
+       DWORD_PTR       dwret = 0;
        char_u          *str;
        char_u          *tofree;
 
@@ -2114,9 +2122,17 @@ Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
            reply.lpData = res;
            reply.cbData = (DWORD)STRLEN(res) + 1;
 
-           serverSendEnc(sender);
-           retval = (int)SendMessage(sender, WM_COPYDATA,
-                                   (WPARAM)message_window, (LPARAM)(&reply));
+           if (serverSendEnc(sender) < 0)
+               retval = -1;
+           else
+           {
+               if (SendMessageTimeout(sender, WM_COPYDATA,
+                       (WPARAM)message_window, (LPARAM)&reply,
+                       SMTO_ABORTIFHUNG, SENDMESSAGE_TIMEOUT, &dwret) == 0)
+                   retval = -1;
+               else
+                   retval = (int)dwret;
+           }
            vim_free(tofree);
            vim_free(res);
            return retval;
@@ -2394,6 +2410,7 @@ serverSendReply(
     HWND       target;
     COPYDATASTRUCT data;
     long_u     n = 0;
+    DWORD_PTR  dwret = 0;
 
     // The "name" argument is a magic cookie obtained from expand("<client>").
     // It should be of the form 0xXXXXX - i.e. a C hex literal, which is the
@@ -2410,12 +2427,13 @@ serverSendReply(
     data.cbData = (DWORD)STRLEN(reply) + 1;
     data.lpData = reply;
 
-    serverSendEnc(target);
-    if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
-                                                            (LPARAM)(&data)))
-       return 0;
-
-    return -1;
+    if (serverSendEnc(target) < 0)
+       return -1;
+    if (SendMessageTimeout(target, WM_COPYDATA,
+               (WPARAM)message_window, (LPARAM)&data,
+               SMTO_ABORTIFHUNG, SENDMESSAGE_TIMEOUT, &dwret) == 0)
+       return -1;
+    return dwret ? 0 : -1;
 }
 
     int
@@ -2432,6 +2450,7 @@ serverSendToVim(
     COPYDATASTRUCT data;
     char_u     *retval = NULL;
     int                retcode = 0;
+    DWORD_PTR  dwret = 0;
     char_u     altname_buf[MAX_PATH];
 
     // Execute locally if no display or target is ourselves
@@ -2463,9 +2482,13 @@ serverSendToVim(
     data.cbData = (DWORD)STRLEN(cmd) + 1;
     data.lpData = cmd;
 
-    serverSendEnc(target);
-    if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
-                                                       (LPARAM)(&data)) == 0)
+    if (serverSendEnc(target) < 0)
+       return -1;
+    if (SendMessageTimeout(target, WM_COPYDATA,
+               (WPARAM)message_window, (LPARAM)&data,
+               SMTO_ABORTIFHUNG, SENDMESSAGE_TIMEOUT, &dwret) == 0)
+       return -1;
+    if (dwret == 0)
        return -1;
 
     if (asExpr)
index 1b6fd289333df6818034ca12df7b074fb42c38be..6ea4a379eb1191c2c65412d5bf1a111fd2878af2 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    5118,
 /**/
     5117,
 /**/