Implemented file descriptor inheritance for NT.
authorwtc%netscape.com
Fri, 05 Feb 1999 06:45:06 +0000
changeset 423 4f3c04ae6b78be38e7be0e5bdbf8e9a30a6acf34
parent 422 8fd57743dfabf046dd642f9cd972c6633a525032
child 424 c5e4edef28edc852289253c7e5923b7202bb7871
push idunknown
push userunknown
push dateunknown
Implemented file descriptor inheritance for NT. Modified files: _winnt.h, prfile.c, prio.c, prsocket.c, ntio.c, w32poll.c, and prinit.c.
pr/include/md/_winnt.h
pr/src/io/prfile.c
pr/src/io/prio.c
pr/src/io/prsocket.c
pr/src/md/windows/ntio.c
pr/src/md/windows/w32poll.c
pr/src/misc/prinit.c
--- a/pr/include/md/_winnt.h
+++ b/pr/include/md/_winnt.h
@@ -171,20 +171,19 @@ struct _MDFileDesc {
                       *   which is a void*.
                       * - For sockets, we are using Winsock SOCKET, which
                       *   is a u_int.
                       */
     PRBool io_model_committed;  /* The io model (blocking or nonblocking)
                                  * for this osfd has been committed and
                                  * cannot be changed.  The osfd has been
                                  * either associated with the io
-                                 * completion port or made nonblocking.
-                                 * This is only used for sockets, not
-                                 * for files. */
-    PRBool nonoverlapped;
+                                 * completion port or made nonblocking. */
+    PRBool sync_file_io;        /* Use synchronous file I/O on the osfd
+                                 * (a file handle) */
     PRBool accepted_socket;     /* Is this an accepted socket (on the
                                  * server side)? */
     PRNetAddr peer_addr;        /* If this is an accepted socket, cache
                                  * the peer's address returned by
                                  * AcceptEx().  This is to work around
                                  * the bug that getpeername() on an
                                  * socket accepted by AcceptEx() returns
                                  * an all-zero net address. */
@@ -236,16 +235,18 @@ extern PRInt32 _PR_MD_CLOSE(PRInt32 osfd
 #define _MD_SENDTO                    _PR_MD_SENDTO
 #define _MD_RECVFROM                  _PR_MD_RECVFROM
 #define _MD_SOCKETPAIR(s, type, proto, sv) -1
 #define _MD_GETSOCKNAME               _PR_MD_GETSOCKNAME
 #define _MD_GETPEERNAME               _PR_MD_GETPEERNAME
 #define _MD_GETSOCKOPT                _PR_MD_GETSOCKOPT
 #define _MD_SETSOCKOPT                _PR_MD_SETSOCKOPT
 #define _MD_SELECT                    select
+extern int _PR_NTFiberSafeSelect(int, fd_set *, fd_set *, fd_set *,
+    const struct timeval *);
 #define _MD_FSYNC                     _PR_MD_FSYNC
 #define _MD_SOCKETAVAILABLE           _PR_MD_SOCKETAVAILABLE
 #define _MD_SET_FD_INHERITABLE        _PR_MD_SET_FD_INHERITABLE
 
 #define _MD_INIT_ATOMIC()
 #if defined(_M_IX86) || defined(_X86_)
 #define _MD_ATOMIC_INCREMENT          _PR_MD_ATOMIC_INCREMENT
 #define _MD_ATOMIC_ADD          	  _PR_MD_ATOMIC_ADD
--- a/pr/src/io/prfile.c
+++ b/pr/src/io/prfile.c
@@ -543,18 +543,18 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
     }
     *writePipe = PR_AllocFileDesc((PRInt32)writeEnd, &_pr_fileMethods);
     if (NULL == *writePipe) {
         PR_Close(*readPipe);
         CloseHandle(writeEnd);
         return PR_FAILURE;
     }
 #ifdef WINNT
-    (*readPipe)->secret->md.nonoverlapped = PR_TRUE;
-    (*writePipe)->secret->md.nonoverlapped = PR_TRUE;
+    (*readPipe)->secret->md.sync_file_io = PR_TRUE;
+    (*writePipe)->secret->md.sync_file_io = PR_TRUE;
 #endif
     return PR_SUCCESS;
 #elif defined(XP_UNIX)
     int pipefd[2];
 
     if (!_pr_initialized) _PR_ImplicitInitialization();
 
     if (pipe(pipefd) == -1) {
--- a/pr/src/io/prio.c
+++ b/pr/src/io/prio.c
@@ -36,19 +36,19 @@ void _PR_InitIO(void)
 #ifdef WIN32
     _pr_stdin = PR_AllocFileDesc((PRInt32)GetStdHandle(STD_INPUT_HANDLE),
             methods);
     _pr_stdout = PR_AllocFileDesc((PRInt32)GetStdHandle(STD_OUTPUT_HANDLE),
             methods);
     _pr_stderr = PR_AllocFileDesc((PRInt32)GetStdHandle(STD_ERROR_HANDLE),
             methods);
 #ifdef WINNT
-    _pr_stdin->secret->md.nonoverlapped = PR_TRUE;
-    _pr_stdout->secret->md.nonoverlapped = PR_TRUE;
-    _pr_stderr->secret->md.nonoverlapped = PR_TRUE;
+    _pr_stdin->secret->md.sync_file_io = PR_TRUE;
+    _pr_stdout->secret->md.sync_file_io = PR_TRUE;
+    _pr_stderr->secret->md.sync_file_io = PR_TRUE;
 #endif
 #else
     _pr_stdin = PR_AllocFileDesc(0, methods);
     _pr_stdout = PR_AllocFileDesc(1, methods);
     _pr_stderr = PR_AllocFileDesc(2, methods);
 #endif
 
     _PR_MD_INIT_IO();
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -344,18 +344,25 @@ PRIntervalTime timeout)
 
 	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
 	if (!fd2) {
 		_PR_MD_CLOSE_SOCKET(osfd);
 		return NULL;
 	}
 
 	fd2->secret->nonblocking = fd->secret->nonblocking;
+	fd2->secret->inheritable = fd->secret->inheritable;
 #ifdef WINNT
-	fd2->secret->md.io_model_committed = PR_TRUE;
+	if (!fd2->secret->nonblocking && !fd2->secret->inheritable) {
+		/*
+		 * The new socket has been associated with an I/O
+		 * completion port.  There is no going back.
+		 */
+		fd2->secret->md.io_model_committed = PR_TRUE;
+	}
 	PR_ASSERT(al == PR_NETADDR_SIZE(addr));
 	fd2->secret->md.accepted_socket = PR_TRUE;
 	memcpy(&fd2->secret->md.peer_addr, addr, al);
 #endif
 
 	/*
 	 * On some platforms, the new socket created by accept()
 	 * inherits the nonblocking (or overlapped io) attribute
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -1064,27 +1064,35 @@ PRInt32
     PRThread *me = _PR_MD_CURRENT_THREAD();
     SOCKET accept_sock;
     int bytes;
     PRNetAddr *Laddr;
     PRNetAddr *Raddr;
     PRUint32 llen, err;
     int rv;
 
-    if (!_nt_use_async || fd->secret->nonblocking) {
+    if (!_nt_use_async || fd->secret->nonblocking || fd->secret->inheritable) {
         if (!fd->secret->md.io_model_committed) {
             rv = _md_MakeNonblock((HANDLE)osfd);
             PR_ASSERT(0 != rv);
             fd->secret->md.io_model_committed = PR_TRUE;
         }
         /*
-         * The accepted socket inherits the nonblocking attribute of
-         * the listening socket, so no need to call _md_MakeNonblock().
+         * The accepted socket inherits the nonblocking and
+         * inheritable (HANDLE_FLAG_INHERIT) attributes of
+         * the listening socket.
          */
-        return _nt_nonblock_accept(fd, (struct sockaddr_in *)raddr, rlen, timeout);
+        accept_sock = _nt_nonblock_accept(fd, (struct sockaddr_in *)raddr, rlen, timeout);
+        if (_nt_use_async && !fd->secret->nonblocking) {
+            u_long zero = 0;
+
+            rv = ioctlsocket(accept_sock, FIONBIO, &zero);
+            PR_ASSERT(0 == rv);
+        }
+        return accept_sock;
     }
 
     if (me->io_suspended) {
         PR_SetError(PR_INVALID_STATE_ERROR, 0);
         return -1;
     }
 
     if (!fd->secret->md.io_model_committed) {
@@ -1431,17 +1439,17 @@ PRInt32
 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, 
             PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     int bytes;
     int rv, err;
 
-    if (!_nt_use_async || fd->secret->nonblocking) {
+    if (!_nt_use_async || fd->secret->nonblocking || fd->secret->inheritable) {
         if (!fd->secret->md.io_model_committed) {
             rv = _md_MakeNonblock((HANDLE)osfd);
             PR_ASSERT(0 != rv);
             fd->secret->md.io_model_committed = PR_TRUE;
         }
         return _nt_nonblock_recv(fd, buf, amount, timeout);
     }
 
@@ -1508,17 +1516,17 @@ PRInt32
 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
             PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     int bytes;
     int rv, err;
 
-    if (!_nt_use_async || fd->secret->nonblocking) {
+    if (!_nt_use_async || fd->secret->nonblocking || fd->secret->inheritable) {
         if (!fd->secret->md.io_model_committed) {
             rv = _md_MakeNonblock((HANDLE)osfd);
             PR_ASSERT(0 != rv);
             fd->secret->md.io_model_committed = PR_TRUE;
         }
         return _nt_nonblock_send(fd, (char *)buf, amount, timeout);
     }
 
@@ -1584,17 +1592,17 @@ PRInt32
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv;
 
     if (!fd->secret->md.io_model_committed) {
         rv = _md_MakeNonblock((HANDLE)osfd);
         PR_ASSERT(0 != rv);
         fd->secret->md.io_model_committed = PR_TRUE;
     }
-    if (_nt_use_async && !fd->secret->nonblocking)
+    if (_nt_use_async && !fd->secret->nonblocking && !fd->secret->inheritable)
         return pt_SendTo(osfd, buf, amount, flags, addr, addrlen, timeout);
     else
         return _nt_nonblock_sendto(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout);
 }
 
 PRInt32
 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
                 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
@@ -1602,32 +1610,32 @@ PRInt32
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv;
 
     if (!fd->secret->md.io_model_committed) {
         rv = _md_MakeNonblock((HANDLE)osfd);
         PR_ASSERT(0 != rv);
         fd->secret->md.io_model_committed = PR_TRUE;
     }
-    if (_nt_use_async && !fd->secret->nonblocking)
+    if (_nt_use_async && !fd->secret->nonblocking && !fd->secret->inheritable)
         return pt_RecvFrom(osfd, buf, amount, flags, addr, addrlen, timeout);
     else
         return _nt_nonblock_recvfrom(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout);
 }
 
 /* XXXMB - for now this is a sockets call only */
 PRInt32
 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     int index;
     int sent = 0;
     int rv;
 
-    if (!_nt_use_async || fd->secret->nonblocking) {
+    if (!_nt_use_async || fd->secret->nonblocking || fd->secret->inheritable) {
         if (!fd->secret->md.io_model_committed) {
             rv = _md_MakeNonblock((HANDLE)osfd);
             PR_ASSERT(0 != rv);
             fd->secret->md.io_model_committed = PR_TRUE;
         }
         return _nt_nonblock_writev(fd, iov, iov_size, timeout);
     }
 
@@ -1787,22 +1795,17 @@ PRInt32
         file = CreateFile(name, 
                           access, 
                           FILE_SHARE_READ|FILE_SHARE_WRITE,
                           NULL,
                           flags, 
                           flag6,
                           NULL);
         if (file == INVALID_HANDLE_VALUE) {
-			_PR_MD_MAP_OPEN_ERROR(GetLastError());
-            return -1;
-		}
-
-        if (_md_Associate(file) == 0) {
-            CloseHandle(file);
+            _PR_MD_MAP_OPEN_ERROR(GetLastError());
             return -1;
         }
 
         if (osflags & PR_APPEND) {
             if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) {
                 _PR_MD_MAP_LSEEK_ERROR(GetLastError());
                 CloseHandle(file);
                 return -1;
@@ -1849,165 +1852,231 @@ PRInt32
 
 PRInt32 
 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
 {
     PRInt32 f = fd->secret->md.osfd;
     PRUint32 bytes;
     int rv, err;
 
-    if (_nt_use_async && !fd->secret->md.nonoverlapped) {
+    if (_nt_use_async && !fd->secret->md.sync_file_io) {
         PRThread *me = _PR_MD_CURRENT_THREAD();
 
         if (me->io_suspended) {
             PR_SetError(PR_INVALID_STATE_ERROR, 0);
             return -1;
         }
 
         memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
 
         me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, 0, FILE_CURRENT);
 
-        me->io_pending = PR_TRUE;
-        me->io_fd = f;
-        me->state = _PR_IO_WAIT;
-        rv = ReadFile((HANDLE)f, 
-                      (LPVOID)buf, 
-                      len, 
-                      &bytes, 
-                      &me->md.overlapped.overlapped);
-        if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
-            me->io_pending = PR_FALSE;
-            me->state = _PR_RUNNING;
-            if (err == ERROR_HANDLE_EOF)
+        if (fd->secret->inheritable) {
+            rv = ReadFile((HANDLE)f, 
+                          (LPVOID)buf, 
+                          len, 
+                          &bytes, 
+                          &me->md.overlapped.overlapped);
+            if (rv != 0) {
+                SetFilePointer((HANDLE)f, bytes, 0, FILE_CURRENT);
+                return bytes;
+            }
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                rv = GetOverlappedResult((HANDLE)f,
+                        &me->md.overlapped.overlapped, &bytes, TRUE);
+                if (rv != 0) {
+                    SetFilePointer((HANDLE)f, bytes, 0, FILE_CURRENT);
+                    return bytes;
+                }
+                err = GetLastError();
+            }
+            if (err == ERROR_HANDLE_EOF) {
                 return 0;
-			_PR_MD_MAP_READ_ERROR(err);
-            return -1;
-        }
-
-        if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
-            PR_ASSERT(0);
-            return -1;
+            } else {
+                _PR_MD_MAP_READ_ERROR(err);
+                return -1;
+            }
+        } else {
+            if (!fd->secret->md.io_model_committed) {
+                rv = _md_Associate((HANDLE)f);
+                PR_ASSERT(rv != 0);
+                fd->secret->md.io_model_committed = PR_TRUE;
+            }
+
+            me->io_pending = PR_TRUE;
+            me->io_fd = f;
+            me->state = _PR_IO_WAIT;
+            rv = ReadFile((HANDLE)f, 
+                          (LPVOID)buf, 
+                          len, 
+                          &bytes, 
+                          &me->md.overlapped.overlapped);
+            if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
+                me->io_pending = PR_FALSE;
+                me->state = _PR_RUNNING;
+                if (err == ERROR_HANDLE_EOF) {
+                    return 0;
+                }
+                _PR_MD_MAP_READ_ERROR(err);
+                return -1;
+            }
+
+            if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+                PR_ASSERT(0);
+                return -1;
+            }
+
+            PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);
+
+            if (me->io_suspended) {
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                } else {
+                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                }
+                return -1;
+            }
+
+            if (me->md.blocked_io_status == 0) {
+                if (me->md.blocked_io_error == ERROR_HANDLE_EOF) {
+                    return 0;
+                }
+                _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error);
+                return -1;
+            }
+
+            SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT);
+    
+            PR_ASSERT(me->io_pending == PR_FALSE);
+
+            return me->md.blocked_io_bytes;
         }
