diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index ec81ae8a1..aa0951ee9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,19 @@ +2004-03-29 Corinna Vinschen + + * fhandler.h (class fhandler_socket): Add has_been_closed member. + * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize + has_been_closed to 0. + (fhandler_socket::recvfrom): Use new asynchronous I/O driven + wsock_event methods. + (fhandler_socket::recvmsg): Ditto. + (fhandler_socket::sendto): Ditto. + (fhandler_socket::sendmsg): Ditto. + * net.cc (wsock_event::prepare): Reimplement using asynchronous I/O. + (wsock_event::wait): Ditto. + (wsock_event::release): New method. + * wsock_event.h (class wsock_event): Remove ovr member. Accomodate + new implementation of prepare and wait methods. Add release method. + 2004-03-29 Thomas Pfaff * thread.cc (pthread::atforkprepare): Call diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 0b5c71299..a38b50a55 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -377,6 +377,7 @@ class fhandler_socket: public fhandler_base struct _WSAPROTOCOL_INFOA *prot_info_ptr; char *sun_path; int had_connect_or_listen; + int has_been_closed; public: fhandler_socket (); diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 63f28fb27..0c3058867 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -122,7 +122,7 @@ get_inet_addr (const struct sockaddr *in, int inlen, /* fhandler_socket */ fhandler_socket::fhandler_socket () - : fhandler_base (), sun_path (NULL) + : fhandler_base (), sun_path (NULL), has_been_closed (0) { set_need_fork_fixup (); prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF, @@ -726,19 +726,28 @@ fhandler_socket::recvfrom (void *ptr, size_t len, int flags, { WSABUF wsabuf = { len, (char *) ptr }; - if (is_nonblocking ()) + if (is_nonblocking () || has_been_closed) res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags, from, fromlen, NULL, NULL); else { wsock_event wsock_evt; - res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, (DWORD *) &flags, - from, fromlen, - wsock_evt.prepare (), NULL); - - if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) - ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); + long evt = (FD_CLOSE | ((flags & MSG_OOB) ? FD_OOB : FD_READ)); + if (wsock_evt.prepare (get_socket (), evt)) + { + do + { + if (!(res = wsock_evt.wait (get_socket (), has_been_closed))) + res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, + (DWORD *) &flags, from, fromlen, + NULL, NULL); + } + while (res == SOCKET_ERROR + && WSAGetLastError () == WSAEWOULDBLOCK + && !has_been_closed); + wsock_evt.release (get_socket ()); + } } } @@ -844,7 +853,7 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot) DWORD ret; - if (is_nonblocking ()) + if (is_nonblocking () || has_been_closed) res = WSARecvFrom (get_socket (), wsabuf, iovcnt, &ret, (DWORD *) &flags, from, fromlen, @@ -852,13 +861,21 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot) else { wsock_event wsock_evt; - res = WSARecvFrom (get_socket (), - wsabuf, iovcnt, &ret, (DWORD *) &flags, - from, fromlen, - wsock_evt.prepare (), NULL); - - if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) - ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); + long evt = (FD_CLOSE | ((flags & MSG_OOB) ? FD_OOB : FD_READ)); + if (wsock_evt.prepare (get_socket (), evt)) + { + do + { + if (!(res = wsock_evt.wait (get_socket (), has_been_closed))) + res = WSARecvFrom (get_socket (), wsabuf, iovcnt, &ret, + (DWORD *) &flags, from, fromlen, + NULL, NULL); + } + while (res == SOCKET_ERROR + && WSAGetLastError () == WSAEWOULDBLOCK + && !has_been_closed); + wsock_evt.release (get_socket ()); + } } if (res == SOCKET_ERROR) @@ -915,7 +932,7 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, { WSABUF wsabuf = { len, (char *) ptr }; - if (is_nonblocking ()) + if (is_nonblocking () || has_been_closed) res = WSASendTo (get_socket (), &wsabuf, 1, &ret, flags & MSG_WINMASK, (to ? (const struct sockaddr *) &sin : NULL), tolen, @@ -923,13 +940,26 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, else { wsock_event wsock_evt; - res = WSASendTo (get_socket (), &wsabuf, 1, &ret, - flags & MSG_WINMASK, - (to ? (const struct sockaddr *) &sin : NULL), tolen, - wsock_evt.prepare (), NULL); - - if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) - ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); + if (wsock_evt.prepare (get_socket (), FD_CLOSE | FD_WRITE)) + { + do + { + res = WSASendTo (get_socket (), &wsabuf, 1, &ret, + flags & MSG_WINMASK, + (to ? (const struct sockaddr *) &sin : NULL), + tolen, NULL, NULL); + if (res != SOCKET_ERROR + || WSAGetLastError () != WSAEWOULDBLOCK) + break; + if (ret > 0) + { + res = 0; + break; + } + } + while (!(res = wsock_evt.wait (get_socket (), has_been_closed))); + wsock_evt.release (get_socket ()); + } } } @@ -1041,7 +1071,7 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot) DWORD ret; - if (is_nonblocking ()) + if (is_nonblocking () || has_been_closed) res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags, (struct sockaddr *) msg->msg_name, msg->msg_namelen, @@ -1049,13 +1079,25 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot) else { wsock_event wsock_evt; - res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, flags, - (struct sockaddr *) msg->msg_name, - msg->msg_namelen, - wsock_evt.prepare (), NULL); - - if (res == SOCKET_ERROR && WSAGetLastError () == WSA_IO_PENDING) - ret = res = wsock_evt.wait (get_socket (), (DWORD *) &flags); + if (wsock_evt.prepare (get_socket (), FD_CLOSE | FD_WRITE)) + { + do + { + res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret, + flags, (struct sockaddr *) msg->msg_name, + msg->msg_namelen, NULL, NULL); + if (res != SOCKET_ERROR + || WSAGetLastError () != WSAEWOULDBLOCK) + break; + if (ret > 0) + { + res = 0; + break; + } + } + while (!(res = wsock_evt.wait (get_socket (), has_been_closed))); + wsock_evt.release (get_socket ()); + } } if (res == SOCKET_ERROR) diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 8c4090b28..3d76a433b 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -50,58 +50,75 @@ extern "C" int sscanf (const char *, const char *, ...); } /* End of "C" section */ -LPWSAOVERLAPPED -wsock_event::prepare () +bool +wsock_event::prepare (int sock, long event_mask) { - LPWSAOVERLAPPED ret = NULL; - SetLastError (0); - if ((event = WSACreateEvent ()) != WSA_INVALID_EVENT) + if ((event = WSACreateEvent ()) != WSA_INVALID_EVENT + && WSAEventSelect (sock, event, event_mask) == SOCKET_ERROR) { - memset (&ovr, 0, sizeof ovr); - ovr.hEvent = event; - ret = &ovr; + debug_printf ("WSAEventSelect: %E"); + WSACloseEvent (event); + event = WSA_INVALID_EVENT; } - else if (GetLastError () == ERROR_PROC_NOT_FOUND) /* winsock2 not available */ - WSASetLastError (0); - - debug_printf ("%d = wsock_event::prepare ()", ret); - return ret; + return event != WSA_INVALID_EVENT; } int -wsock_event::wait (int socket, LPDWORD flags) +wsock_event::wait (int sock, int &closed) { int ret = -1; + DWORD wsa_err = 0; WSAEVENT ev[2] = { event, signal_arrived }; - DWORD len; - switch (WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE, FALSE)) { case WSA_WAIT_EVENT_0: - if (WSAGetOverlappedResult (socket, &ovr, &len, FALSE, flags)) - ret = (int) len; + WSANETWORKEVENTS evts; + memset (&evts, 0, sizeof evts); + WSAEnumNetworkEvents (sock, event, &evts); + if (evts.lNetworkEvents & FD_READ) + { + if (evts.iErrorCode[FD_READ_BIT]) + wsa_err = evts.iErrorCode[FD_READ_BIT]; + else + ret = 0; + } + else if (evts.lNetworkEvents & FD_WRITE) + { + if (evts.iErrorCode[FD_WRITE_BIT]) + wsa_err = evts.iErrorCode[FD_WRITE_BIT]; + else + ret = 0; + } + if (evts.lNetworkEvents & FD_CLOSE) + { + closed = 1; + if (!wsa_err && evts.iErrorCode[FD_CLOSE_BIT]) + wsa_err = evts.iErrorCode[FD_CLOSE_BIT]; + else + ret = 0; + } + if (wsa_err) + WSASetLastError (wsa_err); break; case WSA_WAIT_EVENT_0 + 1: - if (!CancelIo ((HANDLE) socket)) - { - debug_printf ("CancelIo() %E, fallback to blocking io"); - WSAGetOverlappedResult (socket, &ovr, &len, TRUE, flags); - } - else - WSASetLastError (WSAEINTR); + WSASetLastError (WSAEINTR); break; - case WSA_WAIT_FAILED: - break; - default: /* Should be impossible. *LOL* */ + default: WSASetLastError (WSAEFAULT); - break; } - WSACloseEvent (event); - event = NULL; return ret; } +void +wsock_event::release (int sock) +{ + WSAEventSelect (sock, event, 0); + WSACloseEvent (event); + unsigned long non_block = 0; + ioctlsocket (sock, FIONBIO, &non_block); +} + WSADATA wsadata; static fhandler_socket * diff --git a/winsup/cygwin/wsock_event.h b/winsup/cygwin/wsock_event.h index 3f8638134..9a1f07ac1 100644 --- a/winsup/cygwin/wsock_event.h +++ b/winsup/cygwin/wsock_event.h @@ -14,7 +14,6 @@ details. */ class wsock_event { WSAEVENT event; - WSAOVERLAPPED ovr; public: wsock_event () : event (NULL) {}; ~wsock_event () @@ -25,8 +24,9 @@ public: }; /* The methods are implemented in net.cc */ - LPWSAOVERLAPPED prepare (); - int wait (int socket, LPDWORD flags); + bool prepare (int sock, long event_mask); + int wait (int sock, int &closed); + void release (int sock); }; #endif /* __WSOCK_EVENT_H__ */