Bugzilla bug 100776: handle non-blocking connect correctly on OS/2.
authorwtc%netscape.com
Fri, 18 Jan 2002 01:27:20 +0000
changeset 2176 33920a701b458cdd0bfee7c01a86f410dcc42044
parent 2174 4d2bb1c0d2fabbd52749e02cc54a8a4f59eac67b
child 2180 4e9ea52c1307320100af13d4f4e416ca3cf14444
push idunknown
push userunknown
push dateunknown
bugs100776
Bugzilla bug 100776: handle non-blocking connect correctly on OS/2. The fix is contributed by Javier Pedemonte <pedemont@us.ibm.com>. r=mkaply. Modified files: configure configure.in _os2.h _os2_errors.h prsocket.c os2_errors.c os2poll.c os2sock.c
configure
configure.in
pr/include/md/_os2.h
pr/include/md/_os2_errors.h
pr/src/io/prsocket.c
pr/src/md/os2/os2_errors.c
pr/src/md/os2/os2poll.c
pr/src/md/os2/os2sock.c
--- a/configure
+++ b/configure
@@ -4536,20 +4536,16 @@ EOF
     ;;
 
 *-os2*)
     cat >> confdefs.h <<\EOF
 #define XP_OS2 1
 EOF
 
     cat >> confdefs.h <<\EOF
-#define BSD_SELECT 1
-EOF
-
-    cat >> confdefs.h <<\EOF
 #define XP_PC 1
 EOF
 
     cat >> confdefs.h <<\EOF
 #define _PR_GLOBAL_THREADS_ONLY 1
 EOF
 
     OBJ_SUFFIX=obj
@@ -4566,16 +4562,20 @@ EOF
 
     # EMX/GCC build
     if test "$GNU_CC"; then
         cat >> confdefs.h <<\EOF
 #define XP_OS2_EMX 1
 EOF
 
         cat >> confdefs.h <<\EOF
+#define BSD_SELECT 1
+EOF
+
+        cat >> confdefs.h <<\EOF
 #define OS2 1
 EOF
 
         AR=emxomfar
         AR_FLAGS='-p256 r $@'
         CFLAGS="-Zmtd -Zomf"
         HOST_CFLAGS="$CFLAGS"
         CXXFLAGS="-Zmtd -Zomf"
@@ -5568,17 +5568,17 @@ trap 'rm -f $CONFIG_STATUS conftest*; ex
 # Protect against Makefile macro expansion.
 cat > conftest.defs <<\EOF
 s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
 s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
 s%\[%\\&%g
 s%\]%\\&%g
 s%\$%$$%g
 EOF
-DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' ' |  tr '\015' ' '`
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' ' | tr '\015' ' '`
 rm -f conftest.defs
 
 
 # Without the "./", some shells look in PATH for config.status.
 : ${CONFIG_STATUS=./config.status}
 
 echo creating $CONFIG_STATUS
 rm -f $CONFIG_STATUS
--- a/configure.in
+++ b/configure.in
@@ -1669,17 +1669,16 @@ mips-sony-newsos*)
     fi
     PR_MD_CSRCS=unixware.c
     DSO_LDOPTS=-G
     CPU_ARCH=x86
     ;;
 
 *-os2*)
     AC_DEFINE(XP_OS2)
-    AC_DEFINE(BSD_SELECT)
     AC_DEFINE(XP_PC)
     AC_DEFINE(_PR_GLOBAL_THREADS_ONLY)
     OBJ_SUFFIX=obj
     LIB_SUFFIX=lib
     DLL_SUFFIX=dll
     ASM_SUFFIX=asm
     DLLTOOL=''
     RC=rc.exe
@@ -1687,16 +1686,17 @@ mips-sony-newsos*)
     PROG_SUFFIX=.exe
     NSINSTALL=nsinstall
     MDCPUCFG_H=_os2.cfg
     RESOLVE_LINK_SYMBOLS=1
 
     # EMX/GCC build
     if test "$GNU_CC"; then
         AC_DEFINE(XP_OS2_EMX)
+        AC_DEFINE(BSD_SELECT)
         AC_DEFINE(OS2)
         AR=emxomfar
         AR_FLAGS='-p256 r $@'
         CFLAGS="-Zmtd -Zomf"
         HOST_CFLAGS="$CFLAGS"
         CXXFLAGS="-Zmtd -Zomf"
         OS_LIBS="-lsocket -lemxio"
         LD='$(CC)'
--- a/pr/include/md/_os2.h
+++ b/pr/include/md/_os2.h
@@ -532,9 +532,11 @@ unsigned long _System _DLL_InitTerm( uns
 
 /* Some simple mappings of Windows API's to OS/2 API's to make our lives a
  * little bit easier.  Only add one here if it is a DIRECT mapping.  We are
  * not emulating anything.  Just mapping.
  */
 #define FreeLibrary(x) DosFreeModule((HMODULE)x)
 #define OutputDebugString(x)
                                
+extern int _MD_os2_get_nonblocking_connect_error(int osfd);
+
 #endif /* nspr_os2_defs_h___ */
--- a/pr/include/md/_os2_errors.h
+++ b/pr/include/md/_os2_errors.h
@@ -41,18 +41,18 @@
 #endif  
 
 NSPR_API(void) _MD_os2_map_opendir_error(PRInt32 err);
 #define	_PR_MD_MAP_OPENDIR_ERROR	_MD_os2_map_opendir_error
 
 NSPR_API(void) _MD_os2_map_closedir_error(PRInt32 err);
 #define	_PR_MD_MAP_CLOSEDIR_ERROR	_MD_os2_map_closedir_error
 
-NSPR_API(void) _MD_unix_readdir_error(PRInt32 err);
-#define	_PR_MD_MAP_READDIR_ERROR	_MD_unix_readdir_error
+NSPR_API(void) _MD_os2_readdir_error(PRInt32 err);
+#define	_PR_MD_MAP_READDIR_ERROR	_MD_os2_readdir_error
 
 NSPR_API(void) _MD_os2_map_delete_error(PRInt32 err);
 #define	_PR_MD_MAP_DELETE_ERROR	_MD_os2_map_delete_error
 
 NSPR_API(void) _MD_os2_map_stat_error(PRInt32 err);
 #define	_PR_MD_MAP_STAT_ERROR	_MD_os2_map_stat_error
 
 NSPR_API(void) _MD_os2_map_fstat_error(PRInt32 err);
@@ -98,16 +98,19 @@ NSPR_API(void) _MD_os2_map_recvfrom_erro
 #define	_PR_MD_MAP_RECVFROM_ERROR	_MD_os2_map_recvfrom_error
 
 NSPR_API(void) _MD_os2_map_send_error(PRInt32 err);
 #define	_PR_MD_MAP_SEND_ERROR	_MD_os2_map_send_error
 
 NSPR_API(void) _MD_os2_map_sendto_error(PRInt32 err);
 #define	_PR_MD_MAP_SENDTO_ERROR	_MD_os2_map_sendto_error
 
+NSPR_API(void) _MD_os2_map_writev_error(int err);
+#define	_PR_MD_MAP_WRITEV_ERROR	_MD_os2_map_writev_error
+
 NSPR_API(void) _MD_os2_map_accept_error(PRInt32 err);
 #define	_PR_MD_MAP_ACCEPT_ERROR	_MD_os2_map_accept_error
 
 NSPR_API(void) _MD_os2_map_acceptex_error(PRInt32 err);
 #define	_PR_MD_MAP_ACCEPTEX_ERROR	_MD_os2_map_acceptex_error
 
 NSPR_API(void) _MD_os2_map_connect_error(PRInt32 err);
 #define	_PR_MD_MAP_CONNECT_ERROR	_MD_os2_map_connect_error
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -333,32 +333,21 @@ static PRStatus PR_CALLBACK SocketConnec
         return PR_FAILURE;
     }
 
     PR_ASSERT(out_flags & PR_POLL_WRITE);
     return PR_SUCCESS;
 
 #elif defined(XP_OS2)
 
