diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index d205c4754..a1f575ab4 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,21 @@
+2005-04-18  Corinna Vinschen  <corinna@vinschen.de>
+
+	* fhandler.h (enum conn_state): Add connect_failed state.
+	* fhandler_socket.cc (fhandler_socket::connect): Set connect_state to
+	connect_failed when connect failed.
+	* poll.cc (poll): Change errno to EINVAL if allocating memory fails,
+	according to SUSv3. Add socket descriptors always to except_fds. Test
+	for failed connect and set revents flags appropriately.
+	* select.cc (set_bits): Set connect_state to connect_failed when
+	select indicates failed nonblocking connect.
+	(fhandler_dev_null::select_except): Set except_ready to false so that
+	/dev/null is not always in except state.
+	(peek_socket): Fix bogus conditional.
+	(fhandler_socket::select_write): Treat all connect_states except
+	unconnected equivalent to return consistent results.
+	(fhandler_windows::select_except): Set except_ready to false so that
+	/dev/windows is not always in except state.
+
 2005-04-18  Christopher Faylor  <cgf@timesys.com>
 
 	* include/cygwin/version.h: Bump DLL minor number to 16.
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index a7fcb9086..7611378bd 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -50,7 +50,8 @@ enum conn_state
 {
   unconnected = 0,
   connect_pending = 1,
-  connected = 2
+  connected = 2,
+  connect_failed = 3
 };
 
 enum line_edit_status
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index aa412081e..7c7e2daf8 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -706,7 +706,7 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
       err = WSAGetLastError ();
       /* Special handling for connect to return the correct error code
 	 when called on a non-blocking socket. */
-      if (is_nonblocking () || connect_state () == connect_pending)
+      if (is_nonblocking ())
 	{
 	  if (err == WSAEWOULDBLOCK || err == WSAEALREADY)
 	    in_progress = true;
@@ -736,6 +736,8 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
 
   if (err == WSAEINPROGRESS || err == WSAEALREADY)
     connect_state (connect_pending);
+  else if (err)
+    connect_state (connect_failed);
   else
     connect_state (connected);
 
diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc
index c6a98f422..50f675372 100644
--- a/winsup/cygwin/poll.cc
+++ b/winsup/cygwin/poll.cc
@@ -45,7 +45,7 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
 
   if (!read_fds || !write_fds || !except_fds)
     {
-      set_errno (ENOMEM);
+      set_errno (EINVAL);	/* According to SUSv3. */
       return -1;
     }
 
@@ -63,7 +63,9 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
 	    FD_SET(fds[i].fd, read_fds);
 	  if (fds[i].events & POLLOUT)
 	    FD_SET(fds[i].fd, write_fds);
-	  if (fds[i].events & POLLPRI)
+	  /* On sockets, except_fds is needed to catch failed connects. */
+	  if ((fds[i].events & POLLPRI)
+	      || cygheap->fdtab[fds[i].fd]->is_socket ())
 	    FD_SET(fds[i].fd, except_fds);
 	}
       else if (fds[i].fd >= 0)
@@ -87,11 +89,12 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
 	      fds[i].revents = POLLHUP;
 	    else
 	      {
+		fhandler_socket *sock;
+
 		if (FD_ISSET(fds[i].fd, read_fds))
 		  {
 		    char peek[1];
-		    fhandler_socket *sock =
-				      cygheap->fdtab[fds[i].fd]->is_socket ();
+		    sock = cygheap->fdtab[fds[i].fd]->is_socket ();
 		    if (!sock)
 		      fds[i].revents |= POLLIN;
 		    else
@@ -125,10 +128,19 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
 			set_errno (old_errno);
 		      }
 		  }
-		if (FD_ISSET(fds[i].fd, write_fds))
-		  fds[i].revents |= POLLOUT;
-		if (FD_ISSET(fds[i].fd, except_fds))
-		  fds[i].revents |= POLLPRI;
+		/* Handle failed connect. */
+		if (FD_ISSET(fds[i].fd, write_fds)
+		    && FD_ISSET(fds[i].fd, except_fds)
+		    && (sock = cygheap->fdtab[fds[i].fd]->is_socket ())
+		    && sock->connect_state () == connect_failed)
+		  fds[i].revents |= (POLLIN | POLLERR);
+		else 
+		  {
+		    if (FD_ISSET(fds[i].fd, write_fds))
+		      fds[i].revents |= POLLOUT;
+		    if (FD_ISSET(fds[i].fd, except_fds))
+		      fds[i].revents |= POLLPRI;
+		  }
 	      }
 	  }
       }
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 1c469cf63..2daa88a5f 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -352,7 +352,7 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
 	{
 	  UNIX_FD_SET (me->fd, writefds);
 	  if ((sock = me->fh->is_socket ()))
-	    sock->connect_state (connected);
+	    sock->connect_state (connect_failed);
 	}
       if (me->except_selected)
 	UNIX_FD_SET (me->fd, exceptfds);
@@ -915,7 +915,7 @@ fhandler_dev_null::select_except (select_record *s)
     }
   s->h = get_handle ();
   s->except_selected = true;
-  s->except_ready = true;
+  s->except_ready = false;
   return s;
 }
 
@@ -1271,11 +1271,11 @@ peek_socket (select_record *me, bool)
 	  set_winsock_errno ();
 	  return 0;
 	}
-      if (WINSOCK_FD_ISSET (h, &ws_readfds) || (me->read_selected && me->read_ready))
+      if (WINSOCK_FD_ISSET (h, &ws_readfds))
 	me->read_ready = true;
-      if (WINSOCK_FD_ISSET (h, &ws_writefds) || (me->write_selected && me->write_ready))
+      if (WINSOCK_FD_ISSET (h, &ws_writefds))
 	me->write_ready = true;
-      if (WINSOCK_FD_ISSET (h, &ws_exceptfds) || ((me->except_selected || me->except_on_write) && me->except_ready))
+      if (WINSOCK_FD_ISSET (h, &ws_exceptfds))
 	me->except_ready = true;
     }
   return me->read_ready || me->write_ready || me->except_ready;
@@ -1460,7 +1460,7 @@ fhandler_socket::select_write (select_record *s)
   s->peek = peek_socket;
   s->write_ready = saw_shutdown_write () || connect_state () == unconnected;
   s->write_selected = true;
-  if (connect_state () == connect_pending)
+  if (connect_state () != unconnected)
     {
       s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
       s->except_on_write = true;
@@ -1559,7 +1559,7 @@ fhandler_windows::select_except (select_record *s)
   s->peek = peek_windows;
   s->h = get_handle ();
   s->except_selected = true;
-  s->except_ready = true;
+  s->except_ready = false;
   s->windows_handle = true;
   return s;
 }