# HG changeset patch # User Bram Moolenaar # Date 1655493303 -7200 # Node ID 2e6c9df8bea1de692a167005f1eee3e0fcd7ad50 # Parent d2d4cfebc668bb32529409668ef8eb0b33d1f214 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 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) diff --git a/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim b/runtime/pack/dist/opt/editexisting/plugin/editexisting.vim --- 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 diff --git a/src/os_mswin.c b/src/os_mswin.c --- 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(""). // 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) diff --git a/src/version.c b/src/version.c --- 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,