-    if (out_flags & PR_POLL_EXCEPT) {
-        int len = sizeof(err);
-        if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len)
-                < 0) {
-            _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
-            return PR_FAILURE;
-        }
-        if (err != 0) {
-            _PR_MD_MAP_CONNECT_ERROR(err);
-        } else {
-            PR_SetError(PR_UNKNOWN_ERROR, 0);
-        }
+    err = _MD_os2_get_nonblocking_connect_error(osfd);
+    if (err != 0) {
+        _PR_MD_MAP_CONNECT_ERROR(err);
         return PR_FAILURE;
     }
-
-    PR_ASSERT(out_flags & PR_POLL_WRITE);
     return PR_SUCCESS;
 
 #elif defined(XP_MAC)
 
     err = _MD_mac_get_nonblocking_connect_error(osfd);
     if (err == -1)
         return PR_FAILURE;
 	else     
--- a/pr/src/md/os2/os2_errors.c
+++ b/pr/src/md/os2/os2_errors.c
@@ -30,16 +30,54 @@
  * the GPL.  If you do not delete the provisions above, a recipient
  * may use your version of this file under either the MPL or the
  * GPL.
  */
 
 #include "prerror.h"
 #include "primpl.h"
 
+void _MD_os2_map_default_error(PRInt32 err)
+{
+	switch (err) {
+		case EWOULDBLOCK:
+			PR_SetError(PR_WOULD_BLOCK_ERROR, err);
+			break;
+		case EBADF:
+			PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
+			break;
+		case ENOTSOCK:
+			PR_SetError(PR_NOT_SOCKET_ERROR, err);
+			break;
+		case EMSGSIZE:
+		case EINVAL:
+			PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
+			break;
+		case ENOBUFS:
+			PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
+			break;
+		case ECONNREFUSED:
+			PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
+			break;
+		case EISCONN:
+			PR_SetError(PR_IS_CONNECTED_ERROR, err);
+			break;
+#ifdef SOCEFAULT
+		case SOCEFAULT:
+			PR_SetError(PR_ACCESS_FAULT_ERROR, err);
+			break;
+#endif
+		case ERROR_NETNAME_DELETED:
+			PR_SetError(PR_CONNECT_RESET_ERROR, err);
+			break;
+		default:
+			PR_SetError(PR_UNKNOWN_ERROR, err);
+			break;
+	}
+}
 void _MD_os2_map_opendir_error(PRInt32 err)
 {
 	switch (err) {
 		case ERROR_FILE_NOT_FOUND:
 		case ERROR_PATH_NOT_FOUND:
 			PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
 			break;
 		case ERROR_ACCESS_DENIED:
@@ -87,17 +125,17 @@ void _MD_os2_map_closedir_error(PRInt32 
 			PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
 			break;
 		default:
 			PR_SetError(PR_UNKNOWN_ERROR, err);
 			break;
 	}
 }
 
-void _MD_unix_readdir_error(PRInt32 err)
+void _MD_os2_readdir_error(PRInt32 err)
 {
 
 	switch (err) {
 		case ERROR_NO_MORE_FILES:
 			PR_SetError(PR_NO_MORE_FILES_ERROR, err);
 			break;
 		case ERROR_FILE_NOT_FOUND:
 		case ERROR_INVALID_HANDLE:
@@ -666,83 +704,27 @@ void _MD_os2_map_send_error(PRInt32 err)
 		default:
 			PR_SetError(PR_UNKNOWN_ERROR, err);
 			break;
 	}
 }
 
 void _MD_os2_map_sendto_error(PRInt32 err)
 {
-	switch (err) {
-		case EWOULDBLOCK:
-			PR_SetError(PR_WOULD_BLOCK_ERROR, err);
-			break;
-		case EBADF:
-			PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
-			break;
-		case ENOTSOCK:
-			PR_SetError(PR_NOT_SOCKET_ERROR, err);
-			break;
-		case EMSGSIZE:
-		case EINVAL:
-			PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
-			break;
-		case ENOBUFS:
-			PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
-			break;
-		case ECONNREFUSED:
-			PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
-			break;
-		case EISCONN:
-			PR_SetError(PR_IS_CONNECTED_ERROR, err);
-			break;
-#ifdef SOCEFAULT
-		case SOCEFAULT:
-			PR_SetError(PR_ACCESS_FAULT_ERROR, err);
-			break;
-#endif
-		case ERROR_NETNAME_DELETED:
-			PR_SetError(PR_CONNECT_RESET_ERROR, err);
-			break;
-		default:
-			PR_SetError(PR_UNKNOWN_ERROR, err);
-			break;
-	}
+  _MD_os2_map_default_error(err);
+}
+
+void _MD_os2_map_writev_error(int err)
+{
+  _MD_os2_map_default_error(err);
 }
 
 void _MD_os2_map_accept_error(PRInt32 err)
 {
-	switch (err) {
-		case EWOULDBLOCK:
-			PR_SetError(PR_WOULD_BLOCK_ERROR, err);
-			break;
-		case EBADF:
-			PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
-			break;
-		case ENOTSOCK:
-			PR_SetError(PR_NOT_SOCKET_ERROR, err);
-			break;
-		case EOPNOTSUPP:
-			PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err);
-			break;
-#ifdef SOCEFAULT
-		case SOCEFAULT:
-			PR_SetError(PR_ACCESS_FAULT_ERROR, err);
-			break;
-#endif
-		case EMFILE:
-			PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err);
-			break;
-		case ENOBUFS:
-			PR_SetError(PR_OUT_OF_MEMORY_ERROR, err);
-			break;
-		default:
-			PR_SetError(PR_UNKNOWN_ERROR, err);
-			break;
-	}
+  _MD_os2_map_default_error(err);
 }
 
 void _MD_os2_map_acceptex_error(PRInt32 err)
 {
 	switch (err) {
 		case ERROR_INVALID_HANDLE:
 			PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
 			break;
@@ -754,16 +736,31 @@ void _MD_os2_map_acceptex_error(PRInt32 
 			PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err);
 			break;
 		default:
 			PR_SetError(PR_UNKNOWN_ERROR, err);
 			break;
 	}
 }
 
