summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2015-09-15 14:12:05 +0200
committerBram Moolenaar <Bram@vim.org>2015-09-15 14:12:05 +0200
commit93c88e0f6a4a8f7634ed84721daf4af46fc0d5db (patch)
treeb325606d26d69c3804a9007cf7d1fa4a8034f4aa
parented84b76021df763619cabaedddc44eb5ee849136 (diff)
downloadvim-git-93c88e0f6a4a8f7634ed84721daf4af46fc0d5db.tar.gz
patch 7.4.866v7.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)
-rw-r--r--src/ex_docmd.c10
-rw-r--r--src/getchar.c5
-rw-r--r--src/gui_gtk_x11.c7
-rw-r--r--src/gui_w48.c5
-rw-r--r--src/gui_x11.c7
-rw-r--r--src/if_xcmdsrv.c139
-rw-r--r--src/macros.h4
-rw-r--r--src/misc2.c20
-rw-r--r--src/os_unix.c39
-rw-r--r--src/proto/if_xcmdsrv.pro4
-rw-r--r--src/proto/misc2.pro1
-rw-r--r--src/version.c2
12 files changed, 185 insertions, 58 deletions
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 045375ac4..bb07c8bf4 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -9033,11 +9033,11 @@ do_sleep(msec)
{
ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE);
ui_breakcheck();
-#ifdef FEAT_NETBEANS_INTG
- /* Process the netbeans messages that may have been received in the
- * call to ui_breakcheck() when the GUI is in use. This may occur when
- * running a test case. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ /* Process the netbeans and clientserver messages that may have been
+ * received in the call to ui_breakcheck() when the GUI is in use. This
+ * may occur when running a test case. */
+ parse_queued_messages();
#endif
}
}
diff --git a/src/getchar.c b/src/getchar.c
index a80432fc5..87588a93a 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -3034,9 +3034,8 @@ inchar(buf, maxlen, wait_time, tb_change_cnt)
)
{
-#if defined(FEAT_NETBEANS_INTG)
- /* Process the queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
if (got_int || (script_char = getc(scriptin[curscript])) < 0)
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c
index bcd05c43e..d19e61a8e 100644
--- a/src/gui_gtk_x11.c
+++ b/src/gui_gtk_x11.c
@@ -650,7 +650,7 @@ property_event(GtkWidget *widget,
xev.xproperty.atom = commProperty;
xev.xproperty.window = commWindow;
xev.xproperty.state = PropertyNewValue;
- serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev);
+ serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev, 0);
}
return FALSE;
}
@@ -5476,9 +5476,8 @@ gui_mch_wait_for_chars(long wtime)
focus = gui.in_focus;
}
-#if defined(FEAT_NETBEANS_INTG)
- /* Process any queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
/*
diff --git a/src/gui_w48.c b/src/gui_w48.c
index 1096ec845..b40a6b9e0 100644
--- a/src/gui_w48.c
+++ b/src/gui_w48.c
@@ -2016,9 +2016,8 @@ gui_mch_wait_for_chars(int wtime)
s_need_activate = FALSE;
}
-#ifdef FEAT_NETBEANS_INTG
- /* Process the queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
/*
diff --git a/src/gui_x11.c b/src/gui_x11.c
index ed71b26ce..276930728 100644
--- a/src/gui_x11.c
+++ b/src/gui_x11.c
@@ -2895,9 +2895,8 @@ gui_mch_wait_for_chars(wtime)
focus = gui.in_focus;
}
-#if defined(FEAT_NETBEANS_INTG)
- /* Process any queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
/*
@@ -3199,7 +3198,7 @@ gui_x11_send_event_handler(w, client_data, event, dum)
if (e->type == PropertyNotify && e->window == commWindow
&& e->atom == commProperty && e->state == PropertyNewValue)
{
- serverEventProc(gui.dpy, event);
+ serverEventProc(gui.dpy, event, 0);
}
}
#endif
diff --git a/src/if_xcmdsrv.c b/src/if_xcmdsrv.c
index d8c64ad4b..dfa8fcbcb 100644
--- a/src/if_xcmdsrv.c
+++ b/src/if_xcmdsrv.c
@@ -169,6 +169,19 @@ enum ServerReplyOp { SROP_Find, SROP_Add, SROP_Delete };
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:
*/
@@ -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 x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
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 */
static Atom registryProperty = None;
@@ -595,7 +610,7 @@ ServerWait(dpy, w, endCond, endData, localLoop, seconds)
while (TRUE)
{
while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event))
- serverEventProc(dpy, &event);
+ serverEventProc(dpy, &event, 1);
if (endCond(endData) != 0)
break;
@@ -1127,22 +1142,25 @@ GetRegProp(dpy, regPropp, numItemsp, domsg)
return OK;
}
+
/*
* This procedure is invoked by the various X event loops throughout Vims when
* 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
-serverEventProc(dpy, eventPtr)
+serverEventProc(dpy, eventPtr, immediate)
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 *p;
- int result, actualFormat, code;
+ int result, actualFormat;
long_u numItems, bytesAfter;
Atom actualType;
- char_u *tofree;
if (eventPtr != NULL)
{
@@ -1168,6 +1186,87 @@ serverEventProc(dpy, eventPtr)
XFree(propInfo);
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
@@ -1248,16 +1347,16 @@ serverEventProc(dpy, eventPtr)
if (script == NULL || name == NULL)
continue;
- if (serverName != NULL && STRICMP(name, serverName) == 0)
- {
- script = serverConvert(enc, script, &tofree);
- if (asKeys)
- server_to_input_buf(script);
- else
- {
- char_u *res;
+ if (serverName != NULL && STRICMP(name, serverName) == 0)
+ {
+ script = serverConvert(enc, script, &tofree);
+ if (asKeys)
+ server_to_input_buf(script);
+ else
+ {
+ char_u *res;
- res = eval_client_expr_to_string(script);
+ res = eval_client_expr_to_string(script);
if (resWindow != None)
{
garray_T reply;
@@ -1290,10 +1389,10 @@ serverEventProc(dpy, eventPtr)
reply.ga_data, reply.ga_len);
ga_clear(&reply);
}
- vim_free(res);
- }
- vim_free(tofree);
- }
+ vim_free(res);
+ }
+ vim_free(tofree);
+ }
}
else if (*p == 'r' && p[1] == 0)
{
diff --git a/src/macros.h b/src/macros.h
index f70e20614..caaca9a3e 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -321,3 +321,7 @@
#else
# define PLINES_NOFILL(x) plines(x)
#endif
+
+#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_CLIENTSERVER)
+# define MESSAGE_QUEUE
+#endif
diff --git a/src/misc2.c b/src/misc2.c
index 379916b39..e6a4e747d 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -6328,3 +6328,23 @@ has_non_ascii(s)
return FALSE;
}
#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
diff --git a/src/os_unix.c b/src/os_unix.c
index 2439c5e25..8f059be8f 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -388,9 +388,8 @@ mch_inchar(buf, maxlen, wtime, tb_change_cnt)
{
int len;
-#ifdef FEAT_NETBEANS_INTG
- /* Process the queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
/* 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 */
return 0;
handle_resize();
-#ifdef FEAT_NETBEANS_INTG
- /* Process the queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
}
}
@@ -439,9 +437,8 @@ mch_inchar(buf, maxlen, wtime, tb_change_cnt)
while (do_resize) /* window changed size */
handle_resize();
-#ifdef FEAT_NETBEANS_INTG
- /* Process the queued netbeans messages. */
- netbeans_parse_messages();
+#ifdef MESSAGE_QUEUE
+ parse_queued_messages();
#endif
/*
* 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
* Returns also, when a request from Sniff is waiting -- toni.
* Or when a Linux GPM mouse event is waiting.
+ * Or when a clientserver message is on the queue.
*/
#if defined(__BEOS__)
int
@@ -5601,6 +5599,11 @@ select_eintr:
if (finished || msec == 0)
break;
+# ifdef FEAT_CLIENTSERVER
+ if (server_waiting())
+ break;
+# endif
+
/* We're going to loop around again, find out for how long */
if (msec > 0)
{
@@ -7106,31 +7109,31 @@ xterm_update()
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;
- if (mask & XtIMXEvent)
+ if (mask & XtIMXEvent)
{
/* There is an event to process. */
- XtAppNextEvent(app_context, &event);
+ XtAppNextEvent(app_context, &event);
#ifdef FEAT_CLIENTSERVER
{
XPropertyEvent *e = (XPropertyEvent *)&event;
if (e->type == PropertyNotify && e->window == commWindow
&& e->atom == commProperty && e->state == PropertyNewValue)
- serverEventProc(xterm_dpy, &event);
+ serverEventProc(xterm_dpy, &event, 0);
}
#endif
- XtDispatchEvent(&event);
- }
+ XtDispatchEvent(&event);
+ }
else
{
/* There is something else than an event to process. */
- XtAppProcessEvent(app_context, mask);
- }
+ XtAppProcessEvent(app_context, mask);
+ }
}
}
diff --git a/src/proto/if_xcmdsrv.pro b/src/proto/if_xcmdsrv.pro
index dd6a12084..30647539e 100644
--- a/src/proto/if_xcmdsrv.pro
+++ b/src/proto/if_xcmdsrv.pro
@@ -7,5 +7,7 @@ Window serverStrToWin __ARGS((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 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 : */
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index f09ff33ac..490b1aff8 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -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 time_to_bytes __ARGS((time_t the_time, char_u *buf));
int has_non_ascii __ARGS((char_u *s));
+void parse_queued_messages __ARGS((void));
/* vim: set ft=c : */
diff --git a/src/version.c b/src/version.c
index a9b20dc0d..e5038260f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 866,
+/**/
865,
/**/
864,