-
-        PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);
-
-        if (me->io_suspended) {
-            if (_PR_PENDING_INTERRUPT(me)) {
-                me->flags &= ~_PR_INTERRUPT;
-                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
-            } else {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-            }
-            return -1;
-        }
-
-        if (me->md.blocked_io_status == 0) {
-            if (me->md.blocked_io_error == ERROR_HANDLE_EOF)
-                return 0;
-			_PR_MD_MAP_READ_ERROR(me->md.blocked_io_error);
-            return -1;
-        }
-
-        SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT);
-    
-        PR_ASSERT(me->io_pending == PR_FALSE);
-
-        return me->md.blocked_io_bytes;
     } else {
 
         rv = ReadFile((HANDLE)f,
                       (LPVOID)buf,
                       len,
                       &bytes,
                       NULL);
         if (rv == 0) {
             err = GetLastError();
             /* ERROR_HANDLE_EOF can only be returned by async io */
             PR_ASSERT(err != ERROR_HANDLE_EOF);
             if (err == ERROR_BROKEN_PIPE) {
                 /* The write end of the pipe has been closed. */ 
                 return 0;
             }
-			_PR_MD_MAP_READ_ERROR(err);
+            _PR_MD_MAP_READ_ERROR(err);
             return -1;
         }
         return bytes;
     }
 }
 
 PRInt32
 _PR_MD_WRITE(PRFileDesc *fd, void *buf, PRInt32 len)
 {
     PRInt32 f = fd->secret->md.osfd;
     PRInt32 bytes;
     int rv, err;
 
-    if (_nt_use_async && !fd->secret->md.nonoverlapped) {
+    if (_nt_use_async && !fd->secret->md.sync_file_io) {
         PRThread *me = _PR_MD_CURRENT_THREAD();
 
         if (me->io_suspended) {
             PR_SetError(PR_INVALID_STATE_ERROR, 0);
             return -1;
         }
 
         memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
 
         me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, 0, FILE_CURRENT);
 
-        me->io_pending = PR_TRUE;
-        me->io_fd = f;
-        me->state = _PR_IO_WAIT;
-        rv = WriteFile((HANDLE)f, 
-                       buf, 
-                       len, 
-                       &bytes, 
-                       &(me->md.overlapped.overlapped));
-        if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
-            me->io_pending = PR_FALSE;
-            me->state = _PR_RUNNING;
-			_PR_MD_MAP_WRITE_ERROR(err);
+        if (fd->secret->inheritable) {
+            rv = WriteFile((HANDLE)f, 
+                          (LPVOID)buf, 
+                          len, 
+                          &bytes, 
+                          &me->md.overlapped.overlapped);
+            if (rv != 0) {
+                SetFilePointer((HANDLE)f, bytes, 0, FILE_CURRENT);
+                return bytes;
+            }
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                rv = GetOverlappedResult((HANDLE)f,
+                        &me->md.overlapped.overlapped, &bytes, TRUE);
+                if (rv != 0) {
+                    SetFilePointer((HANDLE)f, bytes, 0, FILE_CURRENT);
+                    return bytes;
+                }
+                err = GetLastError();
+            }
+            _PR_MD_MAP_READ_ERROR(err);
             return -1;
-        }
-
-        if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
-            PR_ASSERT(0);
-            return -1;
+        } else {
+            if (!fd->secret->md.io_model_committed) {
+                rv = _md_Associate((HANDLE)f);
+                PR_ASSERT(rv != 0);
+                fd->secret->md.io_model_committed = PR_TRUE;
+            }
+
+            me->io_pending = PR_TRUE;
+            me->io_fd = f;
+            me->state = _PR_IO_WAIT;
+            rv = WriteFile((HANDLE)f, 
+                           buf, 
+                           len, 
+                           &bytes, 
+                           &(me->md.overlapped.overlapped));
+            if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
+                me->io_pending = PR_FALSE;
+                me->state = _PR_RUNNING;
+                _PR_MD_MAP_WRITE_ERROR(err);
+                return -1;
+            }
+
+            if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+                PR_ASSERT(0);
+                return -1;
+            }
+
+            PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);
+
+            if (me->io_suspended) {
+                if (_PR_PENDING_INTERRUPT(me)) {
+                    me->flags &= ~_PR_INTERRUPT;
+                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+                } else {
+                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                }
+                return -1;
+            }
+
+            if (me->md.blocked_io_status == 0) {
+                _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error);
+                return -1;
+            }
+
+            SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT);
+    
+            PR_ASSERT(me->io_pending == PR_FALSE);
+
+            return me->md.blocked_io_bytes;
         }
