diff options
| author | Eli Zaretskii | 2015-03-27 12:44:31 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2015-03-27 12:44:31 +0300 |
| commit | d133cf839421462280ac0bfd9bd84c591f0e0249 (patch) | |
| tree | d964223f8da827058aece69ed66ca25ba82ebbf4 /src | |
| parent | 792d44b3c31d2a682607ab8b79ae7d26b7402f41 (diff) | |
| download | emacs-d133cf839421462280ac0bfd9bd84c591f0e0249.tar.gz emacs-d133cf839421462280ac0bfd9bd84c591f0e0249.zip | |
Support non-blocking connect on MS-Windows (Bug#20207)
Based on ideas from Kim F. Storm <storm@cua.dk>, see
http://lists.gnu.org/archive/html/emacs-devel/2006-12/msg00873.html.
src/w32proc.c (reader_thread): If the FILE_CONNECT flag is set, call
'_sys_wait_connect'. If it returns STATUS_CONNECT_FAILED, exit
the thread with code 2.
(sys_select): Support 'wfds' in addition to 'rfds'. If a
descriptor in 'wfds' has its bit set, but the corresponding
fd_info member doesn't have its FILE_CONNECT flag set, ignore the
descriptor. Otherwise, acknowledge a successful non-blocking
connect by resetting the FILE_CONNECT flag and setting cp->status
to STATUS_READ_ACKNOWLEDGED.
src/w32.h (STATUS_CONNECT_FAILED): New enumeration value.
(struct _child_process): New member 'errcode'.
(FILE_CONNECT): New flag.
(_sys_wait_connect): Add prototype.
src/w32.c (pfn_WSAEnumNetworkEvents): New function pointer.
(init_winsock): Load WSAEnumNetworkEvents from winsock DLL.
(set_errno): Map WSAEWOULDBLOCK and WSAENOTCONN.
(sys_connect): Support non-blocking 'connect' calls by setting the
FILE_CONNECT flag in the fd_info member and returning EINPROGRESS.
(_sys_read_ahead): Add debug message if this function is called
for a descriptor that waits for a non-blocking connect to complete.
(_sys_wait_connect): New function.
(sys_read): Support STATUS_CONNECT_FAILED. Return the error code
recorded by _sys_wait_connect when the non-blocking connect
failed. Don't call WSAGetLastError before a call to set_errno had
a chance to use its value, since WSAGetLastError clears the last
error.
nt/inc/ms-w32.h (BROKEN_NON_BLOCKING_CONNECT): Don't define.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 35 | ||||
| -rw-r--r-- | src/w32.c | 105 | ||||
| -rw-r--r-- | src/w32.h | 9 | ||||
| -rw-r--r-- | src/w32proc.c | 77 |
4 files changed, 204 insertions, 22 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 632b798ce08..67e04f6f41c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,38 @@ | |||
| 1 | 2015-03-27 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | Support non-blocking connect on MS-Windows. | ||
| 4 | Based on ideas from Kim F. Storm <storm@cua.dk>, see | ||
| 5 | http://lists.gnu.org/archive/html/emacs-devel/2006-12/msg00873.html. | ||
| 6 | |||
| 7 | * w32proc.c (reader_thread): If the FILE_CONNECT flag is set, call | ||
| 8 | '_sys_wait_connect'. If it returns STATUS_CONNECT_FAILED, exit | ||
| 9 | the thread with code 2. | ||
| 10 | (sys_select): Support 'wfds' in addition to 'rfds'. If a | ||
| 11 | descriptor in 'wfds' has its bit set, but the corresponding | ||
| 12 | fd_info member doesn't have its FILE_CONNECT flag set, ignore the | ||
| 13 | descriptor. Otherwise, acknowledge a successful non-blocking | ||
| 14 | connect by resetting the FILE_CONNECT flag and setting cp->status | ||
| 15 | to STATUS_READ_ACKNOWLEDGED. (Bug#20207) | ||
| 16 | |||
| 17 | * w32.h (STATUS_CONNECT_FAILED): New enumeration value. | ||
| 18 | (struct _child_process): New member 'errcode'. | ||
| 19 | (FILE_CONNECT): New flag. | ||
| 20 | (_sys_wait_connect): Add prototype. | ||
| 21 | |||
| 22 | * w32.c (pfn_WSAEnumNetworkEvents): New function pointer. | ||
| 23 | (init_winsock): Load WSAEnumNetworkEvents from winsock DLL. | ||
| 24 | (set_errno): Map WSAEWOULDBLOCK and WSAENOTCONN. | ||
| 25 | (sys_connect): Support non-blocking 'connect' calls by setting the | ||
| 26 | FILE_CONNECT flag in the fd_info member and returning EINPROGRESS. | ||
| 27 | (_sys_read_ahead): Add debug message if this function is called | ||
| 28 | for a descriptor that waits for a non-blocking connect to complete. | ||
| 29 | (_sys_wait_connect): New function. | ||
| 30 | (sys_read): Support STATUS_CONNECT_FAILED. Return the error code | ||
| 31 | recorded by _sys_wait_connect when the non-blocking connect | ||
| 32 | failed. Don't call WSAGetLastError before a call to set_errno had | ||
| 33 | a chance to use its value, since WSAGetLastError clears the last | ||
| 34 | error. | ||
| 35 | |||
| 1 | 2015-03-25 Stefan Monnier <monnier@iro.umontreal.ca> | 36 | 2015-03-25 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 37 | ||
| 3 | * editfns.c (save_excursion_save): Don't save the mark. | 38 | * editfns.c (save_excursion_save): Don't save the mark. |
| @@ -7038,6 +7038,9 @@ int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData); | |||
| 7038 | void (PASCAL *pfn_WSASetLastError) (int iError); | 7038 | void (PASCAL *pfn_WSASetLastError) (int iError); |
| 7039 | int (PASCAL *pfn_WSAGetLastError) (void); | 7039 | int (PASCAL *pfn_WSAGetLastError) (void); |
| 7040 | int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents); | 7040 | int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents); |
| 7041 | int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject, | ||
| 7042 | WSANETWORKEVENTS *NetworkEvents); | ||
| 7043 | |||
| 7041 | HANDLE (PASCAL *pfn_WSACreateEvent) (void); | 7044 | HANDLE (PASCAL *pfn_WSACreateEvent) (void); |
| 7042 | int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent); | 7045 | int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent); |
| 7043 | int (PASCAL *pfn_socket) (int af, int type, int protocol); | 7046 | int (PASCAL *pfn_socket) (int af, int type, int protocol); |
| @@ -7123,6 +7126,7 @@ init_winsock (int load_now) | |||
| 7123 | LOAD_PROC (WSASetLastError); | 7126 | LOAD_PROC (WSASetLastError); |
| 7124 | LOAD_PROC (WSAGetLastError); | 7127 | LOAD_PROC (WSAGetLastError); |
| 7125 | LOAD_PROC (WSAEventSelect); | 7128 | LOAD_PROC (WSAEventSelect); |
| 7129 | LOAD_PROC (WSAEnumNetworkEvents); | ||
| 7126 | LOAD_PROC (WSACreateEvent); | 7130 | LOAD_PROC (WSACreateEvent); |
| 7127 | LOAD_PROC (WSACloseEvent); | 7131 | LOAD_PROC (WSACloseEvent); |
| 7128 | LOAD_PROC (socket); | 7132 | LOAD_PROC (socket); |
| @@ -7206,6 +7210,8 @@ set_errno (void) | |||
| 7206 | case WSAEMFILE: errno = EMFILE; break; | 7210 | case WSAEMFILE: errno = EMFILE; break; |
| 7207 | case WSAENAMETOOLONG: errno = ENAMETOOLONG; break; | 7211 | case WSAENAMETOOLONG: errno = ENAMETOOLONG; break; |
| 7208 | case WSAENOTEMPTY: errno = ENOTEMPTY; break; | 7212 | case WSAENOTEMPTY: errno = ENOTEMPTY; break; |
| 7213 | case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break; | ||
| 7214 | case WSAENOTCONN: errno = ENOTCONN; break; | ||
| 7209 | default: errno = wsa_err; break; | 7215 | default: errno = wsa_err; break; |
| 7210 | } | 7216 | } |
| 7211 | } | 7217 | } |
| @@ -7473,8 +7479,18 @@ sys_connect (int s, const struct sockaddr * name, int namelen) | |||
| 7473 | { | 7479 | { |
| 7474 | int rc = pfn_connect (SOCK_HANDLE (s), name, namelen); | 7480 | int rc = pfn_connect (SOCK_HANDLE (s), name, namelen); |
| 7475 | if (rc == SOCKET_ERROR) | 7481 | if (rc == SOCKET_ERROR) |
| 7476 | set_errno (); | 7482 | { |
| 7477 | return rc; | 7483 | set_errno (); |
| 7484 | /* If this is a non-blocking 'connect', set the bit in flags | ||
| 7485 | that will tell reader_thread to wait for connection | ||
| 7486 | before trying to read. */ | ||
| 7487 | if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0) | ||
| 7488 | { | ||
| 7489 | errno = EINPROGRESS; /* that's what process.c expects */ | ||
| 7490 | fd_info[s].flags |= FILE_CONNECT; | ||
| 7491 | } | ||
| 7492 | return rc; | ||
| 7493 | } | ||
| 7478 | } | 7494 | } |
| 7479 | errno = ENOTSOCK; | 7495 | errno = ENOTSOCK; |
| 7480 | return SOCKET_ERROR; | 7496 | return SOCKET_ERROR; |
| @@ -7984,6 +8000,8 @@ _sys_read_ahead (int fd) | |||
| 7984 | emacs_abort (); | 8000 | emacs_abort (); |
| 7985 | } | 8001 | } |
| 7986 | 8002 | ||
| 8003 | if ((fd_info[fd].flags & FILE_CONNECT) != 0) | ||
| 8004 | DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd)); | ||
| 7987 | cp->status = STATUS_READ_IN_PROGRESS; | 8005 | cp->status = STATUS_READ_IN_PROGRESS; |
| 7988 | 8006 | ||
| 7989 | if (fd_info[fd].flags & FILE_PIPE) | 8007 | if (fd_info[fd].flags & FILE_PIPE) |
| @@ -8106,6 +8124,60 @@ _sys_wait_accept (int fd) | |||
| 8106 | } | 8124 | } |
| 8107 | 8125 | ||
| 8108 | int | 8126 | int |
| 8127 | _sys_wait_connect (int fd) | ||
| 8128 | { | ||
| 8129 | HANDLE hEv; | ||
| 8130 | child_process * cp; | ||
| 8131 | int rc; | ||
| 8132 | |||
| 8133 | if (fd < 0 || fd >= MAXDESC) | ||
| 8134 | return STATUS_READ_ERROR; | ||
| 8135 | |||
| 8136 | cp = fd_info[fd].cp; | ||
| 8137 | if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY) | ||
| 8138 | return STATUS_READ_ERROR; | ||
| 8139 | |||
| 8140 | cp->status = STATUS_READ_FAILED; | ||
| 8141 | |||
| 8142 | hEv = pfn_WSACreateEvent (); | ||
| 8143 | rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT); | ||
| 8144 | if (rc != SOCKET_ERROR) | ||
| 8145 | { | ||
| 8146 | do { | ||
| 8147 | rc = WaitForSingleObject (hEv, 500); | ||
| 8148 | Sleep (5); | ||
| 8149 | } while (rc == WAIT_TIMEOUT | ||
| 8150 | && cp->status != STATUS_READ_ERROR | ||
| 8151 | && cp->char_avail); | ||
| 8152 | if (rc == WAIT_OBJECT_0) | ||
| 8153 | { | ||
| 8154 | /* We've got an event, but it could be a successful | ||
| 8155 | connection, or it could be a failure. Find out | ||
| 8156 | which one is it. */ | ||
| 8157 | WSANETWORKEVENTS events; | ||
| 8158 | |||
| 8159 | pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events); | ||
| 8160 | if ((events.lNetworkEvents & FD_CONNECT) != 0 | ||
| 8161 | && events.iErrorCode[FD_CONNECT_BIT]) | ||
| 8162 | { | ||
| 8163 | cp->status = STATUS_CONNECT_FAILED; | ||
| 8164 | cp->errcode = events.iErrorCode[FD_CONNECT_BIT]; | ||
| 8165 | } | ||
| 8166 | else | ||
| 8167 | { | ||
| 8168 | cp->status = STATUS_READ_SUCCEEDED; | ||
| 8169 | cp->errcode = 0; | ||
| 8170 | } | ||
| 8171 | } | ||
| 8172 | pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0); | ||
| 8173 | } | ||
| 8174 | else | ||
| 8175 | pfn_WSACloseEvent (hEv); | ||
| 8176 | |||
| 8177 | return cp->status; | ||
| 8178 | } | ||
| 8179 | |||
| 8180 | int | ||
| 8109 | sys_read (int fd, char * buffer, unsigned int count) | 8181 | sys_read (int fd, char * buffer, unsigned int count) |
| 8110 | { | 8182 | { |
| 8111 | int nchars; | 8183 | int nchars; |
| @@ -8174,6 +8246,7 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 8174 | ResetEvent (cp->char_avail); | 8246 | ResetEvent (cp->char_avail); |
| 8175 | 8247 | ||
| 8176 | case STATUS_READ_ACKNOWLEDGED: | 8248 | case STATUS_READ_ACKNOWLEDGED: |
| 8249 | case STATUS_CONNECT_FAILED: | ||
| 8177 | break; | 8250 | break; |
| 8178 | 8251 | ||
| 8179 | default: | 8252 | default: |
| @@ -8239,7 +8312,29 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 8239 | { | 8312 | { |
| 8240 | if (winsock_lib == NULL) emacs_abort (); | 8313 | if (winsock_lib == NULL) emacs_abort (); |
| 8241 | 8314 | ||
| 8242 | /* do the equivalent of a non-blocking read */ | 8315 | /* When a non-blocking 'connect' call fails, |
| 8316 | wait_reading_process_output detects this by calling | ||
| 8317 | 'getpeername', and then attempts to obtain the connection | ||
| 8318 | error code by trying to read 1 byte from the socket. If | ||
| 8319 | we try to serve that read by calling 'recv' below, the | ||
| 8320 | error we get is a generic WSAENOTCONN, not the actual | ||
| 8321 | connection error. So instead, we use the actual error | ||
| 8322 | code stashed by '_sys_wait_connect' in cp->errcode. | ||
| 8323 | Alternatively, we could have used 'getsockopt', like on | ||
| 8324 | GNU/Linux, but: (a) I have no idea whether the winsock | ||
| 8325 | version could hang, as it does "on some systems" (see the | ||
| 8326 | comment in process.c); and (b) 'getsockopt' on Windows is | ||
| 8327 | documented to clear the socket error for the entire | ||
| 8328 | process, which I'm not sure is TRT; FIXME. */ | ||
| 8329 | if (current_status == STATUS_CONNECT_FAILED | ||
| 8330 | && (fd_info[fd].flags & FILE_CONNECT) != 0 | ||
| 8331 | && cp->errcode != 0) | ||
| 8332 | { | ||
| 8333 | pfn_WSASetLastError (cp->errcode); | ||
| 8334 | set_errno (); | ||
| 8335 | return -1; | ||
| 8336 | } | ||
| 8337 | /* Do the equivalent of a non-blocking read. */ | ||
| 8243 | pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); | 8338 | pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); |
| 8244 | if (waiting == 0 && nchars == 0) | 8339 | if (waiting == 0 && nchars == 0) |
| 8245 | { | 8340 | { |
| @@ -8253,9 +8348,9 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 8253 | int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0); | 8348 | int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0); |
| 8254 | if (res == SOCKET_ERROR) | 8349 | if (res == SOCKET_ERROR) |
| 8255 | { | 8350 | { |
| 8256 | DebPrint (("sys_read.recv failed with error %d on socket %ld\n", | ||
| 8257 | pfn_WSAGetLastError (), SOCK_HANDLE (fd))); | ||
| 8258 | set_errno (); | 8351 | set_errno (); |
| 8352 | DebPrint (("sys_read.recv failed with error %d on socket %ld\n", | ||
| 8353 | errno, SOCK_HANDLE (fd))); | ||
| 8259 | return -1; | 8354 | return -1; |
| 8260 | } | 8355 | } |
| 8261 | nchars += res; | 8356 | nchars += res; |
| @@ -61,7 +61,8 @@ enum { | |||
| 61 | STATUS_READ_IN_PROGRESS, | 61 | STATUS_READ_IN_PROGRESS, |
| 62 | STATUS_READ_FAILED, | 62 | STATUS_READ_FAILED, |
| 63 | STATUS_READ_SUCCEEDED, | 63 | STATUS_READ_SUCCEEDED, |
| 64 | STATUS_READ_ACKNOWLEDGED | 64 | STATUS_READ_ACKNOWLEDGED, |
| 65 | STATUS_CONNECT_FAILED | ||
| 65 | }; | 66 | }; |
| 66 | 67 | ||
| 67 | /* This structure is used for both pipes and sockets; for | 68 | /* This structure is used for both pipes and sockets; for |
| @@ -96,6 +97,8 @@ typedef struct _child_process | |||
| 96 | /* Status of subprocess/connection and of reading its output. For | 97 | /* Status of subprocess/connection and of reading its output. For |
| 97 | values, see the enumeration above. */ | 98 | values, see the enumeration above. */ |
| 98 | volatile int status; | 99 | volatile int status; |
| 100 | /* Used to store errno value of failed async 'connect' calls. */ | ||
| 101 | volatile int errcode; | ||
| 99 | /* Holds a single character read by _sys_read_ahead, when a | 102 | /* Holds a single character read by _sys_read_ahead, when a |
| 100 | subprocess has some output ready. */ | 103 | subprocess has some output ready. */ |
| 101 | char chr; | 104 | char chr; |
| @@ -122,7 +125,8 @@ extern filedesc fd_info [ MAXDESC ]; | |||
| 122 | /* fd_info flag definitions */ | 125 | /* fd_info flag definitions */ |
| 123 | #define FILE_READ 0x0001 | 126 | #define FILE_READ 0x0001 |
| 124 | #define FILE_WRITE 0x0002 | 127 | #define FILE_WRITE 0x0002 |
| 125 | #define FILE_LISTEN 0x0004 | 128 | #define FILE_LISTEN 0x0004 |
| 129 | #define FILE_CONNECT 0x0008 | ||
| 126 | #define FILE_BINARY 0x0010 | 130 | #define FILE_BINARY 0x0010 |
| 127 | #define FILE_LAST_CR 0x0020 | 131 | #define FILE_LAST_CR 0x0020 |
| 128 | #define FILE_AT_EOF 0x0040 | 132 | #define FILE_AT_EOF 0x0040 |
| @@ -171,6 +175,7 @@ extern void init_timers (void); | |||
| 171 | 175 | ||
| 172 | extern int _sys_read_ahead (int fd); | 176 | extern int _sys_read_ahead (int fd); |
| 173 | extern int _sys_wait_accept (int fd); | 177 | extern int _sys_wait_accept (int fd); |
| 178 | extern int _sys_wait_connect (int fd); | ||
| 174 | 179 | ||
| 175 | extern HMODULE w32_delayed_load (Lisp_Object); | 180 | extern HMODULE w32_delayed_load (Lisp_Object); |
| 176 | 181 | ||
diff --git a/src/w32proc.c b/src/w32proc.c index 74731db2426..2d10534aa47 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -1011,7 +1011,9 @@ reader_thread (void *arg) | |||
| 1011 | { | 1011 | { |
| 1012 | int rc; | 1012 | int rc; |
| 1013 | 1013 | ||
| 1014 | if (cp->fd >= 0 && fd_info[cp->fd].flags & FILE_LISTEN) | 1014 | if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_CONNECT) != 0) |
| 1015 | rc = _sys_wait_connect (cp->fd); | ||
| 1016 | else if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_LISTEN) != 0) | ||
| 1015 | rc = _sys_wait_accept (cp->fd); | 1017 | rc = _sys_wait_accept (cp->fd); |
| 1016 | else | 1018 | else |
| 1017 | rc = _sys_read_ahead (cp->fd); | 1019 | rc = _sys_read_ahead (cp->fd); |
| @@ -1031,8 +1033,8 @@ reader_thread (void *arg) | |||
| 1031 | return 1; | 1033 | return 1; |
| 1032 | } | 1034 | } |
| 1033 | 1035 | ||
| 1034 | if (rc == STATUS_READ_ERROR) | 1036 | if (rc == STATUS_READ_ERROR || rc == STATUS_CONNECT_FAILED) |
| 1035 | return 1; | 1037 | return 2; |
| 1036 | 1038 | ||
| 1037 | /* If the read died, the child has died so let the thread die */ | 1039 | /* If the read died, the child has died so let the thread die */ |
| 1038 | if (rc == STATUS_READ_FAILED) | 1040 | if (rc == STATUS_READ_FAILED) |
| @@ -1929,7 +1931,7 @@ int | |||
| 1929 | sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | 1931 | sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, |
| 1930 | struct timespec *timeout, void *ignored) | 1932 | struct timespec *timeout, void *ignored) |
| 1931 | { | 1933 | { |
| 1932 | SELECT_TYPE orfds; | 1934 | SELECT_TYPE orfds, owfds; |
| 1933 | DWORD timeout_ms, start_time; | 1935 | DWORD timeout_ms, start_time; |
| 1934 | int i, nh, nc, nr; | 1936 | int i, nh, nc, nr; |
| 1935 | DWORD active; | 1937 | DWORD active; |
| @@ -1947,15 +1949,27 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | |||
| 1947 | return 0; | 1949 | return 0; |
| 1948 | } | 1950 | } |
| 1949 | 1951 | ||
| 1950 | /* Otherwise, we only handle rfds, so fail otherwise. */ | 1952 | /* Otherwise, we only handle rfds and wfds, so fail otherwise. */ |
| 1951 | if (rfds == NULL || wfds != NULL || efds != NULL) | 1953 | if ((rfds == NULL && wfds == NULL) || efds != NULL) |
| 1952 | { | 1954 | { |
| 1953 | errno = EINVAL; | 1955 | errno = EINVAL; |
| 1954 | return -1; | 1956 | return -1; |
| 1955 | } | 1957 | } |
| 1956 | 1958 | ||
| 1957 | orfds = *rfds; | 1959 | if (rfds) |
| 1958 | FD_ZERO (rfds); | 1960 | { |
| 1961 | orfds = *rfds; | ||
| 1962 | FD_ZERO (rfds); | ||
| 1963 | } | ||
| 1964 | else | ||
| 1965 | FD_ZERO (&orfds); | ||
| 1966 | if (wfds) | ||
| 1967 | { | ||
| 1968 | owfds = *wfds; | ||
| 1969 | FD_ZERO (wfds); | ||
| 1970 | } | ||
| 1971 | else | ||
| 1972 | FD_ZERO (&owfds); | ||
| 1959 | nr = 0; | 1973 | nr = 0; |
| 1960 | 1974 | ||
| 1961 | /* If interrupt_handle is available and valid, always wait on it, to | 1975 | /* If interrupt_handle is available and valid, always wait on it, to |
| @@ -1970,7 +1984,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | |||
| 1970 | 1984 | ||
| 1971 | /* Build a list of pipe handles to wait on. */ | 1985 | /* Build a list of pipe handles to wait on. */ |
| 1972 | for (i = 0; i < nfds; i++) | 1986 | for (i = 0; i < nfds; i++) |
| 1973 | if (FD_ISSET (i, &orfds)) | 1987 | if (FD_ISSET (i, &orfds) || FD_ISSET (i, &owfds)) |
| 1974 | { | 1988 | { |
| 1975 | if (i == 0) | 1989 | if (i == 0) |
| 1976 | { | 1990 | { |
| @@ -1984,7 +1998,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | |||
| 1984 | 1998 | ||
| 1985 | /* Check for any emacs-generated input in the queue since | 1999 | /* Check for any emacs-generated input in the queue since |
| 1986 | it won't be detected in the wait */ | 2000 | it won't be detected in the wait */ |
| 1987 | if (detect_input_pending ()) | 2001 | if (rfds && detect_input_pending ()) |
| 1988 | { | 2002 | { |
| 1989 | FD_SET (i, rfds); | 2003 | FD_SET (i, rfds); |
| 1990 | return 1; | 2004 | return 1; |
| @@ -1999,6 +2013,13 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | |||
| 1999 | { | 2013 | { |
| 2000 | /* Child process and socket/comm port input. */ | 2014 | /* Child process and socket/comm port input. */ |
| 2001 | cp = fd_info[i].cp; | 2015 | cp = fd_info[i].cp; |
| 2016 | if (FD_ISSET (i, &owfds) | ||
| 2017 | && cp | ||
| 2018 | && (fd_info[i].flags && FILE_CONNECT) == 0) | ||
| 2019 | { | ||
| 2020 | DebPrint (("sys_select: fd %d is in wfds, but FILE_CONNECT is reset!\n", i)); | ||
| 2021 | cp = NULL; | ||
| 2022 | } | ||
| 2002 | if (cp) | 2023 | if (cp) |
| 2003 | { | 2024 | { |
| 2004 | int current_status = cp->status; | 2025 | int current_status = cp->status; |
| @@ -2007,6 +2028,8 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | |||
| 2007 | { | 2028 | { |
| 2008 | /* Tell reader thread which file handle to use. */ | 2029 | /* Tell reader thread which file handle to use. */ |
| 2009 | cp->fd = i; | 2030 | cp->fd = i; |
| 2031 | /* Zero out the error code. */ | ||
| 2032 | cp->errcode = 0; | ||
| 2010 | /* Wake up the reader thread for this process */ | 2033 | /* Wake up the reader thread for this process */ |
| 2011 | cp->status = STATUS_READ_READY; | 2034 | cp->status = STATUS_READ_READY; |
| 2012 | if (!SetEvent (cp->char_consumed)) | 2035 | if (!SetEvent (cp->char_consumed)) |
| @@ -2197,7 +2220,7 @@ count_children: | |||
| 2197 | 2220 | ||
| 2198 | if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_AT_EOF) == 0) | 2221 | if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_AT_EOF) == 0) |
| 2199 | fd_info[cp->fd].flags |= FILE_SEND_SIGCHLD; | 2222 | fd_info[cp->fd].flags |= FILE_SEND_SIGCHLD; |
| 2200 | /* SIG_DFL for SIGCHLD is ignore */ | 2223 | /* SIG_DFL for SIGCHLD is ignored */ |
| 2201 | else if (sig_handlers[SIGCHLD] != SIG_DFL && | 2224 | else if (sig_handlers[SIGCHLD] != SIG_DFL && |
| 2202 | sig_handlers[SIGCHLD] != SIG_IGN) | 2225 | sig_handlers[SIGCHLD] != SIG_IGN) |
| 2203 | { | 2226 | { |
| @@ -2214,7 +2237,7 @@ count_children: | |||
| 2214 | errno = EINTR; | 2237 | errno = EINTR; |
| 2215 | return -1; | 2238 | return -1; |
| 2216 | } | 2239 | } |
| 2217 | else if (fdindex[active] == 0) | 2240 | else if (rfds && fdindex[active] == 0) |
| 2218 | { | 2241 | { |
| 2219 | /* Keyboard input available */ | 2242 | /* Keyboard input available */ |
| 2220 | FD_SET (0, rfds); | 2243 | FD_SET (0, rfds); |
| @@ -2222,9 +2245,33 @@ count_children: | |||
| 2222 | } | 2245 | } |
| 2223 | else | 2246 | else |
| 2224 | { | 2247 | { |
| 2225 | /* must be a socket or pipe - read ahead should have | 2248 | /* Must be a socket or pipe - read ahead should have |
| 2226 | completed, either succeeding or failing. */ | 2249 | completed, either succeeding or failing. If this handle |
| 2227 | FD_SET (fdindex[active], rfds); | 2250 | was waiting for an async 'connect', reset the connect |
| 2251 | flag, so it could read from now on. */ | ||
| 2252 | if (wfds && (fd_info[fdindex[active]].flags & FILE_CONNECT) != 0) | ||
| 2253 | { | ||
| 2254 | cp = fd_info[fdindex[active]].cp; | ||
| 2255 | if (cp) | ||
| 2256 | { | ||
| 2257 | /* Don't reset the FILE_CONNECT bit and don't | ||
| 2258 | acknowledge the read if the status is | ||
| 2259 | STATUS_CONNECT_FAILED or some other | ||
| 2260 | failure. That's because the thread exits in those | ||
| 2261 | cases, so it doesn't need the ACK, and we want to | ||
| 2262 | keep the FILE_CONNECT bit as evidence that the | ||
| 2263 | connect failed, to be checked in sys_read. */ | ||
| 2264 | if (cp->status == STATUS_READ_SUCCEEDED) | ||
| 2265 | { | ||
| 2266 | fd_info[cp->fd].flags &= ~FILE_CONNECT; | ||
| 2267 | cp->status = STATUS_READ_ACKNOWLEDGED; | ||
| 2268 | } | ||
| 2269 | ResetEvent (cp->char_avail); | ||
| 2270 | } | ||
| 2271 | FD_SET (fdindex[active], wfds); | ||
| 2272 | } | ||
| 2273 | else if (rfds) | ||
| 2274 | FD_SET (fdindex[active], rfds); | ||
| 2228 | nr++; | 2275 | nr++; |
| 2229 | } | 2276 | } |
| 2230 | 2277 | ||