changeset 29198:2e6c9df8bea1 v8.2.5118

patch 8.2.5118: MS-Windows: sending a message to another Vim may hang Commit: https://github.com/vim/vim/commit/f9f2a330b961fe1623d428b61afdc52f0af0a666 Author: K.Takata <kentkt@csc.jp> Date: Fri Jun 17 20:05:40 2022 +0100 patch 8.2.5118: MS-Windows: sending a message to another Vim may hang 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)
author Bram Moolenaar <Bram@vim.org>
date Fri, 17 Jun 2022 21:15:03 +0200
parents d2d4cfebc668
children a93c1596c799
files runtime/pack/dist/opt/editexisting/plugin/editexisting.vim src/os_mswin.c src/version.c
diffstat 3 files changed, 69 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim
+++ b/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim
@@ -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
+
+	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
-
-      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
+    catch /^Vim\%((\a\+)\)\=:E241:/
+      " Unable to send to this server, ignore it.
+    endtry
   endwhile
   return ''
 endfunc
--- a/src/os_mswin.c
+++ b/src/os_mswin.c
@@ -1971,6 +1971,10 @@ HWND message_window = 0;	    // window t
 # 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, W
 	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, W
 	    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)
--- a/src/version.c
+++ b/src/version.c
@@ -735,6 +735,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    5118,
+/**/
     5117,
 /**/
     5116,