+/*
+ * An error code of 0 means that the nonblocking connect succeeded.
+ */
+
+int _MD_os2_get_nonblocking_connect_error(int osfd)
+{
+    int err;
+    int len = sizeof(err);
+    if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) {
+        return sock_errno();
+    } else {
+        return err;
+    }
+}
+
 void _MD_os2_map_connect_error(PRInt32 err)
 {
 	switch (err) {
        case EWOULDBLOCK:
 			PR_SetError(PR_WOULD_BLOCK_ERROR, err);
 			break;
         case EINPROGRESS:
 			PR_SetError(PR_IN_PROGRESS_ERROR, err);
--- a/pr/src/md/os2/os2poll.c
+++ b/pr/src/md/os2/os2poll.c
@@ -32,87 +32,95 @@
  * GPL.
  */
 
 /*
  * This file implements _PR_MD_PR_POLL for OS/2.
  */
 
 #ifdef XP_OS2_EMX
-	#include <sys/time.h> /* For timeval. */
+ #include <sys/time.h> /* For timeval. */
 #endif
 
 #include "primpl.h"
 
-PRInt32 _PR_MD_PR_POLL(
-    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+#ifndef BSD_SELECT
+/* Utility functions called when using OS/2 select */
+
+PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count )
 {
-    PRInt32 osfd;
-    int maxfd = -1;
+  int i;
+  PRBool isSet = PR_FALSE;
+
+  for( i = start; i < start+count; i++ )
+  {
+    if( socks[i] == osfd )
+      isSet = PR_TRUE;
+  }
+  
+  return isSet; 
+}
+#endif
+
+PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+#ifdef BSD_SELECT
     fd_set rd, wt, ex;
+#else
+    int rd, wt, ex;
+    int* socks;
+    unsigned long msecs;
+    int i, j;
+#endif
     PRFileDesc *bottom;
     PRPollDesc *pd, *epd;
-    PRInt32 ready, err;
-	PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRInt32 maxfd = -1, ready, err;
+    PRIntervalTime remaining, elapsed, start;
+
+#ifdef BSD_SELECT
     struct timeval tv, *tvp = NULL;
 
-    /*
-     * For restarting _MD_SELECT() if it is interrupted by a signal.
-     * We use these variables to figure out how much time has elapsed
-     * and how much of the timeout still remains.
-     */
-    PRIntervalTime start, elapsed, remaining;
-
-    if (_PR_PENDING_INTERRUPT(me))
+    FD_ZERO(&rd);
+    FD_ZERO(&wt);
+    FD_ZERO(&ex);
+#else
+    rd = 0;
+    wt = 0;
+    ex = 0;
+    socks = (int) PR_MALLOC( npds * 3 * sizeof(int) );
+    
+    if (!socks)
     {
-        me->flags &= ~_PR_INTERRUPT;
-        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
         return -1;
     }
+#endif
 
-    /*
-    ** Is it an empty set? If so, just sleep for the timeout and return
-    */
-    if (0 == npds)
-    {
-        PR_Sleep(timeout);
-        return 0;
-    }
-
-    remaining = timeout;
-    start = PR_IntervalNow();
-
-  	FD_ZERO(&rd);
-  	FD_ZERO(&wt);
-    FD_ZERO(&ex);
-
-	ready = 0;
+    ready = 0;
     for (pd = pds, epd = pd + npds; pd < epd; pd++)
     {
         PRInt16 in_flags_read = 0, in_flags_write = 0;
         PRInt16 out_flags_read = 0, out_flags_write = 0;
 
         if ((NULL != pd->fd) && (0 != pd->in_flags))
         {
             if (pd->in_flags & PR_POLL_READ)
             {
                 in_flags_read = (pd->fd->methods->poll)(
-                    pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE),
-                    &out_flags_read);
+                    pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
             }
             if (pd->in_flags & PR_POLL_WRITE)
             {
                 in_flags_write = (pd->fd->methods->poll)(
-                    pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ),
-                    &out_flags_write);
+                    pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
             }
-            if ((0 != (in_flags_read & out_flags_read))
-            || (0 != (in_flags_write & out_flags_write)))
+            if ((0 != (in_flags_read & out_flags_read)) ||
+                (0 != (in_flags_write & out_flags_write)))
             {
-                /* this one's ready right now (buffered input) */
+                /* this one's ready right now */
                 if (0 == ready)
                 {
                     /*
                      * We will have to return without calling the
                      * system poll/select function.  So zero the
                      * out_flags fields of all the poll descriptors
                      * before this one.
                      */
@@ -123,47 +131,77 @@ PRInt32 _PR_MD_PR_POLL(
                     }
                 }
                 ready += 1;
                 pd->out_flags = out_flags_read | out_flags_write;
             }
             else
             {
                 pd->out_flags = 0;  /* pre-condition */
+
                 /* make sure this is an NSPR supported stack */
                 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
                 PR_ASSERT(NULL != bottom);  /* what to do about that? */
-                if ((NULL != bottom)
-                && (_PR_FILEDESC_OPEN == bottom->secret->state))
+                if ((NULL != bottom) &&
+                    (_PR_FILEDESC_OPEN == bottom->secret->state))
                 {
                     if (0 == ready)
                     {
-                        osfd = bottom->secret->md.osfd;
-    	                if (osfd > maxfd) maxfd = osfd;
+                        PRInt32 osfd = bottom->secret->md.osfd;
+                        if (osfd > maxfd) 
+                            maxfd = osfd;
                         if (in_flags_read & PR_POLL_READ)
                         {
                             pd->out_flags |= _PR_POLL_READ_SYS_READ;
+#ifdef BSD_SELECT
                             FD_SET(osfd, &rd);
+#else
+                            socks[rd] = osfd;
+                            rd++;              
+#endif
                         }
                         if (in_flags_read & PR_POLL_WRITE)
                         {
                             pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
+#ifdef BSD_SELECT
                             FD_SET(osfd, &wt);
+#else
+                            socks[npds+wt] = osfd;
+                            wt++;              
+#endif
                         }
                         if (in_flags_write & PR_POLL_READ)
                         {
                             pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
+#ifdef BSD_SELECT
                             FD_SET(osfd, &rd);
+#else
+                            socks[rd] = osfd;
+                            rd++;              
+#endif
                         }
                         if (in_flags_write & PR_POLL_WRITE)
                         {
                             pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
+#ifdef BSD_SELECT
                             FD_SET(osfd, &wt);
+#else
+                            socks[npds+wt] = osfd;
+                            wt++;              
+#endif
                         }
-                        if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex);
+                        if (pd->in_flags & PR_POLL_EXCEPT)
+                        {
+#ifdef BSD_SELECT
+                            FD_SET(osfd, &ex);
+#else
+                            socks[npds*2+ex] = osfd;
+                            ex++;
+#endif
+                        }
                     }
                 }
                 else
                 {
                     if (0 == ready)
                     {
                         PRPollDesc *prev;
                         for (prev = pds; prev < pd; prev++)
@@ -173,113 +211,173 @@ PRInt32 _PR_MD_PR_POLL(
                     }
                     ready += 1;  /* this will cause an abrupt return */
                     pd->out_flags = PR_POLL_NVAL;  /* bogii */
                 }
             }
         }
     }
 
-    if (0 != ready) return ready;  /* no need to block */
+    if (0 != ready)
+    {
+#ifndef BSD_SELECT
+        free(socks);
+#endif
+        return ready;  /* no need to block */
+    }
+
+    remaining = timeout;
+    start = PR_IntervalNow();
 
 retry:
+#ifdef BSD_SELECT
     if (timeout != PR_INTERVAL_NO_TIMEOUT)
     {
         PRInt32 ticksPerSecond = PR_TicksPerSecond();
         tv.tv_sec = remaining / ticksPerSecond;
         tv.tv_usec = remaining - (ticksPerSecond * tv.tv_sec);
         tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond;
         tvp = &tv;
     }
 
     ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp);
-    if (ready == -1 && errno == EINTR)
+#else
+    switch (timeout)
     {
-        if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry;
-     	else
-        {
-     		elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
-  	   	    if (elapsed > timeout) ready = 0;  /* timed out */
-     	    else
-            {
-        		remaining = timeout - elapsed;
-     	   	    goto retry;
-            }
-  	    }
+        case PR_INTERVAL_NO_WAIT:
+            msecs = 0;
+            break;
+        case PR_INTERVAL_NO_TIMEOUT:
+            msecs = -1;
+            break;
+        default:
+            msecs = PR_IntervalToMilliseconds(remaining);
     }
 