-
-        PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);
-
-        if (me->io_suspended) {
-            if (_PR_PENDING_INTERRUPT(me)) {
-                me->flags &= ~_PR_INTERRUPT;
-                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
-            } else {
-                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-            }
-            return -1;
-        }
-
-        if (me->md.blocked_io_status == 0) {
-			_PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error);
-            return -1;
-        }
-
-        SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT);
-    
-        PR_ASSERT(me->io_pending == PR_FALSE);
-
-        return me->md.blocked_io_bytes;
     } else {
         rv = WriteFile((HANDLE)f,
                        buf,
                        len,
                        &bytes,
                        NULL);
         if (rv == 0) {
-			_PR_MD_MAP_WRITE_ERROR(GetLastError());
+            _PR_MD_MAP_WRITE_ERROR(GetLastError());
             return -1;
         }
         return bytes;
     }
 }
 
 PRInt32
 _PR_MD_SOCKETAVAILABLE(PRFileDesc *fd)
@@ -2182,16 +2251,20 @@ PRInt32
     }
 }
 
 PRStatus
 _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
 {
     BOOL rv;
 
+    if (fd->secret->md.io_model_committed) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
     rv = SetHandleInformation(
             (HANDLE)fd->secret->md.osfd,
             HANDLE_FLAG_INHERIT,
             inheritable ? HANDLE_FLAG_INHERIT : 0);
     if (0 == rv) {
         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
         return PR_FAILURE;
     }
@@ -3116,58 +3189,59 @@ PRInt32 _nt_nonblock_accept(PRFileDesc *
     struct timeval tv, *tvp;
 
     FD_ZERO(&rd);
     FD_SET((SOCKET)osfd, &rd);
     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
         while ((rv = accept(osfd, (struct sockaddr *) addr, len)) == -1) {
             if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                     && (!fd->secret->nonblocking)) {
-                if ((rv = select(osfd + 1, &rd, NULL, NULL,NULL)) == -1) {
-					_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL,
+                        NULL)) == -1) {
+                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                     break;
-				}
+                }
             } else {
-				_PR_MD_MAP_ACCEPT_ERROR(err);
+                _PR_MD_MAP_ACCEPT_ERROR(err);
                 break;
-        }
+            }
         }
