diff options
| author | Kim F. Storm | 2002-02-28 23:53:59 +0000 |
|---|---|---|
| committer | Kim F. Storm | 2002-02-28 23:53:59 +0000 |
| commit | dd2a17ab8b7d44b6ab3500c45d03972799833e65 (patch) | |
| tree | 680cf1e12c8cbcc969a402767d6f58f87453c704 /src/process.c | |
| parent | 8bfb170b05f5a11d9982a80f0ac83288fcda9fa6 (diff) | |
| download | emacs-dd2a17ab8b7d44b6ab3500c45d03972799833e65.tar.gz emacs-dd2a17ab8b7d44b6ab3500c45d03972799833e65.zip | |
(Qconnect, Qfailed): New variables.
(syms_of_process): Intern and staticpro them.
[NON_BLOCKING_CONNECT]: New conditional.
(connect_wait_mask, num_pending_connects): New variables.
(status_message): Convert Qfailed status.
(Fopen_network_stream): Added support for non-blocking connect.
New optional args: filter, sentinel, non_blocking. Doc updated.
[HAVE_GETADDRINFO, !HAVE_GETADDRINFO]: Merged common code.
(deactivate_process): Handle pending non-blocking connect.
(wait_reading_process_input): Poll for status of non-blocking
connects. Exec sentinel directly when connect succeeds.
(status_notify): Don't read process output if not yet connected.
Diffstat (limited to 'src/process.c')
| -rw-r--r-- | src/process.c | 495 |
1 files changed, 350 insertions, 145 deletions
diff --git a/src/process.c b/src/process.c index 56d3a67e8d1..6f6f681f041 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* Asynchronous subprocess control for GNU Emacs. | 1 | /* Asynchronous subprocess control for GNU Emacs. |
| 2 | Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 96, 98, 1999, 2001 | 2 | Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 96, 98, 1999, |
| 3 | Free Software Foundation, Inc. | 3 | 2001, 2002 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | This file is part of GNU Emacs. | 5 | This file is part of GNU Emacs. |
| 6 | 6 | ||
| @@ -112,7 +112,8 @@ Boston, MA 02111-1307, USA. */ | |||
| 112 | #include "atimer.h" | 112 | #include "atimer.h" |
| 113 | 113 | ||
| 114 | Lisp_Object Qprocessp; | 114 | Lisp_Object Qprocessp; |
| 115 | Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed; | 115 | Lisp_Object Qrun, Qstop, Qsignal; |
| 116 | Lisp_Object Qopen, Qclosed, Qconnect, Qfailed; | ||
| 116 | Lisp_Object Qlast_nonmenu_event; | 117 | Lisp_Object Qlast_nonmenu_event; |
| 117 | /* Qexit is declared and initialized in eval.c. */ | 118 | /* Qexit is declared and initialized in eval.c. */ |
| 118 | 119 | ||
| @@ -173,6 +174,30 @@ int process_tick; | |||
| 173 | /* Number of events for which the user or sentinel has been notified. */ | 174 | /* Number of events for which the user or sentinel has been notified. */ |
| 174 | int update_tick; | 175 | int update_tick; |
| 175 | 176 | ||
| 177 | /* Define NON_BLOCKING_CONNECT if we can support non-blocking connects. */ | ||
| 178 | |||
| 179 | #ifdef BROKEN_NON_BLOCKING_CONNECT | ||
| 180 | #undef NON_BLOCKING_CONNECT | ||
| 181 | #else | ||
| 182 | #ifndef NON_BLOCKING_CONNECT | ||
| 183 | #ifdef HAVE_SOCKETS | ||
| 184 | #ifdef HAVE_SELECT | ||
| 185 | #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX) | ||
| 186 | #if defined (O_NONBLOCK) || defined (O_NDELAY) | ||
| 187 | #if defined (EWOULDBLOCK) || defined (EINPROGRESS) | ||
| 188 | #define NON_BLOCKING_CONNECT | ||
| 189 | #endif /* EWOULDBLOCK || EINPROGRESS */ | ||
| 190 | #endif /* O_NONBLOCK || O_NDELAY */ | ||
| 191 | #endif /* HAVE_GETPEERNAME || GNU_LINUX */ | ||
| 192 | #endif /* HAVE_SELECT */ | ||
| 193 | #endif /* HAVE_SOCKETS */ | ||
| 194 | #endif /* NON_BLOCKING_CONNECT */ | ||
| 195 | #endif /* BROKEN_NON_BLOCKING_CONNECT */ | ||
| 196 | |||
| 197 | #ifdef TERM | ||
| 198 | #undef NON_BLOCKING_CONNECT | ||
| 199 | #endif | ||
| 200 | |||
| 176 | #include "sysselect.h" | 201 | #include "sysselect.h" |
| 177 | 202 | ||
| 178 | extern int keyboard_bit_set P_ ((SELECT_TYPE *)); | 203 | extern int keyboard_bit_set P_ ((SELECT_TYPE *)); |
| @@ -195,6 +220,15 @@ static SELECT_TYPE non_keyboard_wait_mask; | |||
| 195 | 220 | ||
| 196 | static SELECT_TYPE non_process_wait_mask; | 221 | static SELECT_TYPE non_process_wait_mask; |
| 197 | 222 | ||
| 223 | /* Mask of bits indicating the descriptors that we wait for connect to | ||
| 224 | complete on. Once they complete, they are removed from this mask | ||
| 225 | and added to the input_wait_mask and non_keyboard_wait_mask. */ | ||
| 226 | |||
| 227 | static SELECT_TYPE connect_wait_mask; | ||
| 228 | |||
| 229 | /* Number of bits set in connect_wait_mask. */ | ||
| 230 | static int num_pending_connects; | ||
| 231 | |||
| 198 | /* The largest descriptor currently in use for a process object. */ | 232 | /* The largest descriptor currently in use for a process object. */ |
| 199 | static int max_process_desc; | 233 | static int max_process_desc; |
| 200 | 234 | ||
| @@ -224,6 +258,7 @@ static struct coding_system *proc_decode_coding_system[MAXDESC]; | |||
| 224 | static struct coding_system *proc_encode_coding_system[MAXDESC]; | 258 | static struct coding_system *proc_encode_coding_system[MAXDESC]; |
| 225 | 259 | ||
| 226 | static Lisp_Object get_process (); | 260 | static Lisp_Object get_process (); |
| 261 | static void exec_sentinel (); | ||
| 227 | 262 | ||
| 228 | extern EMACS_TIME timer_check (); | 263 | extern EMACS_TIME timer_check (); |
| 229 | extern int timers_run; | 264 | extern int timers_run; |
| @@ -335,6 +370,13 @@ status_message (status) | |||
| 335 | return concat2 (build_string ("exited abnormally with code "), | 370 | return concat2 (build_string ("exited abnormally with code "), |
| 336 | concat2 (string, string2)); | 371 | concat2 (string, string2)); |
| 337 | } | 372 | } |
| 373 | else if (EQ (symbol, Qfailed)) | ||
| 374 | { | ||
| 375 | string = Fnumber_to_string (make_number (code)); | ||
| 376 | string2 = build_string ("\n"); | ||
| 377 | return concat2 (build_string ("failed with code "), | ||
| 378 | concat2 (string, string2)); | ||
| 379 | } | ||
| 338 | else | 380 | else |
| 339 | return Fcopy_sequence (Fsymbol_name (symbol)); | 381 | return Fcopy_sequence (Fsymbol_name (symbol)); |
| 340 | } | 382 | } |
| @@ -1741,28 +1783,37 @@ create_process (process, new_argv, current_dir) | |||
| 1741 | deactivate and close it via delete-process */ | 1783 | deactivate and close it via delete-process */ |
| 1742 | 1784 | ||
| 1743 | DEFUN ("open-network-stream", Fopen_network_stream, Sopen_network_stream, | 1785 | DEFUN ("open-network-stream", Fopen_network_stream, Sopen_network_stream, |
| 1744 | 4, 4, 0, | 1786 | 4, 7, 0, |
| 1745 | doc: /* Open a TCP connection for a service to a host. | 1787 | doc: /* Open a TCP connection for a service to a host. |
| 1746 | Returns a subprocess-object to represent the connection. | 1788 | Returns a subprocess-object to represent the connection. |
| 1789 | Returns nil if a non-blocking connect is attempted on a system which | ||
| 1790 | cannot support that; in that case, the caller should attempt a | ||
| 1791 | normal connect instead. | ||
| 1792 | |||
| 1747 | Input and output work as for subprocesses; `delete-process' closes it. | 1793 | Input and output work as for subprocesses; `delete-process' closes it. |
| 1748 | Args are NAME BUFFER HOST SERVICE. | 1794 | Args are NAME BUFFER HOST SERVICE FILTER SENTINEL NON-BLOCKING. |
| 1749 | NAME is name for process. It is modified if necessary to make it unique. | 1795 | NAME is name for process. It is modified if necessary to make it unique. |
| 1750 | BUFFER is the buffer (or buffer-name) to associate with the process. | 1796 | BUFFER is the buffer (or buffer-name) to associate with the process. |
| 1751 | Process output goes at end of that buffer, unless you specify | 1797 | Process output goes at end of that buffer, unless you specify |
| 1752 | an output stream or filter function to handle the output. | 1798 | an output stream or filter function to handle the output. |
| 1753 | BUFFER may be also nil, meaning that this process is not associated | 1799 | BUFFER may be also nil, meaning that this process is not associated |
| 1754 | with any buffer | 1800 | with any buffer. |
| 1755 | Third arg is name of the host to connect to, or its IP address. | 1801 | HOST is name of the host to connect to, or its IP address. |
| 1756 | Fourth arg SERVICE is name of the service desired, or an integer | 1802 | SERVICE is name of the service desired, or an integer specifying a |
| 1757 | specifying a port number to connect to. */) | 1803 | port number to connect to. |
| 1758 | (name, buffer, host, service) | 1804 | FILTER and SENTINEL are optional args specifying the filter and |
| 1759 | Lisp_Object name, buffer, host, service; | 1805 | sentinel functions associated with the network stream. |
| 1806 | NON-BLOCKING is optional arg requesting an non-blocking connect. | ||
| 1807 | When non-nil, open-network-stream will return immediately without | ||
| 1808 | waiting for the connection to be made. Instead, the sentinel function | ||
| 1809 | will be called with second matching "open" (if successful) or | ||
| 1810 | "failed" when the connect completes. */) | ||
| 1811 | (name, buffer, host, service, filter, sentinel, non_blocking) | ||
| 1812 | Lisp_Object name, buffer, host, service, filter, sentinel, non_blocking; | ||
| 1760 | { | 1813 | { |
| 1761 | Lisp_Object proc; | 1814 | Lisp_Object proc; |
| 1762 | #ifdef HAVE_GETADDRINFO | 1815 | #ifdef HAVE_GETADDRINFO |
| 1763 | struct addrinfo hints, *res, *lres; | 1816 | struct addrinfo hints, *res, *lres; |
| 1764 | int ret = 0; | ||
| 1765 | int xerrno = 0; | ||
| 1766 | char *portstring, portbuf[128]; | 1817 | char *portstring, portbuf[128]; |
| 1767 | #else /* HAVE_GETADDRINFO */ | 1818 | #else /* HAVE_GETADDRINFO */ |
| 1768 | struct sockaddr_in address; | 1819 | struct sockaddr_in address; |
| @@ -1771,19 +1822,43 @@ specifying a port number to connect to. */) | |||
| 1771 | char *(addr_list[2]); | 1822 | char *(addr_list[2]); |
| 1772 | IN_ADDR numeric_addr; | 1823 | IN_ADDR numeric_addr; |
| 1773 | int port; | 1824 | int port; |
| 1825 | struct _emacs_addrinfo | ||
| 1826 | { | ||
| 1827 | int ai_family; | ||
| 1828 | int ai_socktype; | ||
| 1829 | int ai_protocol; | ||
| 1830 | int ai_addrlen; | ||
| 1831 | struct sockaddr *ai_addr; | ||
| 1832 | struct _emacs_addrinfo *ai_next; | ||
| 1833 | } ai, *res, *lres; | ||
| 1774 | #endif /* HAVE_GETADDRINFO */ | 1834 | #endif /* HAVE_GETADDRINFO */ |
| 1835 | int ret = 0; | ||
| 1836 | int xerrno = 0; | ||
| 1775 | int s = -1, outch, inch; | 1837 | int s = -1, outch, inch; |
| 1776 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | 1838 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; |
| 1777 | int retry = 0; | 1839 | int retry = 0; |
| 1778 | int count = specpdl_ptr - specpdl; | 1840 | int count = specpdl_ptr - specpdl; |
| 1779 | int count1; | 1841 | int count1; |
| 1842 | int is_non_blocking = 0; | ||
| 1843 | |||
| 1844 | if (!NILP (non_blocking)) | ||
| 1845 | { | ||
| 1846 | #ifndef NON_BLOCKING_CONNECT | ||
| 1847 | return Qnil; | ||
| 1848 | #else | ||
| 1849 | non_blocking = Qt; /* Instead of GCPRO */ | ||
| 1850 | is_non_blocking = 1; | ||
| 1851 | #endif | ||
| 1852 | } | ||
| 1780 | 1853 | ||
| 1781 | #ifdef WINDOWSNT | 1854 | #ifdef WINDOWSNT |
| 1782 | /* Ensure socket support is loaded if available. */ | 1855 | /* Ensure socket support is loaded if available. */ |
| 1783 | init_winsock (TRUE); | 1856 | init_winsock (TRUE); |
| 1784 | #endif | 1857 | #endif |
| 1785 | 1858 | ||
| 1786 | GCPRO4 (name, buffer, host, service); | 1859 | /* Can only GCPRO 5 variables */ |
| 1860 | sentinel = Fcons (sentinel, filter); | ||
| 1861 | GCPRO5 (name, buffer, host, service, sentinel); | ||
| 1787 | CHECK_STRING (name); | 1862 | CHECK_STRING (name); |
| 1788 | CHECK_STRING (host); | 1863 | CHECK_STRING (host); |
| 1789 | 1864 | ||
| @@ -1841,87 +1916,6 @@ specifying a port number to connect to. */) | |||
| 1841 | #endif | 1916 | #endif |
| 1842 | immediate_quit = 0; | 1917 | immediate_quit = 0; |
| 1843 | 1918 | ||
| 1844 | /* Do this in case we never enter the for-loop below. */ | ||
| 1845 | count1 = specpdl_ptr - specpdl; | ||
| 1846 | s = -1; | ||
| 1847 | |||
| 1848 | for (lres = res; lres; lres = lres->ai_next) | ||
| 1849 | { | ||
| 1850 | s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol); | ||
| 1851 | if (s < 0) | ||
| 1852 | { | ||
| 1853 | xerrno = errno; | ||
| 1854 | continue; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR) | ||
| 1858 | when connect is interrupted. So let's not let it get interrupted. | ||
| 1859 | Note we do not turn off polling, because polling is only used | ||
| 1860 | when not interrupt_input, and thus not normally used on the systems | ||
| 1861 | which have this bug. On systems which use polling, there's no way | ||
| 1862 | to quit if polling is turned off. */ | ||
| 1863 | if (interrupt_input) | ||
| 1864 | unrequest_sigio (); | ||
| 1865 | |||
| 1866 | /* Make us close S if quit. */ | ||
| 1867 | count1 = specpdl_ptr - specpdl; | ||
| 1868 | record_unwind_protect (close_file_unwind, make_number (s)); | ||
| 1869 | |||
| 1870 | loop: | ||
| 1871 | |||
| 1872 | immediate_quit = 1; | ||
| 1873 | QUIT; | ||
| 1874 | |||
| 1875 | /* This turns off all alarm-based interrupts; the | ||
| 1876 | bind_polling_period call above doesn't always turn all the | ||
| 1877 | short-interval ones off, especially if interrupt_input is | ||
| 1878 | set. | ||
| 1879 | |||
| 1880 | It'd be nice to be able to control the connect timeout | ||
| 1881 | though. Would non-blocking connect calls be portable? */ | ||
| 1882 | turn_on_atimers (0); | ||
| 1883 | ret = connect (s, lres->ai_addr, lres->ai_addrlen); | ||
| 1884 | xerrno = errno; | ||
| 1885 | turn_on_atimers (1); | ||
| 1886 | |||
| 1887 | if (ret == 0 || xerrno == EISCONN) | ||
| 1888 | /* The unwind-protect will be discarded afterwards. | ||
| 1889 | Likewise for immediate_quit. */ | ||
| 1890 | break; | ||
| 1891 | |||
| 1892 | immediate_quit = 0; | ||
| 1893 | |||
| 1894 | if (xerrno == EINTR) | ||
| 1895 | goto loop; | ||
| 1896 | if (xerrno == EADDRINUSE && retry < 20) | ||
| 1897 | { | ||
| 1898 | /* A delay here is needed on some FreeBSD systems, | ||
| 1899 | and it is harmless, since this retrying takes time anyway | ||
| 1900 | and should be infrequent. */ | ||
| 1901 | Fsleep_for (make_number (1), Qnil); | ||
| 1902 | retry++; | ||
| 1903 | goto loop; | ||
| 1904 | } | ||
| 1905 | |||
| 1906 | /* Discard the unwind protect closing S. */ | ||
| 1907 | specpdl_ptr = specpdl + count1; | ||
| 1908 | count1 = specpdl_ptr - specpdl; | ||
| 1909 | |||
| 1910 | emacs_close (s); | ||
| 1911 | s = -1; | ||
| 1912 | } | ||
| 1913 | |||
| 1914 | freeaddrinfo (res); | ||
| 1915 | if (s < 0) | ||
| 1916 | { | ||
| 1917 | if (interrupt_input) | ||
| 1918 | request_sigio (); | ||
| 1919 | |||
| 1920 | errno = xerrno; | ||
| 1921 | report_file_error ("connection failed", | ||
| 1922 | Fcons (host, Fcons (name, Qnil))); | ||
| 1923 | } | ||
| 1924 | |||
| 1925 | #else /* not HAVE_GETADDRINFO */ | 1919 | #else /* not HAVE_GETADDRINFO */ |
| 1926 | 1920 | ||
| 1927 | while (1) | 1921 | while (1) |
| @@ -1973,37 +1967,109 @@ specifying a port number to connect to. */) | |||
| 1973 | address.sin_family = host_info_ptr->h_addrtype; | 1967 | address.sin_family = host_info_ptr->h_addrtype; |
| 1974 | address.sin_port = port; | 1968 | address.sin_port = port; |
| 1975 | 1969 | ||
| 1976 | s = socket (host_info_ptr->h_addrtype, SOCK_STREAM, 0); | 1970 | /* Emulate HAVE_GETADDRINFO for the loop over `res' below. */ |
| 1977 | if (s < 0) | 1971 | ai.ai_family = host_info_ptr->h_addrtype; |
| 1978 | report_file_error ("error creating socket", Fcons (name, Qnil)); | 1972 | ai.ai_socktype = SOCK_STREAM; |
| 1973 | ai.ai_protocol = 0; | ||
| 1974 | ai.ai_addr = (struct sockaddr *) &address; | ||
| 1975 | ai.ai_addrlen = sizeof address; | ||
| 1976 | ai.ai_next = NULL; | ||
| 1977 | res = &ai; | ||
| 1978 | #endif /* not HAVE_GETADDRINFO */ | ||
| 1979 | 1979 | ||
| 1980 | /* Do this in case we never enter the for-loop below. */ | ||
| 1980 | count1 = specpdl_ptr - specpdl; | 1981 | count1 = specpdl_ptr - specpdl; |
| 1981 | record_unwind_protect (close_file_unwind, make_number (s)); | 1982 | s = -1; |
| 1982 | |||
| 1983 | /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR) | ||
| 1984 | when connect is interrupted. So let's not let it get interrupted. | ||
| 1985 | Note we do not turn off polling, because polling is only used | ||
| 1986 | when not interrupt_input, and thus not normally used on the systems | ||
| 1987 | which have this bug. On systems which use polling, there's no way | ||
| 1988 | to quit if polling is turned off. */ | ||
| 1989 | if (interrupt_input) | ||
| 1990 | unrequest_sigio (); | ||
| 1991 | 1983 | ||
| 1992 | loop: | 1984 | for (lres = res; lres; lres = lres->ai_next) |
| 1985 | { | ||
| 1986 | s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol); | ||
| 1987 | if (s < 0) | ||
| 1988 | { | ||
| 1989 | xerrno = errno; | ||
| 1990 | continue; | ||
| 1991 | } | ||
| 1993 | 1992 | ||
| 1994 | immediate_quit = 1; | 1993 | #ifdef NON_BLOCKING_CONNECT |
| 1995 | QUIT; | 1994 | if (is_non_blocking) |
| 1995 | { | ||
| 1996 | #ifdef O_NONBLOCK | ||
| 1997 | ret = fcntl (s, F_SETFL, O_NONBLOCK); | ||
| 1998 | #else | ||
| 1999 | ret = fcntl (s, F_SETFL, O_NDELAY); | ||
| 2000 | #endif | ||
| 2001 | if (ret < 0) | ||
| 2002 | { | ||
| 2003 | xerrno = errno; | ||
| 2004 | emacs_close (s); | ||
| 2005 | s = -1; | ||
| 2006 | continue; | ||
| 2007 | } | ||
| 2008 | } | ||
| 2009 | #endif | ||
| 1996 | 2010 | ||
| 1997 | if (connect (s, (struct sockaddr *) &address, sizeof address) == -1 | 2011 | /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR) |
| 1998 | && errno != EISCONN) | 2012 | when connect is interrupted. So let's not let it get interrupted. |
| 1999 | { | 2013 | Note we do not turn off polling, because polling is only used |
| 2000 | int xerrno = errno; | 2014 | when not interrupt_input, and thus not normally used on the systems |
| 2015 | which have this bug. On systems which use polling, there's no way | ||
| 2016 | to quit if polling is turned off. */ | ||
| 2017 | if (interrupt_input) | ||
| 2018 | unrequest_sigio (); | ||
| 2019 | |||
| 2020 | /* Make us close S if quit. */ | ||
| 2021 | count1 = specpdl_ptr - specpdl; | ||
| 2022 | record_unwind_protect (close_file_unwind, make_number (s)); | ||
| 2023 | |||
| 2024 | loop: | ||
| 2025 | |||
| 2026 | immediate_quit = 1; | ||
| 2027 | QUIT; | ||
| 2028 | |||
| 2029 | /* This turns off all alarm-based interrupts; the | ||
| 2030 | bind_polling_period call above doesn't always turn all the | ||
| 2031 | short-interval ones off, especially if interrupt_input is | ||
| 2032 | set. | ||
| 2033 | |||
| 2034 | It'd be nice to be able to control the connect timeout | ||
| 2035 | though. Would non-blocking connect calls be portable? | ||
| 2036 | |||
| 2037 | This used to be conditioned by HAVE_GETADDRINFO. Why? */ | ||
| 2038 | |||
| 2039 | if (!is_non_blocking) | ||
| 2040 | turn_on_atimers (0); | ||
| 2041 | |||
| 2042 | ret = connect (s, lres->ai_addr, lres->ai_addrlen); | ||
| 2043 | xerrno = errno; | ||
| 2044 | |||
| 2045 | if (!is_non_blocking) | ||
| 2046 | turn_on_atimers (1); | ||
| 2047 | |||
| 2048 | if (ret == 0 || xerrno == EISCONN) | ||
| 2049 | { | ||
| 2050 | is_non_blocking = 0; | ||
| 2051 | /* The unwind-protect will be discarded afterwards. | ||
| 2052 | Likewise for immediate_quit. */ | ||
| 2053 | break; | ||
| 2054 | } | ||
| 2055 | |||
| 2056 | #ifdef NON_BLOCKING_CONNECT | ||
| 2057 | #ifdef EINPROGRESS | ||
| 2058 | if (is_non_blocking && xerrno == EINPROGRESS) | ||
| 2059 | break; | ||
| 2060 | #else | ||
| 2061 | #ifdef EWOULDBLOCK | ||
| 2062 | if (is_non_blocking && xerrno == EWOULDBLOCK) | ||
| 2063 | break; | ||
| 2064 | #endif | ||
| 2065 | #endif | ||
| 2066 | #endif | ||
| 2001 | 2067 | ||
| 2002 | immediate_quit = 0; | 2068 | immediate_quit = 0; |
| 2003 | 2069 | ||
| 2004 | if (errno == EINTR) | 2070 | if (xerrno == EINTR) |
| 2005 | goto loop; | 2071 | goto loop; |
| 2006 | if (errno == EADDRINUSE && retry < 20) | 2072 | if (xerrno == EADDRINUSE && retry < 20) |
| 2007 | { | 2073 | { |
| 2008 | /* A delay here is needed on some FreeBSD systems, | 2074 | /* A delay here is needed on some FreeBSD systems, |
| 2009 | and it is harmless, since this retrying takes time anyway | 2075 | and it is harmless, since this retrying takes time anyway |
| @@ -2013,21 +2079,40 @@ specifying a port number to connect to. */) | |||
| 2013 | goto loop; | 2079 | goto loop; |
| 2014 | } | 2080 | } |
| 2015 | 2081 | ||
| 2016 | /* Discard the unwind protect. */ | 2082 | /* Discard the unwind protect closing S. */ |
| 2017 | specpdl_ptr = specpdl + count1; | 2083 | specpdl_ptr = specpdl + count1; |
| 2018 | 2084 | count1 = specpdl_ptr - specpdl; | |
| 2085 | |||
| 2019 | emacs_close (s); | 2086 | emacs_close (s); |
| 2087 | s = -1; | ||
| 2088 | } | ||
| 2020 | 2089 | ||
| 2090 | #ifdef HAVE_GETADDRINFO | ||
| 2091 | freeaddrinfo (res); | ||
| 2092 | #endif | ||
| 2093 | |||
| 2094 | if (s < 0) | ||
| 2095 | { | ||
| 2021 | if (interrupt_input) | 2096 | if (interrupt_input) |
| 2022 | request_sigio (); | 2097 | request_sigio (); |
| 2023 | 2098 | ||
| 2099 | /* If non-blocking got this far - and failed - assume non-blocking is | ||
| 2100 | not supported after all. This is probably a wrong assumption, but | ||
| 2101 | the normal blocking calls to open-network-stream handles this error | ||
| 2102 | better. */ | ||
| 2103 | if (is_non_blocking) | ||
| 2104 | { | ||
| 2105 | #ifdef POLL_FOR_INPUT | ||
| 2106 | unbind_to (count, Qnil); | ||
| 2107 | #endif | ||
| 2108 | return Qnil; | ||
| 2109 | } | ||
| 2110 | |||
| 2024 | errno = xerrno; | 2111 | errno = xerrno; |
| 2025 | report_file_error ("connection failed", | 2112 | report_file_error ("connection failed", |
| 2026 | Fcons (host, Fcons (name, Qnil))); | 2113 | Fcons (host, Fcons (name, Qnil))); |
| 2027 | } | 2114 | } |
| 2028 | 2115 | ||
| 2029 | #endif /* not HAVE_GETADDRINFO */ | ||
| 2030 | |||
| 2031 | immediate_quit = 0; | 2116 | immediate_quit = 0; |
| 2032 | 2117 | ||
| 2033 | /* Discard the unwind protect, if any. */ | 2118 | /* Discard the unwind protect, if any. */ |
| @@ -2068,15 +2153,35 @@ specifying a port number to connect to. */) | |||
| 2068 | XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil)); | 2153 | XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil)); |
| 2069 | XPROCESS (proc)->command_channel_p = Qnil; | 2154 | XPROCESS (proc)->command_channel_p = Qnil; |
| 2070 | XPROCESS (proc)->buffer = buffer; | 2155 | XPROCESS (proc)->buffer = buffer; |
| 2071 | XPROCESS (proc)->sentinel = Qnil; | 2156 | XPROCESS (proc)->sentinel = XCAR (sentinel); |
| 2072 | XPROCESS (proc)->filter = Qnil; | 2157 | XPROCESS (proc)->filter = XCDR (sentinel); |
| 2073 | XPROCESS (proc)->command = Qnil; | 2158 | XPROCESS (proc)->command = Qnil; |
| 2074 | XPROCESS (proc)->pid = Qnil; | 2159 | XPROCESS (proc)->pid = Qnil; |
| 2075 | XSETINT (XPROCESS (proc)->infd, inch); | 2160 | XSETINT (XPROCESS (proc)->infd, inch); |
| 2076 | XSETINT (XPROCESS (proc)->outfd, outch); | 2161 | XSETINT (XPROCESS (proc)->outfd, outch); |
| 2077 | XPROCESS (proc)->status = Qrun; | 2162 | XPROCESS (proc)->status = Qrun; |
| 2078 | FD_SET (inch, &input_wait_mask); | 2163 | |
| 2079 | FD_SET (inch, &non_keyboard_wait_mask); | 2164 | #ifdef NON_BLOCKING_CONNECT |
| 2165 | if (!NILP (non_blocking)) | ||
| 2166 | { | ||
| 2167 | /* We may get here if connect did succeed immediately. However, | ||
| 2168 | in that case, we still need to signal this like a non-blocking | ||
| 2169 | connection. */ | ||
| 2170 | XPROCESS (proc)->status = Qconnect; | ||
| 2171 | if (!FD_ISSET (inch, &connect_wait_mask)) | ||
| 2172 | { | ||
| 2173 | FD_SET (inch, &connect_wait_mask); | ||
| 2174 | num_pending_connects++; | ||
| 2175 | } | ||
| 2176 | } | ||
| 2177 | else | ||
| 2178 | #endif | ||
| 2179 | if (!EQ (XPROCESS (proc)->filter, Qt)) | ||
| 2180 | { | ||
| 2181 | FD_SET (inch, &input_wait_mask); | ||
| 2182 | FD_SET (inch, &non_keyboard_wait_mask); | ||
| 2183 | } | ||
| 2184 | |||
| 2080 | if (inch > max_process_desc) | 2185 | if (inch > max_process_desc) |
| 2081 | max_process_desc = inch; | 2186 | max_process_desc = inch; |
| 2082 | 2187 | ||
| @@ -2194,6 +2299,12 @@ deactivate_process (proc) | |||
| 2194 | chan_process[inchannel] = Qnil; | 2299 | chan_process[inchannel] = Qnil; |
| 2195 | FD_CLR (inchannel, &input_wait_mask); | 2300 | FD_CLR (inchannel, &input_wait_mask); |
| 2196 | FD_CLR (inchannel, &non_keyboard_wait_mask); | 2301 | FD_CLR (inchannel, &non_keyboard_wait_mask); |
| 2302 | if (FD_ISSET (inchannel, &connect_wait_mask)) | ||
| 2303 | { | ||
| 2304 | FD_CLR (inchannel, &connect_wait_mask); | ||
| 2305 | if (--num_pending_connects < 0) | ||
| 2306 | abort (); | ||
| 2307 | } | ||
| 2197 | if (inchannel == max_process_desc) | 2308 | if (inchannel == max_process_desc) |
| 2198 | { | 2309 | { |
| 2199 | int i; | 2310 | int i; |
| @@ -2358,10 +2469,11 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2358 | { | 2469 | { |
| 2359 | register int channel, nfds; | 2470 | register int channel, nfds; |
| 2360 | static SELECT_TYPE Available; | 2471 | static SELECT_TYPE Available; |
| 2472 | static SELECT_TYPE Connecting; | ||
| 2473 | int check_connect, no_avail; | ||
| 2361 | int xerrno; | 2474 | int xerrno; |
| 2362 | Lisp_Object proc; | 2475 | Lisp_Object proc; |
| 2363 | EMACS_TIME timeout, end_time; | 2476 | EMACS_TIME timeout, end_time; |
| 2364 | SELECT_TYPE Atemp; | ||
| 2365 | int wait_channel = -1; | 2477 | int wait_channel = -1; |
| 2366 | struct Lisp_Process *wait_proc = 0; | 2478 | struct Lisp_Process *wait_proc = 0; |
| 2367 | int got_some_input = 0; | 2479 | int got_some_input = 0; |
| @@ -2370,6 +2482,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2370 | Lisp_Object wait_for_cell = Qnil; | 2482 | Lisp_Object wait_for_cell = Qnil; |
| 2371 | 2483 | ||
| 2372 | FD_ZERO (&Available); | 2484 | FD_ZERO (&Available); |
| 2485 | FD_ZERO (&Connecting); | ||
| 2373 | 2486 | ||
| 2374 | /* If read_kbd is a process to watch, set wait_proc and wait_channel | 2487 | /* If read_kbd is a process to watch, set wait_proc and wait_channel |
| 2375 | accordingly. */ | 2488 | accordingly. */ |
| @@ -2511,11 +2624,15 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2511 | timeout to get our attention. */ | 2624 | timeout to get our attention. */ |
| 2512 | if (update_tick != process_tick && do_display) | 2625 | if (update_tick != process_tick && do_display) |
| 2513 | { | 2626 | { |
| 2627 | SELECT_TYPE Atemp, Ctemp; | ||
| 2628 | |||
| 2514 | Atemp = input_wait_mask; | 2629 | Atemp = input_wait_mask; |
| 2630 | Ctemp = connect_wait_mask; | ||
| 2515 | EMACS_SET_SECS_USECS (timeout, 0, 0); | 2631 | EMACS_SET_SECS_USECS (timeout, 0, 0); |
| 2516 | if ((select (max (max_process_desc, max_keyboard_desc) + 1, | 2632 | if ((select (max (max_process_desc, max_keyboard_desc) + 1, |
| 2517 | &Atemp, (SELECT_TYPE *)0, (SELECT_TYPE *)0, | 2633 | &Atemp, |
| 2518 | &timeout) | 2634 | (num_pending_connects > 0 ? &Ctemp : (SELECT_TYPE *)0), |
| 2635 | (SELECT_TYPE *)0, &timeout) | ||
| 2519 | <= 0)) | 2636 | <= 0)) |
| 2520 | { | 2637 | { |
| 2521 | /* It's okay for us to do this and then continue with | 2638 | /* It's okay for us to do this and then continue with |
| @@ -2525,11 +2642,13 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2525 | } | 2642 | } |
| 2526 | } | 2643 | } |
| 2527 | 2644 | ||
| 2528 | /* Don't wait for output from a non-running process. */ | 2645 | /* Don't wait for output from a non-running process. Just |
| 2646 | read whatever data has already been received. */ | ||
| 2529 | if (wait_proc != 0 && !NILP (wait_proc->raw_status_low)) | 2647 | if (wait_proc != 0 && !NILP (wait_proc->raw_status_low)) |
| 2530 | update_status (wait_proc); | 2648 | update_status (wait_proc); |
| 2531 | if (wait_proc != 0 | 2649 | if (wait_proc != 0 |
| 2532 | && ! EQ (wait_proc->status, Qrun)) | 2650 | && ! EQ (wait_proc->status, Qrun) |
| 2651 | && ! EQ (wait_proc->status, Qconnect)) | ||
| 2533 | { | 2652 | { |
| 2534 | int nread, total_nread = 0; | 2653 | int nread, total_nread = 0; |
| 2535 | 2654 | ||
| @@ -2568,11 +2687,18 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2568 | /* Wait till there is something to do */ | 2687 | /* Wait till there is something to do */ |
| 2569 | 2688 | ||
| 2570 | if (!NILP (wait_for_cell)) | 2689 | if (!NILP (wait_for_cell)) |
| 2571 | Available = non_process_wait_mask; | 2690 | { |
| 2572 | else if (! XINT (read_kbd)) | 2691 | Available = non_process_wait_mask; |
| 2573 | Available = non_keyboard_wait_mask; | 2692 | check_connect = 0; |
| 2693 | } | ||
| 2574 | else | 2694 | else |
| 2575 | Available = input_wait_mask; | 2695 | { |
| 2696 | if (! XINT (read_kbd)) | ||
| 2697 | Available = non_keyboard_wait_mask; | ||
| 2698 | else | ||
| 2699 | Available = input_wait_mask; | ||
| 2700 | check_connect = (num_pending_connects > 0); | ||
| 2701 | } | ||
| 2576 | 2702 | ||
| 2577 | /* If frame size has changed or the window is newly mapped, | 2703 | /* If frame size has changed or the window is newly mapped, |
| 2578 | redisplay now, before we start to wait. There is a race | 2704 | redisplay now, before we start to wait. There is a race |
| @@ -2587,15 +2713,21 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2587 | set_waiting_for_input (&timeout); | 2713 | set_waiting_for_input (&timeout); |
| 2588 | } | 2714 | } |
| 2589 | 2715 | ||
| 2716 | no_avail = 0; | ||
| 2590 | if (XINT (read_kbd) && detect_input_pending ()) | 2717 | if (XINT (read_kbd) && detect_input_pending ()) |
| 2591 | { | 2718 | { |
| 2592 | nfds = 0; | 2719 | nfds = 0; |
| 2593 | FD_ZERO (&Available); | 2720 | no_avail = 1; |
| 2594 | } | 2721 | } |
| 2595 | else | 2722 | else |
| 2596 | nfds = select (max (max_process_desc, max_keyboard_desc) + 1, | 2723 | { |
| 2597 | &Available, (SELECT_TYPE *)0, (SELECT_TYPE *)0, | 2724 | if (check_connect) |
| 2598 | &timeout); | 2725 | Connecting = connect_wait_mask; |
| 2726 | nfds = select (max (max_process_desc, max_keyboard_desc) + 1, | ||
| 2727 | &Available, | ||
| 2728 | (check_connect ? &Connecting : (SELECT_TYPE *)0), | ||
| 2729 | (SELECT_TYPE *)0, &timeout); | ||
| 2730 | } | ||
| 2599 | 2731 | ||
| 2600 | xerrno = errno; | 2732 | xerrno = errno; |
| 2601 | 2733 | ||
| @@ -2611,7 +2743,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2611 | if (nfds < 0) | 2743 | if (nfds < 0) |
| 2612 | { | 2744 | { |
| 2613 | if (xerrno == EINTR) | 2745 | if (xerrno == EINTR) |
| 2614 | FD_ZERO (&Available); | 2746 | no_avail = 1; |
| 2615 | #ifdef ultrix | 2747 | #ifdef ultrix |
| 2616 | /* Ultrix select seems to return ENOMEM when it is | 2748 | /* Ultrix select seems to return ENOMEM when it is |
| 2617 | interrupted. Treat it just like EINTR. Bleah. Note | 2749 | interrupted. Treat it just like EINTR. Bleah. Note |
| @@ -2619,13 +2751,13 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2619 | "__ultrix__"; the latter is only defined under GCC, but | 2751 | "__ultrix__"; the latter is only defined under GCC, but |
| 2620 | not by DEC's bundled CC. -JimB */ | 2752 | not by DEC's bundled CC. -JimB */ |
| 2621 | else if (xerrno == ENOMEM) | 2753 | else if (xerrno == ENOMEM) |
| 2622 | FD_ZERO (&Available); | 2754 | no_avail = 1; |
| 2623 | #endif | 2755 | #endif |
| 2624 | #ifdef ALLIANT | 2756 | #ifdef ALLIANT |
| 2625 | /* This happens for no known reason on ALLIANT. | 2757 | /* This happens for no known reason on ALLIANT. |
| 2626 | I am guessing that this is the right response. -- RMS. */ | 2758 | I am guessing that this is the right response. -- RMS. */ |
| 2627 | else if (xerrno == EFAULT) | 2759 | else if (xerrno == EFAULT) |
| 2628 | FD_ZERO (&Available); | 2760 | no_avail = 1; |
| 2629 | #endif | 2761 | #endif |
| 2630 | else if (xerrno == EBADF) | 2762 | else if (xerrno == EBADF) |
| 2631 | { | 2763 | { |
| @@ -2637,7 +2769,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2637 | So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF | 2769 | So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF |
| 2638 | in m/ibmrt-aix.h), and here we just ignore the select error. | 2770 | in m/ibmrt-aix.h), and here we just ignore the select error. |
| 2639 | Cleanup occurs c/o status_notify after SIGCLD. */ | 2771 | Cleanup occurs c/o status_notify after SIGCLD. */ |
| 2640 | FD_ZERO (&Available); /* Cannot depend on values returned */ | 2772 | no_avail = 1; /* Cannot depend on values returned */ |
| 2641 | #else | 2773 | #else |
| 2642 | abort (); | 2774 | abort (); |
| 2643 | #endif | 2775 | #endif |
| @@ -2645,9 +2777,16 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2645 | else | 2777 | else |
| 2646 | error ("select error: %s", emacs_strerror (xerrno)); | 2778 | error ("select error: %s", emacs_strerror (xerrno)); |
| 2647 | } | 2779 | } |
| 2780 | |||
| 2781 | if (no_avail) | ||
| 2782 | { | ||
| 2783 | FD_ZERO (&Available); | ||
| 2784 | check_connect = 0; | ||
| 2785 | } | ||
| 2786 | |||
| 2648 | #if defined(sun) && !defined(USG5_4) | 2787 | #if defined(sun) && !defined(USG5_4) |
| 2649 | else if (nfds > 0 && keyboard_bit_set (&Available) | 2788 | if (nfds > 0 && keyboard_bit_set (&Available) |
| 2650 | && interrupt_input) | 2789 | && interrupt_input) |
| 2651 | /* System sometimes fails to deliver SIGIO. | 2790 | /* System sometimes fails to deliver SIGIO. |
| 2652 | 2791 | ||
| 2653 | David J. Mackenzie says that Emacs doesn't compile under | 2792 | David J. Mackenzie says that Emacs doesn't compile under |
| @@ -2746,6 +2885,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2746 | do_pending_window_change (0); | 2885 | do_pending_window_change (0); |
| 2747 | 2886 | ||
| 2748 | /* Check for data from a process. */ | 2887 | /* Check for data from a process. */ |
| 2888 | if (no_avail || nfds == 0) | ||
| 2889 | continue; | ||
| 2890 | |||
| 2749 | /* Really FIRST_PROC_DESC should be 0 on Unix, | 2891 | /* Really FIRST_PROC_DESC should be 0 on Unix, |
| 2750 | but this is safer in the short run. */ | 2892 | but this is safer in the short run. */ |
| 2751 | for (channel = 0; channel <= max_process_desc; channel++) | 2893 | for (channel = 0; channel <= max_process_desc; channel++) |
| @@ -2837,6 +2979,64 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) | |||
| 2837 | = Fcons (Qexit, Fcons (make_number (256), Qnil)); | 2979 | = Fcons (Qexit, Fcons (make_number (256), Qnil)); |
| 2838 | } | 2980 | } |
| 2839 | } | 2981 | } |
| 2982 | #ifdef NON_BLOCKING_CONNECT | ||
| 2983 | if (check_connect && FD_ISSET (channel, &Connecting)) | ||
| 2984 | { | ||
| 2985 | struct Lisp_Process *p; | ||
| 2986 | struct sockaddr pname; | ||
| 2987 | socklen_t pnamelen = sizeof(pname); | ||
| 2988 | |||
| 2989 | FD_CLR (channel, &connect_wait_mask); | ||
| 2990 | if (--num_pending_connects < 0) | ||
| 2991 | abort (); | ||
| 2992 | |||
| 2993 | proc = chan_process[channel]; | ||
| 2994 | if (NILP (proc)) | ||
| 2995 | continue; | ||
| 2996 | |||
| 2997 | p = XPROCESS (proc); | ||
| 2998 | |||
| 2999 | #ifdef GNU_LINUX | ||
| 3000 | /* getsockopt(,,SO_ERROR,,) is said to hang on some systems. | ||
| 3001 | So only use it on systems where it is known to work. */ | ||
| 3002 | { | ||
| 3003 | socklen_t xlen = sizeof(xerrno); | ||
| 3004 | if (getsockopt(channel, SOL_SOCKET, SO_ERROR, &xerrno, &xlen)) | ||
| 3005 | xerrno = errno; | ||
| 3006 | } | ||
| 3007 | #else | ||
| 3008 | /* If connection failed, getpeername will fail. */ | ||
| 3009 | xerrno = 0; | ||
| 3010 | if (getpeername(channel, &pname, &pnamelen) < 0) | ||
| 3011 | { | ||
| 3012 | /* Obtain connect failure code through error slippage. */ | ||
| 3013 | char dummy; | ||
| 3014 | xerrno = errno; | ||
| 3015 | if (errno == ENOTCONN && read(channel, &dummy, 1) < 0) | ||
| 3016 | xerrno = errno; | ||
| 3017 | } | ||
| 3018 | #endif | ||
| 3019 | if (xerrno) | ||
| 3020 | { | ||
| 3021 | XSETINT (p->tick, ++process_tick); | ||
| 3022 | p->status = Fcons (Qfailed, Fcons (make_number (xerrno), Qnil)); | ||
| 3023 | deactivate_process (proc); | ||
| 3024 | } | ||
| 3025 | else | ||
| 3026 | { | ||
| 3027 | p->status = Qrun; | ||
| 3028 | /* Execute the sentinel here. If we had relied on | ||
| 3029 | status_notify to do it later, it will read input | ||
| 3030 | from the process before calling the sentinel. */ | ||
| 3031 | exec_sentinel (proc, build_string ("open\n")); | ||
| 3032 | if (!EQ (p->filter, Qt)) | ||
| 3033 | { | ||
| 3034 | FD_SET (XINT (p->infd), &input_wait_mask); | ||
| 3035 | FD_SET (XINT (p->infd), &non_keyboard_wait_mask); | ||
| 3036 | } | ||
| 3037 | } | ||
| 3038 | } | ||
| 3039 | #endif /* NON_BLOCKING_CONNECT */ | ||
| 2840 | } /* end for each file descriptor */ | 3040 | } /* end for each file descriptor */ |
| 2841 | } /* end while exit conditions not met */ | 3041 | } /* end while exit conditions not met */ |
| 2842 | 3042 | ||
| @@ -4419,6 +4619,7 @@ status_notify () | |||
| 4419 | 4619 | ||
| 4420 | /* If process is still active, read any output that remains. */ | 4620 | /* If process is still active, read any output that remains. */ |
| 4421 | while (! EQ (p->filter, Qt) | 4621 | while (! EQ (p->filter, Qt) |
| 4622 | && ! EQ (p->status, Qconnect) | ||
| 4422 | && XINT (p->infd) >= 0 | 4623 | && XINT (p->infd) >= 0 |
| 4423 | && read_process_output (proc, XINT (p->infd)) > 0); | 4624 | && read_process_output (proc, XINT (p->infd)) > 0); |
| 4424 | 4625 | ||
| @@ -4653,6 +4854,10 @@ syms_of_process () | |||
| 4653 | staticpro (&Qopen); | 4854 | staticpro (&Qopen); |
| 4654 | Qclosed = intern ("closed"); | 4855 | Qclosed = intern ("closed"); |
| 4655 | staticpro (&Qclosed); | 4856 | staticpro (&Qclosed); |
| 4857 | Qconnect = intern ("connect"); | ||
| 4858 | staticpro (&Qconnect); | ||
| 4859 | Qfailed = intern ("failed"); | ||
| 4860 | staticpro (&Qfailed); | ||
| 4656 | 4861 | ||
| 4657 | Qlast_nonmenu_event = intern ("last-nonmenu-event"); | 4862 | Qlast_nonmenu_event = intern ("last-nonmenu-event"); |
| 4658 | staticpro (&Qlast_nonmenu_event); | 4863 | staticpro (&Qlast_nonmenu_event); |