+     /* compact array */
+    for( i = rd, j = npds; j < npds+wt; i++,j++ )
+        socks[i] = socks[j];
+    for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ )
+        socks[i] = socks[j];
+    
+    ready = _MD_SELECT(socks, rd, wt, ex, msecs);
+#endif
+
+    if (ready == -1 && errno == SOCEINTR)
+    {
+        if (timeout == PR_INTERVAL_NO_TIMEOUT)
+            goto retry;
+        else
+        {
+            elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
+            if (elapsed > timeout)
+                ready = 0;  /* timed out */
+            else
+            {
+                remaining = timeout - elapsed;
+                goto retry;
+            }
+        }
+    }
+
+    /*
+    ** Now to unravel the select sets back into the client's poll
+    ** descriptor list. Is this possibly an area for pissing away
+    ** a few cycles or what?
+    */
     if (ready > 0)
     {
         ready = 0;
         for (pd = pds, epd = pd + npds; pd < epd; pd++)
         {
             PRInt16 out_flags = 0;
             if ((NULL != pd->fd) && (0 != pd->in_flags))
             {
+                PRInt32 osfd;
                 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
                 PR_ASSERT(NULL != bottom);
 
                 osfd = bottom->secret->md.osfd;
 
+#ifdef BSD_SELECT
                 if (FD_ISSET(osfd, &rd))
+#else
+                if( IsSocketSet(osfd, socks, 0, rd) )        
+#endif
                 {
                     if (pd->out_flags & _PR_POLL_READ_SYS_READ)
                         out_flags |= PR_POLL_READ;
                     if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
                         out_flags |= PR_POLL_WRITE;
-                }
+                } 
+
+#ifdef BSD_SELECT
                 if (FD_ISSET(osfd, &wt))
+#else
+                if( IsSocketSet(osfd, socks, rd, wt) )        
+#endif
                 {
                     if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
                         out_flags |= PR_POLL_READ;
                     if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
                         out_flags |= PR_POLL_WRITE;
+                } 
+
+#ifdef BSD_SELECT
+                if (FD_ISSET(osfd, &ex))
+#else
+                if( IsSocketSet(osfd, socks, rd+wt, ex) )        
+#endif
+                {
+                    out_flags |= PR_POLL_EXCEPT;
                 }
-                if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT;
             }
             pd->out_flags = out_flags;
             if (out_flags) ready++;
         }
         PR_ASSERT(ready > 0);
     }
     else if (ready < 0)
     {
-   	    err = _MD_ERRNO();
-   	    if (err == EBADF)
+        err = _MD_ERRNO();
+        if (err == EBADF)
         {
-   		    /* Find the bad fds */
-   		    ready = 0;
-   		    for (pd = pds, epd = pd + npds; pd < epd; pd++)
+            /* Find the bad fds */
+            int optval;
+            int optlen = sizeof(optval);
+            ready = 0;
+            for (pd = pds, epd = pd + npds; pd < epd; pd++)
             {
-                int optval;
-                int optlen = sizeof(optval);
-			    pd->out_flags = 0;
-   			    if ((NULL == pd->fd) || (pd->in_flags == 0)) continue;
-   			    bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
-                if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
-                    SO_TYPE, (char *) &optval, &optlen) == -1)
+                pd->out_flags = 0;
+                if ((NULL != pd->fd) && (0 != pd->in_flags))
                 {
-                    PR_ASSERT(_MD_ERRNO() == ENOTSOCK);
-                    if (_MD_ERRNO() == ENOTSOCK)
+                    bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+                    if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
+                        SO_TYPE, (char *) &optval, &optlen) == -1)
                     {
-                        pd->out_flags = PR_POLL_NVAL;
-                        ready++;
+                        PR_ASSERT(sock_errno() == SOCENOTSOCK);
+                        if (sock_errno() == SOCENOTSOCK)
+                        {
+                            pd->out_flags = PR_POLL_NVAL;
+                            ready++;
+                        }
                     }
                 }
-   		    }
-   		    PR_ASSERT(ready > 0);
-   	    }
+            }
+            PR_ASSERT(ready > 0);
+        }
         else