-        return(rv);
     } else if (timeout == PR_INTERVAL_NO_WAIT) {
-        if ((rv = accept(osfd, (struct sockaddr *) addr, len)) == -1)
+        if ((rv = accept(osfd, (struct sockaddr *) addr, len)) == -1) {
             if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                     && (!fd->secret->nonblocking)) {
-				PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
             } else {
-				_PR_MD_MAP_ACCEPT_ERROR(err);
-            }
-            return(rv);
-        } else {
-retry:
-            if ((rv = accept(osfd, (struct sockaddr *) addr, len)) == -1) {
-                if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
-                        && (!fd->secret->nonblocking)) {
-                    tv.tv_sec = PR_IntervalToSeconds(timeout);
-                    tv.tv_usec = PR_IntervalToMicroseconds(
-                        timeout - PR_SecondsToInterval(tv.tv_sec));
-                    tvp = &tv;
-
-                    rv = select(osfd + 1, &rd, NULL, NULL, tvp);
-                    if (rv > 0) {
-                        goto retry;
-                    } else if (rv == 0) {
-						PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
-                    	rv = -1;
-                	} else
-						_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-            	} else {
-					_PR_MD_MAP_ACCEPT_ERROR(err);
-                }
+                _PR_MD_MAP_ACCEPT_ERROR(err);
             }
         }
