]> granicus.if.org Git - vim/commitdiff
patch 7.4.866 v7.4.866
authorBram Moolenaar <Bram@vim.org>
Tue, 15 Sep 2015 12:12:05 +0000 (14:12 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 15 Sep 2015 12:12:05 +0000 (14:12 +0200)
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)

12 files changed:
src/ex_docmd.c
src/getchar.c
src/gui_gtk_x11.c
src/gui_w48.c
src/gui_x11.c
src/if_xcmdsrv.c
src/macros.h
src/misc2.c
src/os_unix.c
src/proto/if_xcmdsrv.pro
src/proto/misc2.pro
src/version.c

index 045375ac40777ad8af6e1609853a515159b1b951..bb07c8bf45fa9e4b43519d995964c56603273d02 100644 (file)
@@ -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
     }
 }
index a80432fc5a288dd3738b5b5aa1a6f821d1f47007..87588a93ac40f1b3a1e3e97a65d4981fa5ea9619 100644 (file)
@@ -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)
index bcd05c43e57e394c3b1d9f4c63986e2894d91998..d19e61a8ed2cfe061d31335e6189aa8d97576a7c 100644 (file)
@@ -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
 
        /*
index 1096ec8452427a4d515edb2e0d4184b3430e7d84..b40a6b9e00b1666f0d12a45ce52262c7630ef734 100644 (file)
@@ -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
 
        /*
index ed71b26ce87d63fd95c2063588bbf03d2e1ad10f..276930728f51228b3e0484928e140718b11e036b 100644 (file)
@@ -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
index d8c64ad4b03e160ff64f721b0267eaa42dfeae36..dfa8fcbcb8dad5097540b1d2405270a4910791a7 100644 (file)
@@ -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)
        {
index f70e206144c6b4a78f48691f6fd63d9b579f5d5f..caaca9a3ef084f55ad74aaa4bf54594d1f231826 100644 (file)
 #else
 # define PLINES_NOFILL(x) plines(x)
 #endif
+
+#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_CLIENTSERVER)
+# define MESSAGE_QUEUE
+#endif
index 379916b393f52ccd07ce8131b2b429c54bccbb14..e6a4e747d92ceacd06e6bbf442644f94bd5c04ef 100644 (file)
@@ -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
index 2439c5e252ef02b99d173d8363b5b8dcfa2b25db..8f059be8fe3031089b93952b8e308a55367b429a 100644 (file)
@@ -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);
+       }
     }
 }
 
index dd6a12084dd932e62930487bf24a46a1ef01e8d0..30647539ee1cf1c6fc5e3edb1339f13d012cecae 100644 (file)
@@ -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 : */
index f09ff33ac3c64c1de51f74698f564b69b7e35d8d..490b1aff8d8458f3993efe7e7c117320e0475838 100644 (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 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 : */
index a9b20dc0dbea1f16ad1041591996ab66237134b7..e5038260fcb42a9c1e0e24b24cff1555301a0af2 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    866,
 /**/
     865,
 /**/