-        {
-   		    PR_ASSERT(err != EINTR);  /* should have been handled above */
-   		    _PR_MD_MAP_SELECT_ERROR(err);
-        }
-   }
-   return ready;
- }
+            _PR_MD_MAP_SELECT_ERROR(err);
+    }
+
+#ifndef BSD_SELECT
+    free(socks);
+#endif
+    return ready;
+}
 
 #ifdef XP_OS2_EMX
 HMTX thread_select_mutex = 0;	/* because EMX's select is not thread safe - duh! */
 
 typedef struct _thread_select_st {
 	int		nfds;
 	int		isrdfds;
 	struct _fd_set *readfds;
--- a/pr/src/md/os2/os2sock.c
+++ b/pr/src/md/os2/os2sock.c
@@ -41,803 +41,598 @@
 /*There is standard BSD (which is kind of slow) and a new flavor of select() that takes      */
 /*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */
 /*a millisecond count for timeout. In the interest of performance I have choosen the OS/2    */
 /*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info.          */ 
 
 #include "primpl.h"
 
 #ifdef XP_OS2_EMX
-    #include <sys/time.h> /* For timeval. */
+ #include <sys/time.h> /* For timeval. */
 #endif
 
+#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
+#define READ_FD   1
+#define WRITE_FD  2
+
 void
 _PR_MD_INIT_IO()
 {
     sock_init();
 }
 
 /* --- SOCKET IO --------------------------------------------------------- */
 
 
 PRInt32
-_PR_MD_SOCKET(int af, int type, int flags)
+_PR_MD_SOCKET(int domain, int type, int flags)
 {
-    int sock;
-    PRUint32  one = 1;
-    PRInt32   rv;
-    PRInt32   err;
+    PRInt32 osfd, err;
 
-    sock = socket(af, type, flags);
+    osfd = socket(domain, type, flags);
 
-    if (sock == -1 ) 
+    if (osfd == -1) 
     {
-        int rv = sock_errno();
-        soclose(sock);
-        _PR_MD_MAP_SOCKET_ERROR(rv);
-        return (PRInt32) -1;
+        err = sock_errno();
+        _PR_MD_MAP_SOCKET_ERROR(err);
     }
 
-    /*
-    ** Make the socket Non-Blocking
-    */
-    rv = ioctl( sock, FIONBIO, (char *) &one, sizeof(one));
-    if ( rv != 0 )
-    {
-        err = sock_errno();
-        return -1;
-    }
-
-    return (PRInt32)sock;
+    return(osfd);
 }
 
 /*
 ** _MD_CloseSocket() -- Close a socket
 **
 */
 PRInt32
 _MD_CloseSocket(PRInt32 osfd)
 {
-    PRInt32 rv = -1;
+    PRInt32 rv, err;
 
-    rv = soclose((int) osfd );
-    if (rv < 0)
-        _PR_MD_MAP_SOCKET_ERROR(sock_errno());
-
+    rv = soclose(osfd);
+    if (rv == -1) {
+        err = sock_errno();
+        _PR_MD_MAP_CLOSE_ERROR(err);
+    }
     return rv;
 }
 
 PRInt32
 _MD_SocketAvailable(PRFileDesc *fd)
 {
     PRInt32 result;
 
     if (ioctl(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) {
         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno());
         return -1;
     }
     return result;
 }
 
+static PRInt32
+socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout )
+{
+    PRInt32 rv = -1;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRIntervalTime epoch, now, elapsed, remaining;
+    PRInt32 syserror;
+#ifdef BSD_SELECT
+    struct timeval tv;
+    fd_set rd_wr;
+#else
+    int socks[1];
+    long lTimeout;
+#endif
+
+    switch (timeout) {
+        case PR_INTERVAL_NO_WAIT:
+            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+            break;
+        case PR_INTERVAL_NO_TIMEOUT:
+            /*
+             * This is a special case of the 'default' case below.
+             * Please see the comments there.
+             */
+#ifdef BSD_SELECT
+            tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
+            tv.tv_usec = 0;
+            FD_ZERO(&rd_wr);
+            do {
+                FD_SET(osfd, &rd_wr);
+                if (fd_type == READ_FD)
+                    rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
+                else
+                    rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
+#else
+            lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; 
+            do {
+                socks[0] = osfd;
+                if (fd_type == READ_FD)
+                    rv = _MD_SELECT(socks, 1, 0, 0, lTimeout);
+                else
+                    rv = _MD_SELECT(socks, 0, 1, 0, lTimeout);
+#endif                    
+                if (rv == -1 && (syserror = sock_errno()) != SOCEINTR) {
+                    _PR_MD_MAP_SELECT_ERROR(syserror);
+                    break;
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+            } while (rv == 0 || (rv == -1 && syserror == EINTR));
+            break;
+        default:
+            now = epoch = PR_IntervalNow();
+            remaining = timeout;
+#ifdef BSD_SELECT
+            FD_ZERO(&rd_wr);
+#endif
+            do {
+                /*
+                 * We block in _MD_SELECT for at most
+                 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
+                 * so that there is an upper limit on the delay
+                 * before the interrupt bit is checked.
+                 */
+#ifdef BSD_SELECT
+                tv.tv_sec = PR_IntervalToSeconds(remaining);
+                if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
+                    tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
+                    tv.tv_usec = 0;
+                } else {
+                    tv.tv_usec = PR_IntervalToMicroseconds(
+                        remaining -
+                        PR_SecondsToInterval(tv.tv_sec));
+                }
+                FD_SET(osfd, &rd_wr);
+                if (fd_type == READ_FD)
+                    rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
+                else
+                    rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
+#else
+                lTimeout = PR_IntervalToMilliseconds(remaining);
+                if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000)
+                    lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
+                socks[0] = osfd;
+                if (fd_type == READ_FD)
+                    rv = _MD_SELECT(socks, 1, 0, 0, lTimeout);
+                else
+                    rv = _MD_SELECT(socks, 0, 1, 0, lTimeout);
+#endif
+                /*
+                 * we don't consider EINTR a real error
+                 */
+                if (rv == -1 && (syserror = sock_errno()) != SOCEINTR) {
+                    _PR_MD_MAP_SELECT_ERROR(syserror);
+                    break;
+                }
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                    rv = -1;
+                    break;
+                }
+                /*
+                 * We loop again if _MD_SELECT timed out or got interrupted
+                 * by a signal, and the timeout deadline has not passed yet.
+                 */
+                if (rv == 0 || (rv == -1 && syserror == SOCEINTR)) {
+                    /*
+                     * If _MD_SELECT timed out, we know how much time
+                     * we spent in blocking, so we can avoid a
+                     * PR_IntervalNow() call.
+                     */
+                    if (rv == 0) {
+#ifdef BSD_SELECT
+                        now += PR_SecondsToInterval(tv.tv_sec)
+                            + PR_MicrosecondsToInterval(tv.tv_usec);
+#else
+                        now += PR_MillisecondsToInterval(lTimeout);
+#endif
+                    } else {
+                        now = PR_IntervalNow();
+                    }
+                    elapsed = (PRIntervalTime) (now - epoch);
+                    if (elapsed >= timeout) {
+                        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                        rv = -1;
+                        break;
+                    } else {
+                        remaining = timeout - elapsed;
+                    }
+                }
+            } while (rv == 0 || (rv == -1 && syserror == SOCEINTR));
+            break;
+        }
+    return(rv);
+}
+
 PRInt32
-_MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
-              PRIntervalTime timeout )
+_MD_Accept(PRFileDesc *fd, PRNetAddr *addr,
+           PRUint32 *addrlen, PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
-#ifdef BSD_SELECT
-    fd_set rd;
-    struct timeval tv, *tvp;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
 
-    FD_ZERO(&rd);
-    FD_SET(osfd, &rd);
-#else
-    int socks[1];
-    socks[0] = osfd; 
-#endif
-    if (timeout == PR_INTERVAL_NO_TIMEOUT) 
+    while ((rv = accept(osfd, (struct sockaddr*) addr, (int*)addrlen)) == -1)
     {
-        while ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1) 
+        err = sock_errno();
+        if ((err == SOCEWOULDBLOCK) || (err == SOCECONNABORTED))
         {
-            if (((err = sock_errno()) == EWOULDBLOCK) 
-                && (!fd->secret->nonblocking))
-            {
-#ifdef BSD_SELECT
-                if ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL,NULL)) == -1) {
-#else
-                if ((rv = _MD_SELECT(socks, 1, 0, 0, -1)) == -1) {
-#endif
-                    _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                    break;
-                } 
-            } 
-            else {
-                _PR_MD_MAP_ACCEPT_ERROR(err);
+            if (fd->secret->nonblocking) {
                 break;
             }
-        }
-        return(rv);
-    } 
-    else if (timeout == PR_INTERVAL_NO_WAIT) 
-    {
-        if ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1)
-        {
-            if (((err = sock_errno()) == EWOULDBLOCK) 
-                && (!fd->secret->nonblocking))
-            {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-            }
-            else
-            {
-                _PR_MD_MAP_ACCEPT_ERROR(err);
-            }
-        }
-        return(rv);
-    } 
-    else 
-    {
-retry:
-        if ((rv = accept(osfd, (struct sockaddr *) raddr, (int *) rlen)) == -1) 
-        {
-            if (((err = sock_errno()) == EWOULDBLOCK) 
-                && (!fd->secret->nonblocking))
-            {
-#ifdef BSD_SELECT
-                tv.tv_sec = PR_IntervalToSeconds(timeout);
-                tv.tv_usec = PR_IntervalToMicroseconds(timeout - PR_SecondsToInterval(tv.tv_sec));
-                tvp = &tv;
-                rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, tvp);
-#else
-                long lTimeout = PR_IntervalToMilliseconds(timeout); 
-                rv = _MD_SELECT(socks, 1, 0, 0, lTimeout);
-#endif
-                if (rv > 0) {
-                    goto retry;
-                } 
-                else if (rv == 0) 
-                {
-                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                    rv = -1;
-                } else {
-                    _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                }
-            } else {
-                _PR_MD_MAP_ACCEPT_ERROR(err);
-            }
+                if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+                    goto done;
+        } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
         }
     }
+    if (rv < 0) {
+        _PR_MD_MAP_ACCEPT_ERROR(err);
+    }
+done:
     return(rv);