+    } else {
+retry:
+        if ((rv = accept(osfd, (struct sockaddr *) addr, len)) == -1) {
+            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
+                    && (!fd->secret->nonblocking)) {
+                tv.tv_sec = PR_IntervalToSeconds(timeout);
+                tv.tv_usec = PR_IntervalToMicroseconds(
+                    timeout - PR_SecondsToInterval(tv.tv_sec));
+                tvp = &tv;
+
+                rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL, tvp);
+                if (rv > 0) {
+                    goto retry;
+                } else if (rv == 0) {
+                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                    rv = -1;
+                } else {
+                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                }
+            } else {
+                _PR_MD_MAP_ACCEPT_ERROR(err);
+            }
+        }
+    }
     return(rv);
 }
 
 PRInt32 _nt_nonblock_recv(PRFileDesc *fd, char *buf, int len, PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
     struct timeval tv, *tvp;
@@ -3181,26 +3255,27 @@ PRInt32 _nt_nonblock_recv(PRFileDesc *fd
             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 = select(osfd + 1, &rd, NULL,NULL,tvp)) == -1) {
-				_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-                return -1;
+            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL,
+                    tvp)) == -1) {
+                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                break;
             } else if (rv == 0) {
-				PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                 rv = -1;
                 break;
             }
         } else {
-			_PR_MD_MAP_RECV_ERROR(err);
+            _PR_MD_MAP_RECV_ERROR(err);
             break;
         }
     }
     return(rv);
 }
 
 PRInt32 _nt_nonblock_send(PRFileDesc *fd, char *buf, int len, PRIntervalTime timeout)
 {
@@ -3219,50 +3294,52 @@ PRInt32 _nt_nonblock_send(PRFileDesc *fd
                 } 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((SOCKET)osfd, &wd);
-                if ((rv = select(osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
-					_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-                    break;
-				}
+                if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
+                        tvp)) == -1) {
+                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                    return -1;
+                }
                 if (rv == 0) {
-					PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                     return -1;
                 }
             } else {
-				_PR_MD_MAP_SEND_ERROR(err);
+                _PR_MD_MAP_SEND_ERROR(err);
                 return -1;
-        }
+            }
         }
         bytesSent += rv;
         if (fd->secret->nonblocking) {
             break;
         }
