0
0
mirror of https://github.com/vim/vim.git synced 2025-09-27 04:14:06 -04:00

patch 7.4.866

Problem:    Crash when changing the 'tags' option from a remote command.
            (Benjamin Fritz)
Solution:   Instead of executing messages immediately, use a queue, like for
            netbeans. (James Kolb)
This commit is contained in:
Bram Moolenaar
2015-09-15 14:12:05 +02:00
parent ed84b76021
commit 93c88e0f6a
12 changed files with 185 additions and 58 deletions

View File

@@ -9033,11 +9033,11 @@ do_sleep(msec)
{ {
ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE); ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE);
ui_breakcheck(); ui_breakcheck();
#ifdef FEAT_NETBEANS_INTG #ifdef MESSAGE_QUEUE
/* Process the netbeans messages that may have been received in the /* Process the netbeans and clientserver messages that may have been
* call to ui_breakcheck() when the GUI is in use. This may occur when * received in the call to ui_breakcheck() when the GUI is in use. This
* running a test case. */ * may occur when running a test case. */
netbeans_parse_messages(); parse_queued_messages();
#endif #endif
} }
} }

View File

@@ -3034,9 +3034,8 @@ inchar(buf, maxlen, wait_time, tb_change_cnt)
) )
{ {
#if defined(FEAT_NETBEANS_INTG) #ifdef MESSAGE_QUEUE
/* Process the queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
if (got_int || (script_char = getc(scriptin[curscript])) < 0) if (got_int || (script_char = getc(scriptin[curscript])) < 0)

View File

@@ -650,7 +650,7 @@ property_event(GtkWidget *widget,
xev.xproperty.atom = commProperty; xev.xproperty.atom = commProperty;
xev.xproperty.window = commWindow; xev.xproperty.window = commWindow;
xev.xproperty.state = PropertyNewValue; xev.xproperty.state = PropertyNewValue;
serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev); serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev, 0);
} }
return FALSE; return FALSE;
} }
@@ -5476,9 +5476,8 @@ gui_mch_wait_for_chars(long wtime)
focus = gui.in_focus; focus = gui.in_focus;
} }
#if defined(FEAT_NETBEANS_INTG) #ifdef MESSAGE_QUEUE
/* Process any queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
/* /*

View File

@@ -2016,9 +2016,8 @@ gui_mch_wait_for_chars(int wtime)
s_need_activate = FALSE; s_need_activate = FALSE;
} }
#ifdef FEAT_NETBEANS_INTG #ifdef MESSAGE_QUEUE
/* Process the queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
/* /*

View File

@@ -2895,9 +2895,8 @@ gui_mch_wait_for_chars(wtime)
focus = gui.in_focus; focus = gui.in_focus;
} }
#if defined(FEAT_NETBEANS_INTG) #ifdef MESSAGE_QUEUE
/* Process any queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
/* /*
@@ -3199,7 +3198,7 @@ gui_x11_send_event_handler(w, client_data, event, dum)
if (e->type == PropertyNotify && e->window == commWindow if (e->type == PropertyNotify && e->window == commWindow
&& e->atom == commProperty && e->state == PropertyNewValue) && e->atom == commProperty && e->state == PropertyNewValue)
{ {
serverEventProc(gui.dpy, event); serverEventProc(gui.dpy, event, 0);
} }
} }
#endif #endif

View File

@@ -169,6 +169,19 @@ enum ServerReplyOp { SROP_Find, SROP_Add, SROP_Delete };
typedef int (*EndCond) __ARGS((void *)); typedef int (*EndCond) __ARGS((void *));
struct x_cmdqueue
{
char_u *propInfo;
int len;
struct x_cmdqueue *next;
struct x_cmdqueue *prev;
};
typedef struct x_cmdqueue x_queue_T;
/* dummy node, header for circular queue */
static x_queue_T head = {NULL, 0, NULL, NULL};
/* /*
* Forward declarations for procedures defined later in this file: * Forward declarations for procedures defined later in this file:
*/ */
@@ -186,6 +199,8 @@ static struct ServerReply *ServerReplyFind __ARGS((Window w, enum ServerReplyOp
static int AppendPropCarefully __ARGS((Display *display, Window window, Atom property, char_u *value, int length)); static int AppendPropCarefully __ARGS((Display *display, Window window, Atom property, char_u *value, int length));
static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event)); static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
static int IsSerialName __ARGS((char_u *name)); static int IsSerialName __ARGS((char_u *name));
static void save_in_queue __ARGS((char_u *buf, int len));
static void server_parse_message __ARGS((Display *dpy, char_u *propInfo, int numItems));
/* Private variables for the "server" functionality */ /* Private variables for the "server" functionality */
static Atom registryProperty = None; static Atom registryProperty = None;
@@ -595,7 +610,7 @@ ServerWait(dpy, w, endCond, endData, localLoop, seconds)
while (TRUE) while (TRUE)
{ {
while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event)) while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event))
serverEventProc(dpy, &event); serverEventProc(dpy, &event, 1);
if (endCond(endData) != 0) if (endCond(endData) != 0)
break; break;
@@ -1127,22 +1142,25 @@ GetRegProp(dpy, regPropp, numItemsp, domsg)
return OK; return OK;
} }
/* /*
* This procedure is invoked by the various X event loops throughout Vims when * This procedure is invoked by the various X event loops throughout Vims when
* a property changes on the communication window. This procedure reads the * a property changes on the communication window. This procedure reads the
* property and handles command requests and responses. * property and enqueues command requests and responses. If immediate is true,
* it runs the event immediatly instead of enqueuing it. Immediate can cause
* unintended behavior and should only be used for code that blocks for a
* response.
*/ */
void void
serverEventProc(dpy, eventPtr) serverEventProc(dpy, eventPtr, immediate)
Display *dpy; Display *dpy;
XEvent *eventPtr; /* Information about event. */ XEvent *eventPtr; /* Information about event. */
int immediate; /* Run event immediately. Should mostly be 0. */
{ {
char_u *propInfo; char_u *propInfo;
char_u *p; int result, actualFormat;
int result, actualFormat, code;
long_u numItems, bytesAfter; long_u numItems, bytesAfter;
Atom actualType; Atom actualType;
char_u *tofree;
if (eventPtr != NULL) if (eventPtr != NULL)
{ {
@@ -1168,6 +1186,87 @@ serverEventProc(dpy, eventPtr)
XFree(propInfo); XFree(propInfo);
return; return;
} }
if (immediate)
server_parse_message(dpy, propInfo, numItems);
else
save_in_queue(propInfo, numItems);
}
/*
* Saves x clientserver commands in a queue so that they can be called when
* vim is idle.
*/
static void
save_in_queue(propInfo, len)
char_u *propInfo;
int len;
{
x_queue_T *node;
node = (x_queue_T *)alloc(sizeof(x_queue_T));
if (node == NULL)
return; /* out of memory */
node->propInfo = propInfo;
node->len = len;
if (head.next == NULL) /* initialize circular queue */
{
head.next = &head;
head.prev = &head;
}
/* insert node at tail of queue */
node->next = &head;
node->prev = head.prev;
head.prev->next = node;
head.prev = node;
}
/*
* Parses queued clientserver messages.
*/
void
server_parse_messages()
{
char_u *p;
x_queue_T *node;
if (!X_DISPLAY)
return; /* cannot happen? */
while (head.next != NULL && head.next != &head)
{
node = head.next;
server_parse_message(X_DISPLAY, node->propInfo, node->len);
head.next = node->next;
node->next->prev = node->prev;
vim_free(node);
}
}
/*
* Returns a non-zero value if there are clientserver messages waiting
* int the queue.
*/
int
server_waiting()
{
return head.next != NULL && head.next != &head;
}
/*
* Prases a single clientserver message. A single message may contain multiple
* commands.
* "propInfo" will be freed.
*/
static void
server_parse_message(dpy, propInfo, numItems)
Display *dpy;
char_u *propInfo; /* A string containing 0 or more X commands */
int numItems; /* The size of propInfo in bytes. */
{
char_u *p;
int code;
char_u *tofree;
/* /*
* Several commands and results could arrive in the property at * Several commands and results could arrive in the property at
@@ -1248,16 +1347,16 @@ serverEventProc(dpy, eventPtr)
if (script == NULL || name == NULL) if (script == NULL || name == NULL)
continue; continue;
if (serverName != NULL && STRICMP(name, serverName) == 0) if (serverName != NULL && STRICMP(name, serverName) == 0)
{ {
script = serverConvert(enc, script, &tofree); script = serverConvert(enc, script, &tofree);
if (asKeys) if (asKeys)
server_to_input_buf(script); server_to_input_buf(script);
else else
{ {
char_u *res; char_u *res;
res = eval_client_expr_to_string(script); res = eval_client_expr_to_string(script);
if (resWindow != None) if (resWindow != None)
{ {
garray_T reply; garray_T reply;
@@ -1290,10 +1389,10 @@ serverEventProc(dpy, eventPtr)
reply.ga_data, reply.ga_len); reply.ga_data, reply.ga_len);
ga_clear(&reply); ga_clear(&reply);
} }
vim_free(res); vim_free(res);
} }
vim_free(tofree); vim_free(tofree);
} }
} }
else if (*p == 'r' && p[1] == 0) else if (*p == 'r' && p[1] == 0)
{ {

View File

@@ -321,3 +321,7 @@
#else #else
# define PLINES_NOFILL(x) plines(x) # define PLINES_NOFILL(x) plines(x)
#endif #endif
#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_CLIENTSERVER)
# define MESSAGE_QUEUE
#endif

View File

@@ -6328,3 +6328,23 @@ has_non_ascii(s)
return FALSE; return FALSE;
} }
#endif #endif
#if defined(MESSAGE_QUEUE) || defined(PROTO)
/*
* Process messages that have been queued for netbeans or clientserver.
* These functions can call arbitrary vimscript and should only be called when
* it is safe to do so.
*/
void
parse_queued_messages()
{
# ifdef FEAT_NETBEANS_INTG
/* Process the queued netbeans messages. */
netbeans_parse_messages();
# endif
# ifdef FEAT_CLIENTSERVER
/* Process the queued clientserver messages. */
server_parse_messages();
# endif
}
#endif

View File

@@ -388,9 +388,8 @@ mch_inchar(buf, maxlen, wtime, tb_change_cnt)
{ {
int len; int len;
#ifdef FEAT_NETBEANS_INTG #ifdef MESSAGE_QUEUE
/* Process the queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
/* Check if window changed size while we were busy, perhaps the ":set /* Check if window changed size while we were busy, perhaps the ":set
@@ -405,9 +404,8 @@ mch_inchar(buf, maxlen, wtime, tb_change_cnt)
if (!do_resize) /* return if not interrupted by resize */ if (!do_resize) /* return if not interrupted by resize */
return 0; return 0;
handle_resize(); handle_resize();
#ifdef FEAT_NETBEANS_INTG #ifdef MESSAGE_QUEUE
/* Process the queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
} }
} }
@@ -439,9 +437,8 @@ mch_inchar(buf, maxlen, wtime, tb_change_cnt)
while (do_resize) /* window changed size */ while (do_resize) /* window changed size */
handle_resize(); handle_resize();
#ifdef FEAT_NETBEANS_INTG #ifdef MESSAGE_QUEUE
/* Process the queued netbeans messages. */ parse_queued_messages();
netbeans_parse_messages();
#endif #endif
/* /*
* We want to be interrupted by the winch signal * We want to be interrupted by the winch signal
@@ -5208,6 +5205,7 @@ WaitForChar(msec)
* When a GUI is being used, this will not be used for input -- webb * When a GUI is being used, this will not be used for input -- webb
* Returns also, when a request from Sniff is waiting -- toni. * Returns also, when a request from Sniff is waiting -- toni.
* Or when a Linux GPM mouse event is waiting. * Or when a Linux GPM mouse event is waiting.
* Or when a clientserver message is on the queue.
*/ */
#if defined(__BEOS__) #if defined(__BEOS__)
int int
@@ -5601,6 +5599,11 @@ select_eintr:
if (finished || msec == 0) if (finished || msec == 0)
break; break;
# ifdef FEAT_CLIENTSERVER
if (server_waiting())
break;
# endif
/* We're going to loop around again, find out for how long */ /* We're going to loop around again, find out for how long */
if (msec > 0) if (msec > 0)
{ {
@@ -7106,31 +7109,31 @@ xterm_update()
for (;;) for (;;)
{ {
XtInputMask mask = XtAppPending(app_context); XtInputMask mask = XtAppPending(app_context);
if (mask == 0 || vim_is_input_buf_full()) if (mask == 0 || vim_is_input_buf_full())
break; break;
if (mask & XtIMXEvent) if (mask & XtIMXEvent)
{ {
/* There is an event to process. */ /* There is an event to process. */
XtAppNextEvent(app_context, &event); XtAppNextEvent(app_context, &event);
#ifdef FEAT_CLIENTSERVER #ifdef FEAT_CLIENTSERVER
{ {
XPropertyEvent *e = (XPropertyEvent *)&event; XPropertyEvent *e = (XPropertyEvent *)&event;
if (e->type == PropertyNotify && e->window == commWindow if (e->type == PropertyNotify && e->window == commWindow
&& e->atom == commProperty && e->state == PropertyNewValue) && e->atom == commProperty && e->state == PropertyNewValue)
serverEventProc(xterm_dpy, &event); serverEventProc(xterm_dpy, &event, 0);
} }
#endif #endif
XtDispatchEvent(&event); XtDispatchEvent(&event);
} }
else else
{ {
/* There is something else than an event to process. */ /* There is something else than an event to process. */
XtAppProcessEvent(app_context, mask); XtAppProcessEvent(app_context, mask);
} }
} }
} }

View File

@@ -7,5 +7,7 @@ Window serverStrToWin __ARGS((char_u *str));
int serverSendReply __ARGS((char_u *name, char_u *str)); int serverSendReply __ARGS((char_u *name, char_u *str));
int serverReadReply __ARGS((Display *dpy, Window win, char_u **str, int localLoop)); int serverReadReply __ARGS((Display *dpy, Window win, char_u **str, int localLoop));
int serverPeekReply __ARGS((Display *dpy, Window win, char_u **str)); int serverPeekReply __ARGS((Display *dpy, Window win, char_u **str));
void serverEventProc __ARGS((Display *dpy, XEvent *eventPtr)); void serverEventProc __ARGS((Display *dpy, XEvent *eventPtr, int immediate));
void server_parse_messages __ARGS((void));
int server_waiting __ARGS((void));
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -106,4 +106,5 @@ int put_bytes __ARGS((FILE *fd, long_u nr, int len));
void put_time __ARGS((FILE *fd, time_t the_time)); void put_time __ARGS((FILE *fd, time_t the_time));
void time_to_bytes __ARGS((time_t the_time, char_u *buf)); void time_to_bytes __ARGS((time_t the_time, char_u *buf));
int has_non_ascii __ARGS((char_u *s)); int has_non_ascii __ARGS((char_u *s));
void parse_queued_messages __ARGS((void));
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
866,
/**/ /**/
865, 865,
/**/ /**/