-} /* end _MD_Accept() */
-
-
+}
 
 PRInt32
 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, 
                PRIntervalTime timeout)
 {
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
     PRInt32 osfd = fd->secret->md.osfd;
-    PRInt32 rv;
-    int err, len;
-#ifdef BSD_SELECT
-#ifdef XP_OS2//_VACPP
-    fd_set wd;
-#else
-    fd_set wd, ex;
-#endif  #vacpp
-    struct timeval tv, *tvp;
-#else
-    int socks[1]; 
-    long lTimeout = -1;
-#endif
 
-    if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) 
+     /*
+      * We initiate the connection setup by making a nonblocking connect()
+      * call.  If the connect() call fails, there are two cases we handle
+      * specially:
+      * 1. The connect() call was interrupted by a signal.  In this case
+      *    we simply retry connect().
+      * 2. The NSPR socket is nonblocking and connect() fails with
+      *    EINPROGRESS.  We first wait until the socket becomes writable.
+      *    Then we try to find out whether the connection setup succeeded
+      *    or failed.
+      */
+
+retry:
+    if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1)
     {
         err = sock_errno();
-        if ((!fd->secret->nonblocking) && ((err == EINPROGRESS) || (err == EWOULDBLOCK)))
+
+        if (err == SOCEINTR) {
+            if (_PR_PENDING_INTERRUPT(me)) {
+                me->flags &= ~_PR_INTERRUPT;
+                PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
+                return -1;
+            }
+            goto retry;
+        }
+
+        if (!fd->secret->nonblocking && (err == SOCEINPROGRESS))
         {
-#ifdef BSD_SELECT
-           if (timeout == PR_INTERVAL_NO_TIMEOUT)
-               tvp = NULL;
-            else 
-            {
-                tv.tv_sec = PR_IntervalToSeconds(timeout);
-                tv.tv_usec = PR_IntervalToMicroseconds(timeout - PR_SecondsToInterval(tv.tv_sec));
-                tvp = &tv;
+            /*
+             * socket_io_wait() may return -1 or 1.
+             */
+
+            rv = socket_io_wait(osfd, WRITE_FD, timeout);
+            if (rv == -1) {
+                return -1;
             }
 
-            FD_ZERO(&wd);
-            FD_SET(osfd, &wd);
-#ifdef XP_OS2//_VACPP
-            rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, tvp);
-#else
-            FD_ZERO(&ex);
-            FD_SET(osfd, &ex);
-            rv = _MD_SELECT(osfd + 1, NULL, &wd, &ex, tvp);
-#endif  #vacpp
-#else #!bsd_select
-            if (timeout == PR_INTERVAL_NO_TIMEOUT)
-                lTimeout = -1;
-            else 
-            {
-                lTimeout = PR_IntervalToMilliseconds(timeout);  
+            PR_ASSERT(rv == 1);
+            if (_PR_PENDING_INTERRUPT(me)) {
+                me->flags &= ~_PR_INTERRUPT;
+                PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
+                return -1;
             }
-	    
-            socks[0] = osfd; 
-#ifdef XP_OS2//_VACPP
-            rv = _MD_SELECT(socks, 0, 1, 0, lTimeout);
-#else
-            rv = _MD_SELECT(socks, 0, 1, 1, lTimeout);
-#endif  #vacpp
-#endif
-            if (rv > 0) 
-            {
-#ifdef BSD_SELECT
-#ifdef XP_OS2//_VACPP
-                if (FD_ISSET(osfd, &wd))
-                {
-                    //DosSleep(0);
-                    len = sizeof(err);
-                    if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
-                           (char *) &err, &len) < 0)
-                    {  
-                        _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
-                        return -1;
-                    }
-
-                    if (err != 0)
-                    {
-                        _PR_MD_MAP_CONNECT_ERROR(err);
-                        return -1;
-                    }
-                    else
-                        return 0;   /* it's connected */
-                }
-                else
-                    return -1;
-#else
-               if (FD_ISSET(osfd, &ex))
-               {
-                   DosSleep(0);
-                   len = sizeof(err);
-                   if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
-                           (char *) &err, &len) < 0)
-                   {  
-                       _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
-                       return -1;
-                   }
-                   if (err != 0)
-                       _PR_MD_MAP_CONNECT_ERROR(err);
-                   else
-                       PR_SetError(PR_UNKNOWN_ERROR, 0);
-                   return -1;
-               }
-               if (FD_ISSET(osfd, &wd))
-               {
-                   /* it's connected */
-                   return 0;
-               }
-#endif  #vacpp
-#else #!bsd_select
-                if (socks[0] == osfd)
-                {
-                  len = sizeof(err);
-                  if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
-                         (char *) &err, &len) < 0)
-                  {  
-                    _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
-                    return -1;
-                  }
-
-                  if (err != 0)
-                  {
-                    _PR_MD_MAP_CONNECT_ERROR(err);
-                    return -1;
-                  }
-                  else
-                    return 0;   /* it's connected */
-                }
-                else
-                  return -1;
-#endif
+            err = _MD_os2_get_nonblocking_connect_error(osfd);
+            if (err != 0) {
+                _PR_MD_MAP_CONNECT_ERROR(err);
+                return -1;
             }
-            else if (rv == 0) 
-            {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                return(-1);
-            } else if (rv < 0) 
-            {
-                _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                return(-1);
-            }
-        } 
+            return 0;
+        }
+        
         _PR_MD_MAP_CONNECT_ERROR(err);
     }
+
     return rv;
-}
-
+}  /* _MD_connect */
 
 PRInt32
 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
 {
-    PRInt32 rv;
-
-    rv = bind(fd->secret->md.osfd, (struct sockaddr*) &(addr->inet), addrlen);
-
-    if (rv == -1)  {
-		_PR_MD_MAP_BIND_ERROR(sock_errno());
-        return -1;
-	}
-
-    return 0;
+    PRInt32 rv, err;
+    rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
+    if (rv < 0) {
+        err = sock_errno();
+        _PR_MD_MAP_BIND_ERROR(err);
+    }
+    return(rv);
 }
 
 
 PRInt32
 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, 
             PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
-#ifdef BSD_SELECT
-    struct timeval tv, *tvp;
-    fd_set rd;
-#else
-    int socks[1]; 
-    long lTimeout = -1; 
-#endif
-    int osflags;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
 
-    if (0 == flags) {
-        osflags = 0;
-    } else {
-        PR_ASSERT(PR_MSG_PEEK == flags);
-        osflags = MSG_PEEK;
-    }
-    while ((rv = recv( osfd, buf, amount, osflags)) == -1) 
+    while ((rv = recv(osfd,buf,amount,flags)) == -1)
     {
-        if (((err = sock_errno()) == EWOULDBLOCK) 
-            && (!fd->secret->nonblocking))
-        {
-#ifdef BSD_SELECT
-           FD_ZERO(&rd);
-           FD_SET(osfd, &rd);
-           if (timeout == PR_INTERVAL_NO_TIMEOUT) 
-           {
-               tvp = NULL;
-           } 
-           else 
-           {
-               tv.tv_sec = PR_IntervalToSeconds(timeout);
-               tv.tv_usec = PR_IntervalToMicroseconds(
-               timeout - PR_SecondsToInterval(tv.tv_sec));
-               tvp = &tv;
-           }
-           if ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, tvp)) == -1) 
-#else
-            socks[0] = osfd; 
-            if (timeout == PR_INTERVAL_NO_TIMEOUT) 
-            {
-                lTimeout = -1; 
-            } 
-            else 
-            {
-                lTimeout = PR_IntervalToMilliseconds(timeout); 
-            }
-            if ((rv = _MD_SELECT(socks, 1, 0, 0, lTimeout)) == -1) 
-#endif
-            {
-                _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                return -1;
-            } 
-            else if (rv == 0) 
-            {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                rv = -1;
+        err = sock_errno();
+        if ((err == SOCEWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
                 break;
             }
-        } 
-        else 
-        {
-            _PR_MD_MAP_RECV_ERROR(err);
+            if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+                goto done;
+        } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
             break;
         }