-        if ((rv >= 0) && (bytesSent < len)) {
+        if (bytesSent < len) {
             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((SOCKET)osfd, &wd);
-            if ((rv = select(osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
-				_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-                break;
-			}
+            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
+                    tvp)) == -1) {
+                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                return -1;
+            }
             if (rv == 0) {
-				PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                 return -1;
             }
         }
     }
     return bytesSent;
 }
 
 PRInt32 _nt_nonblock_writev(PRFileDesc *fd, const PRIOVec *iov, int size, PRIntervalTime timeout)
@@ -3271,17 +3348,17 @@ PRInt32 _nt_nonblock_writev(PRFileDesc *
     int sent = 0;
     int rv;
 
     for (index=0; index<size; index++) {
         rv = _nt_nonblock_send(fd, iov[index].iov_base, iov[index].iov_len, timeout);
         if (rv > 0) 
             sent += rv;
         if ( rv != iov[index].iov_len ) {
-            if (rv <= 0) {
+            if (rv < 0) {
                 if (fd->secret->nonblocking
                         && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
                         && (sent > 0)) {
                     return sent;
                 } else {
                     return -1;
                 }
             }
@@ -3313,50 +3390,52 @@ PRInt32 _nt_nonblock_sendto(
                 } 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((SOCKET)osfd, &wd);
-                if ((rv = select(osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
-					_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-                    break;
-				}
+                if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
+                        tvp)) == -1) {
+                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                    return -1;
+                }
                 if (rv == 0) {
-					PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                     return -1;
                 }
             } else {
-				_PR_MD_MAP_SENDTO_ERROR(err);
+                _PR_MD_MAP_SENDTO_ERROR(err);
                 return -1;
-        }
+            }
         }
         bytesSent += rv;
         if (fd->secret->nonblocking) {
             break;
         }