-    } /* end while() */
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_RECV_ERROR(err);
+    }
+done:
     return(rv);
 }
 
 PRInt32
 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
             PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
-#ifdef BSD_SELECT
-    struct timeval tv, *tvp;
-    fd_set wd;
-#else
-    int socks[1]; 
-    long lTimeout = -1; 
-#endif
-    PRInt32 bytesSent = 0;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
 
-    while(bytesSent < amount ) 
+    while ((rv = send(osfd,buf,amount,flags)) == -1)
     {
-        while ((rv = send( osfd, (char *) buf, amount, 0 )) == -1) 
-        {
-            if (((err = sock_errno()) == EWOULDBLOCK) 
-                && (!fd->secret->nonblocking))
-            {
-#ifdef BSD_SELECT
-                if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-                {
-                    tvp = NULL;
-                } 
-                else 
-                {
-                    tv.tv_sec = PR_IntervalToSeconds(timeout);
-                    tv.tv_usec = PR_IntervalToMicroseconds(
-                        timeout - PR_SecondsToInterval(tv.tv_sec));
-                    tvp = &tv;
-                }
-                FD_ZERO(&wd);
-                FD_SET(osfd, &wd);
-                if ((rv = _MD_SELECT( osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
-#else
-                if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-                {
-                    lTimeout = -1; 
-                } 
-                else 
-                {
-                    lTimeout = PR_IntervalToMilliseconds(timeout); 
-                }
-                socks[0] = osfd; 
-                if ((rv = _MD_SELECT( socks, 0, 1, 0, lTimeout)) == -1) {
-#endif
-                    _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                    break;
-                }
-                if (rv == 0) 
-                {
-                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                    return -1;
-                }
-            } 
-            else {
-                _PR_MD_MAP_SEND_ERROR(err);
-                return -1;
+        err = sock_errno();
+        if ((err == SOCEWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
+                break;
             }
-        }
-        bytesSent += rv;
-        if (fd->secret->nonblocking)
-        {
+            if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0)
+                goto done;
+        } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
             break;
         }
-        if ((rv >= 0) && (bytesSent < amount )) 
-        {
-#ifdef BSD_SELECT
-           if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-           {
-               tvp = NULL;
-           } 
-           else 
-           {
-               tv.tv_sec = PR_IntervalToSeconds(timeout);
-               tv.tv_usec = PR_IntervalToMicroseconds(
-                   timeout - PR_SecondsToInterval(tv.tv_sec));
-               tvp = &tv;
-           }
-           FD_ZERO(&wd);
-           FD_SET(osfd, &wd);
-           if ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
-#else
-            if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-            {
-                lTimeout = -1; 
-            } 
-            else 
-            {
-                lTimeout = PR_IntervalToMilliseconds(timeout); 
-            }
-            socks[0] = osfd; 
-            if ((rv = _MD_SELECT(socks, 0, 1, 0,lTimeout)) == -1) {
-#endif
-                _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                break;
-            }
-            if (rv == 0) 
-            {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                return -1;
-            }
+    }
+
+     /*
+      * optimization; if bytes sent is less than "amount" call
+      * select before returning. This is because it is likely that
+      * the next send() call will return EWOULDBLOCK.
+      */
+    if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
+        && (timeout != PR_INTERVAL_NO_WAIT))
+    {
+        if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) {
+            rv = -1;
+            goto done;
         }
     }
-    return bytesSent;
+    if (rv < 0) {
+        _PR_MD_MAP_SEND_ERROR(err);
+    }
+done:
+    return(rv);
 }
 
 PRInt32
 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
               const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
-    PRInt32 bytesSent = 0;
-#ifdef BSD_SELECT
-    struct timeval tv, *tvp;
-    fd_set wd;
-#else
-    int socks[1];
-    long lTimeout = -1; 
-#endif
-
-    while(bytesSent < amount) 
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    while ((rv = sendto(osfd, buf, amount, flags,
+           (struct sockaddr *) addr, addrlen)) == -1)
     {
-        while ((rv = sendto( osfd, (char *) buf, amount, 0, (struct sockaddr *) addr,
-                addrlen)) == -1) 
+        err = sock_errno();
+        if ((err == SOCEWOULDBLOCK))
         {
-            if (((err = sock_errno()) == EWOULDBLOCK) 
-                && (!fd->secret->nonblocking))
-            {
-#ifdef BSD_SELECT
-               if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-               {
-                   tvp = NULL;
-               } 
-               else 
-               {
-                   tv.tv_sec = PR_IntervalToSeconds(timeout);
-                   tv.tv_usec = PR_IntervalToMicroseconds(
-                       timeout - PR_SecondsToInterval(tv.tv_sec));
-                   tvp = &tv;
-               }
-               FD_ZERO(&wd);
-               FD_SET(osfd, &wd);
-               if ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, tvp)) == -1) {
-#else
-                if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-                {
-                    lTimeout = -1; 
-                } 
-                else 
-                {
-                    lTimeout = PR_IntervalToMilliseconds(timeout);
-                }
-                socks[0] = osfd; 
-                if ((rv = _MD_SELECT(socks, 0, 1, 0, lTimeout)) == -1) {
-#endif
-                    _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                    break;
-                }
-                if (rv == 0) 
-                {
-                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                    return -1;
-                }
-            } 
-            else {
-                _PR_MD_MAP_SENDTO_ERROR(err);
-                return -1;
+            if (fd->secret->nonblocking) {
+                break;
             }
-        }
-        bytesSent += rv;
-        if (fd->secret->nonblocking)
-        {
+            if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0)
+                goto done;
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
             break;
         }
-        if ((rv >= 0) && (bytesSent < amount )) 
-        {
-#ifdef BSD_SELECT
-           if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-           {
-               tvp = NULL;
-           } 
-           else 
-           {
-               tv.tv_sec = PR_IntervalToSeconds(timeout);
-               tv.tv_usec = PR_IntervalToMicroseconds(
-                   timeout - PR_SecondsToInterval(tv.tv_sec));
-               tvp = &tv;
-           }
-           FD_ZERO(&wd);
-           FD_SET(osfd, &wd);
-           if ((rv = _MD_SELECT( osfd + 1, NULL, &wd, NULL, tvp)) == -1) {
-#else
-            if ( timeout == PR_INTERVAL_NO_TIMEOUT ) 
-            {
-                lTimeout = -1; 
-            } 
-            else 
-            {
-                lTimeout = PR_IntervalToMilliseconds(timeout);  
-            }
-            socks[0] = osfd; 
-            if ((rv = _MD_SELECT( socks, 0, 1, 0, lTimeout)) == -1) {
-#endif
-                _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                break;
-            }
-            if (rv == 0) 
-            {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                return -1;
-            }
-        }
     }
-    return bytesSent;
+    if (rv < 0) {
+        _PR_MD_MAP_SENDTO_ERROR(err);
+    }
+done:
+    return(rv);
 }
 
 PRInt32
 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
                 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
-    PRUint32 addrlen_temp = *addrlen;
-#ifdef BSD_SELECT
-    struct timeval tv, *tvp;
-    fd_set rd;
-#else
-    int socks[1]; 
-    long lTimeout = -1; 
-#endif
+    PRThread *me = _PR_MD_CURRENT_THREAD();
 