-        if ((rv >= 0) && (bytesSent < len)) {
+        if (bytesSent < len) {
             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((SOCKET)osfd, &wd);
-            if ((rv = select(osfd + 1, NULL, &wd, NULL,tvp)) == -1) {
-				_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-                break;
-			}
+            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
+                    tvp)) == -1) {
+                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                return -1;
+            }
             if (rv == 0) {
-				PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                 return -1;
             }
         }
     }
     return bytesSent;
 }
 
 PRInt32 _nt_nonblock_recvfrom(PRFileDesc *fd, char *buf, int len, struct sockaddr *addr, int *addrlen, PRIntervalTime timeout)
@@ -3374,26 +3453,27 @@ PRInt32 _nt_nonblock_recvfrom(PRFileDesc
             } 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((SOCKET)osfd, &rd);
-            if ((rv = select(osfd + 1, &rd, NULL,NULL,tvp)) == -1) {
-				_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
-                return -1;
+            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL,
+                    tvp)) == -1) {
+                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
+                break;
             } else if (rv == 0) {
-				PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                 rv = -1;
                 break;
             }
         } else {
-			_PR_MD_MAP_RECVFROM_ERROR(err);
+            _PR_MD_MAP_RECVFROM_ERROR(err);
             break;
         }
     }
     return(rv);
 }
 
 /*
  * UDP support: the continuation thread functions and recvfrom and sendto.
--- a/pr/src/md/windows/w32poll.c
+++ b/pr/src/md/windows/w32poll.c
@@ -23,31 +23,71 @@
 #include "primpl.h"
 
 #if !defined(_PR_GLOBAL_THREADS_ONLY)
 
 struct select_data_s {
     PRInt32 status;
     PRInt32 error;
     fd_set *rd, *wt, *ex;
-    struct timeval *tv;
+    const struct timeval *tv;
 };
 
 static void
 _PR_MD_select_thread(void *cdata)
 {
     struct select_data_s *cd = (struct select_data_s *)cdata;
 
     cd->status = select(0, cd->rd, cd->wt, cd->ex, cd->tv);
 
     if (cd->status == SOCKET_ERROR) {
         cd->error = WSAGetLastError();
     }
 }
 
+int _PR_NTFiberSafeSelect(
+    int nfds,
+    fd_set *readfds,
+    fd_set *writefds,
+    fd_set *exceptfds,
+    const struct timeval *timeout)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+    int ready;
+
+    if (_PR_IS_NATIVE_THREAD(me)) {
+        ready = _MD_SELECT(nfds, readfds, writefds, exceptfds, timeout);
+    }
+    else
+    {
+        /*
+        ** Creating a new thread on each call!!
+        ** I guess web server doesn't use non-block I/O.
+        */
+        PRThread *selectThread;
+        struct select_data_s data;
+        data.status = 0;
+        data.error = 0;
+        data.rd = readfds;
+        data.wt = writefds;
+        data.ex = exceptfds;
+        data.tv = timeout;
+
+        selectThread = PR_CreateThread(
+            PR_USER_THREAD, _PR_MD_select_thread, &data,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (selectThread == NULL) return -1;
+
+        PR_JoinThread(selectThread);
+        ready = data.status;
+        if (ready == SOCKET_ERROR) WSASetLastError(data.error);
+    }
+    return ready;
+}
+
 #endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */
 
 PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
 {
     int ready, err;
     fd_set rd, wt, ex;
     PRFileDesc *bottom;
     PRPollDesc *pd, *epd;
@@ -178,43 +218,17 @@ PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, 
         tv.tv_usec = timeout - (ticksPerSecond * tv.tv_sec);
         tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond;
         tvp = &tv;
     }
 
 #if defined(_PR_GLOBAL_THREADS_ONLY)
     ready = _MD_SELECT(0, &rd, &wt, &ex, tvp);
 #else
-    if (_PR_IS_NATIVE_THREAD(me)) {
-        ready = _MD_SELECT(0, &rd, &wt, &ex, tvp);
-    }
-    else
-    {
-        /*
-        ** Creating a new thread on each call to Poll()!!
-        ** I guess web server doesn't use non-block I/O.
-        */
-        PRThread *selectThread;
-        struct select_data_s data;
-        data.status = 0;
-        data.error = 0;
-        data.rd = &rd;
-        data.wt = &wt;
-        data.ex = &ex;
-        data.tv = tvp;
-
-        selectThread = PR_CreateThread(
-            PR_USER_THREAD, _PR_MD_select_thread, &data,
-            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
-        if (selectThread == NULL) return -1;
-
-        PR_JoinThread(selectThread);
-        ready = data.status;
-        if (ready == SOCKET_ERROR) WSASetLastError(data.error);
-    }
+    ready = _PR_NTFiberSafeSelect(0, &rd, &wt, &ex, tvp);
 #endif
 
     /*
     ** 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)
--- a/pr/src/misc/prinit.c
+++ b/pr/src/misc/prinit.c
@@ -477,17 +477,17 @@ PR_ProcessAttrSetInheritableFD(
     /* We malloc the fd inherit buffer in multiples of this number. */
 #define FD_INHERIT_BUFFER_INCR 128
     /* The length of "NSPR_INHERIT_FDS=" */
 #define NSPR_INHERIT_FDS_STRLEN 17
     /* The length of osfd (PRInt32) printed in hexadecimal with 0x prefix */
 #define OSFD_STRLEN 10
     /* The length of fd type (PRDescType) printed in decimal */
 #define FD_TYPE_STRLEN 1
-    int newSize;
+    PRSize newSize;
     int remainder;
     char *newBuffer;
     int nwritten;
     char *cur;
     int freeSize;
 
     if (fd->identity != PR_NSPR_IO_LAYER) {
         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
@@ -576,16 +576,24 @@ PR_IMPLEMENT(PRFileDesc *) PR_GetInherit
                     fd = PR_ImportUDPSocket(osfd);
                     break;
                 default:
                     PR_ASSERT(0);
                     PR_SetError(PR_UNKNOWN_ERROR, 0);
                     fd = NULL;
                     break;
             }
+            if (fd) {
+                /*
+                 * An inherited FD is inheritable by default.
+                 * The child process needs to call PR_SetFDInheritable
+                 * to make it non-inheritable if so desired.
+                 */
+                fd->secret->inheritable = PR_TRUE;
+            }
             return fd;
         }
         /* Skip three colons */
         nColons = 0;
         while (*ptr) {
             if (*ptr == ':') {
                 if (++nColons == 3) {
                     break;