-    while ((rv = recvfrom( osfd, (char *) buf, amount, 0, (struct sockaddr *) addr,
-            (int *) addrlen)) == -1) 
+    while( (*addrlen = PR_NETADDR_SIZE(addr)),
+           ((rv = recvfrom(osfd, buf, amount, flags,
+             (struct sockaddr *) addr, (int *)addrlen)) == -1))
     {
-        if (((err = sock_errno()) == EWOULDBLOCK) 
-            && (!fd->secret->nonblocking))
-        {
-#ifdef BSD_SELECT
-            if (timeout == PR_INTERVAL_NO_TIMEOUT) 
-            {
-                tvp = NULL;
-            } 
-            else 
-            {
-                tv.tv_sec = PR_IntervalToSeconds(timeout);
-                tv.tv_usec = PR_IntervalToMicroseconds(
-                timeout - PR_SecondsToInterval(tv.tv_sec));
-                tvp = &tv;
-            }
-            FD_ZERO(&rd);
-            FD_SET(osfd, &rd);
-            if ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, tvp)) == -1) 
-#else
-            if (timeout == PR_INTERVAL_NO_TIMEOUT) 
-            {
-                lTimeout = -1;
-            } 
-            else 
-            {
-                lTimeout = PR_IntervalToMilliseconds(timeout);  
-            }
-            socks[0] = osfd; 
-            if ((rv = _MD_SELECT(socks, 1, 0, 0, lTimeout)) == -1) 
-#endif
-            {
-                _PR_MD_MAP_SELECT_ERROR(sock_errno());
-                return -1;
-            } else if (rv == 0) 
-            {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                rv = -1;
+        err = sock_errno();
+        if ((err == SOCEWOULDBLOCK)) {
+            if (fd->secret->nonblocking) {
                 break;
             }
-
-            /* recvfrom blows this value away if it fails first time */
-            *addrlen = addrlen_temp;
-        } 
-        else 
-        {
-            _PR_MD_MAP_RECVFROM_ERROR(err);
+            if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
+                goto done;
+        } else if ((err == SOCEINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
             break;
         }
     }
+    if (rv < 0) {
+        _PR_MD_MAP_RECVFROM_ERROR(err);
+    }
+done:
     return(rv);
 }
 
 PRInt32
-_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
+_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size,
+              PRIntervalTime timeout)
 {
-    int index;
-    int sent = 0;
-    int rv;
+    PRInt32 rv, err;
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    PRInt32 index, amount = 0;
+    PRInt32 osfd = fd->secret->md.osfd;
 
-    for (index=0; index < iov_size; index++) 
-    {
-        rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
-        if (rv > 0) 
-            sent += rv;
-        if ( rv != iov[index].iov_len ) 
-        {
-            if (rv < 0)
-            {
-                if (fd->secret->nonblocking
-                    && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
-                    && (sent > 0))
-                {
-                    return sent;
-                }
-                else
-                {
-                    return -1;
-                }
-            }
-            /* Only a nonblocking socket can have partial sends */
-            PR_ASSERT(fd->secret->nonblocking);
-            return sent;
+     /*
+      * Calculate the total number of bytes to be sent; needed for
+      * optimization later.
+      * We could avoid this if this number was passed in; but it is
+      * probably not a big deal because iov_size is usually small (less than
+      * 3)
+      */
+    if (!fd->secret->nonblocking) {
+        for (index=0; index<iov_size; index++) {
+            amount += iov[index].iov_len;
         }
     }
-    return sent;
+
+    while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) {
+        err = sock_errno();
+        if ((err == SOCEWOULDBLOCK))    {
+            if (fd->secret->nonblocking) {
+                break;
+            }
+            if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
+                goto done;
+        } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
+            continue;
+        } else {
+            break;
+        }
+    }
+
+     /*
+      * optimization; if bytes sent is less than "amount" call
+      * select before returning. This is because it is likely that
+      * the next writev() call will return EWOULDBLOCK.
+      */
+    if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
+          && (timeout != PR_INTERVAL_NO_WAIT)) {
+        if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
+            rv = -1;
+            goto done;
+        }
+    }
+    if (rv < 0) {
+        _PR_MD_MAP_WRITEV_ERROR(err);
+    }
+done:
+    return(rv);
 }
 
 PRInt32
 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
 {
     PRInt32 rv;
 
     rv = shutdown(fd->secret->md.osfd, how);
     if (rv < 0)
         _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno());
     return rv;
 }
 
 PRStatus
-_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
+_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
 {
-    PRInt32 rv;
+    PRInt32 rv, err;
 
-    rv = getsockname((int)fd->secret->md.osfd, (struct sockaddr *)addr, (int *) len);
-    if (rv==0)
-        return PR_SUCCESS;
-    else {
-        _PR_MD_MAP_GETSOCKNAME_ERROR(sock_errno());
-        return PR_FAILURE;
+    rv = getsockname(fd->secret->md.osfd,
+                     (struct sockaddr *) addr, (int *)addrlen);
+    if (rv < 0) {
+        err = sock_errno();
+        _PR_MD_MAP_GETSOCKNAME_ERROR(err);
     }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
 }
 
 PRStatus
-_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
+_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
 {
-    PRInt32 rv;
+    PRInt32 rv, err;
 
-    rv = getpeername((int)fd->secret->md.osfd, (struct sockaddr *)addr, (int *) len);
-    if (rv==0)
-        return PR_SUCCESS;
-    else {
-        _PR_MD_MAP_GETPEERNAME_ERROR(sock_errno());
-        return PR_FAILURE;
+    rv = getpeername(fd->secret->md.osfd,
+                     (struct sockaddr *) addr, (int *)addrlen);
+    if (rv < 0) {
+        err = sock_errno();
+        _PR_MD_MAP_GETPEERNAME_ERROR(err);
     }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
 }
 
 PRStatus
-_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
+_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
+                  char* optval, PRInt32* optlen)
 {
-    PRInt32 rv;
+    PRInt32 rv, err;
 
-    rv = getsockopt((int)fd->secret->md.osfd, level, optname, optval, optlen);
-    if (rv==0)
-        return PR_SUCCESS;
-    else {
-        _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
-        return PR_FAILURE;
+    rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen);
+    if (rv < 0) {
+        err = sock_errno();
+        _PR_MD_MAP_GETSOCKOPT_ERROR(err);
     }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
 }
 
 PRStatus
-_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
+_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
+                  const char* optval, PRInt32 optlen)
 {
-    PRInt32 rv;
+    PRInt32 rv, err;
 
-    rv = setsockopt((int)fd->secret->md.osfd, level, optname, (char *) optval, optlen);
-    if (rv==0)
-        return PR_SUCCESS;
-    else {
-        _PR_MD_MAP_SETSOCKOPT_ERROR(sock_errno());
-        return PR_FAILURE;
+    rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
+    if (rv < 0) {
+        err = sock_errno();
+        _PR_MD_MAP_SETSOCKOPT_ERROR(err);
     }
+    return rv==0?PR_SUCCESS:PR_FAILURE;
 }
 
 void
-_MD_MakeNonblock(PRFileDesc *f)
+_MD_MakeNonblock(PRFileDesc *fd)
 {
-    return; /* do nothing! */ 
+    PRInt32 osfd = fd->secret->md.osfd;
+    PRInt32 err;
+    PRUint32  one = 1;
+    
+    if (osfd <= 2) {
+        /* Don't mess around with stdin, stdout or stderr */
+        return;
+    }
+
+    err = ioctl( osfd, FIONBIO, (char *) &one, sizeof(one));
+    if ( err != 0 )
+    {
+        err = sock_errno();
+        _PR_MD_MAP_SOCKET_ERROR(err);
+    }
 }