Created NSPRPUB_RELEASE_3_5_LANDING_BRANCH, rooted at NSPRPUB_RELEASE_3_5_LANDING_BRANCH
authorwtc%netscape.com
Thu, 07 Oct 1999 20:15:02 +0000
branchNSPRPUB_RELEASE_3_5_LANDING_BRANCH
changeset 852 7d6deae3e97a98b560581976c1e43918001c7452
parent 851 c6afd3661de449bb37e696fc6d0eede0ecc2f6b1
child 853 e049457243e77b6cd0a2615ce1228babd1e782a8
push idunknown
push userunknown
push dateunknown
Created NSPRPUB_RELEASE_3_5_LANDING_BRANCH, rooted at NSPRPUB_RELEASE_3_5_BASE.
config/AIX.mk
config/HP-UX.mk
config/IRIX.mk
config/Linux.mk
config/Makefile
config/OSF1.mk
config/SINIX.mk
config/SunOS4.mk
config/SunOS5.mk
config/WIN32.mk
config/config.mk
config/rules.mk
lib/ds/plevent.c
lib/ds/plvrsion.c
lib/libc/src/plvrsion.c
lib/prstreams/plvrsion.c
pr/include/md/Makefile
pr/include/md/_aix.h
pr/include/md/_aix32in6.cfg
pr/include/md/_aix64.cfg
pr/include/md/_beos.h
pr/include/md/_hpux.h
pr/include/md/_irix.h
pr/include/md/_linux.h
pr/include/md/_os2.h
pr/include/md/_osf1.h
pr/include/md/_solaris.cfg
pr/include/md/_solaris.h
pr/include/md/_solaris32.cfg
pr/include/md/_solaris64.cfg
pr/include/md/_unix_errors.h
pr/include/md/_unixos.h
pr/include/md/_win16.h
pr/include/md/_win32_errors.h
pr/include/md/_win95.h
pr/include/md/_winnt.h
pr/include/nspr.h
pr/include/prinit.h
pr/include/prio.h
pr/include/pripcsem.h
pr/include/private/pprio.h
pr/include/private/primpl.h
pr/include/prnetdb.h
pr/include/prshm.h
pr/include/prshma.h
pr/src/Makefile
pr/src/io/prfdcach.c
pr/src/io/prlayer.c
pr/src/io/prlog.c
pr/src/io/prmwait.c
pr/src/io/prpolevt.c
pr/src/io/prsocket.c
pr/src/md/beos/bnet.c
pr/src/md/unix/Makefile
pr/src/md/unix/aix.c
pr/src/md/unix/objs.mk
pr/src/md/unix/os_Irix.s
pr/src/md/unix/os_SunOS.s
pr/src/md/unix/os_SunOS_32.s
pr/src/md/unix/unix.c
pr/src/md/unix/unix_errors.c
pr/src/md/unix/uxproces.c
pr/src/md/unix/uxshm.c
pr/src/md/windows/Makefile
pr/src/md/windows/ntio.c
pr/src/md/windows/ntmisc.c
pr/src/md/windows/ntthread.c
pr/src/md/windows/w32ipcsem.c
pr/src/md/windows/w32shm.c
pr/src/md/windows/win32_errors.c
pr/src/memory/Makefile
pr/src/memory/prshm.c
pr/src/memory/prshma.c
pr/src/misc/Makefile
pr/src/misc/pralarm.c
pr/src/misc/prinit.c
pr/src/misc/pripc.c
pr/src/misc/pripcsem.c
pr/src/misc/prnetdb.c
pr/src/nspr.rc
pr/src/prvrsion.c
pr/src/pthreads/ptio.c
pr/src/pthreads/ptmisc.c
pr/src/pthreads/ptsynch.c
pr/src/pthreads/ptthread.c
pr/src/threads/combined/prucpu.c
pr/src/threads/combined/prucv.c
pr/src/threads/combined/prulock.c
pr/src/threads/combined/pruthr.c
pr/src/threads/prcthr.c
pr/src/threads/prdump.c
pr/src/threads/prtpd.c
pr/tests/Makefile
pr/tests/accept.c
pr/tests/affinity.c
pr/tests/anonfm.c
pr/tests/concur.c
pr/tests/gethost.c
pr/tests/io_timeout.c
pr/tests/ioconthr.c
pr/tests/many_cv.c
pr/tests/nameshm1.c
pr/tests/parent.c
pr/tests/poll_to.c
pr/tests/pollable.c
pr/tests/provider.c
pr/tests/runtests.ksh
pr/tests/runy2ktests.ksh
pr/tests/sema.c
pr/tests/semaerr.c
pr/tests/semaerr1.c
pr/tests/semaping.c
pr/tests/semapong.c
pr/tests/socket.c
pr/tests/testfile.c
pr/tests/tmoacc.c
pr/tests/tmocon.c
pr/tests/vercheck.c
pr/tests/y2k.c
pr/tests/y2ktmo.c
--- a/config/AIX.mk
+++ b/config/AIX.mk
@@ -52,16 +52,21 @@ ifeq ($(PTHREADS_USER),1)
 	USE_PTHREADS =
 	IMPL_STRATEGY = _PTH_USER
 else
 	USE_PTHREADS = 1
 	IMPL_STRATEGY = _PTH
 endif
 endif
 
+# IPv6 support part of the standard AIX 4.3 release.
+ifneq (,$(filter-out 3.2 4.1 4.2,$(OS_RELEASE)))
+USE_IPV6 = 1
+endif
+
 ifeq ($(CLASSIC_NSPR),1)
 CC		= xlC
 CCC		= xlC
 else
 CC		= xlC_r
 CCC		= xlC_r
 endif
 OS_CFLAGS	= -qro -qroconst
--- a/config/HP-UX.mk
+++ b/config/HP-UX.mk
@@ -115,20 +115,20 @@ OS_CFLAGS		+= -DHPUX10 -DHPUX10_30
 DEFAULT_IMPL_STRATEGY = _PTH
 endif
 
 # 11.00 is similar to 10.30.
 ifeq ($(OS_RELEASE),B.11.00)
 	ifndef NS_USE_GCC
 		CCC			        = /opt/aCC/bin/aCC -ext
 		ifeq ($(USE_64), 1)
-			OS_CFLAGS       += +DA2.0W +DChpux
+			OS_CFLAGS       += +DA2.0W +DS2.0
 			COMPILER_TAG    = _64
 		else
-			OS_CFLAGS       += +DAportable +DS1.1
+			OS_CFLAGS       += +DAportable +DS2.0
 			COMPILER_TAG    = _32
 		endif
 	endif
 OS_CFLAGS		+= -DHPUX10 -DHPUX11 -D_LARGEFILE64_SOURCE -D_PR_HAVE_OFF64_T
 DEFAULT_IMPL_STRATEGY = _PTH
 endif
 
 ifeq ($(DEFAULT_IMPL_STRATEGY),_EMU)
@@ -171,20 +171,18 @@ endif
 endif
 
 ifdef PTHREADS_USER
 OS_CFLAGS		+= -D_POSIX_C_SOURCE=199506L
 endif
 
 MKSHLIB			= $(LD) $(DSO_LDOPTS)
 
-DSO_LDOPTS		= -b
+DSO_LDOPTS		= -b +h $(notdir $@)
 DSO_LDFLAGS		=
 
 # -fPIC or +Z generates position independent code for use in shared
 # libraries.
 ifdef NS_USE_GCC
 DSO_CFLAGS		= -fPIC
 else
 DSO_CFLAGS		= +Z
 endif
-
-HAVE_PURIFY		= 1
--- a/config/IRIX.mk
+++ b/config/IRIX.mk
@@ -129,17 +129,11 @@ ifndef NO_MDUPDATE
 OS_CFLAGS		+= $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES)
 else
 OS_CFLAGS		+= $(NOMD_OS_CFLAGS)
 endif
 
 # -rdata_shared is an ld option that puts string constants and
 # const data into the text segment, where they will be shared
 # across processes and be read-only.
-MKSHLIB			= $(LD) $(SHLIB_LD_OPTS) -rdata_shared -shared -soname $(@:$(OBJDIR)/%.so=%.so)
-
-HAVE_PURIFY		= 1
+MKSHLIB			= $(LD) $(SHLIB_LD_OPTS) -rdata_shared -shared -soname $(notdir $@)
 
 DSO_LDOPTS		= -elf -shared -all
-
-ifdef DSO_BACKEND
-DSO_LDOPTS		+= -soname $(DSO_NAME)
-endif
--- a/config/Linux.mk
+++ b/config/Linux.mk
@@ -96,17 +96,17 @@ OPTIMIZER		+= -O
 endif
 PLATFORM_FLAGS		+= -m68020-40
 endif
 
 #
 # Linux 2.x has shared libraries.
 #
 
-MKSHLIB			= $(LD) $(DSO_LDOPTS) -soname $(@:$(OBJDIR)/%.so=%.so)
+MKSHLIB			= $(LD) $(DSO_LDOPTS) -soname $(notdir $@)
 ifdef BUILD_OPT
 OPTIMIZER		= -O2
 endif
 
 ######################################################################
 # Overrides for defaults in config.mk (or wherever)
 ######################################################################
 
--- a/config/Makefile
+++ b/config/Makefile
@@ -79,21 +79,19 @@ PROGS	= $(OBJDIR)/now$(PROG_SUFFIX)
 
 ifeq ($(OS_ARCH),WINNT)
 TARGETS = $(PROGS)
 else
 PROGS	+= $(OBJDIR)/nsinstall$(PROG_SUFFIX)
 TARGETS = $(PROGS) $(PLSRCS:.pl=)
 endif
 
-OUTOPTION = -o
-ifeq ($(OS_ARCH), WINNT)
-ifeq ($(CPU_ARCH),ALPHA)
-OUTOPTION = /link /out:
-endif
+OUTOPTION = -o # end of the line
+ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET)))
+OUTOPTION = /Fe
 endif
 
 # Redefine MAKE_OBJDIR for just this directory
 define MAKE_OBJDIR
 if test ! -d $(@D); then rm -rf $(@D); mkdir $(@D); else true; fi
 endef
 
 export:: $(TARGETS)
--- a/config/OSF1.mk
+++ b/config/OSF1.mk
@@ -88,10 +88,10 @@ ifeq (V4,$(findstring V4,$(OS_RELEASE)))
 OS_CFLAGS		+= -DHAVE_POINTER_LOCALTIME_R
 endif
 
 ifeq ($(USE_PTHREADS),1)
 OS_CFLAGS		+= -pthread
 endif
 
 # The command to build a shared library on OSF1.
-MKSHLIB = ld -shared -all -expect_unresolved "*"
+MKSHLIB = ld -shared -all -expect_unresolved "*" -soname $(notdir $@)
 DSO_LDOPTS		= -shared
--- a/config/SINIX.mk
+++ b/config/SINIX.mk
@@ -84,11 +84,9 @@ RANLIB			= /bin/true
 # For purify
 NOMD_OS_CFLAGS		= $(ODD_CFLAGS)
 
 # we do not have -MDupdate ...
 OS_CFLAGS		= $(NOMD_OS_CFLAGS)
 OS_LIBS			= -lsocket -lnsl -lresolv -ldl -lc
 NOSUCHFILE		= /no-such-file
 
-HAVE_PURIFY		= 0
-
 DEFINES			+= -D_PR_LOCAL_THREADS_ONLY
--- a/config/SunOS4.mk
+++ b/config/SunOS4.mk
@@ -40,15 +40,13 @@ NOMD_OS_CFLAGS		= -Wall -Wno-format -DSU
 ifdef NO_MDUPDATE
 OS_CFLAGS		= $(DSO_CFLAGS) $(NOMD_OS_CFLAGS)
 else
 OS_CFLAGS		= $(DSO_CFLAGS) $(NOMD_OS_CFLAGS) -MDupdate $(DEPENDENCIES)
 endif
 
 MKSHLIB			= $(LD) $(DSO_LDOPTS)
 
-HAVE_PURIFY		= 1
-
 NOSUCHFILE		= /no-such-file
 
 DSO_LDOPTS		=
 # -fPIC generates position-independent code for use in a shared library.
 DSO_CFLAGS		= -fPIC
--- a/config/SunOS5.mk
+++ b/config/SunOS5.mk
@@ -74,16 +74,28 @@ OS_CFLAGS		= $(NOMD_OS_CFLAGS)
 #
 ifdef BUILD_NUMBER
 ifndef BUILD_OPT
 OS_CFLAGS		+= -xs
 endif
 endif
 endif
 
+ifeq ($(USE_64),1)
+ifndef INTERNAL_TOOLS
+ifndef NS_USE_GCC
+CC			+= -xarch=v9
+CCC			+= -xarch=v9
+endif
+endif
+COMPILER_TAG		= _64
+else
+COMPILER_TAG		= _32
+endif
+
 RANLIB			= echo
 
 OS_DEFINES		= -DSVR4 -DSYSV -D__svr4 -D__svr4__ -DSOLARIS
 
 ifeq ($(OS_TEST),i86pc)
 CPU_ARCH		= x86
 OS_DEFINES		+= -Di386
 # The default debug format, DWARF (-g), is not supported by gcc
@@ -127,28 +139,26 @@ endif
 # Purify doesn't like -MDupdate
 NOMD_OS_CFLAGS		= $(DSO_CFLAGS) $(OS_DEFINES) $(SOL_CFLAGS)
 
 MKSHLIB			= $(LD) $(DSO_LDOPTS)
 
 # ld options:
 # -G: produce a shared object
 # -z defs: no unresolved symbols allowed
-DSO_LDOPTS		= -G
+DSO_LDOPTS		= -G -h $(notdir $@)
 
 # -KPIC generates position independent code for use in shared libraries.
 # (Similarly for -fPIC in case of gcc.)
 ifdef NS_USE_GCC
 DSO_CFLAGS		= -fPIC
 else
 DSO_CFLAGS		= -KPIC
 endif
 
-HAVE_PURIFY		= 1
-
 NOSUCHFILE		= /no-such-file
 
 #
 # Library of atomic functions for UltraSparc systems
 #
 # The nspr makefiles build ULTRASPARC_LIBRARY (which contains assembly language
 # implementation of the nspr atomic functions for UltraSparc systems) in addition
 # to libnspr.so. (The actual name of the library is
--- a/config/WIN32.mk
+++ b/config/WIN32.mk
@@ -48,17 +48,24 @@ XP_DEFINE = -DXP_PC
 OBJ_SUFFIX = obj
 LIB_SUFFIX = lib
 DLL_SUFFIX = dll
 
 OS_CFLAGS = -W3 -nologo -GF -Gy
 
 ifdef BUILD_OPT
 OS_CFLAGS += -MD
+# The -O2 optimization of MSVC 6.0 SP3 appears to generate
+# code that is unsafe for our use of fibers and static thread
+# local storage.  We temporarily work around this problem by
+# turning off global optimizations (-Og).
 OPTIMIZER = -O2
+ifeq ($(OS_TARGET),WINNT)
+OPTIMIZER += -Og-
+endif
 DEFINES = -UDEBUG -U_DEBUG -DNDEBUG
 DLLFLAGS = -OUT:"$@"
 OBJDIR_TAG = _OPT
 
 # Add symbolic information for use by a profiler
 ifdef MOZ_PROFILE
 OPTIMIZER += -Z7
 DLLFLAGS += -DEBUG -DEBUGTYPE:CV
--- a/config/config.mk
+++ b/config/config.mk
@@ -125,17 +125,17 @@ endif
 #
 # Configuration for the release process
 #
 ####################################################################
 
 MDIST = /m/dist
 ifeq ($(OS_ARCH),WINNT)
 MDIST = //helium/dist
-MDIST_DOS = \\\\helium\\dist
+MDIST_DOS = $(subst /,\\,$(MDIST))
 endif
 
 # RELEASE_DIR is ns/dist/<module name>
 
 RELEASE_DIR = $(NSDEPTH)/dist/release/$(MOD_NAME)
 
 RELEASE_INCLUDE_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/include
 RELEASE_BIN_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/bin
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -53,17 +53,16 @@ include $(MOD_DEPTH)/config/config.mk
 endif
 
 #
 # This makefile contains rules for building the following kinds of
 # libraries:
 # - LIBRARY: a static (archival) library
 # - SHARED_LIBRARY: a shared (dynamic link) library
 # - IMPORT_LIBRARY: an import library, used only on Windows and OS/2
-# - PURE_LIBRARY: a library for Purify
 #
 # The names of these libraries can be generated by simply specifying
 # LIBRARY_NAME and LIBRARY_VERSION.
 #
 
 ifdef LIBRARY_NAME
 ifeq ($(OS_ARCH), WINNT)
 
@@ -86,35 +85,25 @@ else
 LIBRARY		= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
 ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1)
 SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_shr.a
 else
 ifdef MKSHLIB
 SHARED_LIBRARY	= $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
 endif
 endif
-ifdef HAVE_PURIFY
-ifdef DSO_BACKEND
-PURE_LIBRARY	= $(OBJDIR)/purelib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
-else
-PURE_LIBRARY	= $(OBJDIR)/purelib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
-endif
-endif
 
 endif
 endif
 
 ifndef TARGETS
 ifeq ($(OS_ARCH), WINNT)
 TARGETS		= $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY)
 else
 TARGETS		= $(LIBRARY) $(SHARED_LIBRARY)
-ifdef HAVE_PURIFY
-TARGETS		+= $(PURE_LIBRARY)
-endif
 endif
 endif
 
 #
 # OBJS is the list of object files.  It can be constructed by
 # specifying CSRCS (list of C source files) and ASFILES (list
 # of assembly language source files).
 #
@@ -329,23 +318,16 @@ ifeq ($(OS_TARGET), OpenVMS)
 	$(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(OS_LIBS) $(OBJDIR)/VMSuni.opt
 	@echo "`translate $@`" > $(@:.$(DLL_SUFFIX)=.vms)
 else	# OpenVMS
 	$(MKSHLIB) -o $@ $(OBJS) $(EXTRA_LIBS) $(OS_LIBS)
 endif	# OpenVMS
 endif	# WINNT
 endif	# AIX 4.1
 
-$(PURE_LIBRARY):
-	rm -f $@
-ifneq ($(OS_ARCH), WINNT)
-	$(AR) $(OBJS)
-endif
-	$(RANLIB) $@
-
 ifeq ($(OS_ARCH), WINNT)
 $(RES): $(RESNAME)
 	@$(MAKE_OBJDIR)
 ifeq ($(OS_TARGET),OS2)
 	$(RC) -DOS2 -r $(RESNAME) $(RES)
 else
 ifeq ($(OS_TARGET),WINNT)
 	$(RC) -dWINNT -Fo$(RES) $(RESNAME)
--- a/lib/ds/plevent.c
+++ b/lib/ds/plevent.c
@@ -17,20 +17,18 @@
  */
 #if defined(XP_OS2)
 #define INCL_WIN
 #include <os2.h>
 #define DefWindowProc WinDefWindowProc
 typedef MPARAM WPARAM,LPARAM;
 #endif /* XP_OS2 */
 
+#include "primpl.h"
 #include "plevent.h"
-#include "prmem.h"
-#include "prcmon.h"
-#include "prlog.h"
 
 #if !defined(WIN32)
 #include <errno.h>
 #include <stddef.h>
 #if !defined(XP_OS2)
 #include <unistd.h>
 #endif /* !XP_OS2 */
 #endif /* !Win32 */
@@ -38,21 +36,16 @@ typedef MPARAM WPARAM,LPARAM;
 #if defined(XP_UNIX)
 /* for fcntl */
 #include <sys/types.h>
 #include <fcntl.h>
 #endif
 
 #if defined(XP_MAC)
 #include <AppleEvents.h>
-#include "pprthred.h"
-#include "primpl.h"
-#else
-#include "private/pprthred.h"
-#include "private/primpl.h"
 #endif /* XP_MAC */
 
 #if defined(VMS)
 /*
 ** If MOTIF is being used then XtAppAddInput is used as the notification
 ** method and so event flags must be used, so you need to define
 ** VMS_EVENTS_USE_EF. If gdk is being used then select is used for
 ** notification, and then VMS_EVENTS_USE_SOCKETS should be defined.
--- a/lib/ds/plvrsion.c
+++ b/lib/ds/plvrsion.c
@@ -31,16 +31,21 @@
 #endif
 #endif
 #if !defined(_BUILD_STRING)
 #define _BUILD_STRING ""
 #endif
 #if !defined(_PRODUCTION)
 #define _PRODUCTION ""
 #endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
 
 static PRVersionDescription prVersionDescription_libplds3 =
 {
     /* version          */  2,                  /* this is the only one supported */
     /* buildTime        */  _BUILD_TIME,        /* usecs since midnight 1/1/1970 GMT */
     /* buildTimeString  */  _BUILD_STRING,       /*    ditto, but human readable */
     /* vMajor           */  PR_VMAJOR,          /* NSPR's version number */
     /* vMinor           */  PR_VMINOR,          /*  and minor version */
@@ -60,18 +65,20 @@ static PRVersionDescription prVersionDes
     /* specialString    */ ""
 };
 
 #ifdef XP_UNIX
 
 /*
  * Version information for the 'ident' and 'what commands
  */
-static char rcsid[] = "$Version: NSPR " PR_VERSION "  " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION "  " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING;
 
 #endif /* XP_UNIX */
 
 PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint()
 {
 #ifdef XP_UNIX
     /*
      * Add dummy references to rcsid and sccsid to prevent them
--- a/lib/libc/src/plvrsion.c
+++ b/lib/libc/src/plvrsion.c
@@ -31,16 +31,21 @@
 #endif
 #endif
 #if !defined(_BUILD_STRING)
 #define _BUILD_STRING ""
 #endif
 #if !defined(_PRODUCTION)
 #define _PRODUCTION ""
 #endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
 
 static PRVersionDescription prVersionDescription_libplc3 =
 {
     /* version          */  2,                  /* this is the only one supported */
     /* buildTime        */  _BUILD_TIME,        /* usecs since midnight 1/1/1970 GMT */
     /* buildTimeString  */  _BUILD_STRING,       /*    ditto, but human readable */
     /* vMajor           */  PR_VMAJOR,          /* NSPR's version number */
     /* vMinor           */  PR_VMINOR,          /*  and minor version */
@@ -60,18 +65,20 @@ static PRVersionDescription prVersionDes
     /* specialString    */ ""
 };
 
 #ifdef XP_UNIX
 
 /*
  * Version information for the 'ident' and 'what commands
  */
-static char rcsid[] = "$Version: NSPR " PR_VERSION "  " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION "  " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING;
 
 #endif /* XP_UNIX */
 
 PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint()
 {
 #ifdef XP_UNIX
     /*
      * Add dummy references to rcsid and sccsid to prevent them
--- a/lib/prstreams/plvrsion.c
+++ b/lib/prstreams/plvrsion.c
@@ -31,16 +31,21 @@
 #endif
 #endif
 #if !defined(_BUILD_STRING)
 #define _BUILD_STRING ""
 #endif
 #if !defined(_PRODUCTION)
 #define _PRODUCTION ""
 #endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
 
 static PRVersionDescription prVersionDescription_libprstrms3 =
 {
     /* version          */  2,                  /* this is the only one supported */
     /* buildTime        */  _BUILD_TIME,        /* usecs since midnight 1/1/1970 GMT */
     /* buildTimeString  */  _BUILD_STRING,       /*    ditto, but human readable */
     /* vMajor           */  PR_VMAJOR,          /* NSPR's version number */
     /* vMinor           */  PR_VMINOR,          /*  and minor version */
@@ -60,18 +65,20 @@ static PRVersionDescription prVersionDes
     /* specialString    */ ""
 };
 
 #ifdef XP_UNIX
 
 /*
  * Version information for the 'ident' and 'what commands
  */
-static char rcsid[] = "$Version: NSPR " PR_VERSION "  " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION "  " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING;
 
 #endif /* XP_UNIX */
 
 PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint()
 {
 #ifdef XP_UNIX
     /*
      * Add dummy references to rcsid and sccsid to prevent them
--- a/pr/include/md/Makefile
+++ b/pr/include/md/Makefile
@@ -46,19 +46,23 @@ endif
 endif
 endif
 endif
 
 ifeq ($(OS_ARCH),AIX)
 ifeq ($(USE_64),1)
 MDCPUCFG_H = _aix64.cfg
 else
+ifeq ($(USE_IPV6),1)
+MDCPUCFG_H = _aix32in6.cfg
+else
 MDCPUCFG_H = _aix32.cfg
 endif
 endif
+endif
 
 ifeq ($(OS_ARCH),BSD_OS)
 MDCPUCFG_H = _bsdi.cfg
 endif
 
 ifeq ($(OS_ARCH),FreeBSD)
 MDCPUCFG_H = _freebsd.cfg
 endif
@@ -90,17 +94,21 @@ endif
 ifeq ($(OS_ARCH),OSF1)
 MDCPUCFG_H = _osf1.cfg
 endif
 
 ifeq ($(OS_ARCH),SunOS)
 ifeq ($(OS_RELEASE),4.1.3_U1)
 MDCPUCFG_H = _sunos4.cfg
 else
-MDCPUCFG_H = _solaris.cfg
+ifeq ($(USE_64),1)
+MDCPUCFG_H = _solaris64.cfg
+else
+MDCPUCFG_H = _solaris32.cfg
+endif
 endif
 endif
 
 ifeq ($(OS_ARCH),SINIX)
 MDCPUCFG_H = _reliantunix.cfg
 endif
 
 ifeq ($(OS_ARCH),Rhapsody)
--- a/pr/include/md/_aix.h
+++ b/pr/include/md/_aix.h
@@ -49,16 +49,21 @@
 #undef	HAVE_WEAK_IO_SYMBOLS
 #undef	HAVE_WEAK_MALLOC_SYMBOLS
 #define	HAVE_DLL
 #define	USE_DLFCN
 #define _PR_HAVE_SOCKADDR_LEN
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
 #define _PR_STAT_HAS_ONLY_ST_ATIME
+#ifdef _PR_INET6
+#define _PR_HAVE_GETHOSTBYNAME2
+#endif
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
 
 /* Timer operations */
 #if defined(AIX_TIMERS)
 extern PRIntervalTime _MD_AixGetInterval(void);
 #define _MD_GET_INTERVAL _MD_AixGetInterval
 
 extern PRIntervalTime _MD_AixIntervalPerSec(void);
 #define _MD_INTERVAL_PER_SEC _MD_AixIntervalPerSec
@@ -67,17 +72,19 @@ extern PRIntervalTime _MD_AixIntervalPer
 #define _MD_GET_INTERVAL        _PR_UNIX_GetInterval
 #define _MD_INTERVAL_PER_SEC    _PR_UNIX_TicksPerSecond
 #endif  /* defined(AIX_TIMERS) */
 
 #ifdef AIX_HAVE_ATOMIC_OP_H
 /* The atomic operations */
 #include <sys/atomic_op.h>
 #define _PR_HAVE_ATOMIC_OPS
+#ifndef IS_64
 #define _PR_HAVE_ATOMIC_CAS
+#endif
 #define _MD_INIT_ATOMIC()
 #define _MD_ATOMIC_INCREMENT(val)   ((PRInt32)fetch_and_add((atomic_p)val, 1) + 1)
 #define _MD_ATOMIC_ADD(ptr, val)   ((PRInt32)fetch_and_add((atomic_p)ptr, val) + val)
 #define _MD_ATOMIC_DECREMENT(val)   ((PRInt32)fetch_and_add((atomic_p)val, -1) - 1)
 #define _MD_ATOMIC_SET(val, newval) _AIX_AtomicSet(val, newval)
 #endif /* AIX_HAVE_ATOMIC_OP_H */
 
 #define USE_SETJMP
new file mode 100644
--- /dev/null
+++ b/pr/include/md/_aix32in6.cfg
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef AIX
+#define AIX
+#endif
+
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2	5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#define	HAVE_LONG_LONG
+#undef	HAVE_ALIGNED_DOUBLES
+#undef	HAVE_ALIGNED_LONGLONGS
+
+#ifndef _PR_INET6
+#define _PR_INET6
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
--- a/pr/include/md/_aix64.cfg
+++ b/pr/include/md/_aix64.cfg
@@ -69,16 +69,20 @@
 #define PR_ALIGN_OF_FLOAT   4
 #define PR_ALIGN_OF_DOUBLE  4
 #define PR_ALIGN_OF_POINTER 8
 
 #define	HAVE_LONG_LONG
 #undef	HAVE_ALIGNED_DOUBLES
 #undef	HAVE_ALIGNED_LONGLONGS
 
+#ifndef _PR_INET6
+#define _PR_INET6
+#endif
+
 #ifndef NO_NSPR_10_SUPPORT
 
 #define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
 #define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
 #define BYTES_PER_INT 		PR_BYTES_PER_INT
 #define BYTES_PER_INT64		PR_BYTES_PER_INT64
 #define BYTES_PER_LONG		PR_BYTES_PER_LONG
 #define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
--- a/pr/include/md/_beos.h
+++ b/pr/include/md/_beos.h
@@ -313,17 +313,16 @@ struct protoent* getprotobynumber(int nu
 #define _MD_CONNECT _MD_connect
 #define _MD_ACCEPT _MD_accept
 #define _MD_BIND _MD_bind
 #define _MD_LISTEN _MD_listen
 #define _MD_SHUTDOWN _MD_shutdown
 #define _MD_RECV _MD_recv
 #define _MD_SEND _MD_send
 #define _MD_ACCEPT_READ _MD_accept_read
-#define _MD_TRANSMITFILE _MD_transmitfile
 #define _MD_GETSOCKNAME _MD_getsockname
 #define _MD_GETPEERNAME _MD_getpeername
 #define _MD_GETSOCKOPT _MD_getsockopt
 #define _MD_SETSOCKOPT _MD_setsockopt
 #define _MD_RECVFROM _MD_recvfrom
 #define _MD_SENDTO _MD_sendto
 #define _MD_SOCKETPAIR _MD_socketpair
 #define _MD_SOCKET _MD_socket
@@ -509,17 +508,16 @@ PR_EXTERN(PRInt32) _MD_bind(PRFileDesc *
 PR_EXTERN(PRInt32) _MD_listen(PRFileDesc *fd, PRIntn backlog);
 PR_EXTERN(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how);
 PR_EXTERN(PRInt32) _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout);
 PR_EXTERN(PRInt32) _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout);
 PR_EXTERN(PRInt32) _MD_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout);
 // PR_EXTERN(PRInt32) _MD_fast_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg);
 // PR_EXTERN(PRInt32) _MD_fast_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg);
 // PR_EXTERN(void) _MD_update_accept_context(PRInt32 s, PRInt32 ls);
-PR_EXTERN(PRInt32) _MD_transmitfile(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen, PRInt32 flags, PRIntervalTime timeout);
 PR_EXTERN(PRStatus) _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
 PR_EXTERN(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
 PR_EXTERN(PRStatus) _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen);
 PR_EXTERN(PRStatus) _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen);
 PR_EXTERN(PRInt32) _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout);
 PR_EXTERN(PRInt32) _MD_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout);
 PR_EXTERN(PRInt32) _MD_socketpair(int af, int type, int flags, PRInt32 *osfd);
 PR_EXTERN(PRInt32) _MD_socket(int af, int type, int flags);
--- a/pr/include/md/_hpux.h
+++ b/pr/include/md/_hpux.h
@@ -41,16 +41,18 @@
 #define	HAVE_DLL
 #define USE_HPSHL
 #ifndef HAVE_STRERROR
 #define HAVE_STRERROR
 #endif
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
 #define _PR_STAT_HAS_ONLY_ST_ATIME
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
 
 #undef _PR_HAVE_ATOMIC_OPS
 
 #if !defined(_PR_PTHREADS)
 
 #include <syscall.h>
 #include <setjmp.h>
 
--- a/pr/include/md/_irix.h
+++ b/pr/include/md/_irix.h
@@ -53,16 +53,18 @@
 #define HAVE_DLL
 #define USE_DLFCN
 #define _PR_HAVE_ATOMIC_OPS
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
 #define _PR_STAT_HAS_ST_ATIM
 #define _PR_HAVE_OFF64_T
 #define HAVE_POINTER_LOCALTIME_R
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
 
 /* Initialization entry points */
 PR_EXTERN(void) _MD_EarlyInit(void);
 #define _MD_EARLY_INIT _MD_EarlyInit
 
 PR_EXTERN(void) _MD_IrixInit(void);
 #define _MD_FINAL_INIT _MD_IrixInit
 
--- a/pr/include/md/_linux.h
+++ b/pr/include/md/_linux.h
@@ -65,16 +65,18 @@
 #endif
 #undef _PR_USE_POLL
 #define _PR_STAT_HAS_ONLY_ST_ATIME
 #if defined(__alpha)
 #define _PR_HAVE_LARGE_OFF_T
 #else
 #define _PR_NO_LARGE_FILES
 #endif
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
 
 #ifdef _PR_PTHREADS
 
 extern void _MD_CleanupBeforeExit(void);
 #define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit
 
 #else  /* ! _PR_PTHREADS */
 
--- a/pr/include/md/_os2.h
+++ b/pr/include/md/_os2.h
@@ -256,17 +256,16 @@ extern PRInt32 _MD_CloseSocket(PRInt32 o
 
 #define _MD_INIT_ATOMIC               _PR_MD_INIT_ATOMIC
 #define _MD_ATOMIC_INCREMENT(x)       _PR_MD_ATOMIC_INCREMENT(x)
 #define _MD_ATOMIC_ADD(x,y)			  _PR_MD_ATOMIC_ADD(x,y)
 #define _MD_ATOMIC_DECREMENT(x)       _PR_MD_ATOMIC_DECREMENT(x)
 #define _MD_ATOMIC_SET(x,y)           _PR_MD_ATOMIC_SET(x, y)
 
 #define _MD_INIT_IO                   (_PR_MD_INIT_IO)
-#define _MD_TRANSMITFILE              (_PR_MD_TRANSMITFILE)
 #define _MD_PR_POLL                   (_PR_MD_PR_POLL)
 
 /* win95 doesn't have async IO */
 #define _MD_SOCKET                    (_PR_MD_SOCKET)
 extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd);
 #define _MD_SOCKETAVAILABLE           _MD_SocketAvailable
 #define _MD_CONNECT                   (_PR_MD_CONNECT)
 extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
--- a/pr/include/md/_osf1.h
+++ b/pr/include/md/_osf1.h
@@ -41,16 +41,22 @@
 
 #define NEED_TIME_R
 #define USE_DLFCN
 
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
 #define _PR_STAT_HAS_ONLY_ST_ATIME
 #define _PR_HAVE_LARGE_OFF_T
+#ifdef _PR_INET6
+#define _PR_HAVE_GETIPNODEBYNAME
+#define _PR_HAVE_GETIPNODEBYADDR
+#endif
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
 
 #define USE_SETJMP
 
 #include <setjmp.h>
 
 /*
  * A jmp_buf is actually a struct sigcontext.  The sc_sp field of
  * struct sigcontext is the stack pointer.
deleted file mode 100644
--- a/pr/include/md/_solaris.cfg
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/*
- * The contents of this file are subject to the Netscape Public License
- * Version 1.1 (the "NPL"); you may not use this file except in
- * compliance with the NPL.  You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- * 
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- * 
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation.  Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
- * Reserved.
- */
-
-#ifndef nspr_cpucfg___
-#define nspr_cpucfg___
-
-#ifndef XP_UNIX
-#define XP_UNIX
-#endif
-
-#ifndef SOLARIS
-#define SOLARIS
-#endif
-
-#ifdef sparc
-#undef  IS_LITTLE_ENDIAN
-#define IS_BIG_ENDIAN 1
-#define PR_ALIGN_OF_INT64   8
-#define PR_ALIGN_OF_DOUBLE  8
-#elif defined(i386)
-#define IS_LITTLE_ENDIAN 1
-#undef  IS_BIG_ENDIAN
-#define PR_ALIGN_OF_INT64   4
-#define PR_ALIGN_OF_DOUBLE  4
-#else
-#error unknown processor
-#endif
-
-#define PR_BYTES_PER_BYTE   1
-#define PR_BYTES_PER_SHORT  2
-#define PR_BYTES_PER_INT    4
-#define PR_BYTES_PER_INT64  8
-#define PR_BYTES_PER_LONG   4
-#define PR_BYTES_PER_FLOAT  4
-#define PR_BYTES_PER_DOUBLE 8
-#define PR_BYTES_PER_WORD   4
-#define PR_BYTES_PER_DWORD  8
-#define PR_BYTES_PER_WORD_LOG2   2
-#define PR_BYTES_PER_DWORD_LOG2  3
-
-#define PR_BITS_PER_BYTE    8
-#define PR_BITS_PER_SHORT   16
-#define PR_BITS_PER_INT     32
-#define PR_BITS_PER_INT64   64
-#define PR_BITS_PER_LONG    32
-#define PR_BITS_PER_FLOAT   32
-#define PR_BITS_PER_DOUBLE  64
-#define PR_BITS_PER_WORD    32
-
-#define PR_BITS_PER_BYTE_LOG2   3
-#define PR_BITS_PER_SHORT_LOG2  4
-#define PR_BITS_PER_INT_LOG2    5
-#define PR_BITS_PER_INT64_LOG2  6
-#define PR_BITS_PER_LONG_LOG2   5
-#define PR_BITS_PER_FLOAT_LOG2  5
-#define PR_BITS_PER_DOUBLE_LOG2 6
-#define PR_BITS_PER_WORD_LOG2   5
-
-#define PR_ALIGN_OF_SHORT   2
-#define PR_ALIGN_OF_INT     4
-#define PR_ALIGN_OF_LONG    4
-#define PR_ALIGN_OF_FLOAT   4
-#define PR_ALIGN_OF_POINTER 4
-
-#define	HAVE_LONG_LONG
-#define	HAVE_ALIGNED_DOUBLES
-#define	HAVE_ALIGNED_LONGLONGS
-
-#ifndef NO_NSPR_10_SUPPORT
-
-#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
-#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
-#define BYTES_PER_INT 		PR_BYTES_PER_INT
-#define BYTES_PER_INT64		PR_BYTES_PER_INT64
-#define BYTES_PER_LONG		PR_BYTES_PER_LONG
-#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
-#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
-#define BYTES_PER_WORD		PR_BYTES_PER_WORD
-#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
-
-#define BITS_PER_BYTE		PR_BITS_PER_BYTE
-#define BITS_PER_SHORT		PR_BITS_PER_SHORT
-#define BITS_PER_INT		PR_BITS_PER_INT
-#define BITS_PER_INT64		PR_BITS_PER_INT64
-#define BITS_PER_LONG		PR_BITS_PER_LONG
-#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
-#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
-#define BITS_PER_WORD		PR_BITS_PER_WORD
-
-#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
-#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
-#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
-#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
-#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
-#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
-#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
-#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
-
-#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
-#define ALIGN_OF_INT		PR_ALIGN_OF_INT
-#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
-#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
-#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
-#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
-#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
-#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
-
-#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
-#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
-#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
-
-#endif /* NO_NSPR_10_SUPPORT */
-
-#endif /* ifndef nspr_cpucfg___ */
--- a/pr/include/md/_solaris.h
+++ b/pr/include/md/_solaris.h
@@ -39,26 +39,44 @@
 #define	HAVE_WEAK_IO_SYMBOLS
 #endif
 
 #undef	HAVE_WEAK_MALLOC_SYMBOLS
 #define	HAVE_DLL
 #define	USE_DLFCN
 #define NEED_STRFTIME_LOCK
 
-#ifdef _PR_LOCAL_THREADS_ONLY
-#undef _PR_HAVE_ATOMIC_OPS
-#else
+/*
+ * Sparc v8 does not have instructions to efficiently implement
+ * atomic increment/decrement operations.  In the local threads
+ * only and pthreads versions, we use the default atomic routine
+ * implementation in pratom.c.  The obsolete global threads only
+ * version uses a global mutex_t to implement the atomic routines
+ * in solaris.c, which is actually equivalent to the default
+ * implementation.
+ */
+#ifdef _PR_GLOBAL_THREADS_ONLY
 #define _PR_HAVE_ATOMIC_OPS
+#endif
+
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
+/*
+ * We have assembly language implementation of atomic
+ * stacks for the 32-bit sparc and x86 architectures only.
+ */
+#if !defined(sparc) || !defined(IS_64)
 #define _PR_HAVE_ATOMIC_CAS
 #endif
+#endif
 
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
 #define _PR_STAT_HAS_ST_ATIM
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
 
 #include "prinrval.h"
 PR_EXTERN(PRIntervalTime) _MD_Solaris_GetInterval(void);
 #define _MD_GET_INTERVAL                  _MD_Solaris_GetInterval
 PR_EXTERN(PRIntervalTime) _MD_Solaris_TicksPerSecond(void);
 #define _MD_INTERVAL_PER_SEC              _MD_Solaris_TicksPerSecond
 
 #if defined(_PR_HAVE_ATOMIC_OPS)
new file mode 100644
--- /dev/null
+++ b/pr/include/md/_solaris32.cfg
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef SOLARIS
+#define SOLARIS
+#endif
+
+#ifdef sparc
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_DOUBLE  8
+#elif defined(i386)
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_DOUBLE  4
+#else
+#error unknown processor
+#endif
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   2
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_POINTER 4
+
+#define	HAVE_LONG_LONG
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* ifndef nspr_cpucfg___ */
new file mode 100644
--- /dev/null
+++ b/pr/include/md/_solaris64.cfg
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef SOLARIS
+#define SOLARIS
+#endif
+
+#ifdef sparc
+#undef  IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_DOUBLE  8
+#elif defined(i386)
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+#define PR_ALIGN_OF_INT64   4
+#define PR_ALIGN_OF_DOUBLE  4
+#else
+#error unknown processor
+#endif
+#define IS_64
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   8
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   8
+#define PR_BYTES_PER_DWORD  8
+#define PR_BYTES_PER_WORD_LOG2   3
+#define PR_BYTES_PER_DWORD_LOG2  3
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_POINTER 8
+
+#define	HAVE_LONG_LONG
+#define	HAVE_ALIGNED_DOUBLES
+#define	HAVE_ALIGNED_LONGLONGS
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE		PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT 	PR_BYTES_PER_SHORT
+#define BYTES_PER_INT 		PR_BYTES_PER_INT
+#define BYTES_PER_INT64		PR_BYTES_PER_INT64
+#define BYTES_PER_LONG		PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT		PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE	PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD		PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD		PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE		PR_BITS_PER_BYTE
+#define BITS_PER_SHORT		PR_BITS_PER_SHORT
+#define BITS_PER_INT		PR_BITS_PER_INT
+#define BITS_PER_INT64		PR_BITS_PER_INT64
+#define BITS_PER_LONG		PR_BITS_PER_LONG
+#define BITS_PER_FLOAT		PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE		PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD		PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2	PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2	PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2	PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2	PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2	PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2	PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 	PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2	PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT		PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT		PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG		PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64		PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT		PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE		PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER	PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD		PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2	PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2	PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2	PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* ifndef nspr_cpucfg___ */
--- a/pr/include/md/_unix_errors.h
+++ b/pr/include/md/_unix_errors.h
@@ -19,18 +19,18 @@
 #ifndef prunixerrors_h___
 #define prunixerrors_h___
 
 #include <unistd.h>
 #include <stddef.h>
 
 PR_BEGIN_EXTERN_C
 
-PR_EXTERN(PRStatus) _MD_gethostname(char *name, PRUint32 namelen);
-#define _MD_GETHOSTNAME		_MD_gethostname
+PR_EXTERN(void) _MD_unix_map_default_error(int err);
+#define	_PR_MD_MAP_DEFAULT_ERROR	_MD_unix_map_default_error
 
 PR_EXTERN(void) _MD_unix_map_opendir_error(int err);
 #define	_PR_MD_MAP_OPENDIR_ERROR	_MD_unix_map_opendir_error
 
 PR_EXTERN(void) _MD_unix_map_closedir_error(int err);
 #define	_PR_MD_MAP_CLOSEDIR_ERROR	_MD_unix_map_closedir_error
 
 PR_EXTERN(void) _MD_unix_readdir_error(int err);
--- a/pr/include/md/_unixos.h
+++ b/pr/include/md/_unixos.h
@@ -319,18 +319,17 @@ extern PRInt32  _MD_getfileinfo64(const 
 extern PRInt32  _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info);
 extern PRInt32  _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info);
 extern PRInt32	_MD_rename(const char *from, const char *to);
 extern PRInt32	_MD_access(const char *name, PRAccessHow how);
 extern PRInt32	_MD_mkdir(const char *name, PRIntn mode);
 extern PRInt32	_MD_rmdir(const char *name);
 extern PRInt32	_MD_accept_read(PRInt32 sock, PRInt32 *newSock,
 				PRNetAddr **raddr, void *buf, PRInt32 amount);
-extern PRInt32 	_PR_UnixTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
-			const void *headers, PRInt32 hlen,
+extern PRInt32 	_PR_UnixSendFile(PRFileDesc *sd, PRSendFileData *sfd,
 			PRTransmitFileFlags flags, PRIntervalTime timeout);
 
 extern PRStatus _MD_LockFile(PRInt32 osfd);
 extern PRStatus _MD_TLockFile(PRInt32 osfd);
 extern PRStatus _MD_UnlockFile(PRInt32 osfd);
 
 #define _MD_OPEN_DIR(dir, name)		    _MD_open_dir(dir, name)
 #define _MD_CLOSE_DIR(dir)		        _MD_close_dir(dir)
@@ -441,16 +440,17 @@ extern int _MD_unix_get_nonblocking_conn
 #define HAVE_SOCKET_REUSEADDR
 #define HAVE_SOCKET_KEEPALIVE
 
 /* Memory-mapped files */
 
 struct _MDFileMap {
     PRIntn prot;
     PRIntn flags;
+    PRBool isAnonFM; /* when true, PR_CloseFileMap() must close the related fd */
 };
 
 extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size);
 #define _MD_CREATE_FILE_MAP _MD_CreateFileMap
 
 extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset,
         PRUint32 len);
 #define _MD_MEM_MAP _MD_MemMap
--- a/pr/include/md/_win16.h
+++ b/pr/include/md/_win16.h
@@ -297,17 +297,16 @@ extern PRStatus _PR_KillWindowsProcess(s
 
 #define _MD_INIT_ATOMIC()
 #define _MD_ATOMIC_INCREMENT(x)       (*x++)
 #define _MD_ATOMIC_ADD(ptr, val)      ((*x) += val)
 #define _MD_ATOMIC_DECREMENT(x)       (*x--)
 #define _MD_ATOMIC_SET(x,y)           (*x, y)
 
 #define _MD_INIT_IO                   _PR_MD_INIT_IO
-#define _MD_TRANSMITFILE              _PR_MD_TRANSMITFILE
 
 /* win95 doesn't have async IO */
 #define _MD_SOCKET                    _PR_MD_SOCKET
 #define _MD_CONNECT                   _PR_MD_CONNECT
 #define _MD_ACCEPT                    _PR_MD_ACCEPT
 #define _MD_BIND                      _PR_MD_BIND
 #define _MD_RECV                      _PR_MD_RECV
 #define _MD_SEND                      _PR_MD_SEND
--- a/pr/include/md/_win32_errors.h
+++ b/pr/include/md/_win32_errors.h
@@ -19,16 +19,19 @@
 #ifndef nspr_win32_errors_h___
 #define nspr_win32_errors_h___
 
 #include <windows.h>
 #include <winsock.h>
 #include <errno.h>
 
 
+extern void _MD_win32_map_default_error(PRInt32 err);
+#define _PR_MD_MAP_DEFAULT_ERROR	_MD_win32_map_default_error
+
 extern void _MD_win32_map_opendir_error(PRInt32 err);
 #define	_PR_MD_MAP_OPENDIR_ERROR	_MD_win32_map_opendir_error
 
 extern void _MD_win32_map_closedir_error(PRInt32 err);
 #define	_PR_MD_MAP_CLOSEDIR_ERROR	_MD_win32_map_closedir_error
 
 extern void _MD_unix_readdir_error(PRInt32 err);
 #define	_PR_MD_MAP_READDIR_ERROR	_MD_unix_readdir_error
--- a/pr/include/md/_win95.h
+++ b/pr/include/md/_win95.h
@@ -33,16 +33,17 @@
 #define _PR_SI_SYSNAME        "WIN95"
 #define _PR_SI_ARCHITECTURE   "x86"    /* XXXMB hardcode for now */
 
 #define HAVE_DLL
 #undef  HAVE_THREAD_AFFINITY
 #define HAVE_SOCKET_REUSEADDR
 #define HAVE_SOCKET_KEEPALIVE
 #define _PR_HAVE_ATOMIC_OPS
+#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY
 
 /* --- Common User-Thread/Native-Thread Definitions --------------------- */
 
 /* --- Globals --- */
 extern struct PRLock                      *_pr_schedLock;
 
 /* --- Typedefs --- */
 typedef void (*FiberFunc)(void *);
@@ -235,17 +236,16 @@ extern PRInt32 _MD_CloseSocket(PRInt32 o
 #else /* non-x86 processors */
 #define _MD_ATOMIC_INCREMENT(x)       InterlockedIncrement((PLONG)x)
 #define _MD_ATOMIC_ADD(ptr,val)    (InterlockedExchangeAdd((PLONG)ptr, (LONG)val) + val)
 #define _MD_ATOMIC_DECREMENT(x)       InterlockedDecrement((PLONG)x)
 #endif /* x86 */
 #define _MD_ATOMIC_SET(x,y)           InterlockedExchange((PLONG)x, (LONG)y)
 
 #define _MD_INIT_IO                   _PR_MD_INIT_IO
-#define _MD_TRANSMITFILE              _PR_MD_TRANSMITFILE
 
 
 /* win95 doesn't have async IO */
 #define _MD_SOCKET                    _PR_MD_SOCKET
 extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd);
 #define _MD_SOCKETAVAILABLE           _MD_SocketAvailable
 #define _MD_CONNECT                   _PR_MD_CONNECT
 extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
@@ -431,9 +431,17 @@ extern void * _MD_MemMap(struct PRFileMa
 #define _MD_MEM_MAP _MD_MemMap
 
 extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size);
 #define _MD_MEM_UNMAP _MD_MemUnmap
 
 extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap);
 #define _MD_CLOSE_FILE_MAP _MD_CloseFileMap
 
+/* --- Named semaphores stuff --- */
+#define _PR_HAVE_NAMED_SEMAPHORES
+#define _MD_OPEN_SEMAPHORE            _PR_MD_OPEN_SEMAPHORE
+#define _MD_WAIT_SEMAPHORE            _PR_MD_WAIT_SEMAPHORE
+#define _MD_POST_SEMAPHORE            _PR_MD_POST_SEMAPHORE
+#define _MD_CLOSE_SEMAPHORE           _PR_MD_CLOSE_SEMAPHORE
+#define _MD_DELETE_SEMAPHORE(name)    PR_SUCCESS  /* no op */
+
 #endif /* nspr_win32_defs_h___ */
--- a/pr/include/md/_winnt.h
+++ b/pr/include/md/_winnt.h
@@ -46,16 +46,17 @@
 
 #define HAVE_DLL
 #define HAVE_CUSTOM_USER_THREADS
 #define HAVE_THREAD_AFFINITY
 #define HAVE_SOCKET_REUSEADDR
 #define HAVE_SOCKET_KEEPALIVE
 #define _PR_HAVE_ATOMIC_OPS
 #define _PR_HAVE_ATOMIC_CAS
+#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY
 
 /* --- Common User-Thread/Native-Thread Definitions --------------------- */
 
 /* --- Globals --- */
 extern struct PRLock                      *_pr_schedLock;
 
 /* --- Typedefs --- */
 typedef void (*FiberFunc)(void *);
@@ -80,17 +81,16 @@ enum _MDIOModel {
 };
 
 typedef struct _MDOverlapped {
     OVERLAPPED overlapped;              /* Used for async I/O */
 
     enum _MDIOModel ioModel;            /* The I/O model to implement
                                          * using overlapped I/O.
                                          */
-
     union {
         struct _MDThread *mdThread;     /* For blocking I/O, this structure
                                          * is embedded in the _MDThread
                                          * structure.
                                          */
         struct {
             PRCList links;              /* for group->io_ready list */
             struct PRRecvWait *desc;    /* For multiwait I/O, this structure
@@ -115,16 +115,20 @@ struct _MDThread {
     PRInt32          blocked_io_status; /* Status of the completed IO */
     PRInt32          blocked_io_bytes;  /* Bytes transferred for completed IO */
     PRInt32          blocked_io_error;  /* Save error if status is FALSE */
     HANDLE           handle;
     PRUint32         id;
     void            *sp;                /* only valid when suspended */
     PRUint32         magic;             /* for debugging */
     PR_CONTEXT_TYPE  gcContext;         /* Thread context for GC */
+	struct _PRCPU    *thr_bound_cpu;		/* thread bound to cpu */
+	PRBool   		 interrupt_disabled;/* thread cannot be interrupted */
+	HANDLE 			 thr_event;			/* For native-threads-only support,
+											thread blocks on this event		*/
 
     /* The following are used only if this is a fiber */
     void            *fiber_id;          /* flag whether or not this is a fiber*/
     FiberFunc        fiber_fn;          /* main fiber routine */
     void            *fiber_arg;         /* arg to main fiber routine */
     PRUint32         fiber_stacksize;   /* stacksize for fiber */
     PRInt32          fiber_last_error;  /* last error for the fiber */
 };
@@ -189,16 +193,17 @@ struct _MDFileDesc {
                                  * an all-zero net address. */
 };
 
 struct _MDProcess {
     HANDLE handle;
     DWORD id;
 };
 
+
 /* --- Misc stuff --- */
 #define _MD_GET_SP(thread)            (thread)->md.gcContext[6]
 
 /* --- IO stuff --- */
 
 extern PRInt32 _md_Associate(HANDLE);
 extern PRInt32 _PR_MD_CLOSE(PRInt32 osfd, PRBool socket);
 
@@ -270,17 +275,17 @@ extern int _PR_NTFiberSafeSelect(int, fd
         _MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, PR_FALSE, NULL, NULL)
 #define _MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, fast, cb, cba) \
         _PR_MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, fast, cb, cba)
 #define _MD_UPDATE_ACCEPT_CONTEXT     _PR_MD_UPDATE_ACCEPT_CONTEXT
 
 #define _MD_BIND                      _PR_MD_BIND
 #define _MD_RECV                      _PR_MD_RECV
 #define _MD_SEND                      _PR_MD_SEND
-#define _MD_TRANSMITFILE              _PR_MD_TRANSMITFILE
+#define _MD_SENDFILE              	  _PR_MD_SENDFILE
 #define _MD_PR_POLL                   _PR_MD_PR_POLL
 
 /* --- Scheduler stuff --- */
 #define _MD_PAUSE_CPU                   _PR_MD_PAUSE_CPU
 
 /* --- DIR stuff --- */
 #define PR_DIRECTORY_SEPARATOR        '\\'
 #define PR_DIRECTORY_SEPARATOR_STR    "\\"
@@ -322,17 +327,17 @@ extern int _PR_NTFiberSafeSelect(int, fd
 
 extern void _PR_Unblock_IO_Wait(PRThread *thr);
 
 /* --- Lock stuff --- */
 #define _MD_NEW_LOCK(lock)            (InitializeCriticalSection(&((lock)->mutex)),PR_SUCCESS)
 #define _MD_FREE_LOCK(lock)           DeleteCriticalSection(&((lock)->mutex))
 #ifndef PROFILE_LOCKS
 #define _MD_LOCK(lock)                EnterCriticalSection(&((lock)->mutex))
-#define _MD_TEST_AND_LOCK(lock)       0  /* XXXMB */
+#define _MD_TEST_AND_LOCK(lock)       (TryEnterCriticalSection(&((lock)->mutex))== FALSE)
 #define _MD_UNLOCK(lock)              LeaveCriticalSection(&((lock)->mutex))
 #else
 #define _MD_LOCK(lock)                 \
     PR_BEGIN_MACRO \
     BOOL rv = TryEnterCriticalSection(&((lock)->mutex)); \
     if (rv == TRUE) { \
         InterlockedIncrement(&((lock)->hitcount)); \
     } else { \
@@ -500,9 +505,17 @@ extern void * _MD_MemMap(struct PRFileMa
 #define _MD_MEM_MAP _MD_MemMap
 
 extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size);
 #define _MD_MEM_UNMAP _MD_MemUnmap
 
 extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap);
 #define _MD_CLOSE_FILE_MAP _MD_CloseFileMap
 
+/* --- Named semaphores stuff --- */
+#define _PR_HAVE_NAMED_SEMAPHORES
+#define _MD_OPEN_SEMAPHORE            _PR_MD_OPEN_SEMAPHORE
+#define _MD_WAIT_SEMAPHORE            _PR_MD_WAIT_SEMAPHORE
+#define _MD_POST_SEMAPHORE            _PR_MD_POST_SEMAPHORE
+#define _MD_CLOSE_SEMAPHORE           _PR_MD_CLOSE_SEMAPHORE
+#define _MD_DELETE_SEMAPHORE(name)    PR_SUCCESS  /* no op */
+
 #endif /* nspr_win32_defs_h___ */
--- a/pr/include/nspr.h
+++ b/pr/include/nspr.h
@@ -26,25 +26,28 @@
 #include "prcvar.h"
 #include "prdtoa.h"
 #include "prenv.h"
 #include "prerror.h"
 #include "prinet.h"
 #include "prinit.h"
 #include "prinrval.h"
 #include "prio.h"
+#include "pripcsem.h"
 #include "prlink.h"
 #include "prlock.h"
 #include "prlog.h"
 #include "prlong.h"
 #include "prmem.h"
 #include "prmon.h"
 #include "prmwait.h"
 #include "prnetdb.h"
 #include "prprf.h"
 #include "prproces.h"
 #include "prrwlock.h"
+#include "prshm.h"
+#include "prshma.h"
 #include "prsystem.h"
 #include "prthread.h"
 #include "prtime.h"
 #include "prtypes.h"
 
 #endif /* nspr_h___ */
--- a/pr/include/prinit.h
+++ b/pr/include/prinit.h
@@ -39,19 +39,19 @@ PR_BEGIN_EXTERN_C
 /*
 ** NSPR's version is used to determine the likelihood that the version you
 ** used to build your component is anywhere close to being compatible with
 ** what is in the underlying library.
 **
 ** The format of the version string is
 **     "<major version>.<minor version> <build date>"
 */
-#define PR_VERSION  "3.1"
+#define PR_VERSION  "3.5"
 #define PR_VMAJOR   3
-#define PR_VMINOR   1
+#define PR_VMINOR   5
 #define PR_VPATCH   0
 #define PR_BETA     PR_FALSE
 
 /*
 ** PRVersionCheck
 **
 ** The basic signature of the function that is called to provide version
 ** checking. The result will be a boolean that indicates the likelihood
@@ -208,16 +208,8 @@ PR_EXTERN(PRStatus) PR_CallOnce(
     PRCallOnceType *once,
     PRCallOnceFN    func
 );
 
 
 PR_END_EXTERN_C
 
 #endif /* prinit_h___ */
-
-
-
-
-
-
-
-
--- a/pr/include/prio.h
+++ b/pr/include/prio.h
@@ -151,16 +151,17 @@ union PRNetAddr {
 #endif
     } inet;
 #if defined(_PR_INET6)
     struct {
         PRUint16 family;                /* address family (AF_INET6) */
         PRUint16 port;                  /* port number */
         PRUint32 flowinfo;              /* routing information */
         PRIPv6Addr ip;                  /* the actual 128 bits of address */
+        PRUint32 scope_id;              /* set of interfaces for a scope */
     } ipv6;
 #endif /* defined(_PR_INET6) */
 #if defined(XP_UNIX)
     struct {                            /* Unix domain socket address */
         PRUint16 family;                /* address family (AF_UNIX) */
         char path[104];                 /* null-terminated pathname */
     } local;
 #endif
@@ -1039,52 +1040,92 @@ PR_EXTERN(PRStatus) PR_MkDir(const char 
 PR_EXTERN(PRStatus) PR_RmDir(const char *name);
 
 PR_EXTERN(PRUintn) PR_NetAddrSize(const PRNetAddr* addr);
 
 /*
  *************************************************************************
  * FUNCTION: PR_NewUDPSocket
  * DESCRIPTION:
- *     Create a new UDP network connection.
+ *     Create a new UDP socket.
  * INPUTS:
  *     None
  * OUTPUTS:
  *     None
  * RETURN: PRFileDesc*
  *     Upon successful completion, PR_NewUDPSocket returns a pointer
  *     to the PRFileDesc created for the newly opened UDP socket.
- *     Returns a NULL pointer if the create of a new UDP connection failed.
+ *     Returns a NULL pointer if the creation of a new UDP socket failed.
  *
  **************************************************************************
  */
 
 PR_EXTERN(PRFileDesc*)    PR_NewUDPSocket(void);
 
 /*
  *************************************************************************
  * FUNCTION: PR_NewTCPSocket
  * DESCRIPTION:
- *     Create a new TCP network connection.
+ *     Create a new TCP socket.
  * INPUTS:
  *     None
  * OUTPUTS:
  *     None
  * RETURN: PRFileDesc*
  *     Upon successful completion, PR_NewTCPSocket returns a pointer
  *     to the PRFileDesc created for the newly opened TCP socket.
- *     Returns a NULL pointer if the create of a new TCP connection failed.
+ *     Returns a NULL pointer if the creation of a new TCP socket failed.
  *
  **************************************************************************
  */
 
 PR_EXTERN(PRFileDesc*)    PR_NewTCPSocket(void);
 
 /*
  *************************************************************************
+ * FUNCTION: PR_OpenUDPSocket
+ * DESCRIPTION:
+ *     Create a new UDP socket of the specified address family.
+ * INPUTS:
+ *     PRIntn af
+ *       Address family
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_OpenUDPSocket returns a pointer
+ *     to the PRFileDesc created for the newly opened UDP socket.
+ *     Returns a NULL pointer if the creation of a new UDP socket failed.
+ *
+ **************************************************************************
+ */
+
+PR_EXTERN(PRFileDesc*)    PR_OpenUDPSocket(PRIntn af);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_OpenTCPSocket
+ * DESCRIPTION:
+ *     Create a new TCP socket of the specified address family.
+ * INPUTS:
+ *     PRIntn af
+ *       Address family
+ * OUTPUTS:
+ *     None
+ * RETURN: PRFileDesc*
+ *     Upon successful completion, PR_NewTCPSocket returns a pointer
+ *     to the PRFileDesc created for the newly opened TCP socket.
+ *     Returns a NULL pointer if the creation of a new TCP socket failed.
+ *
+ **************************************************************************
+ */
+
+PR_EXTERN(PRFileDesc*)    PR_OpenTCPSocket(PRIntn af);
+
+/*
+ *************************************************************************
  * FUNCTION: PR_Connect
  * DESCRIPTION:
  *     Initiate a connection on a socket.
  * INPUTS:
  *     PRFileDesc *fd
  *       Points to a PRFileDesc object representing a socket
  *     PRNetAddr *addr
  *       Specifies the address of the socket in its own communication
@@ -1397,16 +1438,68 @@ PR_EXTERN(PRInt32) PR_SendTo(
 **    by calling PR_GetError().
 **************************************************************************
 */
 
 PR_EXTERN(PRInt32) PR_TransmitFile(
     PRFileDesc *networkSocket, PRFileDesc *sourceFile,
     const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
     PRIntervalTime timeout);
+
+/*
+*************************************************************************
+** FUNCTION: PR_SendFile
+** DESCRIPTION:
+**    PR_SendFile sends data from a file (sendData->fd) across a socket 
+**    (networkSocket).  If specified, a header and/or trailer buffer are sent
+**	  before and after the file, respectively. The file offset, number of bytes
+** 	  of file data to send, the header and trailer buffers are specified in the
+**	  sendData argument.
+** 
+**    Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the
+**    socket is closed after successfully sending the data.
+**
+** INPUTS:
+**    PRFileDesc *networkSocket
+**        The socket to send data over
+**    PRSendFileData *sendData
+**        Contains the FD, file offset and length, header and trailer
+**		  buffer specifications.
+**    PRTransmitFileFlags       flags
+**        If the flags indicate that the connection should be closed,
+**        it will be done immediately after transferring the file, unless
+**        the operation is unsuccessful. 
+.*     PRIntervalTime timeout
+ *        Time limit for completion of the send operation.
+**
+** RETURNS:
+**    Returns the number of bytes written or -1 if the operation failed.
+**    If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_
+**    SOCKET flag is ignored. The reason for the failure is obtained
+**    by calling PR_GetError().
+**************************************************************************
+*/
+
+typedef struct PRSendFileData {
+	PRFileDesc	*fd;			/* file to send							*/
+	PRUint32	file_offset;	/* file offset							*/
+	PRSize		file_nbytes;	/* number of bytes of file data to send	*/
+								/* if 0, send data from file_offset to	*/
+								/* end-of-file.							*/
+	const void	*header;		/* header buffer						*/
+	PRInt32		hlen;			/* header len							*/
+	const void	*trailer;		/* trailer buffer						*/
+	PRInt32		tlen;			/* trailer len							*/
+} PRSendFileData;
+
+
+PR_EXTERN(PRInt32) PR_SendFile(
+    PRFileDesc *networkSocket, PRSendFileData *sendData,
+	PRTransmitFileFlags flags, PRIntervalTime timeout);
+
 /*
 *************************************************************************
 ** FUNCTION: PR_AcceptRead
 ** DESCRIPTION:
 **    AcceptRead accepts a new connection, returns the newly created
 **    socket's descriptor and also returns the connecting peer's address.
 **    AcceptRead, as its name suggests, also receives the first block of data 
 **    sent by the peer.
new file mode 100644
--- /dev/null
+++ b/pr/include/pripcsem.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+ * File: pripcsem.h
+ *
+ * Description: named semaphores for interprocess
+ * synchronization
+ *
+ * Unrelated processes obtain access to a shared semaphore
+ * by specifying its name.
+ *
+ * Our goal is to support named semaphores on at least
+ * Unix and Win32 platforms.  The implementation will use
+ * one of the three native semaphore APIs: POSIX, System V,
+ * and Win32.
+ *
+ * Because POSIX named semaphores have kernel persistence,
+ * we are forced to have a delete function in this API.
+ */
+
+#ifndef pripcsem_h___
+#define pripcsem_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * PRSem is an opaque structure that represents a named
+ * semaphore.
+ */
+typedef struct PRSem PRSem;
+
+/*
+ * PR_OpenSemaphore --
+ *
+ * Create or open a named semaphore with the specified name.
+ * A handle to the semaphore is returned.
+ *
+ * If the named semaphore doesn't exist and the PR_SEM_CREATE
+ * flag is specified, the named semaphore is created.  The
+ * created semaphore needs to be removed from the system with
+ * a PR_DeleteSemaphore call.
+ *
+ * If PR_SEM_CREATE is specified, the third argument is the
+ * access permission bits of the new semaphore (same
+ * interpretation as the mode argument to PR_Open) and the
+ * fourth argument is the initial value of the new semaphore.
+ * If PR_SEM_CREATE is not specified, the third and fourth
+ * arguments are ignored.
+ */
+
+#define PR_SEM_CREATE 0x1  /* create if not exist */
+#define PR_SEM_EXCL   0x2  /* fail if already exists */
+
+PR_EXTERN(PRSem *) PR_OpenSemaphore(
+    const char *name, PRIntn flags, PRIntn mode, PRUintn value);
+
+/*
+ * PR_WaitSemaphore --
+ *
+ * If the value of the semaphore is > 0, decrement the value and return.
+ * If the value is 0, sleep until the value becomes > 0, then decrement
+ * the value and return.
+ *
+ * The "test and decrement" operation is performed atomically.
+ */
+
+PR_EXTERN(PRStatus) PR_WaitSemaphore(PRSem *sem);
+
+/*
+ * PR_PostSemaphore --
+ *
+ * Increment the value of the named semaphore by 1.
+ */
+
+PR_EXTERN(PRStatus) PR_PostSemaphore(PRSem *sem);
+
+/*
+ * PR_CloseSemaphore --
+ *
+ * Close a named semaphore handle.
+ */
+
+PR_EXTERN(PRStatus) PR_CloseSemaphore(PRSem *sem);
+
+/*
+ * PR_DeleteSemaphore --
+ *
+ * Remove a named semaphore from the system.
+ */
+
+PR_EXTERN(PRStatus) PR_DeleteSemaphore(const char *name);
+
+PR_END_EXTERN_C
+
+#endif /* pripcsem_h___ */
--- a/pr/include/private/pprio.h
+++ b/pr/include/private/pprio.h
@@ -230,13 +230,20 @@ PR_EXTERN(void) PR_NTFast_UpdateAcceptCo
 **    function should be called immediately after calling PR_Init().
 **
 **    WARNING: THIS FUNCTION IS A TEMPORARY HACK AND WILL BE REMOVED SHORTLY
 **    (LIKE ALL FUNCTIONS IN THE PRIVATE AREA).  DO NOT USE THIS FUNCTION AT
 **    ALL WITHOUT CONTACTING mbelshe@netscape.com.
 */
 PR_EXTERN(void) PR_NT_UseNonblock();
 
+/* FUNCTION: PR_NT_CancelIo
+** DESCRIPTION:
+**    Cancel IO operations on fd.
+*/
+PR_EXTERN(PRStatus) PR_NT_CancelIo(PRFileDesc *fd);
+
+
 #endif /* WIN32 */
 
 PR_END_EXTERN_C
 
 #endif /* pprio_h___ */
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -55,16 +55,22 @@ typedef struct PRSegment PRSegment;
 #ifdef XP_MAC
 #include "prosdep.h"
 #include "probslet.h"
 #else
 #include "md/prosdep.h"
 #include "obsolete/probslet.h"
 #endif  /* XP_MAC */
 
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#include <semaphore.h>
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+#include <sys/sem.h>
+#endif
+
 /*************************************************************************
 *****  A Word about Model Dependent Function Naming Convention ***********
 *************************************************************************/
 
 /*
 NSPR 2.0 must implement its function across a range of platforms 
 including: MAC, Windows/16, Windows/95, Windows/NT, and several
 variants of Unix. Each implementation shares common code as well 
@@ -302,16 +308,18 @@ PR_EXTERN(PRInt32)                      
 
 
 /* The unbalanced curly braces in these two macros are intentional */
 #define _PR_LOCK_HEAP() { PRIntn _is; if (_pr_currentCPU) _PR_INTSOFF(_is);
 #define _PR_UNLOCK_HEAP() if (_pr_currentCPU) _PR_INTSON(_is); }
 
 #endif /* _PR_LOCAL_THREADS_ONLY */
 
+extern PRInt32                  _native_threads_only;
+
 #if defined(_PR_GLOBAL_THREADS_ONLY)
 
 #define _MD_GET_INTSOFF() 0
 #define _MD_SET_INTSOFF(_val)
 #define _PR_INTSOFF(_is)
 #define _PR_FAST_INTSON(_is)
 #define _PR_INTSON(_is)
 #define _PR_THREAD_LOCK(_thread)
@@ -968,16 +976,33 @@ extern PRStatus _PR_MD_OPEN_DIR(_MDDir *
 #define    _PR_MD_OPEN_DIR _MD_OPEN_DIR
 
 extern char * _PR_MD_READ_DIR(_MDDir *md, PRIntn flags);
 #define    _PR_MD_READ_DIR _MD_READ_DIR
 
 extern PRInt32 _PR_MD_CLOSE_DIR(_MDDir *md);
 #define    _PR_MD_CLOSE_DIR _MD_CLOSE_DIR
 
+/* Named semaphores related */
+extern PRSem * _PR_MD_OPEN_SEMAPHORE(
+    const char *osname, PRIntn flags, PRIntn mode, PRUintn value);
+#define    _PR_MD_OPEN_SEMAPHORE _MD_OPEN_SEMAPHORE
+
+extern PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem);
+#define    _PR_MD_WAIT_SEMAPHORE _MD_WAIT_SEMAPHORE
+
+extern PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem);
+#define    _PR_MD_POST_SEMAPHORE _MD_POST_SEMAPHORE
+
+extern PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem);
+#define    _PR_MD_CLOSE_SEMAPHORE _MD_CLOSE_SEMAPHORE
+
+extern PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname);
+#define    _PR_MD_DELETE_SEMAPHORE _MD_DELETE_SEMAPHORE
+
 /* I/O related */
 extern void _PR_MD_INIT_FILEDESC(PRFileDesc *fd);
 #define    _PR_MD_INIT_FILEDESC _MD_INIT_FILEDESC
 
 #ifdef XP_MAC
 extern void _PR_MD_FREE_FILEDESC(PRFileDesc *fd);
 #define    _PR_MD_FREE_FILEDESC _MD_FREE_FILEDESC
 #endif
@@ -1079,24 +1104,22 @@ extern PRInt32 _PR_MD_FAST_ACCEPT_READ(P
                                 PRIntervalTime timeout, PRBool fast,
                                 _PR_AcceptTimeoutCallback callback,
                                 void *callbackArg);
 
 extern void _PR_MD_UPDATE_ACCEPT_CONTEXT(PRInt32 s, PRInt32 ls);
 #define _PR_MD_UPDATE_ACCEPT_CONTEXT _MD_UPDATE_ACCEPT_CONTEXT
 #endif /* WIN32 */
 
-extern PRInt32 _PR_MD_TRANSMITFILE(
-    PRFileDesc *sock, PRFileDesc *file, 
-    const void *headers, PRInt32 hlen, PRInt32 flags,
-    PRIntervalTime timeout);
-#define _PR_MD_TRANSMITFILE _MD_TRANSMITFILE
-extern PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
-              const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-              PRIntervalTime timeout);
+extern PRInt32 _PR_MD_SENDFILE(
+    PRFileDesc *sock, PRSendFileData *sfd, 
+	PRInt32 flags, PRIntervalTime timeout);
+#define _PR_MD_SENDFILE _MD_SENDFILE
+extern PRInt32 _PR_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+			  PRTransmitFileFlags flags, PRIntervalTime timeout);
 
 extern PRStatus _PR_MD_GETSOCKNAME(
     PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
 #define    _PR_MD_GETSOCKNAME _MD_GETSOCKNAME
 
 extern PRStatus _PR_MD_GETPEERNAME(
     PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
 #define    _PR_MD_GETPEERNAME _MD_GETPEERNAME
@@ -1289,16 +1312,30 @@ struct PRSemaphore {
 #else  /* defined(_PR_PTHREADS) */
     _MDSemaphore md;
 #endif /* defined(_PR_PTHREADS) */
 #endif /* defined(_PR_BTHREADS) */
 };
 
 PR_EXTERN(void) _PR_InitSem(void);
 
+/*************************************************************************/
+
+struct PRSem {
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+    sem_t *sem;
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+    int semid;
+#elif defined(WIN32)
+    HANDLE sem;
+#else
+    PRInt8 notused;
+#endif
+};
+
 /************************************************************************/
 
 /* XXX this needs to be exported (sigh) */
 struct PRThreadStack {
     PRCList links;
     PRUintn flags;
 
     char *allocBase;            /* base of stack's allocated memory */
@@ -1350,16 +1387,17 @@ struct PRThread {
     PRInt32 osErrorCode;            /* mapping of errorCode | zero */
     char *errorString;              /* current error string | NULL */
 
 #if defined(_PR_PTHREADS)
     pthread_t id;                   /* pthread identifier for the thread */
     PRBool okToDelete;              /* ok to delete the PRThread struct? */
     PRCondVar *io_cv;               /* a condition used to run i/o */
     PRCondVar *waiting;             /* where the thread is waiting | NULL */
+	PRIntn io_tq_index;             /* the io-queue index for this thread */
     void *sp;                       /* recorded sp for garbage collection */
     PRThread *next, *prev;          /* simple linked list of all threads */
     PRUint32 suspend;               /* used to store suspend and resume flags */
 #ifdef PT_NO_SIGTIMEDWAIT
     pthread_mutex_t suspendResumeMutex;
     pthread_cond_t suspendResumeCV;
 #endif
 #elif defined(_PR_BTHREADS)
@@ -1457,30 +1495,49 @@ struct PRFileMap {
 };
 
 /************************************************************************/
 
 struct PRFilePrivate {
     PRInt32 state;
     PRBool nonblocking;
     PRBool inheritable;
-#if defined(_PR_PTHREADS)
-    PRInt16 eventMask;  /* A bitmask in which a 0 means
-                         * the event should be ignored in
-                         * the revents returned by poll.
-                         * The eventMask field is only
-                         * accessed by the i/o continuation
-                         * thread.
-                         */
-#endif
     PRFileDesc *next;
     PRIntn lockCount;
     _MDFileDesc md;
+#ifdef _PR_PTHREADS
+    PRIntn eventMask[1];   /* An array of _pt_tq_count bitmasks.
+                            * eventMask[i] is only accessed by
+                            * the i-th i/o continuation thread.
+                            * A 0 in a bitmask means the event
+                            * should be igored in the revents
+                            * bitmask returned by poll.
+                            *
+                            * poll's revents bitmask is a short,
+                            * but we need to declare eventMask
+                            * as an array of PRIntn's so that
+                            * each bitmask can be updated
+                            * individually without disturbing
+                            * adjacent memory.  Only the lower
+                            * 16 bits of each PRIntn are used. */
+#endif
+/* IMPORTANT: eventMask MUST BE THE LAST FIELD OF THIS STRUCTURE */
 };
 
+/*
+ * The actual size of the PRFilePrivate structure,
+ * including the eventMask array at the end
+ */
+#ifdef _PR_PTHREADS
+extern PRIntn _pt_tq_count;
+#define PRFILEPRIVATE_SIZE (sizeof(PRFilePrivate) + (_pt_tq_count-1) * sizeof(PRIntn))
+#else
+#define PRFILEPRIVATE_SIZE sizeof(PRFilePrivate)
+#endif
+
 struct PRDir {
     PRDirEntry d;
     _MDDir md;
 };
 
 extern void _PR_InitSegs(void);
 extern void _PR_InitStacks(void);
 extern void _PR_InitTPD(void);
@@ -1707,16 +1764,107 @@ extern void * _PR_MD_MEM_MAP(
 #define _PR_MD_MEM_MAP _MD_MEM_MAP
 
 extern PRStatus _PR_MD_MEM_UNMAP(void *addr, PRUint32 size);
 #define _PR_MD_MEM_UNMAP _MD_MEM_UNMAP
 
 extern PRStatus _PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap);
 #define _PR_MD_CLOSE_FILE_MAP _MD_CLOSE_FILE_MAP
 
+/* Named Shared Memory */
+
+/*
+** Declare PRSharedMemory.
+*/
+struct PRSharedMemory 
+{
+    char        *ipcname; /* after conversion to native */
+    PRSize      size;  /* from open */
+    PRIntn      mode;  /* from open */
+    PRIntn      flags; /* from open */
+#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY)
+    int         id;
+#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY)
+    int         id;
+#elif defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
+    HANDLE      handle;
+#else
+    PRUint32    nothing; /* placeholder, nothing behind here */
+#endif
+    PRUint32    ident; /* guard word at end of struct */
+#define _PR_SHM_IDENT 0xdeadbad
+};
+                                                      
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+    const char *name,
+    PRSize      size,
+    PRIntn      flags,
+    PRIntn      mode
+);
+#define _PR_MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags );
+#define _PR_MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr );
+#define _PR_MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm );
+#define _PR_MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name );
+#define _PR_MD_DELETE_SHARED_MEMORY  _MD_DeleteSharedMemory
+
+extern PRFileMap* _md_OpenAnonFileMap( 
+    const char *dirName,
+    PRSize      size,
+    PRFileMapProtect prot
+);
+#define _PR_MD_OPEN_ANON_FILE_MAP _md_OpenAnonFileMap
+
+extern PRStatus _md_ExportFileMapAsString(
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+);
+#define _PR_MD_EXPORT_FILE_MAP_AS_STRING _md_ExportFileMapAsString
+
+extern PRFileMap * _md_ImportFileMapFromString(
+    const char *fmstring
+);
+#define _PR_MD_IMPORT_FILE_MAP_FROM_STRING _md_ImportFileMapFromString
+
+
+
+/* Interprocess communications (IPC) */
+
+/*
+ * The maximum length of an NSPR IPC name, including the
+ * terminating null byte.
+ */
+#define PR_IPC_NAME_SIZE 1024
+
+/*
+ * Types of NSPR IPC objects
+ */
+typedef enum {
+    _PRIPCSem,  /* semaphores */
+    _PRIPCShm   /* shared memory segments */
+} _PRIPCType;
+
+/*
+ * Make a native IPC name from an NSPR IPC name.
+ */
+extern PRStatus _PR_MakeNativeIPCName(
+    const char *name,  /* NSPR IPC name */
+    char *result,      /* result buffer */
+    PRIntn size,       /* size of result buffer */
+    _PRIPCType type    /* type of IPC object */
+);
+
 /* Socket call error code */
 
 PR_EXTERN(PRInt32) _PR_MD_GET_SOCKET_ERROR(void);
 #define    _PR_MD_GET_SOCKET_ERROR _MD_GET_SOCKET_ERROR
 
 /* Get name of current host */
 extern PRStatus _PR_MD_GETHOSTNAME(char *name, PRUint32 namelen);
 #define    _PR_MD_GETHOSTNAME _MD_GETHOSTNAME
--- a/pr/include/prnetdb.h
+++ b/pr/include/prnetdb.h
@@ -87,16 +87,59 @@ typedef struct PRHostEnt {
 **                      the result will be PR_FAILURE and the reason
 **                      for the failure can be retrieved by PR_GetError().
 ***********************************************************************/
 PR_EXTERN(PRStatus) PR_GetHostByName(
     const char *hostname, char *buf, PRIntn bufsize, PRHostEnt *hostentry);
 
 /***********************************************************************
 ** FUNCTION:	
+** DESCRIPTION:	PR_GetIPNodeByName()
+** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT)
+** of RFC 2553.
+**
+** INPUTS:
+**  char *hostname      Character string defining the host name of interest
+**  PRUint16 af         Address family (either PR_AF_INET or PR_AF_INET6)
+**  PRIntn flags        Specifies the types of addresses that are searched
+**                      for and the types of addresses that are returned.
+**                      The only supported flag is PR_AI_DEFAULT.
+**  char *buf           A scratch buffer for the runtime to return result.
+**                      This buffer is allocated by the caller.
+**  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
+**                      use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+**  PRHostEnt *hostentry
+**                      This structure is filled in by the runtime if
+**                      the function returns PR_SUCCESS. This structure
+**                      is allocated by the caller.
+** RETURN:
+**  PRStatus            PR_SUCCESS if the lookup succeeds. If it fails
+**                      the result will be PR_FAILURE and the reason
+**                      for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+
+/*
+ * #define PR_AI_ALL        0x08
+ * #define PR_AI_V4MAPPED   0x10
+ * #define PR_AI_ADDRCONFIG 0x20
+ * #define PR_AI_DEFAULT    (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG)
+ */
+#define PR_AI_DEFAULT 0x30
+
+PR_EXTERN(PRStatus) PR_GetIPNodeByName(
+    const char *hostname,
+    PRUint16 af,
+    PRIntn flags,
+    char *buf,
+    PRIntn bufsize,
+    PRHostEnt *hostentry);
+
+/***********************************************************************
+** FUNCTION:	
 ** DESCRIPTION:	PR_GetHostByAddr()
 ** Lookup a host entry by its network address.
 **
 ** INPUTS:
 **  char *hostaddr      IP address of host in question
 **  char *buf           A scratch buffer for the runtime to return result.
 **                      This buffer is allocated by the caller.
 **  PRIntn bufsize      Number of bytes in 'buf'. A recommnded value to
@@ -155,17 +198,17 @@ PR_EXTERN(PRIntn) PR_EnumerateHostEnt(
 **  appropriate.
 **
 ** INPUTS
 **  PRNetAddrValue val  The value to be assigned to the IP Address portion
 **                      of the network address. This can only specify the
 **                      special well known values that are equivalent to
 **                      INADDR_ANY and INADDR_LOOPBACK.
 **
-**  PRUInt16 port       The port number to be assigned in the structure.
+**  PRUint16 port       The port number to be assigned in the structure.
 **
 ** OUTPUTS:
 **  PRNetAddr *addr     The address to be manipulated.
 **
 ** RETURN:
 **  PRStatus            To indicate success or failure. If the latter, the
 **                      reason for the failure can be retrieved by calling
 **                      PR_GetError();
@@ -176,16 +219,90 @@ typedef enum PRNetAddrValue
     PR_IpAddrAny,       /* assign logical INADDR_ANY to IP address */
     PR_IpAddrLoopback   /* assign logical INADDR_LOOPBACK */
 } PRNetAddrValue;
 
 PR_EXTERN(PRStatus) PR_InitializeNetAddr(
     PRNetAddrValue val, PRUint16 port, PRNetAddr *addr);
 
 /***********************************************************************
+** FUNCTION: PR_SetNetAddr(), 
+** DESCRIPTION:
+**  Set the fields of a PRNetAddr, assigning well known values as
+**  appropriate. This function is similar to PR_InitializeNetAddr
+**  but differs in that the address family is specified.
+**
+** INPUTS
+**  PRNetAddrValue val  The value to be assigned to the IP Address portion
+**                      of the network address. This can only specify the
+**                      special well known values that are equivalent to
+**                      INADDR_ANY and INADDR_LOOPBACK.
+**
+**  PRUint16 af         The address family (either PR_AF_INET or PR_AF_INET6)
+**
+**  PRUint16 port       The port number to be assigned in the structure.
+**
+** OUTPUTS:
+**  PRNetAddr *addr     The address to be manipulated.
+**
+** RETURN:
+**  PRStatus            To indicate success or failure. If the latter, the
+**                      reason for the failure can be retrieved by calling
+**                      PR_GetError();
+***********************************************************************/
+PR_EXTERN(PRStatus) PR_SetNetAddr(
+    PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr);
+
+/***********************************************************************
+** FUNCTION:	
+** DESCRIPTION:	PR_IsNetAddrType()
+** Determine if the network address is of the specified type.
+**
+** INPUTS:
+**  const PRNetAddr *addr   A network address.
+**  PRNetAddrValue          The type of network address 
+**
+** RETURN:
+**  PRBool                  PR_TRUE if the network address is of the
+**                          specified type, else PR_FALSE.
+***********************************************************************/
+PR_EXTERN(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val);
+
+/***********************************************************************
+** MACRO:	
+** DESCRIPTION:	PR_NetAddrFamily()
+** Get the 'family' field of a PRNetAddr union.
+**
+** INPUTS:
+**  const PRNetAddr *addr   A network address.
+**
+** RETURN:
+**  PRUint16                The 'family' field of 'addr'.
+***********************************************************************/
+#define PR_NetAddrFamily(addr) ((addr)->raw.family)
+
+/***********************************************************************
+** MACRO:	
+** DESCRIPTION:	PR_NetAddrInetPort()
+** Get the 'port' field of a PRNetAddr union.
+**
+** INPUTS:
+**  const PRNetAddr *addr   A network address.
+**
+** RETURN:
+**  PRUint16                The 'port' field of 'addr'.
+***********************************************************************/
+#ifdef _PR_INET6
+#define PR_NetAddrInetPort(addr) \
+    ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port)
+#else
+#define PR_NetAddrInetPort(addr) ((addr)->inet.port)
+#endif
+
+/***********************************************************************
 ** FUNCTION:	
 ** DESCRIPTION:	PR_GetProtoByName()
 ** Lookup a protocol entry based on protocol's name
 **
 ** INPUTS:
 **  char *protocolname  Character string of the protocol's name.
 **  char *buf           A scratch buffer for the runtime to return result.
 **                      This buffer is allocated by the caller.
new file mode 100644
--- /dev/null
+++ b/pr/include/prshm.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+** prshm.h -- NSPR Shared Memory
+**
+** NSPR Named Shared Memory API provides a cross-platform named
+** shared-memory interface. NSPR Named Shared Memory is modeled on
+** similar constructs in Unix and Windows operating systems. Shared
+** memory allows multiple processes to access one or more common shared
+** memory regions, using it as an inter-process communication channel.
+**
+** Notes on Platform Independence:
+**   NSPR Named Shared Memory is built on the native services offered
+**   by most platforms. The NSPR Named Shared Memory API tries to
+**   provide a least common denominator interface so that it works
+**   across all supported platforms. To ensure that it works everywhere,
+**   some platform considerations must be accomodated and the protocol
+**   for using NSPR Shared Memory API must be observed.
+**
+** Protocol:
+**   Multiple shared memories can be created using NSPR's Shared Memory
+**   feature. For each named shared memory, as defined by the name
+**   given in the PR_OpenSharedMemory() call, a protocol for using the
+**   shared memory API is required to ensure desired behavior. Failing
+**   to follow the protocol may yield unpredictable results.
+**   
+**   PR_OpenSharedMemory() will create the shared memory segment, if it
+**   does not already exist, or open a connection that the existing
+**   shared memory segment if it already exists.
+**   
+**   PR_AttachSharedMemory() should be called following
+**   PR_OpenSharedMemory() to map the memory segment to an address in
+**   the application's address space.
+**   
+**   PR_AttachSharedMemory() may be called to re-map a shared memory
+**   segment after detaching the same PRSharedMemory object. Be
+**   sure to detach it when done.
+**   
+**   PR_DetachSharedMemory() should be called to un-map the shared
+**   memory segment from the application's address space.
+**   
+**   PR_CloseSharedMemory() should be called when no further use of the
+**   PRSharedMemory object is required within a process. Following a
+**   call to  PR_CloseSharedMemory() the PRSharedMemory object is
+**   invalid and cannot be reused.
+**   
+**   PR_DeleteSharedMemory() should be called before process
+**   termination. After calling PR_DeleteSharedMemory() any further use
+**   of the shared memory associated with the name may cause
+**   unpredictable results.
+**   
+** Files:
+**   The name passed to PR_OpenSharedMemory() should be a valid filename
+**   for a unix platform. PR_OpenSharedMemory() creates file using the
+**   name passed in. Some platforms may mangle the name before creating
+**   the file and the shared memory.
+**   
+**   The unix implementation may use SysV IPC shared memory, Posix
+**   shared memory, or memory mapped files; the filename may used to
+**   define the namespace. On Windows, the name is significant, but
+**   there is no file associated with name.
+**   
+**   No assumptions about the persistence of data in the named file
+**   should be made. Depending on platform, the shared memory may be
+**   mapped onto system paging space and be discarded at process
+**   termination.
+**   
+**   All names provided to PR_OpenSharedMemory() should be valid
+**   filename syntax or name syntax for shared memory for the target
+**   platform. Referenced directories should have permissions 
+**   appropriate for writing.
+**
+** Limits:
+**   Different platforms have limits on both the number and size of
+**   shared memory resources. The default system limits on some
+**   platforms may be smaller than your requirements. These limits may
+**   be adjusted on some platforms either via boot-time options or by
+**   setting the size of the system paging space to accomodate more
+**   and/or larger shared memory segment(s).
+**
+** Security:
+**   On unix platforms, depending on implementation, contents of the
+**   backing store for the shared memory can be exposed via the file
+**   system. Set permissions and or access controls at create and attach
+**   time to ensure you get the desired security.
+**
+**   On windows platforms, no special security measures are provided.
+**
+** Example:
+**   The test case pr/tests/nameshm1.c provides an example of use as
+**   well as testing the operation of NSPR's Named Shared Memory.
+**
+** lth. 18-Aug-1999.
+*/
+
+#ifndef prshm_h___
+#define prshm_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Declare opaque type PRSharedMemory.
+*/
+typedef struct PRSharedMemory PRSharedMemory;
+
+/*
+** FUNCTION: PR_OpenSharedMemory()
+**
+** DESCRIPTION:
+**   PR_OpenSharedMemory() creates a new shared-memory segment or
+**   associates a previously created memory segment with name.
+**
+**   When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the
+**   shared memory already exists, the function returns NULL with the
+**   error set to PR_FILE_EXISTS_ERROR.
+**
+**   When parameter create is PR_SHM_CREATE and the shared memory
+**   already exists, a handle to that memory segment is returned. If
+**   the segment does not exist, it is created and a pointer to the
+**   related PRSharedMemory structure is returned.
+**
+**   When parameter create is 0, and the shared memory exists, a
+**   pointer to a PRSharedMemory is returned. If the shared memory does
+**   not exist, NULL is returned with the error set to
+**   PR_FILE_NOT_FOUND_ERROR.
+**
+** INPUTS:
+**   name -- the name the shared-memory segment is known as.
+**   size -- the size of the shared memory segment. 
+**   flags -- Options for creating the shared memory
+**   mode -- Same as is passed to PR_Open()
+**
+** OUTPUTS: 
+**   The shared memory is allocated.
+**
+** RETURNS: Pointer to opaque structure PRSharedMemory or NULL.
+**   NULL is returned on error. The reason for the error can be
+**   retrieved via PR_GetError() and PR_GetOSError();
+**
+*/
+PR_EXTERN( PRSharedMemory * )
+    PR_OpenSharedMemory(
+        const char *name,
+        PRSize      size,
+        PRIntn      flags,
+        PRIntn      mode
+);
+/* Define values for PR_OpenShareMemory(...,create) */
+#define PR_SHM_CREATE 0x1  /* create if not exist */
+#define PR_SHM_EXCL   0x2  /* fail if already exists */
+
+/*
+** FUNCTION: PR_AttachSharedMemory()
+**
+** DESCRIPTION:
+** PR_AttachSharedMemory() maps the shared-memory described by
+** shm to the current process. 
+**
+** INPUTS: 
+**   shm -- The handle returned from PR_OpenSharedMemory().
+**   flags -- options for mapping the shared memory.
+**   PR_SHM_READONLY causes the memory to be attached 
+**   read-only.
+**
+** OUTPUTS:
+**   On success, the shared memory segment represented by shm is mapped
+**   into the process' address space.
+**
+** RETURNS: Address where shared memory is mapped, or NULL.
+**   NULL is returned on error. The reason for the error can be
+**   retrieved via PR_GetError() and PR_GetOSError();
+**
+**
+*/
+PR_EXTERN( void * )
+    PR_AttachSharedMemory(
+        PRSharedMemory *shm,
+        PRIntn  flags
+);
+/* Define values for PR_AttachSharedMemory(...,flags) */ 
+#define PR_SHM_READONLY 0x01
+
+/*
+** FUNCTION: PR_DetachSharedMemory()
+**
+** DESCRIPTION:
+**   PR_DetachSharedMemory() detaches the shared-memory described
+**   by shm. 
+**
+** INPUTS: 
+**   shm -- The handle returned from PR_OpenSharedMemory().
+**   addr -- The address at which the memory was attached.
+**
+** OUTPUTS:
+**   The shared memory mapped to an address via a previous call to
+**   PR_AttachSharedMemory() is unmapped.
+**
+** RETURNS: PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+    PR_DetachSharedMemory(
+        PRSharedMemory *shm,
+        void  *addr
+);
+
+/*
+** FUNCTION: PR_CloseSharedMemory()
+**
+** DESCRIPTION:
+**   PR_CloseSharedMemory() closes the shared-memory described by
+**   shm.
+** 
+** INPUTS:
+**   shm -- The handle returned from PR_OpenSharedMemory().
+**
+** OUTPUTS:
+**   the shared memory represented by shm is closed
+**
+** RETURNS: PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+    PR_CloseSharedMemory(
+        PRSharedMemory *shm
+);
+
+/*
+** FUNCTION: PR_DeleteSharedMemory()
+**
+** DESCRIPTION:
+**   The shared memory resource represented by name is released.
+**
+** INPUTS:
+**   name -- the name the shared-memory segment
+**
+** OUTPUTS:
+**   depending on platform, resources may be returned to the underlying
+**   operating system.
+**
+** RETURNS: PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+    PR_DeleteSharedMemory( 
+        const char *name
+);
+
+PR_END_EXTERN_C
+
+#endif /* prshm_h___ */
new file mode 100644
--- /dev/null
+++ b/pr/include/prshma.h
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+** prshma.h -- NSPR Anonymous Shared Memory
+**
+** NSPR provides an anonymous shared memory based on NSPR's PRFileMap
+** type. The anonymous file-mapped shared memory provides an inheritable
+** shared memory, as in: the child process inherits the shared memory.
+** Compare the file-mapped anonymous shared memory to to a named shared
+** memory described in prshm.h. The intent is to provide a shared
+** memory that is accessable only by parent and child processes. ...
+** It's a security thing.
+** 
+** Depending on the underlying platform, the file-mapped shared memory
+** may be backed by a file. ... surprise! ... On some platforms, no
+** real file backs the shared memory. On platforms where the shared
+** memory is backed by a file, the file's name in the filesystem is
+** visible to other processes for only the duration of the creation of
+** the file, hopefully a very short time. This restricts processess
+** that do not inherit the shared memory from opening the file and
+** reading or writing its contents. Further, when all processes
+** using an anonymous shared memory terminate, the backing file is
+** deleted. ... If you are not paranoid, you're not paying attention.
+** 
+** The file-mapped shared memory requires a protocol for the parent
+** process and child process to share the memory. NSPR provides two
+** protocols. Use one or the other; don't mix and match.
+** 
+** In the first protocol, the job of passing the inheritable shared
+** memory is done via helper-functions with PR_CreateProcess(). In the
+** second protocol, the parent process is responsible for creating the
+** child process; the parent and child are mutually responsible for
+** passing a FileMap string. NSPR provides helper functions for
+** extracting data from the PRFileMap object. ... See the examples
+** below.
+** 
+** Both sides should adhere strictly to the protocol for proper
+** operation. The pseudo-code below shows the use of a file-mapped
+** shared memory by a parent and child processes. In the examples, the
+** server creates the file-mapped shared memory, the client attaches to
+** it.
+**
+** First protocol.
+** Server:
+**
+**   fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); 
+**   addr = PR_MemMap(fm); 
+**   attr = PR_NewProcessAttr();
+**   PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname );
+**   PR_CreateProcess(Client); 
+**   PR_DestroyProcessAttr(attr);
+**   ... yadda ...
+**   PR_MemUnmap( addr );
+**   PR_CloseFileMap(fm);
+**
+**
+** Client: 
+**   ... started by server via PR_CreateProcess()
+**   fm = PR_GetInheritedFileMap( shmname );
+**   addr = PR_MemMap(fm);
+**   ... yadda ...
+**   PR_MemUnmap(addr);
+**   PR_CloseFileMap(fm);
+**
+**
+** Second Protocol:
+** Server:
+**
+**   fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); 
+**   fmstring = PR_ExportFileMapAsString( fm );
+**   addr = PR_MemMap(fm); 
+**    ... application specific technique to pass fmstring to child
+**    ... yadda ... Server uses his own magic to create child
+**   PR_MemUnmap( addr );
+**   PR_CloseFileMap(fm);
+**
+**
+** Client: 
+**   ... started by server via his own magic
+**   ... application specific technique to find fmstring from parent
+**   fm = PR_ImportFileMapFromString( fmstring )
+**   addr = PR_MemMap(fm);
+**   ... yadda ...
+**   PR_MemUnmap(addr);
+**   PR_CloseFileMap(fm);
+**
+**
+** lth. 2-Jul-1999.
+**
+** Note: The second protocol was requested by NelsonB (7/1999); this is
+** to accomodate servers which already create their own child processes
+** using platform native methods.
+** 
+*/
+
+#ifndef prshma_h___
+#define prshma_h___
+
+#include "prtypes.h"
+#include "prio.h"
+#include "prproces.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory
+**
+** Description:
+** PR_OpenAnonFileMap() creates an anonymous shared memory. If the
+** shared memory already exists, a handle is returned to that shared
+** memory object.
+**
+** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a
+** directory name, without the trailing '/', to contain the anonymous
+** file. A filename is generated for the name.
+**
+** On Windows platforms, dirName is ignored.
+**
+** Inputs:
+**   dirName -- A directory name to contain the anonymous file.
+**   size -- The size of the shared memory
+**   prot -- How the shared memory is mapped. See prio.h
+**   
+** Outputs:
+**   PRFileMap *
+**
+** Returns:
+**   Pointer to PRFileMap or NULL on error.
+**
+*/
+PR_EXTERN( PRFileMap *)
+PR_OpenAnonFileMap(
+    const char *dirName,
+    PRSize      size, 
+    PRFileMapProtect prot
+);  
+
+/*
+** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export  
+**   to my children processes via PR_CreateProcess()
+**
+** Description:
+** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to
+** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess()
+** makes the PRFileMap importable by the child process.
+**
+** Inputs:
+**   attr -- PRProcessAttr, used to pass data to PR_CreateProcess()
+**   fm -- PRFileMap structure to be passed to the child process
+**   shmname -- The name for the PRFileMap; used by child.
+**
+** Outputs:
+**   PRFileMap *
+**
+** Returns:
+**   PRStatus
+**
+*/
+PR_EXTERN(PRStatus) 
+PR_ProcessAttrSetInheritableFileMap( 
+    PRProcessAttr   *attr,
+    PRFileMap       *fm, 
+    const char      *shmname
+);
+
+/*
+** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported
+**   by my parent process via PR_CreateProcess()
+**
+** Description:
+** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from
+** its parent process via PR_CreateProcess().
+**
+** Inputs:
+**    shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap()
+** 
+** Outputs:
+**   PRFileMap *
+**
+** Returns:
+**   PRFileMap pointer or NULL.
+**
+*/
+PR_EXTERN( PRFileMap *)
+PR_GetInheritedFileMap( 
+    const char *shmname 
+);
+
+/*
+** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap
+**
+** Description:
+** Creates an identifier, as a string, from a PRFileMap object
+** previously created with PR_OpenAnonFileMap().
+**
+** Inputs:
+**   fm -- PRFileMap pointer to be represented as a string.
+**   bufsize -- sizeof(buf)
+**   buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE
+**
+** Outputs:
+**   buf contains the stringized PRFileMap identifier
+**
+** Returns:
+**   PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+PR_ExportFileMapAsString( 
+    PRFileMap *fm,
+    PRSize    bufsize,
+    char      *buf
+);
+#define PR_FILEMAP_STRING_BUFSIZE 128
+
+/*
+** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string
+**
+** Description:
+** PR_ImportFileMapFromString() creates a PRFileMap object from a
+** string previously created by PR_ExportFileMapAsString().
+**
+** Inputs:
+**   fmstring -- string created by PR_ExportFileMapAsString()
+**
+** Returns:
+**   PRFileMap pointer or NULL.
+**
+*/
+PR_EXTERN( PRFileMap * )
+PR_ImportFileMapFromString( 
+    const char *fmstring
+);
+
+PR_END_EXTERN_C
+#endif /* prshma_h___ */
--- a/pr/src/Makefile
+++ b/pr/src/Makefile
@@ -93,35 +93,32 @@ endif
 
 ifeq ($(OS_ARCH),OSF1)
 ifeq ($(USE_PTHREADS), 1)
 OS_LIBS 	= -lpthread -lrt
 endif
 ifneq ($(OS_RELEASE),V2.0)
 OS_LIBS		+= -lc_r
 endif
-ifeq ($(USE_IPV6), 1)
-OS_LIBS		+= -lip6
-endif
 endif
 
 ifeq ($(OS_ARCH),Linux)
 ifeq ($(USE_PTHREADS), 1)
 OS_LIBS		= -lpthread -ldl -lc
 else
 OS_LIBS		= -ldl -lc
 endif
 endif
 
 ifeq ($(OS_ARCH),HP-UX)
 ifeq ($(USE_PTHREADS), 1)
 ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE)))
 OS_LIBS 	= -ldce
 else
-OS_LIBS 	= -lpthread
+OS_LIBS 	= -lpthread -lrt
 endif
 endif
 ifeq ($(PTHREADS_USER), 1)
 OS_LIBS 	= -lpthread
 endif
 ifeq ($(basename $(OS_RELEASE)),A.09)
 OS_LIBS		+= -ldld -L/lib/pa1.1 -lm
 else
@@ -166,27 +163,30 @@ OBJS = \
     io/$(OBJDIR)/prstdio.$(OBJ_SUFFIX) \
     threads/$(OBJDIR)/prcmon.$(OBJ_SUFFIX) \
 	threads/$(OBJDIR)/prrwlock.$(OBJ_SUFFIX) \
 	threads/$(OBJDIR)/prtpd.$(OBJ_SUFFIX) \
     linking/$(OBJDIR)/prlink.$(OBJ_SUFFIX) \
     malloc/$(OBJDIR)/prmalloc.$(OBJ_SUFFIX) \
     malloc/$(OBJDIR)/prmem.$(OBJ_SUFFIX) \
     md/$(OBJDIR)/prosdep.$(OBJ_SUFFIX) \
+    memory/$(OBJDIR)/prshm.$(OBJ_SUFFIX) \
+    memory/$(OBJDIR)/prshma.$(OBJ_SUFFIX) \
     memory/$(OBJDIR)/prseg.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/pralarm.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/pratom.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prcountr.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prdtoa.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prenv.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prerr.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prerror.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prerrortable.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prinit.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prinrval.$(OBJ_SUFFIX) \
+    misc/$(OBJDIR)/pripc.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prlog2.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prlong.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prnetdb.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prolock.$(OBJ_SUFFIX)	 \
     misc/$(OBJDIR)/prsystem.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prthinfo.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prtrace.$(OBJ_SUFFIX) \
     misc/$(OBJDIR)/prtime.$(OBJ_SUFFIX)
@@ -197,17 +197,18 @@ OBJS += \
     pthreads/$(OBJDIR)/ptio.$(OBJ_SUFFIX) \
     pthreads/$(OBJDIR)/ptthread.$(OBJ_SUFFIX) \
     pthreads/$(OBJDIR)/ptmisc.$(OBJ_SUFFIX)
 else
 OBJS += \
     io/$(OBJDIR)/prdir.$(OBJ_SUFFIX) \
     io/$(OBJDIR)/prfile.$(OBJ_SUFFIX) \
     io/$(OBJDIR)/prio.$(OBJ_SUFFIX) \
-    io/$(OBJDIR)/prsocket.$(OBJ_SUFFIX)
+    io/$(OBJDIR)/prsocket.$(OBJ_SUFFIX) \
+    misc/$(OBJDIR)/pripcsem.$(OBJ_SUFFIX)
 
 ifndef USE_BTHREADS
 OBJS += \
 	threads/$(OBJDIR)/prcthr.$(OBJ_SUFFIX) \
 	threads/$(OBJDIR)/prdump.$(OBJ_SUFFIX) \
 	threads/$(OBJDIR)/prmon.$(OBJ_SUFFIX) \
 	threads/$(OBJDIR)/prsem.$(OBJ_SUFFIX) \
 	threads/combined/$(OBJDIR)/prucpu.$(OBJ_SUFFIX) \
@@ -278,17 +279,19 @@ OBJS +=	md/windows/$(OBJDIR)/w95io.$(OBJ
 	md/windows/$(OBJDIR)/w95sock.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/w95thred.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/w95cv.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntgc.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntmisc.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntinrval.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntsem.$(OBJ_SUFFIX)	\
 	md/windows/$(OBJDIR)/win32_errors.$(OBJ_SUFFIX) \
+	md/windows/$(OBJDIR)/w32ipcsem.$(OBJ_SUFFIX)	\
 	md/windows/$(OBJDIR)/w32poll.$(OBJ_SUFFIX)	\
+	md/windows/$(OBJDIR)/w32shm.$(OBJ_SUFFIX)	\
 	md/windows/$(OBJDIR)/w95dllmain.$(OBJ_SUFFIX)
 else
 ifeq ($(OS_TARGET),OS2)
 OBJS +=	md/os2/$(OBJDIR)/os2io.$(OBJ_SUFFIX) \
 	md/os2/$(OBJDIR)/os2sock.$(OBJ_SUFFIX) \
 	md/os2/$(OBJDIR)/os2thred.$(OBJ_SUFFIX) \
 	md/os2/$(OBJDIR)/os2cv.$(OBJ_SUFFIX) \
 	md/os2/$(OBJDIR)/os2gc.$(OBJ_SUFFIX) \
@@ -301,16 +304,18 @@ else
 OBJS +=	md/windows/$(OBJDIR)/ntdllmn.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntio.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntgc.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntthread.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntmisc.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntinrval.$(OBJ_SUFFIX) \
 	md/windows/$(OBJDIR)/ntsem.$(OBJ_SUFFIX)	\
 	md/windows/$(OBJDIR)/win32_errors.$(OBJ_SUFFIX) \
+	md/windows/$(OBJDIR)/w32ipcsem.$(OBJ_SUFFIX) \
+	md/windows/$(OBJDIR)/w32shm.$(OBJ_SUFFIX)	\
 	md/windows/$(OBJDIR)/w32poll.$(OBJ_SUFFIX)
 endif
 endif
 endif
 
 else
 
 ifeq ($(OS_ARCH), BeOS)
--- a/pr/src/io/prfdcach.c
+++ b/pr/src/io/prfdcach.c
@@ -111,24 +111,24 @@ PRFileDesc *_PR_Getfd()
 
         } while (NULL == fd);  /* then go around and allocate a new one */
     }
 
 finished:
     fd->dtor = NULL;
     fd->lower = fd->higher = NULL;
     fd->identity = PR_NSPR_IO_LAYER;
-    memset(fd->secret, 0, sizeof(PRFilePrivate));
+    memset(fd->secret, 0, PRFILEPRIVATE_SIZE);
     return fd;
 
 allocate:
     fd = PR_NEW(PRFileDesc);
     if (NULL != fd)
     {
-        fd->secret = PR_NEW(PRFilePrivate);
+        fd->secret = (PRFilePrivate *) PR_MALLOC(PRFILEPRIVATE_SIZE);
         if (NULL == fd->secret) PR_DELETE(fd);
     }
     if (NULL != fd) goto finished;
     else return NULL;
 
 }  /* _PR_Getfd */
 
 /*
--- a/pr/src/io/prlayer.c
+++ b/pr/src/io/prlayer.c
@@ -438,18 +438,18 @@ PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
         stack->higher = NULL;
     }
     else
     {
         /* going somewhere in the middle of the stack */
         fd->lower = insert;
         fd->higher = insert->higher;
 
+        insert->higher->lower = fd;
         insert->higher = fd;
-        insert->higher->lower = fd;
     }
 
     return PR_SUCCESS;
 }
 
 PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
 {
     PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
--- a/pr/src/io/prlog.c
+++ b/pr/src/io/prlog.c
@@ -77,17 +77,17 @@ static PRLock *_pr_logLock;
 */
 #if defined(XP_PC)
 #define WIN32_DEBUG_FILE (FILE*)-2
 #endif
 
 /* Macros used to reduce #ifdef pollution */
 
 #if defined(_PR_USE_STDIO_FOR_LOGGING)
-#define _PUT_LOG(fd, buf, nb) fputs(buf, fd)
+#define _PUT_LOG(fd, buf, nb) {fputs(buf, fd); fflush(fd);}
 #elif defined(_PR_PTHREADS)
 #define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
 #elif defined(XP_MAC)
 #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb)
 #else
 #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
 #endif
 
@@ -194,29 +194,16 @@ void _PR_InitLog(void)
                 while (lm != NULL) {
                     if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
                     else if (strcasecmp(module, lm->name) == 0) {
                         lm->level = (PRLogModuleLevel)level;
                         break;
                     }
                     lm = lm->next;
                 }
-                if (( PR_FALSE == skip_modcheck) && (NULL == lm)) {
-#ifdef XP_PC
-                    char* str = PR_smprintf("Unrecognized NSPR_LOG_MODULE: %s=%d\n",
-                                            module, level);
-                    if (str) {
-                        OutputDebugString(str);
-                        PR_smprintf_free(str);
-                    }
-#else
-                    fprintf(stderr, "Unrecognized NSPR_LOG_MODULE: %s=%d\n",
-                            module, level);
-#endif
-                }
             }
             /*found:*/
             count = sscanf(&ev[pos], " , %n", &delta);
             pos += delta;
             if (count == -1) break;
         }
         PR_SetLogBuffering(isSync ? bufSize : 0);
 
--- a/pr/src/io/prmwait.c
+++ b/pr/src/io/prmwait.c
@@ -171,24 +171,24 @@ static PRStatus TimerInit(void)
     {
         goto failed;
     }
     tm_vars.cancel_timer = PR_NewCondVar(tm_vars.ml);
     if (NULL == tm_vars.cancel_timer)
     {
         goto failed;
     }
+    PR_INIT_CLIST(&tm_vars.timer_queue);
     tm_vars.manager_thread = PR_CreateThread(
         PR_SYSTEM_THREAD, TimerManager, NULL, PR_PRIORITY_NORMAL,
         PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
     if (NULL == tm_vars.manager_thread)
     {
         goto failed;
     }
-    PR_INIT_CLIST(&tm_vars.timer_queue);
     return PR_SUCCESS;
 
 failed:
     if (NULL != tm_vars.cancel_timer)
     {
         PR_DestroyCondVar(tm_vars.cancel_timer);
     }
     if (NULL != tm_vars.new_timer)
--- a/pr/src/io/prpolevt.c
+++ b/pr/src/io/prpolevt.c
@@ -16,98 +16,201 @@
  * Reserved.
  */
 
 /*
  *********************************************************************
  *
  * Pollable events
  *
+ * Pollable events are implemented using layered I/O.  The only
+ * I/O methods that are implemented for pollable events are poll
+ * and close.  No other methods can be invoked on a pollable
+ * event.
+ *
+ * A pipe or socket pair is created and the pollable event layer
+ * is pushed onto the read end.  A pointer to the write end is
+ * saved in the PRFilePrivate structure of the pollable event.
+ *
  *********************************************************************
  */
 
-#include "primpl.h"
+#include "prinit.h"
+#include "prio.h"
+#include "prmem.h"
+#include "prerror.h"
+#include "prlog.h"
+
+/*
+ * These internal functions are declared in primpl.h,
+ * but we can't include primpl.h because the definition
+ * of struct PRFilePrivate in this file (for the pollable
+ * event layer) will conflict with the definition of
+ * struct PRFilePrivate in primpl.h (for the NSPR layer).
+ */
+extern PRIntn _PR_InvalidInt(void);
+extern PRInt64 _PR_InvalidInt64(void);
+extern PRStatus _PR_InvalidStatus(void);
+extern PRFileDesc *_PR_InvalidDesc(void);
+
+/*
+ * PRFilePrivate structure for the NSPR pollable events layer
+ */
+struct PRFilePrivate {
+    PRFileDesc *writeEnd;  /* the write end of the pipe/socketpair */
+};
+
+static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd);
+
+static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
 
-typedef struct MyFilePrivate {
-    PRFilePrivate copy;
-    PRFileDesc *writeEnd;
-    PRFilePrivate *oldSecret;
-} MyFilePrivate;
+static PRIOMethods _pr_polevt_methods = {
+    PR_DESC_LAYERED,
+    _pr_PolEvtClose,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+    _pr_PolEvtPoll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRGetsockoptFN)_PR_InvalidStatus,    
+    (PRSetsockoptFN)_PR_InvalidStatus,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus
+};
+
+static PRDescIdentity _pr_polevt_id;
+static PRCallOnceType _pr_polevt_once_control;
+static PRStatus PR_CALLBACK _pr_PolEvtInit(void);
+
+static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
+}
+
+static PRStatus PR_CALLBACK _pr_PolEvtInit(void)
+{
+    _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events");
+    if (PR_INVALID_IO_LAYER == _pr_polevt_id) {
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
 
 #if !defined(XP_UNIX) || defined(VMS)
 #define USE_TCP_SOCKETPAIR
 #endif
 
 PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
 {
+    PRFileDesc *event;
     PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */
-    MyFilePrivate *secret;
+
+    fd[0] = fd[1] = NULL;
 
-    secret = PR_NEW(MyFilePrivate);
-    if (secret == NULL) {
+    if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) {
+        return NULL;
+    }
+
+    event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods);
+    if (NULL == event) {
+        goto errorExit;
+    } 
+    event->secret = PR_NEW(PRFilePrivate);
+    if (event->secret == NULL) {
         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
         goto errorExit;
     }
 
 #ifndef USE_TCP_SOCKETPAIR
     if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) {
         goto errorExit;
     }
 #else
     if (PR_NewTCPSocketPair(fd) == PR_FAILURE) {
         goto errorExit;
     }
 #endif
 
-    secret->copy = *fd[0]->secret;
-    secret->oldSecret = fd[0]->secret;
-    secret->writeEnd = fd[1];
-    fd[0]->secret = (PRFilePrivate *) secret;
+    event->secret->writeEnd = fd[1];
+    if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) {
+        goto errorExit;
+    }
 
     return fd[0];
 
 errorExit:
-    PR_DELETE(secret);
+    if (fd[0]) {
+        PR_Close(fd[0]);
+        PR_Close(fd[1]);
+    }
+    if (event) {
+        PR_DELETE(event->secret);
+        event->dtor(event);
+    }
     return NULL;
 }
 
+static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd)
+{
+    PRFileDesc *event;
+
+    event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+    PR_ASSERT(NULL == event->higher && NULL == event->lower);
+    PR_Close(fd);
+    PR_Close(event->secret->writeEnd);
+    PR_DELETE(event->secret);
+    event->dtor(event);
+    return PR_SUCCESS;
+}
+
 PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
 {
-    MyFilePrivate *secret;
-
-    secret = (MyFilePrivate *) event->secret;
-    event->secret = secret->oldSecret;
-    PR_Close(event);
-    PR_Close(secret->writeEnd);
-    PR_DELETE(secret);
-    return PR_SUCCESS;
+    return PR_Close(event);
 }
 
 static const char magicChar = '\x38';
 
 PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
 {
-    MyFilePrivate *secret;
-
-    secret = (MyFilePrivate *) event->secret;
-    if (PR_Write(secret->writeEnd, &magicChar, 1) != 1) {
+    if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) {
         return PR_FAILURE;
     }
     return PR_SUCCESS;
 }
 
 PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
 {
     char buf[1024];
     PRInt32 nBytes;
 #ifdef DEBUG
     PRIntn i;
 #endif
 
-    nBytes = PR_Read(event, buf, sizeof(buf));
+    nBytes = PR_Read(event->lower, buf, sizeof(buf));
     if (nBytes == -1) {
         return PR_FAILURE;
     }
 
 #ifdef DEBUG
     /*
      * Make sure people do not write to the pollable event fd
      * directly.
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -851,59 +851,27 @@ PR_NTFast_UpdateAcceptContext(PRFileDesc
 		socket->secret->md.osfd, acceptSocket->secret->md.osfd);
 }
 #endif /* WINNT */
 
 static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
 const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
 PRIntervalTime timeout)
 {
-	PRInt32 rv;
-	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRSendFileData sfd;
 
-	if (_PR_PENDING_INTERRUPT(me)) {
-		me->flags &= ~_PR_INTERRUPT;
-		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
-		return -1;
-	}
-	if (_PR_IO_PENDING(me)) {
-		PR_SetError(PR_IO_PENDING_ERROR, 0);
-		return -1;
-	}
-	/* The socket must be in blocking mode. */
-	if (sd->secret->nonblocking) {
-		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
-		return -1;
-	}
-#if defined(WINNT)
-	rv = _PR_MD_TRANSMITFILE(
-		sd, fd,
-		headers, hlen, flags, timeout);
-	if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
-		/*
-		 * This should be kept the same as SocketClose, except
-		 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
-		 * not be called because the socket will be recycled.
-		 */
-		PR_FreeFileDesc(sd);
-	}
-#else
-#if defined(XP_UNIX)
-	/*
-	 * On HPUX11, we could call _PR_HPUXTransmitFile(), but that
-	 * would require that we not override the malloc() functions.
-	 */
-	rv = _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
-#else	/* XP_UNIX */
-	rv = _PR_EmulateTransmitFile(sd, fd, headers, hlen, flags,
-	    timeout);
-#endif	/* XP_UNIX */
-#endif	/* WINNT */
+	sfd.fd = fd;
+	sfd.file_offset = 0;
+	sfd.file_nbytes = 0;
+	sfd.header = headers;
+	sfd.hlen = hlen;
+	sfd.trailer = NULL;
+	sfd.tlen = 0;
 
-	return rv;
+	return(PR_SendFile(sd, &sfd, flags, timeout));
 }
 
 static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
 {
 	PRInt32 result;
 	PRUint32 addrlen;
 
 	addrlen = sizeof(PRNetAddr);
@@ -1240,16 +1208,26 @@ PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocke
 #if defined(_PR_INET6)
 	if (_pr_ipv6_enabled) {
 		domain = AF_INET6;
 	}
 #endif
 	return PR_Socket(domain, SOCK_DGRAM, 0);
 }
 
+PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
+{
+	return PR_Socket(af, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
+{
+	return PR_Socket(af, SOCK_DGRAM, 0);
+}
+
 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
 {
 #ifdef XP_UNIX
 	PRInt32 rv, osfd[2];
 
 	if (!_pr_initialized) _PR_ImplicitInitialization();
 
 	rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
@@ -1447,99 +1425,161 @@ PR_FileDesc2NativeHandle(PRFileDesc *fd)
 PR_IMPLEMENT(void)
 PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
 {
 	if (fd)
 		fd->secret->md.osfd = handle;
 }
 
 /*
- * _PR_EmulateTransmitFile
+ * _PR_EmulateSendFile
  *
- *	Send file fd across socket sd. If headers is non-NULL, 'hlen'
- *	bytes of headers is sent before sending the file.
+ *	Send file sfd->fd across socket sd. The header and trailer buffers
+ *	specified in the 'sfd' argument are sent before and after the file,
+ *	respectively.
  *
  *	PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  *	
  *	return number of bytes sent or -1 on error
  *
  */
 
-PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
-const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-PRIntervalTime timeout)
+PRInt32 _PR_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
+PRTransmitFileFlags flags, PRIntervalTime timeout)
 {
 	PRInt32 rv, count = 0;
 	PRInt32 rlen;
+	const void *buffer;
+	PRInt32 buflen;
+	PRInt32 sendbytes, readbytes;
 	PRThread *me = _PR_MD_CURRENT_THREAD();
 	char *buf = NULL;
-#define _TRANSMITFILE_BUFSIZE	(16 * 1024)
+
+#define _SENDFILE_BUFSIZE	(16 * 1024)
 
 	if (_PR_PENDING_INTERRUPT(me)) {
 		me->flags &= ~_PR_INTERRUPT;
 		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 		return -1;
 	}
 
-	buf = (char*)PR_MALLOC(_TRANSMITFILE_BUFSIZE);
+	buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
 	if (buf == NULL) {
 		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 		return -1;
 	}
 
 	/*
-	 * send headers, first
+	 * send header, first
 	 */
-	while (hlen) {
-		rv =  PR_Send(sd, headers, hlen, 0, timeout);
+	buflen = sfd->hlen;
+	buffer = sfd->header;
+	while (buflen) {
+		rv =  PR_Send(sd, buffer, buflen, 0, timeout);
 		if (rv < 0) {
 			/* PR_Send() has invoked PR_SetError(). */
 			rv = -1;
 			goto done;
 		} else {
 			count += rv;
-			headers = (const void*) ((const char*)headers + rv);
-			hlen -= rv;
+			buffer = (const void*) ((const char*)buffer + rv);
+			buflen -= rv;
 		}
 	}
 	/*
 	 * send file, next
 	 */
-	while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) {
-		while (rlen) {
-			char *bufptr = buf;
 
-			rv =  PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT);
-			if (rv < 0) {
-				/* PR_Send() has invoked PR_SetError(). */
-				rv = -1;
-				goto done;
-			} else {
-				count += rv;
-				bufptr = ((char*)bufptr + rv);
-				rlen -= rv;
+	if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
+		rv = -1;
+		goto done;
+	}
+	sendbytes = sfd->file_nbytes;
+	if (sendbytes == 0) {
+		/* send entire file */
+		while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
+			while (rlen) {
+				char *bufptr = buf;
+
+				rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
+				if (rv < 0) {
+					/* PR_Send() has invoked PR_SetError(). */
+					rv = -1;
+					goto done;
+				} else {
+					count += rv;
+					bufptr = ((char*)bufptr + rv);
+					rlen -= rv;
+				}
 			}
 		}
+		if (rlen < 0) {
+			/* PR_Read() has invoked PR_SetError(). */
+			rv = -1;
+			goto done;
+		}
+	} else {
+		readbytes = sendbytes > _SENDFILE_BUFSIZE ? _SENDFILE_BUFSIZE :
+											sendbytes;
+		while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
+			while (rlen) {
+				char *bufptr = buf;
+
+				rv =  PR_Send(sd, bufptr, rlen, 0, timeout);
+				if (rv < 0) {
+					/* PR_Send() has invoked PR_SetError(). */
+					rv = -1;
+					goto done;
+				} else {
+					count += rv;
+					sendbytes -= rv;
+					bufptr = ((char*)bufptr + rv);
+					rlen -= rv;
+				}
+			}
+			readbytes = sendbytes > _SENDFILE_BUFSIZE ?
+						_SENDFILE_BUFSIZE : sendbytes;
+		}
+		if (rlen < 0) {
+			/* PR_Read() has invoked PR_SetError(). */
+			rv = -1;
+			goto done;
+		} else if (sendbytes != 0) {
+			/*
+			 * there are fewer bytes in file to send than specified
+			 */
+        	PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+			rv = -1;
+			goto done;
+		}
 	}
-	if (rlen == 0) {
-		/*
-		 * end-of-file
-		 */
-		if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
-			PR_Close(sd);
-		rv = count;
-	} else {
-		PR_ASSERT(rlen < 0);
-		/* PR_Read() has invoked PR_SetError(). */
-		rv = -1;
+	/*
+	 * send trailer, last
+	 */
+	buflen = sfd->tlen;
+	buffer = sfd->trailer;
+	while (buflen) {
+		rv =  PR_Send(sd, buffer, buflen, 0, timeout);
+		if (rv < 0) {
+			/* PR_Send() has invoked PR_SetError(). */
+			rv = -1;
+			goto done;
+		} else {
+			count += rv;
+			buffer = (const void*) ((const char*)buffer + rv);
+			buflen -= rv;
+		}
 	}
+	rv = count;
 
 done:
 	if (buf)
 		PR_DELETE(buf);
+    if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
+        PR_Close(sd);
 	return rv;
 }
 
 /*
  * _PR_EmulateAcceptRead
  *
  *	Accept an incoming connection on sd, set *nd to point to the
  *	newly accepted socket, read 'amount' bytes from the accepted
@@ -1825,8 +1865,50 @@ PR_IMPLEMENT(PRInt32) PR_Select(
     return npds;
 out_of_memory:
     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
     return -1;    
 
 #endif /* !defined(NEED_SELECT) */
     
 }
+
+PR_IMPLEMENT(PRInt32) PR_SendFile(
+    PRFileDesc *sd, PRSendFileData *sfd,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	/* The socket must be in blocking mode. */
+	if (sd->secret->nonblocking) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+#if defined(WINNT)
+	rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
+	if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
+		/*
+		 * This should be kept the same as SocketClose, except
+		 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
+		 * not be called because the socket will be recycled.
+		 */
+		PR_FreeFileDesc(sd);
+	}
+#else
+#if defined(XP_UNIX)
+	rv = _PR_UnixSendFile(sd, sfd, flags, timeout);
+#else	/* XP_UNIX */
+	rv = _PR_EmulateSendFile(sd, sfd, flags, timeout);
+#endif	/* XP_UNIX */
+#endif	/* WINNT */
+
+	return rv;
+}
--- a/pr/src/md/beos/bnet.c
+++ b/pr/src/md/beos/bnet.c
@@ -572,22 +572,16 @@ PRStatus
 PRInt32
 _MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
                  void *buf, PRInt32 amount, PRIntervalTime timeout)
 {
     return PR_NOT_IMPLEMENTED_ERROR;
 }
 
 PRInt32
-_MD_transmitfile (PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen, PRInt32 flags, PRIntervalTime timeout)
-{
-    return PR_NOT_IMPLEMENTED_ERROR;
-}
-
-PRInt32
 _MD_socket (int af, int type, int flags)
 {
     PRInt32 osfd, err;
 
     osfd = socket( af, type, 0 );
 
     if( -1 == osfd ) {
 
--- a/pr/src/md/unix/Makefile
+++ b/pr/src/md/unix/Makefile
@@ -27,16 +27,17 @@ endif
 endif
 
 CSRCS =          \
 	unix.c    \
 	unix_errors.c    \
 	uxproces.c \
 	uxwrap.c \
 	uxpoll.c \
+	uxshm.c \
 	$(NULL)
 
 PTH_USER_CSRCS =          \
 	pthreads_user.c \
 	$(NULL)
 
 IRIX_CSRCS =	 \
 	irix.c	 \
@@ -220,16 +221,19 @@ endif
 
 ifeq ($(OS_ARCH),SunOS)
     ifeq ($(CPU_ARCH),x86)
 	ASFILES = os_$(OS_ARCH)_x86.s
     else
 	ifneq ($(OS_RELEASE),4.1.3_U1)
 	ifneq ($(LOCAL_THREADS_ONLY),1)
 		ASFILES = os_$(OS_ARCH).s
+		ifneq ($(USE_64),1)
+		ASFILES += os_$(OS_ARCH)_32.s
+		endif
 	endif
 	endif
     endif
 endif
 
 ifeq ($(OS_ARCH), SINIX)
     ifeq ($(CPU_ARCH),mips)
         ASFILES   = os_ReliantUNIX.s
@@ -283,14 +287,21 @@ export:: $(TARGETS)
 ifeq ($(OS_ARCH),SunOS)
 ifneq ($(OS_RELEASE),4.1.3_U1)
 ifeq ($(OS_TEST),sun4u)
 $(SHARED_LIBRARY): $(ULTRASPARC_ASOBJS)
 	$(LD) -G -z text -o $@ $(ULTRASPARC_ASOBJS)
 	$(INSTALL) -m 444 $(SHARED_LIBRARY) $(DIST)/lib
 
 $(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES)
+ifeq ($(USE_64),1)
+	/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v9 $<
+else
 	/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $<
 endif
+
+clean::
+	rm -rf $(ULTRASPARC_ASOBJS)
+endif
 endif
 endif
 
 install:: export
--- a/pr/src/md/unix/aix.c
+++ b/pr/src/md/unix/aix.c
@@ -76,31 +76,38 @@ PRIntervalTime _MD_AixIntervalPerSec(voi
 /*
  * AIX 4.3 has sched_yield().  AIX 4.2 has pthread_yield().
  * So we look up the appropriate function pointer at run time.
  */
 
 #include <dlfcn.h>
 
 int (*_PT_aix_yield_fcn)() = NULL;
+int _pr_aix_send_file_use_disabled = 0;
 
 void _MD_EarlyInit(void)
 {
     void *main_app_handle;
+	char *evp;
 
     main_app_handle = dlopen(NULL, RTLD_NOW);
     PR_ASSERT(NULL != main_app_handle);
 
     _PT_aix_yield_fcn = (int(*)())dlsym(main_app_handle, "sched_yield");
     if (!_PT_aix_yield_fcn) {
         _PT_aix_yield_fcn = (int(*)())dlsym(main_app_handle,"pthread_yield");
         PR_ASSERT(NULL != _PT_aix_yield_fcn);
     }
     dlclose(main_app_handle);
 
+	if (evp = getenv("NSPR_AIX_SEND_FILE_USE_DISABLED")) {
+		if (1 == atoi(evp))
+			_pr_aix_send_file_use_disabled = 1;
+	}
+
 #if defined(AIX_TIMERS)
     _MD_AixIntervalInit();
 #endif
 }
 
 #else /* _PR_PTHREADS */
 
 void _MD_EarlyInit(void)
--- a/pr/src/md/unix/objs.mk
+++ b/pr/src/md/unix/objs.mk
@@ -17,16 +17,17 @@
 
 # This makefile appends to the variable OBJS the platform-dependent
 # object modules that will be part of the nspr20 library.
 
 CSRCS =          \
 	unix.c    \
 	unix_errors.c \
 	uxproces.c \
+	uxshm.c \
 	uxwrap.c \
 	uxpoll.c \
 	$(NULL)
 
 PTH_USER_CSRCS =          \
 	pthreads_user.c \
 	$(NULL)
 
@@ -212,16 +213,19 @@ endif
 
 ifeq ($(OS_ARCH),SunOS)
     ifeq ($(CPU_ARCH),x86)
 	ASFILES = os_$(OS_ARCH)_x86.s
     else
 	ifneq ($(OS_RELEASE),4.1.3_U1)
 	ifneq ($(LOCAL_THREADS_ONLY),1)
             ASFILES = os_$(OS_ARCH).s
+            ifneq ($(USE_64),1)
+            ASFILES += os_$(OS_ARCH)_32.s
+            endif
 	endif
 	endif
     endif
 endif
 
 ifeq ($(OS_ARCH), SINIX)
     ifeq ($(CPU_ARCH),mips)
         ASFILES   = os_ReliantUNIX.s
--- a/pr/src/md/unix/os_Irix.s
+++ b/pr/src/md/unix/os_Irix.s
@@ -42,16 +42,44 @@ retry_push:
 		beq		v0,t1,retry_push
 		nop
 		sc		t1,0(a0)	
 		beq		t1,0,retry_push
 		nop
 		sw		v0,0(a1)
 		sync
 		sw		t0,0(a0)
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
 		jr		ra
 		nop
 
 END(PR_StackPush)
 
 /*
  *
  *  Atomically remove the element at the top of the stack
@@ -63,27 +91,57 @@ END(PR_StackPush)
 LEAF(PR_StackPop)
 retry_pop:
 .set noreorder
 
 
 		lw		v0,0(a0)
 		li		t1,1
 		beq		v0,0,done
+		nop	
 		beq		v0,t1,retry_pop
 		nop	
 
         ll      v0,0(a0)
 		beq		v0,0,done
+		nop
 		beq		v0,t1,retry_pop
 		nop
 		sc		t1,0(a0)	
 		beq		t1,0,retry_pop
 		nop
 		lw		t0,0(v0)
 		sw		t0,0(a0)
 done:
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
+		nop
 		jr		ra
 		nop
 
 END(PR_StackPop)
 
 #endif /* _PR_HAVE_ATOMIC_CAS */
--- a/pr/src/md/unix/os_SunOS.s
+++ b/pr/src/md/unix/os_SunOS.s
@@ -44,91 +44,8 @@ sol_curthread:
 
 __MD_FlushRegisterWindows:
 _MD_FlushRegisterWindows:
 
 	ta	3
 	ret
 	restore
 
-!  ======================================================================
-!
-!  Atomically add a new element to the top of the stack
-!
-!  usage : PR_StackPush(listp, elementp);
-!
-!  -----------------------
-!  Note on REGISTER USAGE:
-!  as this is a LEAF procedure, a new stack frame is not created.
-!
-!  So, the registers used are:
-!     %o0  [input]   - the address of the stack
-!     %o1  [input]   - the address of the element to be added to the stack
-!  -----------------------
-
-		.section	".text"
-		.global		PR_StackPush
-
-PR_StackPush:
-
-pulock:	ld		[%o0],%o3				! 
-		cmp		%o3,-1					! check if stack is locked
-		be		pulock					! loop, if locked
-		mov		-1,%o3					! use delay-slot
-		swap	[%o0],%o3				! atomically lock the stack and get
-										! the pointer to stack head
-		cmp		%o3,-1					! check, if the stack is locked
-		be		pulock					! loop, if so
-		nop
-		st		%o3,[%o1]
-		retl                           	! return back to the caller
-		st		%o1,[%o0]				! 
-
-		.size	PR_StackPush,(.-PR_StackPush)
-
-
-!  end
-!  ======================================================================
-
-!  ======================================================================
-!
-!  Atomically remove the element at the top of the stack
-!
-!  usage : elemep = PR_StackPop(listp);
-!
-!  -----------------------
-!  Note on REGISTER USAGE:
-!  as this is a LEAF procedure, a new stack frame is not created.
-!
-!  So, the registers used are:
-!     %o0  [input]   - the address of the stack
-!     %o1  [input]   - work register (top element)
-!  -----------------------
-
-		.section	".text"
-		.global		PR_StackPop
-
-PR_StackPop:
-
-polock:	ld		[%o0],%o1				! 
-		cmp		%o1,-1					! check if stack is locked
-		be		polock					! loop, if locked
-		mov		-1,%o1					! use delay-slot
-		swap	[%o0],%o1				! atomically lock the stack and get
-										! the pointer to stack head
-		cmp		%o1,-1					! check, if the stack is locked
-		be		polock					! loop, if so
-		nop
-		tst		%o1						! test for empty stack
-		be,a	empty					! is empty
-		st		%g0,[%o0]
-		ld		[%o1], %o2				! load the second element
-		st		%o2,[%o0]				! set stack head to second
-		st		%g0,[%o1]				! reset the next pointer; for
-										! debugging
-empty:
-        retl                            ! return back to the caller
-		mov		%o1, %o0				! return the first element
-
-		.size	PR_StackPop,(.-PR_StackPop)
-
-!  end
-!  ======================================================================
new file mode 100644
--- /dev/null
+++ b/pr/src/md/unix/os_SunOS_32.s
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+!  ======================================================================
+!
+!  Atomically add a new element to the top of the stack
+!
+!  usage : PR_StackPush(listp, elementp);
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created.
+!
+!  So, the registers used are:
+!     %o0  [input]   - the address of the stack
+!     %o1  [input]   - the address of the element to be added to the stack
+!  -----------------------
+
+		.section	".text"
+		.global		PR_StackPush
+
+PR_StackPush:
+
+pulock:	ld		[%o0],%o3				! 
+		cmp		%o3,-1					! check if stack is locked
+		be		pulock					! loop, if locked
+		mov		-1,%o3					! use delay-slot
+		swap	[%o0],%o3				! atomically lock the stack and get
+										! the pointer to stack head
+		cmp		%o3,-1					! check, if the stack is locked
+		be		pulock					! loop, if so
+		nop
+		st		%o3,[%o1]
+		retl                           	! return back to the caller
+		st		%o1,[%o0]				! 
+
+		.size	PR_StackPush,(.-PR_StackPush)
+
+
+!  end
+!  ======================================================================
+
+!  ======================================================================
+!
+!  Atomically remove the element at the top of the stack
+!
+!  usage : elemep = PR_StackPop(listp);
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created.
+!
+!  So, the registers used are:
+!     %o0  [input]   - the address of the stack
+!     %o1  [input]   - work register (top element)
+!  -----------------------
+
+		.section	".text"
+		.global		PR_StackPop
+
+PR_StackPop:
+
+polock:	ld		[%o0],%o1				! 
+		cmp		%o1,-1					! check if stack is locked
+		be		polock					! loop, if locked
+		mov		-1,%o1					! use delay-slot
+		swap	[%o0],%o1				! atomically lock the stack and get
+										! the pointer to stack head
+		cmp		%o1,-1					! check, if the stack is locked
+		be		polock					! loop, if so
+		nop
+		tst		%o1						! test for empty stack
+		be,a	empty					! is empty
+		st		%g0,[%o0]
+		ld		[%o1], %o2				! load the second element
+		st		%o2,[%o0]				! set stack head to second
+		st		%g0,[%o1]				! reset the next pointer; for
+										! debugging
+empty:
+        retl                            ! return back to the caller
+		mov		%o1, %o0				! return the first element
+
+		.size	PR_StackPop,(.-PR_StackPop)
+
+!  end
+!  ======================================================================
--- a/pr/src/md/unix/unix.c
+++ b/pr/src/md/unix/unix.c
@@ -2134,17 +2134,30 @@ void _MD_BlockClockInterrupts()
 void _MD_UnblockClockInterrupts()
 {
     sigprocmask(SIG_UNBLOCK, &timer_set, 0);
 }
 
 void _MD_InitFileDesc(PRFileDesc *fd)
 {
     /* By default, a Unix fd is not closed on exec. */
-    PR_ASSERT(0 == fcntl(fd->secret->md.osfd, F_GETFD, 0));
+#ifdef DEBUG
+    {
+        int flags;
+
+        /*
+         * Ignore EBADF error on fd's 0, 1, 2 because they are
+         * not open in all processes.
+         */
+        flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
+        PR_ASSERT((0 == flags) || (-1 == flags
+            && (0 <= fd->secret->md.osfd && fd->secret->md.osfd <= 2)
+            && errno == EBADF));
+    }
+#endif
     fd->secret->inheritable = PR_TRUE;
 }
 
 void _MD_MakeNonblock(PRFileDesc *fd)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     int flags;
 
@@ -2913,136 +2926,198 @@ PRIntervalTime _PR_UNIX_GetInterval()
 }  /* _PR_SUNOS_GetInterval */
 
 PRIntervalTime _PR_UNIX_TicksPerSecond()
 {
     return 1000;  /* this needs some work :) */
 }
 
 /*
- * _PR_UnixTransmitFile
+ * _PR_UnixSendFile
  *
- *    Send file fd across socket sd. If headers is non-NULL, 'hlen'
- *    bytes of headers is sent before sending the file.
+ *    Send file sfd->fd across socket sd. If header/trailer are specified
+ *    they are sent before and after the file, respectively.
  *
  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  *    
  *    return number of bytes sent or -1 on error
  *
  */
-#define TRANSMITFILE_MMAP_CHUNK    (256 * 1024)
-PR_IMPLEMENT(PRInt32) _PR_UnixTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
-const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-PRIntervalTime timeout)
+#define SENDFILE_MMAP_CHUNK    (256 * 1024)
+
+PR_IMPLEMENT(PRInt32) _PR_UnixSendFile(PRFileDesc *sd,
+PRSendFileData *sfd,
+PRTransmitFileFlags flags, PRIntervalTime timeout)
 {
     PRInt32 rv, count = 0;
-    PRInt32 len, index = 0;
+    PRInt32 len, file_bytes, index = 0;
     struct stat statbuf;
-    struct PRIOVec iov[2];
+    struct PRIOVec iov[3];
     void *addr;
-    PRInt32 err;
+	PRUint32 file_mmap_offset, pagesize;
+	PRUint32 addr_offset, mmap_len;
 
     /* Get file size */
-    if (fstat(fd->secret->md.osfd, &statbuf) == -1) {
-        err = _MD_ERRNO();
-        switch (err) {
-            case EBADF:
-                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
-                break;
-            case EFAULT:
-                PR_SetError(PR_ACCESS_FAULT_ERROR, err);
-                break;
-            case EINTR:
-                PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
-                break;
-            case ETIMEDOUT:
-#ifdef ENOLINK
-            case ENOLINK:
-#endif
-                PR_SetError(PR_REMOTE_FILE_ERROR, err);
-                break;
-            default:
-                PR_SetError(PR_UNKNOWN_ERROR, err);
-                break;
-        }
+    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
+        _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO());
         count = -1;
         goto done;
     }
-    /*
-     * If the file is large, mmap and send the file in chunks so as
-     * to not consume too much virtual address space
-     */
-    len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size :
-        TRANSMITFILE_MMAP_CHUNK;
-    /*
-     * Map in (part of) file. Take care of zero-length files.
-     */
-    if (len) {
-        addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE,
-            fd->secret->md.osfd, 0);
-
-        if (addr == (void*)-1) {
-            _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
-            count = -1;
-            goto done;
-        }
-    }
-    /*
-     * send headers, first, followed by the file
-     */
-    if (hlen) {
-        iov[index].iov_base = (char *) headers;
-        iov[index].iov_len = hlen;
-        index++;
-    }
-    iov[index].iov_base = (char*)addr;
-    iov[index].iov_len = len;
-    index++;
-    rv = PR_Writev(sd, iov, index, timeout);
-    if (len)
-        munmap(addr,len);
-    if (rv >= 0) {
-        PR_ASSERT(rv == hlen + len);
-        statbuf.st_size -= len;
-        count += rv;
-    } else {
-        count = -1;
-        goto done;
-    }
+    if (sfd->file_nbytes && (statbuf.st_size <
+							(sfd->file_offset + sfd->file_nbytes))) {
+		/*
+		 * there are fewer bytes in file to send than specified
+		 */
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		count = -1;
+		goto done;
+	}
+	if (sfd->file_nbytes)
+		file_bytes = sfd->file_nbytes;
+	else
+		file_bytes = statbuf.st_size - sfd->file_offset;
+
+	pagesize = PR_GetPageSize();
+	/*
+	 * If the file is large, mmap and send the file in chunks so as
+	 * to not consume too much virtual address space
+	 */
+	if ((sfd->file_offset == 0) ||
+			(sfd->file_offset & (pagesize - 1) == 0)) {
+		/*
+		 * case 1: page-aligned file offset
+		 */
+		mmap_len = file_bytes < SENDFILE_MMAP_CHUNK ? file_bytes :
+			SENDFILE_MMAP_CHUNK;
+		
+		len = mmap_len;
+		file_mmap_offset = sfd->file_offset;
+		addr_offset = 0;
+	} else {
+		/*
+		 * case 2: non page-aligned file offset
+		 */
+		/* find previous page boundary */
+		file_mmap_offset = (sfd->file_offset & ~(pagesize - 1));
+
+		/* number of initial bytes to skip in mmap'd segment */
+		addr_offset = sfd->file_offset - file_mmap_offset;
+		PR_ASSERT(addr_offset > 0);
+		mmap_len = (file_bytes + addr_offset) < SENDFILE_MMAP_CHUNK ?
+						(file_bytes + addr_offset) : SENDFILE_MMAP_CHUNK;
+		len = mmap_len - addr_offset;
+	}
+	/*
+	 * Map in (part of) file. Take care of zero-length files.
+	 */
+	if (len) {
+#ifdef OSF1
+		/*
+		 * Use MAP_SHARED to work around a bug in OSF1 that results in
+		 * corrupted data in the memory-mapped region
+		 */
+		addr = mmap((caddr_t) 0, mmap_len, PROT_READ, MAP_SHARED,
+			sfd->fd->secret->md.osfd, file_mmap_offset);
+#else
+		addr = mmap((caddr_t) 0, mmap_len, PROT_READ, MAP_PRIVATE,
+			sfd->fd->secret->md.osfd, file_mmap_offset);
+#endif
+
+		if (addr == (void*)-1) {
+			_PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
+			count = -1;
+			goto done;
+		}
+	}
+	/*
+	 * send headers, first, followed by the file
+	 */
+	if (sfd->hlen) {
+		iov[index].iov_base = (char *) sfd->header;
+		iov[index].iov_len = sfd->hlen;
+		index++;
+	}
+	if (len) {
+		iov[index].iov_base = (char*)addr + addr_offset;
+		iov[index].iov_len = len;
+		index++;
+	}
+	if ((file_bytes == len) && (sfd->tlen)) {
+		/*
+		 * all file data is mapped in; send the trailer too
+		 */
+		iov[index].iov_base = (char *) sfd->trailer;
+		iov[index].iov_len = sfd->tlen;
+		index++;
+	}
+	rv = PR_Writev(sd, iov, index, timeout);
+	if (len)
+		munmap(addr,mmap_len);
+	if (rv >= 0) {
+		PR_ASSERT((len == file_bytes) || (rv == sfd->hlen + len));
+		PR_ASSERT((len != file_bytes) ||
+								(rv == sfd->hlen + len + sfd->tlen));
+		file_bytes -= len;
+		count += rv;
+		if (0 == file_bytes)	/* header, file and trailer are sent */
+			goto done;
+	} else {
+		count = -1;
+		goto done;
+	}
     /*
      * send remaining bytes of the file, if any
      */
-    len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size :
-        TRANSMITFILE_MMAP_CHUNK;
+    len = file_bytes < SENDFILE_MMAP_CHUNK ? file_bytes :
+        SENDFILE_MMAP_CHUNK;
     while (len > 0) {
         /*
          * Map in (part of) file
          */
-        PR_ASSERT((count - hlen) % TRANSMITFILE_MMAP_CHUNK == 0);
+        file_mmap_offset = sfd->file_offset + count - sfd->hlen;
+        PR_ASSERT((file_mmap_offset % pagesize) == 0);
+#ifdef OSF1
+		/*
+		 * Use MAP_SHARED to work around a bug in OSF1 that results in
+		 * corrupted data in the memory-mapped region
+		 */
+        addr = mmap((caddr_t) 0, len, PROT_READ, MAP_SHARED,
+                sfd->fd->secret->md.osfd, file_mmap_offset);
+#else
         addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE,
-                fd->secret->md.osfd, count - hlen);
+                sfd->fd->secret->md.osfd, file_mmap_offset);
+#endif
 
         if (addr == (void*)-1) {
             _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
             count = -1;
             goto done;
         }
         rv =  PR_Send(sd, addr, len, 0, timeout);
         munmap(addr,len);
         if (rv >= 0) {
             PR_ASSERT(rv == len);
-            statbuf.st_size -= rv;
+            file_bytes -= rv;
             count += rv;
-            len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ?
-                statbuf.st_size : TRANSMITFILE_MMAP_CHUNK;
+            len = file_bytes < SENDFILE_MMAP_CHUNK ?
+                file_bytes : SENDFILE_MMAP_CHUNK;
         } else {
             count = -1;
             goto done;
         }
     }
+    PR_ASSERT(0 == file_bytes);
+	if (sfd->tlen) {
+		rv =  PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
+		if (rv >= 0) {
+			PR_ASSERT(rv == sfd->tlen);
+			count += rv;
+		} else
+			count = -1;
+	}		
 done:
     if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
         PR_Close(sd);
     return count;
 }
 
 #if defined(HPUX11) && !defined(_PR_PTHREADS)
 
@@ -3692,16 +3767,24 @@ PRStatus _MD_MemUnmap(void *addr, PRUint
         PR_SetError(PR_UNKNOWN_ERROR, errno);
     }
         return PR_FAILURE;
     }
 }
 
 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
 {
+    if ( PR_TRUE == fmap->md.isAnonFM ) {
+        PRStatus rc = PR_Close( fmap->fd );
+        if ( PR_FAILURE == rc ) {
+            PR_LOG( _pr_io_lm, PR_LOG_DEBUG,
+                ("_MD_CloseFileMap(): error closing anonymnous file map osfd"));
+            return PR_FAILURE;
+        }
+    }
     PR_DELETE(fmap);
     return PR_SUCCESS;
 }
 
 #if defined(_PR_NEED_FAKE_POLL)
 
 /*
  * Some platforms don't have poll().  For easier porting of code
--- a/pr/src/md/unix/unix_errors.c
+++ b/pr/src/md/unix/unix_errors.c
@@ -17,17 +17,17 @@
  */
 
 #include "primpl.h"
 #if defined(_PR_POLL_AVAILABLE)
 #include <poll.h>
 #endif
 #include <errno.h>
 
-static void _MD_unix_map_default_error(int err)
+void _MD_unix_map_default_error(int err)
 {
     PRErrorCode prError;
 
     switch (err ) {
         case EACCES:
             prError = PR_NO_ACCESS_RIGHTS_ERROR;
             break;
         case EADDRINUSE:
--- a/pr/src/md/unix/uxproces.c
+++ b/pr/src/md/unix/uxproces.c
@@ -711,16 +711,17 @@ PRStatus _MD_DetachUnixProcess(PRProcess
 	    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 	    retVal = PR_FAILURE;
 	} else {
 	    DeletePidTable(pRec);
 	    PR_ASSERT(NULL == pRec->reapedCV);
 	    PR_DELETE(pRec);
 	}
     }
+    PR_DELETE(process);
 
 done:
     PR_Unlock(pr_wp.ml);
     return retVal;
 }
 
 PRStatus _MD_WaitUnixProcess(
     PRProcess *process,
@@ -770,16 +771,17 @@ PRStatus _MD_WaitUnixProcess(
 	PR_ASSERT(_PR_PID_REAPED == pRec->state);
 	PR_ASSERT(NULL == pRec->reapedCV);
 	DeletePidTable(pRec);
         if (exitCode) {
             *exitCode = pRec->exitStatus;
         }
 	PR_DELETE(pRec);
     }
+    PR_DELETE(process);
 
 done:
     PR_Unlock(pr_wp.ml);
     return retVal;
 }  /* _MD_WaitUnixProcess */
 
 PRStatus _MD_KillUnixProcess(PRProcess *process)
 {
new file mode 100644
--- /dev/null
+++ b/pr/src/md/unix/uxshm.c
@@ -0,0 +1,639 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+** uxshm.c -- Unix Implementations NSPR Named Shared Memory
+**
+**
+** lth. Jul-1999.
+**
+*/
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+#include "primpl.h"       
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+
+#define NSPR_IPC_SHM_KEY 'b'
+/*
+** Implementation for System V
+*/
+#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+#define _MD_DELETE_SHARED_MEMORY  _MD_DeleteSharedMemory
+
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+    const char *name,
+    PRSize      size,
+    PRIntn      flags,
+    PRIntn      mode
+)
+{
+    PRStatus rc = PR_SUCCESS;
+    key_t   key;
+    PRSharedMemory *shm;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return( NULL );
+    }
+
+    shm = PR_NEWZAP( PRSharedMemory );
+    if ( NULL == shm ) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); 
+        return( NULL );
+    }
+
+    shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+    if ( NULL == shm->ipcname )
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); 
+        return( NULL );
+    }
+
+    /* copy args to struct */
+    strcpy( shm->ipcname, ipcname );
+    shm->size = size; 
+    shm->mode = mode; 
+    shm->flags = flags;
+    shm->ident = _PR_SHM_IDENT;
+
+    /* create the file first */
+    if ( flags & PR_SHM_CREATE )  {
+        int osfd = open( shm->ipcname, (O_RDWR | O_CREAT), shm->mode );
+        if ( -1 == osfd ) {
+            _PR_MD_MAP_OPEN_ERROR( errno );
+            PR_FREEIF( shm->ipcname );
+            PR_DELETE( shm );
+            return( NULL );
+        } 
+        if ( close(osfd == -1 )) {
+            _PR_MD_MAP_CLOSE_ERROR( errno );
+            PR_FREEIF( shm->ipcname );
+            PR_DELETE( shm );
+            return( NULL );
+        }
+    }
+
+    /* hash the shm.name to an ID */
+    key = ftok( shm->ipcname, NSPR_IPC_SHM_KEY );
+    if ( -1 == key )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): ftok() failed on name: %s", shm->ipcname));
+        PR_FREEIF( shm->ipcname );
+        PR_DELETE( shm );
+        return( NULL );
+    }
+
+    /* get the shared memory */
+    if ( flags & PR_SHM_CREATE )  {
+        shm->id = shmget( key, shm->size, ( shm->mode | IPC_CREAT|IPC_EXCL));
+        if ( shm->id >= 0 ) {
+            return( shm );
+        }
+        if ((errno == EEXIST) && (flags & PR_SHM_EXCL)) {
+            PR_SetError( PR_FILE_EXISTS_ERROR, errno );
+            PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+                ("_MD_OpenSharedMemory(): shmget() exclusive failed, errno: %d", errno));
+            PR_FREEIF(shm->ipcname);
+            PR_DELETE(shm);
+            return(NULL);
+        }
+    } 
+
+    shm->id = shmget( key, shm->size, shm->mode );
+    if ( -1 == shm->id ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): shmget() failed, errno: %d", errno));
+        PR_FREEIF(shm->ipcname);
+        PR_DELETE(shm);
+        return(NULL);
+    }
+
+    return( shm );
+} /* end _MD_OpenSharedMemory() */
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    void        *addr;
+    PRUint32    aFlags = shm->mode;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    aFlags |= (flags & PR_SHM_READONLY )? SHM_RDONLY : 0;
+
+    addr = shmat( shm->id, NULL, aFlags );
+    if ( (void*)-1 == addr )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_AttachSharedMemory(): shmat() failed on name: %s, OsError: %d", 
+                shm->ipcname, PR_GetOSError() ));
+        addr = NULL;
+    }
+
+    return addr;
+}    
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PRStatus rc = PR_SUCCESS;
+    PRIntn   urc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    urc = shmdt( addr );
+    if ( -1 == urc )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DetachSharedMemory(): shmdt() failed on name: %s", shm->ipcname ));
+    }
+
+    return rc;
+}    
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    PR_FREEIF(shm->ipcname);
+    PR_DELETE(shm);
+
+    return PR_SUCCESS;
+}    
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    PRStatus rc = PR_SUCCESS;
+    key_t   key;
+    int     id;
+    PRIntn  urc;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError( PR_UNKNOWN_ERROR , errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return(PR_FAILURE);
+    }
+
+    /* create the file first */ 
+    {
+        int osfd = open( ipcname, (O_RDWR | O_CREAT), 0666 );
+        if ( -1 == osfd ) {
+            _PR_MD_MAP_OPEN_ERROR( errno );
+            return( PR_FAILURE );
+        } 
+        if ( close(osfd == -1 )) {
+            _PR_MD_MAP_CLOSE_ERROR( errno );
+            return( PR_FAILURE );
+        }
+    }
+
+    /* hash the shm.name to an ID */
+    key = ftok( ipcname, NSPR_IPC_SHM_KEY );
+    if ( -1 == key )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): ftok() failed on name: %s", ipcname));
+    }
+
+    id = shmget( key, 0, 0 );
+    if ( -1 == id ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno));
+        return(PR_FAILURE);
+    }
+
+    urc = shmctl( id, IPC_RMID, NULL );
+    if ( -1 == urc )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname ));
+        return(PR_FAILURE);
+    }
+
+    urc = unlink( ipcname );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_UNLINK_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname ));
+        return(PR_FAILURE);
+    }
+
+    return rc;
+}  /* end _MD_DeleteSharedMemory() */
+
+/*
+** Implementation for Posix
+*/
+#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+#define _MD_DELETE_SHARED_MEMORY  _MD_DeleteSharedMemory
+
+struct _MDSharedMemory {
+    int     handle;
+};
+
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+    const char *name,
+    PRSize      size,
+    PRIntn      flags,
+    PRIntn      mode
+)
+{
+    PRStatus    rc = PR_SUCCESS;
+    PRIntn      id;
+    PRInt32     end;
+    PRSharedMemory *shm;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError( PR_UNKNOWN_ERROR , errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return( NULL );
+    }
+
+    shm = PR_NEWZAP( PRSharedMemory );
+    if ( NULL == shm ) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); 
+        return( NULL );
+    }
+
+    shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+    if ( NULL == shm->ipcname )
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); 
+        return( NULL );
+    }
+
+    /* copy args to struct */
+    strcpy( shm->ipcname, ipcname );
+    shm->size = size; 
+    shm->mode = mode;
+    shm->flags = flags;
+    shm->ident = _PR_SHM_IDENT;
+
+    /*
+    ** Create the shared memory
+    */
+    if ( flags & PR_SHM_CREATE )  {
+        int oflag = (O_CREAT | O_RDWR);
+        
+        if ( flags & PR_SHM_EXCL )
+            oflag |= O_EXCL;
+        shm->id = shm_open( shm->ipcname, oflag, shm->mode );
+    } else {
+        shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode );
+    }
+
+    if ( -1 == shm->id )  {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d",
+                shm->ipcname, PR_GetOSError())); 
+        PR_DELETE( shm->ipcname );
+        PR_DELETE( shm );
+        return(NULL);
+    }
+
+    end = ftruncate( shm->id, shm->size );
+    if ( -1 == end ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d",
+                PR_GetOSError()));
+        PR_DELETE( shm->ipcname );
+        PR_DELETE( shm );
+        return(NULL);
+    }
+
+    return(shm);
+} /* end _MD_OpenSharedMemory() */
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    void        *addr;
+    PRIntn      prot = (PROT_READ | PROT_WRITE);
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    if ( PR_SHM_READONLY == flags)
+        prot ^= PROT_WRITE;
+
+    addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 );
+    if ((void*)-1 == addr )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d",
+                shm->ipcname, PR_GetOSError()));
+        addr = NULL;
+    } else {
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr));
+    }
+    
+    return addr;
+}    
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PRStatus    rc = PR_SUCCESS;
+    PRIntn      urc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    urc = munmap( addr, shm->size );
+    if ( -1 == urc )
+    {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d", 
+                shm->ipcname, PR_GetOSError()));
+    }
+    return rc;
+}    
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    int urc;
+    
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    urc = close( shm->id );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_CLOSE_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError()));
+        return(PR_FAILURE);
+    }
+    PR_DELETE( shm->ipcname );
+    PR_DELETE( shm );
+    return PR_SUCCESS;
+}    
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    PRStatus    rc = PR_SUCCESS;
+    PRUintn     urc;
+    char        ipcname[PR_IPC_NAME_SIZE];
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError( PR_UNKNOWN_ERROR , errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+        return( NULL );
+    }
+
+    urc = shm_unlink( ipcname );
+    if ( -1 == urc ) {
+        rc = PR_FAILURE;
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d", 
+                ipcname, PR_GetOSError()));
+    } else {
+        PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, 
+            ("_MD_DeleteSharedMemory(): %s, success", ipcname));
+    }
+
+    return rc;
+} /* end _MD_DeleteSharedMemory() */
+#endif
+
+
+
+/*
+** Unix implementation for anonymous memory (file) mapping
+*/
+extern PRLogModuleInfo *_pr_shma_lm;
+
+#include <unistd.h>
+
+extern PRFileMap* _md_OpenAnonFileMap( 
+    const char *dirName,
+    PRSize      size,
+    PRFileMapProtect prot
+)
+{
+    PRFileMap   *fm = NULL;
+    PRFileDesc  *fd;
+    int         osfd;
+    PRIntn      urc;
+    PRIntn      mode = 0600;
+    char        *genName;
+    pid_t       pid = getpid(); /* for generating filename */
+    PRThread    *tid = PR_GetCurrentThread(); /* for generating filename */
+    int         incr; /* for generating filename */
+    const int   maxTries = 20; /* maximum # attempts at a unique filename */
+
+    /*
+    ** generate a filename from input and runtime environment
+    ** open the file, unlink the file.
+    ** make maxTries number of attempts at uniqueness in the filename
+    */
+    for ( incr = 0; incr < maxTries ; incr++ ) {
+        genName = PR_smprintf( "%s/.NSPR-AFM-%d-%p.%d", 
+            dirName, (int) pid, tid, incr );
+        if ( NULL == genName ) {
+            PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+                ("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename"));
+            goto Finished;
+        }
+        
+        /* create the file */
+        osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode );
+        if ( -1 == osfd ) {
+            if ( EEXIST == errno )  {
+                PR_smprintf_free( genName );
+                continue; /* name exists, try again */
+            } else {
+                _PR_MD_MAP_OPEN_ERROR( errno );
+                PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+                    ("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d", 
+                        genName, PR_GetOSError()));
+                PR_smprintf_free( genName );
+                goto Finished;
+            }
+        }
+        break; /* name generation and open successful, break; */
+    } /* end for() */
+
+    if ( incr == maxTries ) {
+        PR_ASSERT( -1 == osfd );
+        PR_ASSERT( EEXIST == errno );
+        _PR_MD_MAP_OPEN_ERROR( errno );
+        goto Finished;
+    }
+
+    urc = unlink( genName );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_UNLINK_ERROR( errno );
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno));
+        PR_smprintf_free( genName );
+        close( osfd );
+        goto Finished;        
+    }
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): unlink(): %s", genName ));
+
+    PR_smprintf_free( genName );
+
+    fd = PR_ImportFile( osfd );
+    if ( NULL == fd ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): PR_ImportFile(): failed"));
+        goto Finished;        
+    }
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): fd: %p", fd ));
+
+    urc = ftruncate( fd->secret->md.osfd, size );
+    if ( -1 == urc ) {
+        _PR_MD_MAP_DEFAULT_ERROR( errno );
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno));
+        PR_Close( fd );
+        goto Finished;        
+    }
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): ftruncate(): size: %d", size ));
+
+    fm = PR_CreateFileMap( fd, size, prot );
+    if ( NULL == fm )  {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("PR_OpenAnonFileMap(): failed"));
+        PR_Close( fd );
+        goto Finished;        
+    }
+    fm->md.isAnonFM = PR_TRUE; /* set fd close */
+
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm ));
+
+Finished:    
+    return(fm);
+} /* end md_OpenAnonFileMap() */
+
+/*
+** _md_ExportFileMapAsString()
+**
+**
+*/
+extern PRStatus _md_ExportFileMapAsString(
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+)
+{
+    PRIntn  written;
+    PRIntn  prot = (PRIntn)fm->prot;
+    
+    written = PR_snprintf( buf, bufSize, "%ld:%d",
+        fm->fd->secret->md.osfd, prot );
+        
+    return((written == -1)? PR_FAILURE : PR_SUCCESS);
+} /* end _md_ExportFileMapAsString() */
+
+
+extern PRFileMap * _md_ImportFileMapFromString(
+    const char *fmstring
+)
+{
+    PRStatus    rc;
+    PRInt32     osfd;
+    PRIntn      prot; /* really: a PRFileMapProtect */
+    PRFileDesc  *fd;
+    PRFileMap   *fm;
+    PRFileInfo  info;
+
+    PR_sscanf( fmstring, "%ld:%d", &osfd, &prot );
+
+    /* import the os file descriptor */
+    fd = PR_ImportFile( osfd );
+    if ( NULL == fd ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_ImportFile() failed"));
+        goto Finished;
+    }
+
+    rc = PR_GetOpenFileInfo( fd, &info );
+    if ( PR_FAILURE == rc )  {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_GetOpenFileInfo() failed"));    
+        goto Finished;
+    }
+
+    fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot );
+    if ( NULL == fm ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_CreateFileMap() failed"));    
+    }
+
+Finished:
+    return(fm);
+} /* end _md_ImportFileMapFromString() */
--- a/pr/src/md/windows/Makefile
+++ b/pr/src/md/windows/Makefile
@@ -43,30 +43,34 @@ CSRCS =          \
     ntsem.c   \
     ntinrval.c \
     ntgc.c \
 	w95thred.c \
 	w95io.c \
 	w95cv.c \
 	w95sock.c \
 	win32_errors.c \
+    w32ipcsem.c \
     w32poll.c \
+    w32shm.c \
     w95dllmain.c \
     $(NULL)
 else
 CSRCS =          \
     ntdllmn.c \
     ntmisc.c \
     ntsem.c   \
     ntinrval.c \
     ntgc.c \
     ntthread.c \
     ntio.c    \
 	win32_errors.c \
+    w32ipcsem.c \
     w32poll.c \
+    w32shm.c \
     $(NULL)
 endif
 endif
 
 TARGETS	= $(OBJS)
 
 INCLUDES = -I$(DIST)/include -I$(MOD_DEPTH)/pr/include -I$(MOD_DEPTH)/pr/include/private
 
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -364,96 +364,151 @@ PRInt32
                     if (completed_io->io_suspended == PR_FALSE) {
                         if (completed_io->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) {
                             _PR_SLEEPQ_LOCK(completed_io->cpu);
                             _PR_DEL_SLEEPQ(completed_io, PR_TRUE);
                             _PR_SLEEPQ_UNLOCK(completed_io->cpu);
 
                             _PR_THREAD_UNLOCK(completed_io);
 
-                            completed_io->cpu = lockedCPU;
+						/*
+						 * If an I/O operation is suspended, the thread
+						 * must be running on the same cpu on which the
+						 * I/O operation was issued.
+						 */
+						PR_ASSERT(!completed_io->md.thr_bound_cpu ||
+					(completed_io->cpu == completed_io->md.thr_bound_cpu));
+
+							if (!completed_io->md.thr_bound_cpu)
+                            	completed_io->cpu = lockedCPU;
                             completed_io->state = _PR_RUNNABLE;
-                            _PR_RUNQ_LOCK(lockedCPU);
-                            _PR_ADD_RUNQ(completed_io, lockedCPU, pri);
-                            _PR_RUNQ_UNLOCK(lockedCPU);
+                            _PR_RUNQ_LOCK(completed_io->cpu);
+                            _PR_ADD_RUNQ(completed_io, completed_io->cpu, pri);
+                            _PR_RUNQ_UNLOCK(completed_io->cpu);
                         } else {
                             _PR_THREAD_UNLOCK(completed_io);
                         }
                     } else {
                         _PR_THREAD_UNLOCK(completed_io);
                     }
                 }
             } else {
-                int old_count;
-                PRBool fNeedRelease = PR_FALSE;
-
                 /* For native threads, they are only notified through this loop
                  * when completing IO.  So, don't worry about this being a CVAR
                  * notification, because that is not possible.
                  */
                 _PR_THREAD_LOCK(completed_io);
                 completed_io->io_pending = PR_FALSE;
                 if (completed_io->io_suspended == PR_FALSE) {
                     completed_io->state = _PR_RUNNABLE;
-                    fNeedRelease = PR_TRUE;
-                }
-                _PR_THREAD_UNLOCK(completed_io);
-                if (fNeedRelease) {
+                    _PR_THREAD_UNLOCK(completed_io);
                     rv = ReleaseSemaphore(completed_io->md.blocked_sema,
-                            1, &old_count);
+                            1, NULL);
                     PR_ASSERT(0 != rv);
+                } else {
+                    _PR_THREAD_UNLOCK(completed_io);
                 }
             }
         }
 
         awoken++;
         timeout = 0;   /* Don't block on subsequent trips through the loop */
     }
 
     /* never reached */
     return 0;
 }
 
+static PRStatus
+_native_thread_md_wait(PRThread *thread, PRIntervalTime ticks)
+{
+    DWORD rv;
+	PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+		INFINITE : PR_IntervalToMilliseconds(ticks);
+
+	/*
+	 * thread waiting for a cvar or a joining thread
+	 */
+	rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
+	switch(rv) {
+		case WAIT_OBJECT_0:
+			return PR_SUCCESS;
+			break;
+		case WAIT_TIMEOUT:
+			_PR_THREAD_LOCK(thread);
+			PR_ASSERT (thread->state != _PR_IO_WAIT);
+			if (thread->wait.cvar != NULL) {
+				PR_ASSERT(thread->state == _PR_COND_WAIT);
+				thread->wait.cvar = NULL;
+				thread->state = _PR_RUNNING;
+				_PR_THREAD_UNLOCK(thread);
+			} else {
+				/* The CVAR was notified just as the timeout
+				 * occurred.  This left the semaphore in the
+				 * signaled state.  Call WaitForSingleObject()
+				 * to clear the semaphore.
+				 */
+				_PR_THREAD_UNLOCK(thread);
+				rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
+				PR_ASSERT(rv == WAIT_OBJECT_0);
+			}
+			return PR_SUCCESS;
+			break;
+		default:
+			return PR_FAILURE;
+			break;
+	}
+
+    return PR_SUCCESS;
+}
+
 PRStatus
 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
 {
     DWORD rv;
 
+	if (_native_threads_only) {
+		return(_native_thread_md_wait(thread, ticks));
+	}
     if ( thread->flags & _PR_GLOBAL_SCOPE ) {
         PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
             INFINITE : PR_IntervalToMilliseconds(ticks);
         rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
         switch(rv) {
             case WAIT_OBJECT_0:
                 return PR_SUCCESS;
                 break;
             case WAIT_TIMEOUT:
                 _PR_THREAD_LOCK(thread);
                 if (thread->state == _PR_IO_WAIT) {
                     if (thread->io_pending == PR_TRUE) {
+                        thread->state = _PR_RUNNING;
                         thread->io_suspended = PR_TRUE;
                         _PR_THREAD_UNLOCK(thread);
                     } else {
                         /* The IO completed just at the same time the timeout
-                         * occurred.  This led to us being notified twice.
-                         * call WaitForSingleObject() to clear the semaphore.
+                         * occurred.  This left the semaphore in the signaled
+                         * state.  Call WaitForSingleObject() to clear the
+                         * semaphore.
                          */
                         _PR_THREAD_UNLOCK(thread);
                         rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
                         PR_ASSERT(rv == WAIT_OBJECT_0);
                     }
                 } else {
                     if (thread->wait.cvar != NULL) {
+                        PR_ASSERT(thread->state == _PR_COND_WAIT);
                         thread->wait.cvar = NULL;
                         thread->state = _PR_RUNNING;
                         _PR_THREAD_UNLOCK(thread);
                     } else {
                         /* The CVAR was notified just as the timeout
-                         * occurred.  This led to us being notified twice.
-                         * call WaitForSingleObject() to clear the semaphore.
+                         * occurred.  This left the semaphore in the
+                         * signaled state.  Call WaitForSingleObject()
+                         * to clear the semaphore.
                          */
                         _PR_THREAD_UNLOCK(thread);
                         rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
                         PR_ASSERT(rv == WAIT_OBJECT_0);
                     }
                 }
                 return PR_SUCCESS;
                 break;
@@ -466,21 +521,160 @@ PRStatus
 
         _PR_INTSOFF(is);
         _PR_MD_SWITCH_CONTEXT(thread);
     }
 
     return PR_SUCCESS;
 }
 
+static void
+_native_thread_io_nowait(
+    PRThread *thread,
+    int rv,
+    int bytes)
+{
+    int rc;
+
+    PR_ASSERT(rv != 0);
+    _PR_THREAD_LOCK(thread);
+    if (thread->state == _PR_IO_WAIT) {
+        PR_ASSERT(thread->io_suspended == PR_FALSE);
+        PR_ASSERT(thread->io_pending == PR_TRUE);
+        thread->state = _PR_RUNNING;
+        thread->io_pending = PR_FALSE;
+        _PR_THREAD_UNLOCK(thread);
+    } else {
+        /* The IO completed just at the same time the
+         * thread was interrupted. This left the semaphore
+         * in the signaled state. Call WaitForSingleObject()
+         * to clear the semaphore.
+         */
+        PR_ASSERT(thread->io_suspended == PR_TRUE);
+        PR_ASSERT(thread->io_pending == PR_TRUE);
+        thread->io_pending = PR_FALSE;
+        _PR_THREAD_UNLOCK(thread);
+        rc = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
+        PR_ASSERT(rc == WAIT_OBJECT_0);
+    }
+
+    thread->md.blocked_io_status = rv;
+    thread->md.blocked_io_bytes = bytes;
+    rc = ResetEvent(thread->md.thr_event);
+    PR_ASSERT(rc != 0);
+    return;
+}
+
+static PRStatus
+_native_thread_io_wait(PRThread *thread, PRIntervalTime ticks)
+{
+    DWORD rv, bytes;
+#define _NATIVE_IO_WAIT_HANDLES		2
+#define _NATIVE_WAKEUP_EVENT_INDEX	0
+#define _NATIVE_IO_EVENT_INDEX		1
+
+	HANDLE wait_handles[_NATIVE_IO_WAIT_HANDLES];
+
+	PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+		INFINITE : PR_IntervalToMilliseconds(ticks);
+
+    PR_ASSERT(thread->flags & _PR_GLOBAL_SCOPE);
+
+	wait_handles[0] = thread->md.blocked_sema;
+	wait_handles[1] = thread->md.thr_event;
+	rv = WaitForMultipleObjects(_NATIVE_IO_WAIT_HANDLES, wait_handles,
+										FALSE, msecs);
+
+	switch(rv) {
+		case WAIT_OBJECT_0 + _NATIVE_IO_EVENT_INDEX:
+			/*
+			 * I/O op completed
+			 */
+			_PR_THREAD_LOCK(thread);
+			if (thread->state == _PR_IO_WAIT) {
+
+				PR_ASSERT(thread->io_suspended == PR_FALSE);
+				PR_ASSERT(thread->io_pending == PR_TRUE);
+				thread->state = _PR_RUNNING;
+				thread->io_pending = PR_FALSE;
+				_PR_THREAD_UNLOCK(thread);
+			} else {
+				/* The IO completed just at the same time the
+				 * thread was interrupted. This led to us being
+				 * notified twice. Call WaitForSingleObject()
+				 * to clear the semaphore.
+				 */
+				PR_ASSERT(thread->io_suspended == PR_TRUE);
+				PR_ASSERT(thread->io_pending == PR_TRUE);
+				thread->io_pending = PR_FALSE;
+				_PR_THREAD_UNLOCK(thread);
+				rv = WaitForSingleObject(thread->md.blocked_sema,
+							INFINITE);
+				PR_ASSERT(rv == WAIT_OBJECT_0);
+			}
+
+			rv = GetOverlappedResult((HANDLE) thread->io_fd,
+				&thread->md.overlapped.overlapped, &bytes, FALSE);
+
+			thread->md.blocked_io_status = rv;
+			if (rv != 0) {
+				thread->md.blocked_io_bytes = bytes;
+			} else {
+				thread->md.blocked_io_error = GetLastError();
+				PR_ASSERT(ERROR_IO_PENDING != thread->md.blocked_io_error);
+			}
+			rv = ResetEvent(thread->md.thr_event);
+			PR_ASSERT(rv != 0);
+			break;
+		case WAIT_OBJECT_0 + _NATIVE_WAKEUP_EVENT_INDEX:
+			/*
+			 * I/O interrupted; 
+			 */
+#ifdef DEBUG
+			_PR_THREAD_LOCK(thread);
+			PR_ASSERT(thread->io_suspended == PR_TRUE);
+			_PR_THREAD_UNLOCK(thread);
+#endif
+			break;
+		case WAIT_TIMEOUT:
+			_PR_THREAD_LOCK(thread);
+			if (thread->state == _PR_IO_WAIT) {
+				thread->state = _PR_RUNNING;
+				thread->io_suspended = PR_TRUE;
+				_PR_THREAD_UNLOCK(thread);
+			} else {
+				/*
+				 * The thread was interrupted just as the timeout
+				 * occurred. This left the semaphore in the signaled
+				 * state. Call WaitForSingleObject() to clear the
+				 * semaphore.
+				 */
+				PR_ASSERT(thread->io_suspended == PR_TRUE);
+				_PR_THREAD_UNLOCK(thread);
+				rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
+				PR_ASSERT(rv == WAIT_OBJECT_0);
+			}
+			break;
+		default:
+			return PR_FAILURE;
+			break;
+	}
+
+    return PR_SUCCESS;
+}
+
+
 static PRStatus
 _NT_IO_WAIT(PRThread *thread, PRIntervalTime timeout)
 {
     PRBool fWait = PR_TRUE;
 
+	if (_native_threads_only) {
+		return(_native_thread_io_wait(thread, timeout));
+	}
     if (!_PR_IS_NATIVE_THREAD(thread))  {
 
         _PR_THREAD_LOCK(thread);
 
         /* The IO may have already completed; if so, don't add to sleepQ, 
          * since we are already on the runQ!
          */
         if (thread->io_pending == PR_TRUE) {
@@ -505,25 +699,40 @@ static PRStatus
  * On return, the thread lock is released.
  */
 void _PR_Unblock_IO_Wait(PRThread *thr)
 {
     PRStatus rv;
     _PRCPU *cpu = thr->cpu;
  
     PR_ASSERT(thr->state == _PR_IO_WAIT);
+	/*
+	 * A thread for which an I/O timed out or was interrupted cannot be
+	 * in an IO_WAIT state except as a result of calling PR_Close or
+	 * PR_NT_CancelIo for the FD. For these two cases, _PR_IO_WAIT state
+	 * is not interruptible
+	 */
+	if (thr->md.interrupt_disabled == PR_TRUE) {
+    	_PR_THREAD_UNLOCK(thr);
+		return;
+	}
     thr->io_suspended = PR_TRUE;
     thr->state = _PR_RUNNABLE;
 
     if (!_PR_IS_NATIVE_THREAD(thr)) {
         PRThread *me = _PR_MD_CURRENT_THREAD();
         PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ));
         _PR_SLEEPQ_LOCK(cpu);
         _PR_DEL_SLEEPQ(thr, PR_TRUE);
         _PR_SLEEPQ_UNLOCK(cpu);
+		/*
+		 * this thread will continue to run on the same cpu until the
+		 * I/O is aborted by closing the FD or calling CancelIO
+		 */
+		thr->md.thr_bound_cpu = me->cpu;
 
         PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD));
         _PR_AddThreadToRunQ(me, thr);
     }
     _PR_THREAD_UNLOCK(thr);
     rv = _PR_MD_WAKEUP_WAITER(thr);
     PR_ASSERT(PR_SUCCESS == rv);
 }
@@ -550,18 +759,22 @@ static PRStatus
     }
     /* We don't put ourselves back on the sleepQ yet; until we 
      * set the suspended bit to false, we can't do that.  Just save
      * the sleep time here, and then continue.  The restarted_io handler
      * will add us to the sleepQ if needed.
      */
     thread->sleep = ticks;
 
-    if (fWait)
-        return _PR_MD_WAIT(thread, ticks);
+    if (fWait) {
+        if (!_PR_IS_NATIVE_THREAD(thread))
+            return _PR_MD_WAIT(thread, ticks);
+        else
+            return _NT_IO_WAIT(thread, ticks);
+    }
     return PR_SUCCESS;
 }
 
 PRStatus
 _PR_MD_WAKEUP_WAITER(PRThread *thread)
 {
     if (thread == NULL) {
         /* If thread is NULL, we aren't waking a thread, we're just poking
@@ -733,23 +946,27 @@ static void
  * Associates a file with the completion port.
  * Returns 0 on failure, 1 on success.
  */
 PRInt32
 _md_Associate(HANDLE file)
 {
     HANDLE port;
 
-    port = CreateIoCompletionPort((HANDLE)file, 
-                                    _pr_completion_port, 
-                                    KEY_IO,
-                                    0);
-
-    /* XXX should map error codes on failures */
-    return (port == _pr_completion_port);
+	if (!_native_threads_only) {
+		port = CreateIoCompletionPort((HANDLE)file, 
+										_pr_completion_port, 
+										KEY_IO,
+										0);
+
+		/* XXX should map error codes on failures */
+		return (port == _pr_completion_port);
+	} else {
+		return 1;
+	}
 }
 
 /*
  * _md_MakeNonblock()
  * Make a socket nonblocking.
  * Returns 0 on failure, 1 on success.
  */
 static PRInt32
@@ -1109,38 +1326,60 @@ PRInt32
         }
     }
 
     accept_sock = _md_get_recycled_socket();
     if (accept_sock == INVALID_SOCKET)
         return -1;
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
- 
+	if (_native_threads_only)
+		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
     me->io_pending = PR_TRUE;
+    me->state = _PR_IO_WAIT;
+    _PR_THREAD_UNLOCK(me);
     me->io_fd = osfd;
-    me->state = _PR_IO_WAIT;
+
     rv = AcceptEx((SOCKET)osfd,
                   accept_sock,
                   me->md.acceptex_buf,
                   0,
                   INET_ADDR_PADDED,
                   INET_ADDR_PADDED,
                   &bytes,
                   &(me->md.overlapped.overlapped));
 
     if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING))  {
         /* Argh! The IO failed */
-        me->io_pending = PR_FALSE;
-        me->state = _PR_RUNNING;
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return -1;
+		}
+		_PR_THREAD_UNLOCK(me);
+
 		_PR_MD_MAP_ACCEPTEX_ERROR(err);
         return -1;
     }
 
-    if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+    if (_native_threads_only && rv) {
+        _native_thread_io_nowait(me, rv, bytes);
+    } else if (_NT_IO_WAIT(me, 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)) {
@@ -1220,37 +1459,59 @@ PRInt32
         sd->secret->md.io_model_committed = PR_TRUE;
     }
 
     *newSock = _md_get_recycled_socket();
     if (*newSock == INVALID_SOCKET)
         return -1;
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
- 
+	if (_native_threads_only)
+		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
     me->io_pending = PR_TRUE;
+    me->state = _PR_IO_WAIT;
+    _PR_THREAD_UNLOCK(me);
     me->io_fd = sock;
-    me->state = _PR_IO_WAIT;
+
     rv = AcceptEx((SOCKET)sock,
                   *newSock,
                   buf,
                   amount,
                   INET_ADDR_PADDED,
                   INET_ADDR_PADDED,
                   &bytes,
                   &(me->md.overlapped.overlapped));
 
     if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) {
-        me->io_pending = PR_FALSE;
-        me->state = _PR_RUNNING;
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return -1;
+		}
+		_PR_THREAD_UNLOCK(me);
+
 		_PR_MD_MAP_ACCEPTEX_ERROR(err);
         return -1;
     }
 
-    if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+    if (_native_threads_only && rv) {
+        _native_thread_io_nowait(me, rv, bytes);
+    } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
         PR_ASSERT(0);
         return -1;
     }
 
 retry:
     if (me->io_suspended) {
         PRInt32 err;
         INT seconds;
@@ -1338,30 +1599,30 @@ retry:
             (unsigned int *)&rlen);
 
     PR_ASSERT(me->io_pending == PR_FALSE);
 
     return me->md.blocked_io_bytes;
 }
 
 PRInt32
-_PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen, 
-                    PRInt32 flags, PRIntervalTime timeout)
+_PR_MD_SENDFILE(PRFileDesc *sock, PRSendFileData *sfd,
+					PRInt32 flags, PRIntervalTime timeout)
 {
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRInt32 tflags;
     int rv, err;
 
     if (!_nt_use_async) {
         if (!sock->secret->md.io_model_committed) {
             rv = _md_MakeNonblock((HANDLE)sock->secret->md.osfd);
             PR_ASSERT(0 != rv);
             sock->secret->md.io_model_committed = PR_TRUE;
         }
-        return _PR_EmulateTransmitFile(sock, file, headers, hlen, flags, timeout);
+        return _PR_EmulateSendFile(sock, sfd, flags, timeout);
     }
 
     if (me->io_suspended) {
         PR_SetError(PR_INVALID_STATE_ERROR, 0);
         return -1;
     }
 
     if (!sock->secret->md.io_model_committed) {
@@ -1371,40 +1632,61 @@ PRInt32
     }
     if (!me->md.xmit_bufs) {
         me->md.xmit_bufs = PR_NEW(TRANSMIT_FILE_BUFFERS);
         if (!me->md.xmit_bufs) {
             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
             return -1;
         }
     }
-    me->md.xmit_bufs->Head       = (void *)headers;
-    me->md.xmit_bufs->HeadLength = hlen;
-    me->md.xmit_bufs->Tail       = (void *)NULL;
-    me->md.xmit_bufs->TailLength = 0;
+    me->md.xmit_bufs->Head       = (void *)sfd->header;
+    me->md.xmit_bufs->HeadLength = sfd->hlen;
+    me->md.xmit_bufs->Tail       = (void *)sfd->trailer;
+    me->md.xmit_bufs->TailLength = sfd->tlen;
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
+    me->md.overlapped.overlapped.Offset = sfd->file_offset;
+	if (_native_threads_only)
+		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
 
     tflags = 0;
     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
         tflags = TF_DISCONNECT | TF_REUSE_SOCKET;
 
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
     me->io_pending = PR_TRUE;
-    me->io_fd = sock->secret->md.osfd;
     me->state = _PR_IO_WAIT;
+    _PR_THREAD_UNLOCK(me);
+    me->io_fd = sock->secret->md.osfd;
+
     rv = TransmitFile((SOCKET)sock->secret->md.osfd,
-                      (HANDLE)file->secret->md.osfd,
-                      (DWORD)0,
+                      (HANDLE)sfd->fd->secret->md.osfd,
+                      (DWORD)sfd->file_nbytes,
                       (DWORD)0,
                       (LPOVERLAPPED)&(me->md.overlapped.overlapped),
                       (TRANSMIT_FILE_BUFFERS *)me->md.xmit_bufs,
                       (DWORD)tflags);
     if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
-        me->io_pending = PR_FALSE;
-        me->state = _PR_RUNNING;
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return -1;
+		}
+		_PR_THREAD_UNLOCK(me);
+
 		_PR_MD_MAP_TRANSMITFILE_ERROR(err);
         return -1;
     }
 
     if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
         PR_ASSERT(0);
         return -1;
     }
@@ -1460,35 +1742,57 @@ PRInt32
 
     if (!fd->secret->md.io_model_committed) {
         rv = _md_Associate((HANDLE)osfd);
         PR_ASSERT(0 != rv);
         fd->secret->md.io_model_committed = PR_TRUE;
     }
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
-
+	if (_native_threads_only)
+		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
     me->io_pending = PR_TRUE;
+    me->state = _PR_IO_WAIT;
+    _PR_THREAD_UNLOCK(me);
     me->io_fd = osfd;
-    me->state = _PR_IO_WAIT;
+
     rv = ReadFile((HANDLE)osfd,
                   buf, 
                   amount,
                   &bytes,
                   &(me->md.overlapped.overlapped));
     if ( (rv == 0) && (GetLastError() != ERROR_IO_PENDING) ) {
+    	_PR_THREAD_LOCK(me);
         me->io_pending = PR_FALSE;
         me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return -1;
+		}
+		_PR_THREAD_UNLOCK(me);
+
         if ((err = GetLastError()) == ERROR_HANDLE_EOF)
             return 0;
 		_PR_MD_MAP_READ_ERROR(err);
         return -1;
     }
 
-    if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+    if (_native_threads_only && rv) {
+        _native_thread_io_nowait(me, rv, bytes);
+    } else if (_NT_IO_WAIT(me, 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)) {
@@ -1537,33 +1841,55 @@ PRInt32
 
     if (!fd->secret->md.io_model_committed) {
         rv = _md_Associate((HANDLE)osfd);
         PR_ASSERT(0 != rv);
         fd->secret->md.io_model_committed = PR_TRUE;
     }
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
-
+	if (_native_threads_only)
+		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
     me->io_pending = PR_TRUE;
+    me->state = _PR_IO_WAIT;
+    _PR_THREAD_UNLOCK(me);
     me->io_fd = osfd;
-    me->state = _PR_IO_WAIT;
+
     rv = WriteFile((HANDLE)osfd,
                    buf, 
                    amount,
                    &bytes,
                    &(me->md.overlapped.overlapped));
     if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
+    	_PR_THREAD_LOCK(me);
         me->io_pending = PR_FALSE;
         me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return -1;
+		}
+		_PR_THREAD_UNLOCK(me);
+
 		_PR_MD_MAP_WRITE_ERROR(err);
         return -1;
     }
 
-    if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+    if (_native_threads_only && rv) {
+        _native_thread_io_nowait(me, rv, bytes);
+    } else if (_NT_IO_WAIT(me, 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)) {
@@ -1840,17 +2166,16 @@ PRInt32
                           flags,
                           flag6,
                           NULL);
         if (file == INVALID_HANDLE_VALUE) {
             _PR_MD_MAP_OPEN_ERROR(GetLastError());
             return -1; 
         }
 
-        /* Note: we didn't bother putting it in nonblocking mode */
         return (PRInt32)file;
     }
 }
 
 PRInt32 
 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
 {
     PRInt32 f = fd->secret->md.osfd;
@@ -1897,35 +2222,58 @@ PRInt32
             }
         } 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;
+			if (_native_threads_only)
+        		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+			_PR_THREAD_LOCK(me);
+			if (_PR_PENDING_INTERRUPT(me)) {
+				me->flags &= ~_PR_INTERRUPT;
+				PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+				_PR_THREAD_UNLOCK(me);
+				return -1;
+			}
+			me->io_pending = PR_TRUE;
+			me->state = _PR_IO_WAIT;
+			_PR_THREAD_UNLOCK(me);
+			me->io_fd = f;
+
             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;
+				_PR_THREAD_LOCK(me);
+				me->io_pending = PR_FALSE;
+				me->state = _PR_RUNNING;
+				if (_PR_PENDING_INTERRUPT(me)) {
+					me->flags &= ~_PR_INTERRUPT;
+					PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+					_PR_THREAD_UNLOCK(me);
+					return -1;
+				}
+				_PR_THREAD_UNLOCK(me);
+
                 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) {
+            if (_native_threads_only && rv) {
+                _native_thread_io_nowait(me, rv, bytes);
+            } else 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)) {
@@ -2015,33 +2363,55 @@ PRInt32
             _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;
+			if (_native_threads_only)
+        		me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+			_PR_THREAD_LOCK(me);
+			if (_PR_PENDING_INTERRUPT(me)) {
+				me->flags &= ~_PR_INTERRUPT;
+				PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+				_PR_THREAD_UNLOCK(me);
+				return -1;
+			}
+			me->io_pending = PR_TRUE;
+			me->state = _PR_IO_WAIT;
+			_PR_THREAD_UNLOCK(me);
+			me->io_fd = f;
+
             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_THREAD_LOCK(me);
+				me->io_pending = PR_FALSE;
+				me->state = _PR_RUNNING;
+				if (_PR_PENDING_INTERRUPT(me)) {
+					me->flags &= ~_PR_INTERRUPT;
+					PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+					_PR_THREAD_UNLOCK(me);
+					return -1;
+				}
+				_PR_THREAD_UNLOCK(me);
+
                 _PR_MD_MAP_WRITE_ERROR(err);
                 return -1;
             }
 
-            if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+            if (_native_threads_only && rv) {
+                _native_thread_io_nowait(me, rv, bytes);
+            } else 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)) {
@@ -2187,73 +2557,74 @@ PRInt32
     }
     return 0;
 }
 
 PRInt32
 _PR_MD_CLOSE(PRInt32 osfd, PRBool socket)
 {
     PRInt32 rv;
-    PRInt32 err;
     if (_nt_use_async) {
         PRThread *me = _PR_MD_CURRENT_THREAD();
 
         if (socket)  {
             rv = closesocket((SOCKET)osfd);
 			if (rv < 0)
-				err = WSAGetLastError();
+				_PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
         } else {
             rv = CloseHandle((HANDLE)osfd)?0:-1;
 			if (rv < 0)
-				err = GetLastError();
+				_PR_MD_MAP_CLOSE_ERROR(GetLastError());
 		}
 
-        if (rv == 0 && me->io_pending) {
+        if (rv == 0 && me->io_suspended) {
             if (me->io_fd == osfd) {
                 PRBool fWait;
 
-                PR_ASSERT(me->io_suspended == PR_TRUE);
                 _PR_THREAD_LOCK(me);
                 me->state = _PR_IO_WAIT;
                 /* The IO could have completed on another thread just after
                  * calling closesocket while the io_suspended flag was true.  
                  * So we now grab the lock to do a safe check on io_pending to
-                 * see if we need to wait or not.  At this point we can check
-                 * io_pending safely because we've reset io_suspended to FALSE.  
-                 * XXXMB - 1-15-97 this seems fishy and begging for a race...
+                 * see if we need to wait or not.
                  */
                 fWait = me->io_pending;
                 me->io_suspended = PR_FALSE;
+                me->md.interrupt_disabled = PR_TRUE;
                 _PR_THREAD_UNLOCK(me);
 
                 if (fWait)
                     _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
                 PR_ASSERT(me->io_suspended ==  PR_FALSE);
                 PR_ASSERT(me->io_pending ==  PR_FALSE);
+				/*
+				 * I/O operation is no longer pending; the thread can now
+				 * run on any cpu
+				 */
+                _PR_THREAD_LOCK(me);
+                me->md.interrupt_disabled = PR_FALSE;
+				me->md.thr_bound_cpu = NULL;
                 me->io_suspended = PR_FALSE;
                 me->io_pending = PR_FALSE;
                 me->state = _PR_RUNNING;
+                _PR_THREAD_UNLOCK(me);
             }
-            } else {
-                me->io_suspended = PR_FALSE;
-			if (rv < 0)
-				_PR_MD_MAP_CLOSE_ERROR(err);
         }
-        return rv;
     } else { 
         if (socket) {
             rv = closesocket((SOCKET)osfd);
 			if (rv == -1)
 				_PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
         } else {
             rv = CloseHandle((HANDLE)osfd)?0:-1;
 			if (rv == -1)
 				_PR_MD_MAP_CLOSE_ERROR(GetLastError());
 		}
     }
+    return rv;
 }
 
 PRStatus
 _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
 {
     BOOL rv;
 
     if (fd->secret->md.io_model_committed) {
@@ -2799,25 +3170,55 @@ PRStatus
 
     if (me->io_suspended) {
         PR_SetError(PR_INVALID_STATE_ERROR, 0);
         return PR_FAILURE;
     }
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
 
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
+    me->io_pending = PR_TRUE;
     me->state = _PR_IO_WAIT;
-    me->io_pending = PR_TRUE;
+    _PR_THREAD_UNLOCK(me);
+
     rv = LockFileEx((HANDLE)f, 
                     LOCKFILE_EXCLUSIVE_LOCK,
                     0,
                     0x7fffffff,
                     0,
                     &me->md.overlapped.overlapped);
 
+    if (_native_threads_only) {
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return PR_FAILURE;
+		}
+		_PR_THREAD_UNLOCK(me);
+
+        if (rv == FALSE) {
+            err = GetLastError();
+            PR_ASSERT(err != ERROR_IO_PENDING);
+            _PR_MD_MAP_LOCKF_ERROR(err);
+            return PR_FAILURE;
+        }
+        return PR_SUCCESS;
+    }
+
     /* HACK AROUND NT BUG
      * NT 3.51 has a bug.  In NT 3.51, if LockFileEx returns true, you
      * don't get any completion on the completion port.  This is a bug.
      *
      * They fixed it on NT4.0 so that you do get a completion.
      *
      * If we pretend we won't get a completion, NSPR gets confused later
      * when the unexpected completion arrives.  If we assume we do get
@@ -2830,18 +3231,27 @@ PRStatus
      *      - running NT 4.0
      *      - running NT 3.51 with a service pack greater than 5.
      * 
      * In the meantime, this code may not work on network file systems.
      *
      */
 
     if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) {
-        me->io_pending = PR_FALSE;
-        me->state = _PR_RUNNING;
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return PR_FAILURE;
+		}
+		_PR_THREAD_UNLOCK(me);
+
 		_PR_MD_MAP_LOCKF_ERROR(err);
         return PR_FAILURE;
     }
 #ifdef _NEED_351_FILE_LOCKING_HACK
     else if (rv)  {
         /* If this is NT 3.51 and the file is local, then we won't get a 
          * completion back from LockFile when it succeeded.
          */
@@ -2851,18 +3261,20 @@ PRStatus
                 me->state = _PR_RUNNING;
                 return PR_SUCCESS; 
             }
         }
     }
 #endif /* _NEED_351_FILE_LOCKING_HACK */
 
     if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+		_PR_THREAD_LOCK(me);
         me->io_pending = PR_FALSE;
         me->state = _PR_RUNNING;
+		_PR_THREAD_UNLOCK(me);
         return PR_FAILURE;
     }
 
     if (me->md.blocked_io_status == 0) {
 		_PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error);
         return PR_FAILURE;
     }
 
@@ -2877,48 +3289,104 @@ PRStatus
 
     if (me->io_suspended) {
         PR_SetError(PR_INVALID_STATE_ERROR, 0);
         return PR_FAILURE;
     }
 
     memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
 
+    _PR_THREAD_LOCK(me);
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+    	_PR_THREAD_UNLOCK(me);
+		return -1;
+	}
+    me->io_pending = PR_TRUE;
     me->state = _PR_IO_WAIT;
-    me->io_pending = PR_TRUE;
+    _PR_THREAD_UNLOCK(me);
+
     rv = LockFileEx((HANDLE)f, 
                     LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK,
                     0,
                     0x7fffffff,
                     0,
                     &me->md.overlapped.overlapped);
+    if (_native_threads_only) {
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return PR_FAILURE;
+		}
+		_PR_THREAD_UNLOCK(me);
+
+        if (rv == FALSE) {
+            err = GetLastError();
+            PR_ASSERT(err != ERROR_IO_PENDING);
+            _PR_MD_MAP_LOCKF_ERROR(err);
+            return PR_FAILURE;
+        }
+        return PR_SUCCESS;
+    }
     if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) {
-        me->io_pending = PR_FALSE;
-        me->state = _PR_RUNNING;
-		_PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error);
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return PR_FAILURE;
+		}
+		_PR_THREAD_UNLOCK(me);
+
+        _PR_MD_MAP_LOCKF_ERROR(err);
         return PR_FAILURE;
     }
 #ifdef _NEED_351_FILE_LOCKING_HACK
     else if (rv)  {
         /* If this is NT 3.51 and the file is local, then we won't get a 
          * completion back from LockFile when it succeeded.
          */
         if (_nt_version_gets_lockfile_completion == PR_FALSE) {
             if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) {
-                me->io_pending = PR_FALSE;
-                me->state = _PR_RUNNING;
+				_PR_THREAD_LOCK(me);
+				me->io_pending = PR_FALSE;
+				me->state = _PR_RUNNING;
+				if (_PR_PENDING_INTERRUPT(me)) {
+					me->flags &= ~_PR_INTERRUPT;
+					PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+					_PR_THREAD_UNLOCK(me);
+					return PR_FAILURE;
+				}
+				_PR_THREAD_UNLOCK(me);
+
                 return PR_SUCCESS; 
             }
         }
     }
 #endif /* _NEED_351_FILE_LOCKING_HACK */
 
     if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
-        me->io_pending = PR_FALSE;
-        me->state = _PR_RUNNING;
+		_PR_THREAD_LOCK(me);
+		me->io_pending = PR_FALSE;
+		me->state = _PR_RUNNING;
+		if (_PR_PENDING_INTERRUPT(me)) {
+			me->flags &= ~_PR_INTERRUPT;
+			PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+			_PR_THREAD_UNLOCK(me);
+			return PR_FAILURE;
+		}
+		_PR_THREAD_UNLOCK(me);
+
         return PR_FAILURE;
     }
 
     if (me->md.blocked_io_status == 0) {
 		_PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error);
         return PR_FAILURE;
     }
 
@@ -3175,16 +3643,59 @@ PRInt32 IsFileLocal(HANDLE hFile)
 }
 #endif /* _NEED_351_FILE_LOCKING_HACK */
 
 PR_IMPLEMENT(void) PR_NT_UseNonblock()
 {
     _nt_use_async = 0;
 }
 
+PR_IMPLEMENT(PRStatus) PR_NT_CancelIo(PRFileDesc *fd)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRBool fWait;
+	PRFileDesc *bottom;
+
+	bottom = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
+    if (!me->io_suspended || (NULL == bottom) ||
+					(me->io_fd != bottom->secret->md.osfd)) {
+        PR_SetError(PR_INVALID_STATE_ERROR, 0);
+        return PR_FAILURE;
+    }
+	/*
+	 * The CancelIO operation has to be issued by the same NT thread that
+	 * issued the I/O operation
+	 */
+	PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || (me->cpu == me->md.thr_bound_cpu));
+	if (me->io_pending) {
+		if (!CancelIo((HANDLE)bottom->secret->md.osfd)) {
+			PR_SetError(PR_INVALID_STATE_ERROR, GetLastError());
+			return PR_FAILURE;
+		}
+	}
+	_PR_THREAD_LOCK(me);
+	fWait = me->io_pending;
+	me->io_suspended = PR_FALSE;
+	me->state = _PR_IO_WAIT;
+	me->md.interrupt_disabled = PR_TRUE;
+	_PR_THREAD_UNLOCK(me);
+	if (fWait)
+		_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
+	me->md.thr_bound_cpu = NULL;
+	PR_ASSERT(me->io_suspended ==  PR_FALSE);
+	PR_ASSERT(me->io_pending ==  PR_FALSE);
+
+	_PR_THREAD_LOCK(me);
+	me->md.interrupt_disabled = PR_FALSE;
+    me->io_suspended = PR_FALSE;
+    me->io_pending = PR_FALSE;
+	me->state = _PR_RUNNING;
+	_PR_THREAD_UNLOCK(me);
+	return PR_SUCCESS;
+}
 
 PRInt32 _nt_nonblock_accept(PRFileDesc *fd, struct sockaddr_in *addr, int *len, PRIntervalTime timeout)
 {
     PRInt32 osfd = fd->secret->md.osfd;
     PRInt32 rv, err;
     fd_set rd;
     struct timeval tv, *tvp;
 
--- a/pr/src/md/windows/ntmisc.c
+++ b/pr/src/md/windows/ntmisc.c
@@ -558,16 +558,19 @@ PRStatus _MD_WindowsGetHostName(char *na
  *
  **********************************************************************
  */
 
 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
 {
     DWORD dwHi, dwLo;
     DWORD flProtect;
+    PRUint32    osfd;
+
+    osfd = ( fmap->fd == (PRFileDesc*)-1 )?  -1 : fmap->fd->secret->md.osfd;
 
     dwLo = (DWORD) (size & 0xffffffff);
     dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
 
     if (fmap->prot == PR_PROT_READONLY) {
         flProtect = PAGE_READONLY;
         fmap->md.dwAccess = FILE_MAP_READ;
     } else if (fmap->prot == PR_PROT_READWRITE) {
@@ -575,42 +578,57 @@ PRStatus _MD_CreateFileMap(PRFileMap *fm
         fmap->md.dwAccess = FILE_MAP_WRITE;
     } else {
         PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY);
         flProtect = PAGE_WRITECOPY;
         fmap->md.dwAccess = FILE_MAP_COPY;
     }
 
     fmap->md.hFileMap = CreateFileMapping(
-        (HANDLE) fmap->fd->secret->md.osfd,
+        (HANDLE) osfd,
         NULL,
         flProtect,
         dwHi,
         dwLo,
         NULL);
 
     if (fmap->md.hFileMap == NULL) {
         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
         return PR_FAILURE;
     }
     return PR_SUCCESS;
 }
-
+#include "prlog.h"
+extern PRLogModuleInfo *_pr_shma_lm;
 void * _MD_MemMap(
     PRFileMap *fmap,
     PRInt64 offset,
     PRUint32 len)
 {
     DWORD dwHi, dwLo;
     void *addr;
 
     dwLo = (DWORD) (offset & 0xffffffff);
     dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff);
     if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess,
             dwHi, dwLo, len)) == NULL) {
+        {
+            LPVOID lpMsgBuf; 
+            
+            FormatMessage( 
+                FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                NULL,
+                GetLastError(),
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                (LPTSTR) &lpMsgBuf,
+                0,
+                NULL 
+            );
+            PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf ));
+        }
         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
     }
     return addr;
 }
 
 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
 {
     if (UnmapViewOfFile(addr)) {
--- a/pr/src/md/windows/ntthread.c
+++ b/pr/src/md/windows/ntthread.c
@@ -154,16 +154,23 @@ PRStatus
                     DUPLICATE_SAME_ACCESS);  /* Options */
         }
 
         /* Create the blocking IO semaphore */
         thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL);
         if (thread->md.blocked_sema == NULL) {
             return PR_FAILURE;
         }
+		if (_native_threads_only) {
+			/* Create the blocking IO semaphore */
+			thread->md.thr_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+			if (thread->md.thr_event == NULL) {
+				return PR_FAILURE;
+			}
+		}
     }
 
     return PR_SUCCESS;
 }
 
 PRStatus 
 _PR_MD_CREATE_THREAD(PRThread *thread, 
                   void (*start)(void *), 
@@ -273,16 +280,23 @@ void
         PR_DELETE(thread->md.xmit_bufs);
     }
 
     if (thread->md.blocked_sema) {
         rv = CloseHandle(thread->md.blocked_sema);
         PR_ASSERT(rv);
         thread->md.blocked_sema = 0;
     }
+	if (_native_threads_only) {
+		if (thread->md.thr_event) {
+			rv = CloseHandle(thread->md.thr_event);
+			PR_ASSERT(rv);
+			thread->md.thr_event = 0;
+		}
+	}
 
     if (thread->md.handle) {
         rv = CloseHandle(thread->md.handle);
         PR_ASSERT(rv);
         thread->md.handle = 0;
     }
 
     /* Don't call DeleteFiber on current fiber or we'll kill the whole thread.
@@ -312,16 +326,24 @@ void
     }
 
     if (thread->md.blocked_sema) {
         rv = CloseHandle(thread->md.blocked_sema);
         PR_ASSERT(rv);
         thread->md.blocked_sema = 0;
     }
 
+	if (_native_threads_only) {
+		if (thread->md.thr_event) {
+			rv = CloseHandle(thread->md.thr_event);
+			PR_ASSERT(rv);
+			thread->md.thr_event = 0;
+		}
+	}
+
     if (thread->md.handle) {
         rv = CloseHandle(thread->md.handle);
         PR_ASSERT(rv);
         thread->md.handle = 0;
     }
 
     if (thread->flags & _PR_GLOBAL_SCOPE) {
         _MD_SET_CURRENT_THREAD(NULL);
@@ -363,17 +385,16 @@ PRThread *_PR_MD_CREATE_USER_THREAD(
     return thread;
 }
 
 void
 _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *thread)
 {
     thread->md.fiber_id = ConvertThreadToFiber(NULL);
     PR_ASSERT(thread->md.fiber_id);
-    thread->flags &= (~_PR_GLOBAL_SCOPE);
     _MD_SET_CURRENT_THREAD(thread);
     _MD_SET_LAST_THREAD(thread);
     thread->no_sched = 1;
     return;
 }
 
 void
 _PR_MD_INIT_CONTEXT(PRThread *thread, char *top, void (*start) (void), PRBool *status)
new file mode 100644
--- /dev/null
+++ b/pr/src/md/windows/w32ipcsem.c
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+ * File: w32ipcsem.c
+ * Description: implements named semaphores for NT and WIN95.
+ */
+
+#include "primpl.h"
+
+#ifndef _PR_GLOBAL_THREADS_ONLY
+
+/*
+ * A fiber cannot call WaitForSingleObject because that
+ * will block the other fibers running on the same thread.
+ * If a fiber needs to wait on a (semaphore) handle, we
+ * create a native thread to call WaitForSingleObject and
+ * have the fiber join the native thread.
+ */
+
+/*
+ * Arguments, return value, and error code for WaitForSingleObject
+ */
+struct WaitSingleArg {
+    HANDLE handle;
+    DWORD timeout;
+    DWORD rv;
+    DWORD error;
+};
+
+static void WaitSingleThread(void *arg)
+{
+    struct WaitSingleArg *warg = (struct WaitSingleArg *) arg;
+
+    warg->rv = WaitForSingleObject(warg->handle, warg->timeout);
+    if (warg->rv == WAIT_FAILED) {
+        warg->error = GetLastError();
+    }
+}
+
+static DWORD FiberSafeWaitForSingleObject(
+    HANDLE hHandle,
+    DWORD dwMilliseconds
+)
+{
+    PRThread *me = _PR_MD_CURRENT_THREAD();
+
+    if (_PR_IS_NATIVE_THREAD(me)) {
+        return WaitForSingleObject(hHandle, dwMilliseconds);
+    } else {
+        PRThread *waitThread;
+        struct WaitSingleArg warg;
+        PRStatus rv;
+
+        warg.handle = hHandle;
+        warg.timeout = dwMilliseconds;
+        waitThread = PR_CreateThread(
+            PR_USER_THREAD, WaitSingleThread, &warg,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (waitThread == NULL) {
+            return WAIT_FAILED;
+        }
+
+        rv = PR_JoinThread(waitThread);
+        PR_ASSERT(rv == PR_SUCCESS);
+        if (rv == PR_FAILURE) {
+            return WAIT_FAILED;
+        }
+        if (warg.rv == WAIT_FAILED) {
+            SetLastError(warg.error);
+        }
+        return warg.rv;
+    }
+}
+
+#endif /* !_PR_GLOBAL_THREADS_ONLY */
+
+PRSem *_PR_MD_OPEN_SEMAPHORE(
+    const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
+{
+    PRSem *sem;
+
+    sem = PR_NEW(PRSem);
+    if (sem == NULL) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return NULL;
+    }
+    if (flags & PR_SEM_CREATE) {
+        sem->sem = CreateSemaphore(NULL, value, 0x7fffffff, osname);
+        if (sem->sem == NULL) {
+            _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+            PR_DELETE(sem);
+            return NULL;
+        }
+        if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) {
+            PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS);
+            CloseHandle(sem->sem);
+            PR_DELETE(sem);
+            return NULL;
+        }
+    } else {
+        sem->sem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, osname);
+        if (sem->sem == NULL) {
+            DWORD err = GetLastError();
+
+            /*
+             * If we open a nonexistent named semaphore, NT
+             * returns ERROR_FILE_NOT_FOUND, while Win95
+             * returns ERROR_INVALID_NAME
+             */
+            if (err == ERROR_INVALID_NAME) {
+                PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+            } else {
+                _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+            }
+            PR_DELETE(sem);
+            return NULL;
+        }
+    }
+    return sem;
+}
+
+PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
+{
+    DWORD rv;
+
+#ifdef _PR_GLOBAL_THREADS_ONLY
+    rv = WaitForSingleObject(sem->sem, INFINITE);
+#else
+    rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE);
+#endif
+    PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0);
+    if (rv == WAIT_FAILED) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    if (rv != WAIT_OBJECT_0) {
+        /* Should not happen */
+        PR_SetError(PR_UNKNOWN_ERROR, 0);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
+{
+    if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) {
+        _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
+{
+    if (CloseHandle(sem->sem) == FALSE) {
+        _PR_MD_MAP_CLOSE_ERROR(GetLastError());
+        return PR_FAILURE;
+    }
+    PR_DELETE(sem);
+    return PR_SUCCESS;
+}
new file mode 100644
--- /dev/null
+++ b/pr/src/md/windows/w32shm.c
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+#include <private/primpl.h>       
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+
+#if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+extern PRSharedMemory * _MD_OpenSharedMemory( 
+        const char *name,
+        PRSize      size,
+        PRIntn      flags,
+        PRIntn      mode
+)
+{
+    char        ipcname[PR_IPC_NAME_SIZE];
+    PRStatus    rc = PR_SUCCESS;
+    DWORD dwHi, dwLo;
+    PRSharedMemory *shm;
+    DWORD flProtect = ( PAGE_READWRITE );
+
+    rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+    if ( PR_FAILURE == rc )
+    {
+        PR_SetError(PR_UNKNOWN_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid")); 
+        return(NULL);
+    }
+
+    shm = PR_NEWZAP( PRSharedMemory );
+    if ( NULL == shm ) 
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); 
+        return(NULL);
+    }
+
+    shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+    if ( NULL == shm->ipcname )
+    {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+        PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); 
+        PR_DELETE(shm);
+        return(NULL);
+    }
+
+    /* copy args to struct */
+    strcpy( shm->ipcname, ipcname );
+    shm->size = size; 
+    shm->mode = mode;
+    shm->flags = flags;
+    shm->ident = _PR_SHM_IDENT;
+
+    if (flags & PR_SHM_CREATE ) {
+        /* XXX: Not 64bit safe. Fix when WinNT goes 64bit, if ever */
+        dwHi = 0;
+        dwLo = shm->size;
+
+        shm->handle = CreateFileMapping(
+            (HANDLE)-1 ,
+            NULL,
+            flProtect,
+            dwHi,
+            dwLo,
+            shm->ipcname);
+
+        if ( NULL == shm->handle ) {
+            PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                ( "PR_OpenSharedMemory: CreateFileMapping() failed: %s",
+                    shm->ipcname )); 
+            PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
+            PR_FREEIF( shm->ipcname )
+            PR_DELETE( shm );
+            return(NULL);
+        } else {
+            if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS ))  {
+                PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                    ( "PR_OpenSharedMemory: Request exclusive & already exists",
+                        shm->ipcname )); 
+                PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
+                CloseHandle( shm->handle );
+                PR_FREEIF( shm->ipcname )
+                PR_DELETE( shm );
+                return(NULL);
+            } else {
+                PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                    ( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d",
+                        shm->ipcname, shm->handle ));
+                return(shm);
+            }
+        }
+    } else {
+        shm->handle = OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, shm->ipcname );
+        if ( NULL == shm->handle ) {
+            _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+            PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                ( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d",
+                    shm->ipcname, PR_GetOSError())); 
+            PR_FREEIF( shm->ipcname );
+            PR_DELETE( shm );
+            return(NULL);
+        } else {
+            PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, 
+                ( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d",
+                    shm->ipcname, shm->handle )); 
+                return(shm);
+        }
+    }
+    /* returns from separate paths */
+}
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    PRUint32    access = FILE_MAP_WRITE;
+    void        *addr;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    if ( PR_SHM_READONLY & flags )
+        access = FILE_MAP_READ;
+
+    addr = MapViewOfFile( shm->handle,
+        access,
+        0, 0,
+        shm->size );
+
+    if ( NULL == addr ) {
+        _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+        PR_LOG( _pr_shm_lm, PR_LOG_ERROR, 
+            ("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
+    }
+
+    return( addr );
+} /* end _MD_ATTACH_SHARED_MEMORY() */
+
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PRStatus rc = PR_SUCCESS;
+    BOOL        wrc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    wrc = UnmapViewOfFile( addr );
+    if ( FALSE == wrc ) 
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+        PR_LOG( _pr_shm_lm, PR_LOG_ERROR, 
+            ("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
+        rc = PR_FAILURE;
+    }
+
+    return( rc );
+}
+
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    PRStatus rc = PR_SUCCESS;
+    BOOL wrc;
+
+    PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+    wrc = CloseHandle( shm->handle );
+    if ( FALSE == wrc )
+    {
+        _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+        PR_LOG( _pr_shm_lm, PR_LOG_ERROR, 
+            ("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError()));
+        rc = PR_FAILURE;
+    }
+    PR_FREEIF( shm->ipcname );
+    PR_DELETE( shm );
+
+    return( rc );
+} /* end _MD_CLOSE_SHARED_MEMORY() */
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    return( PR_SUCCESS );
+}    
+
+
+/*
+** Windows implementation of anonymous memory (file) map
+*/
+extern PRLogModuleInfo *_pr_shma_lm;
+
+extern PRFileMap* _md_OpenAnonFileMap( 
+    const char *dirName,
+    PRSize      size,
+    PRFileMapProtect prot
+)
+{
+    PRFileMap   *fm;
+    HANDLE      hFileMap;
+
+    fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot );
+    if ( NULL == fm )  {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed"));
+        goto Finished;
+    }
+
+    /*
+    ** Make fm->md.hFileMap inheritable. We can't use
+    ** GetHandleInformation and SetHandleInformation
+    ** because these two functions fail with
+    ** ERROR_CALL_NOT_IMPLEMENTED on Win95.
+    */
+    if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap,
+            GetCurrentProcess(), &hFileMap,
+            0, TRUE /* inheritable */,
+            DUPLICATE_SAME_ACCESS) == FALSE) {
+        PR_SetError( PR_UNKNOWN_ERROR, GetLastError() );
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_OpenAnonFileMap(): DuplicateHandle(): failed"));
+        PR_CloseFileMap( fm );
+        fm = NULL;
+        goto Finished;
+    }
+    CloseHandle(fm->md.hFileMap);
+    fm->md.hFileMap = hFileMap;
+
+Finished:    
+    return(fm);
+} /* end md_OpenAnonFileMap() */
+
+/*
+** _md_ExportFileMapAsString()
+**
+*/
+extern PRStatus _md_ExportFileMapAsString(
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+)
+{
+    PRIntn  written;
+
+    written = PR_snprintf( buf, bufSize, "%d:%ld:%ld",
+        (PRIntn)fm->prot, (PRInt32)fm->md.hFileMap, (PRInt32)fm->md.dwAccess );
+    /* Watch out on the above snprintf(). Windows HANDLE assumes 32bits; windows calls it void* */
+
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x",
+            fm->prot, fm->md.hFileMap, fm->md.dwAccess ));
+        
+    return((written == -1)? PR_FAILURE : PR_SUCCESS);
+} /* end _md_ExportFileMapAsString() */
+
+
+/*
+** _md_ImportFileMapFromString()
+**
+*/
+extern PRFileMap * _md_ImportFileMapFromString(
+    const char *fmstring
+)
+{
+    PRIntn  prot;
+    PRInt32 hFileMap;
+    PRInt32 dwAccess;
+    PRFileMap *fm = NULL;
+
+    PR_sscanf( fmstring, "%d:%ld:%ld", &prot, &hFileMap, &dwAccess  );
+
+    fm = PR_NEWZAP(PRFileMap);
+    if ( NULL == fm ) {
+        PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+            ("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed"));
+        return(fm);
+    }
+
+    fm->prot = (PRFileMapProtect)prot;
+    fm->md.hFileMap = (HANDLE)hFileMap;  /* Assumes HANDLE is 32bit */
+    fm->md.dwAccess = (DWORD)dwAccess;
+    fm->fd = (PRFileDesc*)-1;
+
+    PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+        ("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x",
+            fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd));
+    return(fm);
+} /* end _md_ImportFileMapFromString() */
+
+#else
+Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined? 
+#endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */
+/* --- end w32shm.c --- */
--- a/pr/src/md/windows/win32_errors.c
+++ b/pr/src/md/windows/win32_errors.c
@@ -54,17 +54,17 @@ static void _MD_win32_map_default_errno(
             break;
         default:
             prError = PR_UNKNOWN_ERROR;
             break;
     }
     PR_SetError(prError, err);
 }
 
-static void _MD_win32_map_default_error(PRInt32 err)
+void _MD_win32_map_default_error(PRInt32 err)
 {
     PRErrorCode prError;
 
     switch (err) {
         case ERROR_ACCESS_DENIED:
             prError = PR_NO_ACCESS_RIGHTS_ERROR;
             break;
         case ERROR_ALREADY_EXISTS:
--- a/pr/src/memory/Makefile
+++ b/pr/src/memory/Makefile
@@ -23,17 +23,17 @@ include $(MOD_DEPTH)/config/config.mk
 
 # Disable optimization of the nspr on SunOS4.1.3
 ifeq ($(OS_ARCH),SunOS)
 ifeq ($(OS_RELEASE),4.1.3_U1)
 OPTIMIZER =
 endif
 endif
 
-CSRCS = prseg.c
+CSRCS = prseg.c prshm.c prshma.c
 
 TARGETS	= $(OBJS)
 
 INCLUDES = -I$(DIST)/include -I$(MOD_DEPTH)/pr/include -I$(MOD_DEPTH)/pr/include/private
 
 include $(MOD_DEPTH)/config/rules.mk
 
 export:: $(TARGETS)
new file mode 100644
--- /dev/null
+++ b/pr/src/memory/prshm.c
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+** prshm.c -- NSPR Named Shared Memory
+**
+** lth. Jul-1999.
+*/
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+#include <private/primpl.h>       
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+
+#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+/* SysV implementation is in pr/src/md/unix/uxshm.c */
+#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+/* Posix implementation is in pr/src/md/unix/uxshm.c */
+#elif defined PR_HAVE_WIN32_NAMED_SHARED_MEMORY
+/* Win32 implementation is in pr/src/md/windows/w32shm.c */
+#else 
+/* 
+**  there is no named_shared_memory 
+*/
+extern PRSharedMemory*  _MD_OpenSharedMemory( PRSharedMemory *shm )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}    
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}    
+#endif /* HAVE_SYSV_NAMED_SHARED_MEMORY */
+
+/*
+** FUNCTION: PR_OpenSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRSharedMemory * )
+    PR_OpenSharedMemory(
+        const char *name,
+        PRSize      size,
+        PRIntn      flags,
+        PRIntn      mode
+)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return( _PR_MD_OPEN_SHARED_MEMORY( name, size, flags, mode ));
+} /* end PR_OpenSharedMemory() */
+
+/*
+** FUNCTION: PR_AttachSharedMemory()
+**
+*/
+PR_IMPLEMENT( void * )
+    PR_AttachSharedMemory(
+        PRSharedMemory *shm,
+        PRIntn          flags
+)
+{
+    return( _PR_MD_ATTACH_SHARED_MEMORY( shm, flags ));
+} /* end PR_AttachSharedMemory() */
+
+/*
+** FUNCTION: PR_DetachSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRStatus )
+    PR_DetachSharedMemory(
+        PRSharedMemory *shm,
+        void *addr
+)
+{
+    return( _PR_MD_DETACH_SHARED_MEMORY( shm, addr ));
+} /* end PR_DetachSharedMemory() */
+
+/*
+** FUNCTION: PR_CloseSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRStatus )
+    PR_CloseSharedMemory(
+        PRSharedMemory *shm
+)
+{
+    return( _PR_MD_CLOSE_SHARED_MEMORY( shm ));
+} /* end PR_CloseSharedMemory() */
+
+/*
+** FUNCTION: PR_DeleteSharedMemory()
+**
+*/
+PR_EXTERN( PRStatus )
+    PR_DeleteSharedMemory(
+        const char *name
+)
+{
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    return(_PR_MD_DELETE_SHARED_MEMORY( name ));
+} /* end PR_DestroySharedMemory() */
+/* end prshm.c */
new file mode 100644
--- /dev/null
+++ b/pr/src/memory/prshma.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+** prshma.h -- NSPR Anonymous Shared Memory
+**
+** 
+*/
+
+#include "prtypes.h"
+#include "prshma.h"
+#include "prlog.h"
+#include "prio.h"
+#include "prprf.h"
+#include "private/primpl.h"
+
+extern PRLogModuleInfo *_pr_shma_lm;
+
+#if defined(XP_UNIX)
+/* defined in pr/src/md/unix/uxshm.c */
+#elif defined(WIN32)
+/* defined in pr/src/md/windows/w32shm.c */
+#else
+    error! ... not supported on this platform
+#endif
+
+/*
+** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory
+**
+*/
+PR_IMPLEMENT(PRFileMap*)
+PR_OpenAnonFileMap(
+    const char *dirName,
+    PRSize      size, 
+    PRFileMapProtect prot
+)
+{
+    return(_PR_MD_OPEN_ANON_FILE_MAP( dirName, size, prot ));
+} /* end PR_OpenAnonFileMap() */
+
+/*
+** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export  
+**   to my children processes via PR_CreateProcess()
+**
+**
+*/
+PR_IMPLEMENT( PRStatus) 
+PR_ProcessAttrSetInheritableFileMap( 
+    PRProcessAttr   *attr,
+    PRFileMap       *fm, 
+    const char      *shmname
+)
+{
+    PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+    return( PR_FAILURE);
+} /* end PR_ProcessAttrSetInheritableFileMap() */ 
+
+/*
+** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported
+**   by my parent process via PR_CreateProcess()
+**
+*/
+PR_IMPLEMENT( PRFileMap *)
+PR_GetInheritedFileMap( 
+    const char *shmname 
+)
+{
+    PRFileMap   *fm = NULL;
+    PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+    return( fm );
+} /* end PR_GetInhteritedFileMap() */
+
+/*
+** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap
+**
+*/
+PR_IMPLEMENT( PRStatus )
+PR_ExportFileMapAsString( 
+    PRFileMap *fm,
+    PRSize    bufSize,
+    char      *buf
+)
+{
+    return( _PR_MD_EXPORT_FILE_MAP_AS_STRING( fm, bufSize, buf ));
+} /* end PR_ExportFileMapAsString() */
+
+/*
+** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string
+**
+**
+*/
+PR_IMPLEMENT( PRFileMap * )
+PR_ImportFileMapFromString( 
+    const char *fmstring
+)
+{
+    return( _PR_MD_IMPORT_FILE_MAP_FROM_STRING(fmstring));
+} /* end PR_ImportFileMapFromString() */
+/* end prshma.c */
--- a/pr/src/misc/Makefile
+++ b/pr/src/misc/Makefile
@@ -34,26 +34,33 @@ CSRCS = \
 	prcountr.c \
 	prdtoa.c   \
 	prenv.c    \
 	prerr.c  \
 	prerror.c  \
 	prerrortable.c  \
 	prinit.c   \
 	prinrval.c \
+	pripc.c \
 	prlog2.c   \
 	prlong.c   \
 	prnetdb.c  \
 	prolock.c  \
 	prsystem.c \
 	prtime.c   \
 	prthinfo.c \
 	prtrace.c  \
 	$(NULL)
 
+ifndef USE_PTHREADS
+CSRCS += \
+	pripcsem.c \
+	$(NULL)
+endif
+
 TARGETS	= $(OBJS)
 
 INCLUDES = -I$(DIST)/include -I$(MOD_DEPTH)/pr/include -I$(MOD_DEPTH)/pr/include/private
 
 RELEASE_BINS = compile-et.pl prerr.properties
 
 include $(MOD_DEPTH)/config/rules.mk
 
--- a/pr/src/misc/pralarm.c
+++ b/pr/src/misc/pralarm.c
@@ -66,27 +66,27 @@ static PRAlarmID *pr_getNextAlarm(PRAlar
     PRAlarmID *result = id;
     PRIntervalTime now = PR_IntervalNow();
 
     if (!PR_CLIST_IS_EMPTY(&alarm->timers))
     {    
         if (id != NULL)  /* have to put this id back in */
         {        
             PRIntervalTime idDelta = now - id->nextNotify;
-            timer = &alarm->timers;
+            timer = alarm->timers.next;
             do
             {
                 result = (PRAlarmID*)timer;
                 if ((PRIntervalTime)(now - result->nextNotify) > idDelta)
                 {
                     PR_INSERT_BEFORE(&id->list, &alarm->timers);
                     break;
                 }
                 timer = timer->next;
-            } while (timer != alarm->timers.next);
+            } while (timer != &alarm->timers);
         }
         result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers));
         PR_REMOVE_LINK(timer);  /* remove it from the list */
     }
 
     return result;
 }  /* pr_getNextAlarm */
 
--- a/pr/src/misc/prinit.c
+++ b/pr/src/misc/prinit.c
@@ -24,16 +24,18 @@ PRLogModuleInfo *_pr_clock_lm;
 PRLogModuleInfo *_pr_cmon_lm;
 PRLogModuleInfo *_pr_io_lm;
 PRLogModuleInfo *_pr_cvar_lm;
 PRLogModuleInfo *_pr_mon_lm;
 PRLogModuleInfo *_pr_linker_lm;
 PRLogModuleInfo *_pr_sched_lm;
 PRLogModuleInfo *_pr_thread_lm;
 PRLogModuleInfo *_pr_gc_lm;
+PRLogModuleInfo *_pr_shm_lm;
+PRLogModuleInfo *_pr_shma_lm;
 
 PRFileDesc *_pr_stdin;
 PRFileDesc *_pr_stdout;
 PRFileDesc *_pr_stderr;
 
 #if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS)
 
 PRCList _pr_active_local_threadQ =
@@ -101,47 +103,63 @@ PR_IMPLEMENT(PRBool) PR_VersionCheck(con
                 vpatch = 10 * vpatch + *ptr - '0';
                 ptr++;
             }
         }
     }
 
     if (vmajor > PR_VMAJOR) {
         return PR_FALSE;
-    } else if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
-        return PR_FALSE;
-    } else if (vminor == PR_VMINOR && vpatch > PR_VPATCH) {
+    }
+    if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
         return PR_FALSE;
-    } else {
-        return PR_TRUE;
     }
+    if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
 }  /* PR_VersionCheck */
 
 
 PR_IMPLEMENT(PRBool) PR_Initialized(void)
 {
     return _pr_initialized;
 }
+PRInt32 _native_threads_only = 0;
+
 
 static void _PR_InitStuff(void)
 {
+#ifdef WINNT
+	char *envp;
+#endif
+
     if (_pr_initialized) return;
     _pr_initialized = PR_TRUE;
+#ifdef WINNT
+    if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) {
+        if (atoi(envp) == 1)
+            _native_threads_only = 1;
+    }
+#endif
+
 
     (void) PR_GetPageSize();
 
 	_pr_clock_lm = PR_NewLogModule("clock");
 	_pr_cmon_lm = PR_NewLogModule("cmon");
 	_pr_io_lm = PR_NewLogModule("io");
 	_pr_mon_lm = PR_NewLogModule("mon");
 	_pr_linker_lm = PR_NewLogModule("linker");
 	_pr_cvar_lm = PR_NewLogModule("cvar");
 	_pr_sched_lm = PR_NewLogModule("sched");
 	_pr_thread_lm = PR_NewLogModule("thread");
 	_pr_gc_lm = PR_NewLogModule("gc");
+	_pr_shm_lm = PR_NewLogModule("shm");
+	_pr_shma_lm = PR_NewLogModule("shma");
       
     /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ 
     _PR_MD_EARLY_INIT();
 
     _PR_InitLocks();
     _PR_InitAtomic();
     _PR_InitSegs();
     _PR_InitStacks();
@@ -158,17 +176,17 @@ static void _PR_InitStuff(void)
 #ifdef WIN16
 	{
 	PRInt32 top;   /* artificial top of stack, win16 */
     _pr_top_of_task_stack = (char *) &top;
 	}
 #endif    
 
 #ifndef _PR_GLOBAL_THREADS_ONLY
-    _PR_InitCPUs();
+	_PR_InitCPUs();
 #endif
 
 /*
  * XXX: call _PR_InitMem only on those platforms for which nspr implements
  *	malloc, for now.
  */
 #ifdef _PR_OVERRIDE_MALLOC
     _PR_InitMem();
new file mode 100644
--- /dev/null
+++ b/pr/src/misc/pripc.c
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+ * File: pripc.c
+ *
+ * Description: functions for IPC support
+ */
+
+#include "primpl.h"
+
+#include <string.h>
+
+/*
+ * A POSIX IPC name must begin with a '/'.
+ * A POSIX IPC name on Solaris cannot contain any '/' except
+ * the required leading '/'.
+ * A POSIX IPC name on HP-UX and OSF1 must be a valid pathname
+ * in the file system.
+ *
+ * The ftok() function for System V IPC requires a valid pathname
+ * in the file system.
+ *
+ * A Win32 IPC name cannot contain '\'.
+ */
+
+static void _pr_ConvertSemName(char *result)
+{
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#if defined(SOLARIS)
+    char *p;
+
+    /* Convert '/' to '_' except for the leading '/' */
+    for (p = result+1; *p; p++) {
+        if (*p == '/') {
+            *p = '_';
+        }
+    }
+    return;
+#else
+    return;
+#endif
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+    return;
+#elif defined(WIN32)
+    return;
+#endif
+}
+
+static void _pr_ConvertShmName(char *result)
+{
+#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY)
+#if defined(SOLARIS)
+    char *p;
+
+    /* Convert '/' to '_' except for the leading '/' */
+    for (p = result+1; *p; p++) {
+        if (*p == '/') {
+            *p = '_';
+        }
+    }
+    return;
+#else
+    return;
+#endif
+#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY)
+    return;
+#elif defined(WIN32)
+    return;
+#else
+    return;
+#endif
+}
+
+PRStatus _PR_MakeNativeIPCName(
+    const char *name,
+    char *result,
+    PRIntn size,
+    _PRIPCType type)
+{
+    if (strlen(name) >= (PRSize)size) {
+        PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+        return PR_FAILURE;
+    }
+    strcpy(result, name);
+    switch (type) {
+        case _PRIPCSem:
+            _pr_ConvertSemName(result);
+            break;
+        case _PRIPCShm:
+            _pr_ConvertShmName(result);
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
new file mode 100644
--- /dev/null
+++ b/pr/src/misc/pripcsem.c
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL.  You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ * 
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ * 
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
+ * Reserved.
+ */
+
+/*
+ * File: pripcsem.c
+ *
+ * Description: implements the named semaphores API in prsemipc.h
+ * for classic NSPR.  If _PR_HAVE_NAMED_SEMAPHORES is not defined,
+ * the named semaphore functions all fail with the error code
+ * PR_NOT_IMPLEMENTED_ERROR.
+ */
+
+#include "primpl.h"
+
+#ifdef _PR_PTHREADS
+
+#error "This file should not be compiled for the pthreads version"
+
+#else
+
+#ifndef _PR_HAVE_NAMED_SEMAPHORES
+
+PRSem * _PR_MD_OPEN_SEMAPHORE(
+    const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return NULL;
+}
+
+PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname)
+{
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+}
+
+#endif /* !_PR_HAVE_NAMED_SEMAPHORES */
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+    const char *name, PRIntn flags, PRIntn mode, PRUintn value)
+{
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+            == PR_FAILURE) {
+        return NULL;
+    }
+    return _PR_MD_OPEN_SEMAPHORE(osname, flags, mode, value);
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+    return _PR_MD_WAIT_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+    return _PR_MD_POST_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+    return _PR_MD_CLOSE_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+    char osname[PR_IPC_NAME_SIZE];
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+    if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+            == PR_FAILURE) {
+        return PR_FAILURE;
+    }
+    return _PR_MD_DELETE_SEMAPHORE(osname);
+}
+
+#endif /* _PR_PTHREADS */
--- a/pr/src/misc/prnetdb.c
+++ b/pr/src/misc/prnetdb.c
@@ -95,19 +95,16 @@ static sigset_t timer_set;
 PRLock* _getproto_lock = NULL;
 #endif
 
 #if defined(_PR_INET6)
 PRBool _pr_ipv6_enabled = PR_FALSE;
 #if defined(AIX)
 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
-#else
-extern const struct in6_addr in6addr_any;
-extern const struct in6_addr in6addr_loopback;
 #endif /* AIX */
 #endif /* _PR_INET6 */
 
 void _PR_InitNet(void)
 {
 #if defined(XP_UNIX)
 #ifdef HAVE_NETCONFIG
 	/*
@@ -172,29 +169,78 @@ static char *Alloc(PRIntn amount, char *
 	if (buflen < amount) {
 		return 0;
 	}
 	*bufp = buf + amount;
 	*buflenp = buflen - amount;
 	return buf;
 }
 
+#if defined(_PR_INET6)
+
+typedef enum _PRIPAddrConversion {
+    _PRIPAddrNoConversion,
+    _PRIPAddrIPv4Mapped,
+    _PRIPAddrIPv4Compat
+} _PRIPAddrConversion;
+
+/*
+** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).
+*/
+static void MakeIPv4MappedAddr(const char *v4, char *v6)
+{
+    memset(v6, 0, 10);
+    memset(v6 + 10, 0xff, 2);
+    memcpy(v6 + 12, v4, 4);
+    PR_ASSERT(IN6_IS_ADDR_V4MAPPED((struct in6_addr *) v6));
+}
+
+/*
+** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).
+*/
+static void MakeIPv4CompatAddr(const char *v4, char *v6)
+{
+    memset(v6, 0, 12);
+    memcpy(v6 + 12, v4, 4);
+    PR_ASSERT(IN6_IS_ADDR_V4COMPAT((struct in6_addr *) v6));
+}
+
+#endif /* _PR_INET6 */
+
 /*
 ** Copy a hostent, and all of the memory that it refers to into
 ** (hopefully) stacked buffers.
 */
 static PRStatus CopyHostent(
-    struct hostent *from, char *buf, PRIntn bufsize, PRHostEnt *to)
+    struct hostent *from,
+    char *buf,
+    PRIntn bufsize,
+#if defined(_PR_INET6)
+    _PRIPAddrConversion conversion,
+#endif
+    PRHostEnt *to)
 {
 	PRIntn len, na;
 	char **ap;
 
 	/* Do the easy stuff */
+#if defined(_PR_INET6)
+	if (conversion != _PRIPAddrNoConversion
+			&& from->h_addrtype == AF_INET) {
+		PR_ASSERT(from->h_length == 4);
+		to->h_addrtype = AF_INET6;
+		to->h_length = 16;
+	} else {
+		to->h_addrtype = from->h_addrtype;
+		to->h_length = from->h_length;
+	}
+#else
 	to->h_addrtype = from->h_addrtype;
 	to->h_length = from->h_length;
+#endif
 
 	/* Copy the official name */
 	if (!from->h_name) return PR_FAILURE;
 	len = strlen(from->h_name) + 1;
 	to->h_name = Alloc(len, &buf, &bufsize, 0);
 	if (!to->h_name) return PR_FAILURE;
 	memcpy(to->h_name, from->h_name, len);
 
@@ -218,17 +264,31 @@ static PRStatus CopyHostent(
 	to->h_addr_list = (char**)Alloc(
 	    na * sizeof(char*), &buf, &bufsize, sizeof(char**));
 	if (!to->h_addr_list) return PR_FAILURE;
 
 	/* Copy the addresses, one at a time */
 	for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
 		to->h_addr_list[na] = Alloc(to->h_length, &buf, &bufsize, 0);
 		if (!to->h_addr_list[na]) return PR_FAILURE;
+#if defined(_PR_INET6)
+		if (conversion != _PRIPAddrNoConversion
+				&& from->h_addrtype == AF_INET) {
+			if (conversion == _PRIPAddrIPv4Mapped) {
+				MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
+			} else {
+				PR_ASSERT(conversion == _PRIPAddrIPv4Compat);
+				MakeIPv4CompatAddr(*ap, to->h_addr_list[na]);
+			}
+		} else {
+			memcpy(to->h_addr_list[na], *ap, to->h_length);
+		}
+#else
 		memcpy(to->h_addr_list[na], *ap, to->h_length);
+#endif
 	}
 	to->h_addr_list[na] = 0;
 	return PR_SUCCESS;
 }
 
 #if !defined(_PR_HAVE_GETPROTO_R)
 /*
 ** Copy a protoent, and all of the memory that it refers to into
@@ -272,32 +332,41 @@ static PRStatus CopyProtoent(
 PR_IMPLEMENT(PRStatus) PR_GetHostByName(
     const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp)
 {
 	struct hostent *h;
 	PRStatus rv = PR_FAILURE;
 #ifdef XP_UNIX
 	sigset_t oldset;
 #endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+	int error_num;
+#endif
 
     if (!_pr_initialized) _PR_ImplicitInitialization();
 
 #ifdef XP_UNIX
 	DISABLECLOCK(&oldset);
 #endif
 	LOCK_DNS();
 
 #ifdef _PR_INET6
     if (_pr_ipv6_enabled)
     {
+#ifdef _PR_HAVE_GETHOSTBYNAME2
         h = gethostbyname2(name, AF_INET6);
         if (NULL == h)
         {
             h = gethostbyname2(name, AF_INET);
         }
+#elif defined(_PR_HAVE_GETIPNODEBYNAME)
+        h = getipnodebyname(name, AF_INET6, AI_DEFAULT, &error_num);
+#else
+#error "Unknown name-to-address translation function"
+#endif
     }
     else
     {
 #ifdef XP_OS2_VACPP
 	    h = gethostbyname((char *)name);
 #else
         h = gethostbyname(name);
 #endif
@@ -306,22 +375,139 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByName(
 #ifdef XP_OS2_VACPP
 	h = gethostbyname((char *)name);
 #else
     h = gethostbyname(name);
 #endif
 #endif /* _PR_INET6 */
     
 	if (NULL == h)
+	{
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#else
 	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+	}
 	else
 	{
+#if defined(_PR_INET6)
+		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+
+		if (_pr_ipv6_enabled) conversion = _PRIPAddrIPv4Mapped;
+		rv = CopyHostent(h, buf, bufsize, conversion, hp);
+#else
 		rv = CopyHostent(h, buf, bufsize, hp);
+#endif
 		if (PR_SUCCESS != rv)
 		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+		freehostent(h);
+#endif
+	}
+	UNLOCK_DNS();
+#ifdef XP_UNIX
+	ENABLECLOCK(&oldset);
+#endif
+	return rv;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName(
+    const char *name, PRUint16 af, PRIntn flags,
+    char *buf, PRIntn bufsize, PRHostEnt *hp)
+{
+	struct hostent *h;
+	PRStatus rv = PR_FAILURE;
+#ifdef XP_UNIX
+	sigset_t oldset;
+#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+	int error_num;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if defined(_PR_INET6)
+    PR_ASSERT(af == AF_INET || af == AF_INET6);
+    if (af != AF_INET && af != AF_INET6) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+#else
+    PR_ASSERT(af == AF_INET);
+    if (af != AF_INET) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+#endif
+
+    /*
+     * Flags other than PR_AI_DEFAULT are not yet supported.
+     */
+    PR_ASSERT(flags == PR_AI_DEFAULT);
+    if (flags != PR_AI_DEFAULT) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+#ifdef XP_UNIX
+	DISABLECLOCK(&oldset);
+#endif
+	LOCK_DNS();
+
+#ifdef _PR_INET6
+#ifdef _PR_HAVE_GETHOSTBYNAME2
+    if (af == AF_INET6)
+    {
+        h = gethostbyname2(name, af); 
+        if (NULL == h)
+        {
+            h = gethostbyname2(name, AF_INET);
+        }
+    }
+    else
+    {
+        h = gethostbyname2(name, af);
+    }
+#elif defined(_PR_HAVE_GETIPNODEBYNAME)
+    h = getipnodebyname(name, af, AI_DEFAULT, &error_num);
+#else
+#error "Unknown name-to-address translation function"
+#endif
+#else /* _PR_INET6 */
+#ifdef XP_OS2_VACPP
+	h = gethostbyname((char *)name);
+#else
+    h = gethostbyname(name);
+#endif
+#endif /* _PR_INET6 */
+    
+	if (NULL == h)
+	{
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#else
+	    PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+	}
+	else
+	{
+#if defined(_PR_INET6)
+		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+
+		if (af == AF_INET6) conversion = _PRIPAddrIPv4Mapped;
+		rv = CopyHostent(h, buf, bufsize, conversion, hp);
+#else
+		rv = CopyHostent(h, buf, bufsize, hp);
+#endif
+		if (PR_SUCCESS != rv)
+		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+		freehostent(h);
+#endif
 	}
 	UNLOCK_DNS();
 #ifdef XP_UNIX
 	ENABLECLOCK(&oldset);
 #endif
 	return rv;
 }
 
@@ -330,16 +516,19 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
 {
 	struct hostent *h;
 	PRStatus rv = PR_FAILURE;
 	const void *addr;
 	int addrlen;
 #ifdef XP_UNIX
 	sigset_t oldset;
 #endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+	int error_num;
+#endif
 
     if (!_pr_initialized) _PR_ImplicitInitialization();
 
 #ifdef XP_UNIX
 	DISABLECLOCK(&oldset);
 #endif
 	LOCK_DNS();
 #if defined(_PR_INET6)
@@ -350,28 +539,54 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
 	}
 	else
 #endif /* defined(_PR_INET6) */
 	{
 		PR_ASSERT(hostaddr->raw.family == AF_INET);
 		addr = &hostaddr->inet.ip;
 		addrlen = sizeof(hostaddr->inet.ip);
 	}
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+	h = getipnodebyaddr(addr, addrlen, hostaddr->raw.family, &error_num);
+#else
 #ifdef XP_OS2_VACPP
 	h = gethostbyaddr((char *)addr, addrlen, hostaddr->raw.family);
 #else
 	h = gethostbyaddr(addr, addrlen, hostaddr->raw.family);
 #endif
-	if (NULL == h) PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif /* _PR_INET6 && _PR_HAVE_GETIPNODEBYADDR */
+	if (NULL == h)
+	{
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+		PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#else
+		PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+	}
 	else
 	{
+#if defined(_PR_INET6)
+		_PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+		if (hostaddr->raw.family == AF_INET6) {
+			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr*)addr)) {
+				conversion = _PRIPAddrIPv4Mapped;
+			} else if (IN6_IS_ADDR_V4COMPAT((struct in6_addr*)addr)) {
+				conversion = _PRIPAddrIPv4Compat;
+			}
+		}
+		rv = CopyHostent(h, buf, bufsize, conversion, hostentry);
+#else
 		rv = CopyHostent(h, buf, bufsize, hostentry);
+#endif
 		if (PR_SUCCESS != rv) {
 		    PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
 		}
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+		freehostent(h);
+#endif
 	}
 	UNLOCK_DNS();
 #ifdef XP_UNIX
 	ENABLECLOCK(&oldset);
 #endif
 	return rv;
 }
 
@@ -569,21 +784,29 @@ PR_IMPLEMENT(PRStatus) PR_GetProtoByNumb
     return rv;
 
 }
 
 PR_IMPLEMENT(PRUintn) PR_NetAddrSize(const PRNetAddr* addr)
 {
     PRUintn addrsize;
 
+    /*
+     * RFC 2553 added a new field (sin6_scope_id) to
+     * struct sockaddr_in6.  PRNetAddr's ipv6 member has a
+     * scope_id field to match the new field.  In order to
+     * work with older implementations supporting RFC 2133,
+     * we take the size of struct sockaddr_in6 instead of
+     * addr->ipv6.
+     */
     if (AF_INET == addr->raw.family)
         addrsize = sizeof(addr->inet);
 #if defined(_PR_INET6)
     else if (AF_INET6 == addr->raw.family)
-        addrsize = sizeof(addr->ipv6);
+        addrsize = sizeof(struct sockaddr_in6);
 #endif
 #if defined(XP_UNIX)
     else if (AF_UNIX == addr->raw.family)
         addrsize = sizeof(addr->local);
 #endif
     else addrsize = 0;
 
     return addrsize;
@@ -592,38 +815,27 @@ PR_IMPLEMENT(PRUintn) PR_NetAddrSize(con
 PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt(
     PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address)
 {
     void *addr = hostEnt->h_addr_list[enumIndex++];
     memset(address, 0, sizeof(PRNetAddr));
     if (NULL == addr) enumIndex = 0;
     else
     {
+        address->raw.family = hostEnt->h_addrtype;
 #if defined(_PR_INET6)
-        if (_pr_ipv6_enabled)
+        if (AF_INET6 == hostEnt->h_addrtype)
         {
-            address->ipv6.family = AF_INET6;
             address->ipv6.port = htons(port);
-            if (AF_INET6 == hostEnt->h_addrtype)
-                memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
-            else
-            {
-                unsigned char *start = (unsigned char *) &address->ipv6.ip;
-                PR_ASSERT(AF_INET == hostEnt->h_addrtype);
-                memset(start, 0, 10);
-                memset(start + 10, 0xff, 2);
-                memcpy(start + 12, addr, hostEnt->h_length);
-                PR_ASSERT(IN6_IS_ADDR_V4MAPPED(&address->ipv6.ip));
-            }
+            memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
         }
         else
 #endif /* defined(_PR_INET6) */
         {
             PR_ASSERT(AF_INET == hostEnt->h_addrtype);
-            address->inet.family = hostEnt->h_addrtype;
             address->inet.port = htons(port);
             memcpy(&address->inet.ip, addr, hostEnt->h_length);
         }
     }
     return enumIndex;
 }  /* PR_EnumerateHostEnt */
 
 PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr(
@@ -670,16 +882,92 @@ PR_IMPLEMENT(PRStatus) PR_InitializeNetA
         default:
             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
             rv = PR_FAILURE;
         }
     }
     return rv;
 }  /* PR_InitializeNetAddr */
 
+PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
+    PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
+{
+    PRStatus rv = PR_SUCCESS;
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    addr->raw.family = af;
+#if defined(_PR_INET6)
+    if (af == AF_INET6)
+    {
+        addr->ipv6.port = htons(port);
+        switch (val)
+        {
+        case PR_IpAddrNull:
+            break;  /* don't overwrite the address */
+        case PR_IpAddrAny:
+            addr->ipv6.ip = in6addr_any;
+            break;
+        case PR_IpAddrLoopback:
+            addr->ipv6.ip = in6addr_loopback;
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = PR_FAILURE;
+        }
+    }
+    else
+#endif  /* defined(_PR_INET6) */
+    {
+        addr->inet.port = htons(port);
+        switch (val)
+        {
+        case PR_IpAddrNull:
+            break;  /* don't overwrite the address */
+        case PR_IpAddrAny:
+            addr->inet.ip = htonl(INADDR_ANY);
+            break;
+        case PR_IpAddrLoopback:
+            addr->inet.ip = htonl(INADDR_LOOPBACK);
+            break;
+        default:
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+            rv = PR_FAILURE;
+        }
+    }
+    return rv;
+}  /* PR_SetNetAddr */
+
+PR_IMPLEMENT(PRBool)
+PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
+{
+#if defined(_PR_INET6)
+    if (addr->raw.family == AF_INET6) {
+        if (val == PR_IpAddrAny
+                && IN6_IS_ADDR_UNSPECIFIED((struct in6_addr*)&addr->ipv6.ip)) {
+            return PR_TRUE;
+        } else if (val == PR_IpAddrLoopback
+                && IN6_IS_ADDR_LOOPBACK((struct in6_addr*)&addr->ipv6.ip)) {
+            return PR_TRUE;
+        }
+    }
+    else
+#endif
+    {
+        if (addr->raw.family == AF_INET) {
+            if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) {
+                return PR_TRUE;
+            } else if (val == PR_IpAddrLoopback
+                    && addr->inet.ip == htonl(INADDR_LOOPBACK)) {
+                return PR_TRUE;
+            }
+        }
+    }
+    return PR_FALSE;
+}
+
 PR_IMPLEMENT(PRNetAddr*) PR_CreateNetAddr(PRNetAddrValue val, PRUint16 port)
 {
     PRNetAddr *addr = NULL;
     if ((PR_IpAddrAny == val) || (PR_IpAddrLoopback == val))
     {
         addr = PR_NEWZAP(PRNetAddr);
         if (NULL == addr)
             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
@@ -695,90 +983,79 @@ PR_IMPLEMENT(PRNetAddr*) PR_CreateNetAdd
 PR_IMPLEMENT(PRStatus) PR_DestroyNetAddr(PRNetAddr *addr)
 {
     PR_Free(addr);
     return PR_SUCCESS;
 }  /* PR_DestroyNetAddr */
 
 PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
 {
-    /*
-    ** If we're built to support IPv6 addressing AND it's currently enabled,
-    ** then all addresses are of the IPv6 addressing family. Both are required
-    ** before anything overt happens.
-    */
-    PRStatus status = PR_InitializeNetAddr(PR_IpAddrNull, 0, addr);
-
-    PR_ASSERT(PR_SUCCESS == status);
-    if (PR_SUCCESS != status) return status;
+    PRIntn rv;
+    PRStatus status = PR_SUCCESS;
 
 #if defined(_PR_INET6)
-
-    if (_pr_ipv6_enabled)
+    rv = inet_pton(AF_INET6, string, &addr->ipv6.ip);
+    if (1 == rv)
     {
-        /*
-        ** Okay, we're doing it.
-        */
-        PRIntn rv = inet_pton(AF_INET6, string, &addr->ipv6.ip);
-        if (1 != rv)
-        {
-            /*
-             * rv is 0 if the string argument is not a valid IPv4 or IPv6
-	         * address string.
-             * rv is -1 with errno set to EADNOSUPPORT if the af argument is
-             * not a known address family.
-             */
-            PRIntn syserrno = (-1 == rv) ? errno : 0;
-            PR_SetError(PR_INVALID_ARGUMENT_ERROR, syserrno);
-            status = PR_FAILURE;
-        }
+        addr->raw.family = AF_INET6;
     }
     else
-#endif
     {
-	    PRUint32 *ip = (PRUint32*)&addr->inet.ip;
-
-#ifdef XP_OS2_VACPP
-        *ip = inet_addr((char *)string);
-#else
-        *ip = inet_addr(string);
-#endif
-	    if ((PRUint32) -1 == *ip)
+        PR_ASSERT(0 == rv);
+        rv = inet_pton(AF_INET, string, &addr->inet.ip);
+        if (1 == rv)
         {
-            /*
-             * Either the af argument is not AF_INET, or the string argument
-             * is a malformed address string.
-             */
+            addr->raw.family = AF_INET;
+        }
+        else
+        {
+            PR_ASSERT(0 == rv);
             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
             status = PR_FAILURE;
         }
     }
+#else /* _PR_INET6 */
+#ifdef XP_OS2_VACPP
+    addr->inet.ip = inet_addr((char *)string);
+#else
+    addr->inet.ip = inet_addr(string);
+#endif
+    if ((PRUint32) -1 == addr->inet.ip)
+    {
+        /*
+         * Either the af argument is not AF_INET, or the string argument
+         * is a malformed address string.
+         */
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        status = PR_FAILURE;
+    }
+#endif /* _PR_INET6 */
 
-	return status;
+    return status;
 }
 
 PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
     const PRNetAddr *addr, char *string, PRUint32 size)
 {
-    PR_ASSERT(size >= 16);
-    if (size < 16) goto failed;
-
 #if defined(_PR_INET6)
-    if (_pr_ipv6_enabled)
+    if (AF_INET6 == addr->raw.family)
     {
-        PR_ASSERT(AF_INET6 == addr->ipv6.family);
-        if ((AF_INET6 != addr->ipv6.family)
-        || (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)))
-            goto failed;
+        if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size))
+        {
+            PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno);
+            return PR_FAILURE;
+        }
     }
     else
 #endif  /* defined(_PR_INET6) */
     {
-        PR_ASSERT(AF_INET == addr->inet.family);
-        if (AF_INET != addr->inet.family) goto failed;
+        PR_ASSERT(AF_INET == addr->raw.family);
+        PR_ASSERT(size >= 16);
+        if (size < 16) goto failed;
+        if (AF_INET != addr->raw.family) goto failed;
         else
         {
             unsigned char *byte = (unsigned char*)&addr->inet.ip;
             PR_snprintf(string, size, "%u.%u.%u.%u",
                 byte[0], byte[1], byte[2], byte[3]);
         }
     }
 
--- a/pr/src/nspr.rc
+++ b/pr/src/nspr.rc
@@ -40,49 +40,49 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_U
 
 #ifndef _MAC
 /////////////////////////////////////////////////////////////////////////////
 //
 // Version
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 3,2,0,0
- PRODUCTVERSION 3,1,0,0
+ FILEVERSION 3,5,0,0
+ PRODUCTVERSION 3,5,0,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
 #else
  FILEFLAGS 0x0L
 #endif
  FILEOS 0x40004L
- FILETYPE 0x1L
+ FILETYPE 0x2L
  FILESUBTYPE 0x0L
 
 // end win16
 #endif
 
 BEGIN
     BLOCK "StringFileInfo"
     BEGIN
         BLOCK "040904b0"
         BEGIN
             VALUE "CompanyName", "Netscape Communications Corporation\0"
             VALUE "FileDescription", "Netscape Portable Run Time\0"
-            VALUE "FileVersion", "3, 1, 0, 0\0"
+            VALUE "FileVersion", "3.5\0"
 #ifdef WINNT
             VALUE "InternalName", "libnspr3\0"
             VALUE "OriginalFilename", "libnspr3.dll\0"
 #else
             VALUE "InternalName", "nspr3\0"
             VALUE "OriginalFilename", "nspr3.dll\0"
 #endif
             VALUE "LegalCopyright", "Copyright  1996\0"
             VALUE "ProductName", "Netscape Communication Corporation NSPR20\0"
-            VALUE "ProductVersion", "3, 1, 0, 0\0"
+            VALUE "ProductVersion", "3.5\0"
         END
     END
     BLOCK "VarFileInfo"
     BEGIN
         VALUE "Translation", 0x409, 1200
     END
 END
 
--- a/pr/src/prvrsion.c
+++ b/pr/src/prvrsion.c
@@ -31,16 +31,21 @@
 #endif
 #endif
 #if !defined(_BUILD_STRING)
 #define _BUILD_STRING ""
 #endif
 #if !defined(_PRODUCTION)
 #define _PRODUCTION ""
 #endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
 
 static PRVersionDescription prVersionDescription_libnspr3 =
 {
     /* version          */  2,                  /* this is the only one supported */
     /* buildTime        */  _BUILD_TIME,        /* usecs since midnight 1/1/1970 GMT */
     /* buildTimeString  */  _BUILD_STRING,       /*    ditto, but human readable */
     /* vMajor           */  PR_VMAJOR,          /* NSPR's version number */
     /* vMinor           */  PR_VMINOR,          /*  and minor version */
@@ -60,18 +65,20 @@ static PRVersionDescription prVersionDes
     /* specialString    */ ""
 };
 
 #ifdef XP_UNIX
 
 /*
  * Version information for the 'ident' and 'what commands
  */
-static char rcsid[] = "$Version: NSPR " PR_VERSION "  " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION "  " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+        "  " _BUILD_STRING;
 
 #endif /* XP_UNIX */
 
 PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void)
 {
 #ifdef XP_UNIX
     /*
      * Add dummy references to rcsid and sccsid to prevent them
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -14,17 +14,16 @@
  * Communications Corporation.  Portions created by Netscape are
  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  * Reserved.
  */
 
 /*
 ** File:   ptio.c
 ** Descritpion:  Implemenation of I/O methods for pthreads
-** Exports:   ptio.h
 */
 
 #if defined(_PR_PTHREADS)
 
 #include <pthread.h>
 #include <string.h>  /* for memset() */
 #include <sys/types.h>
 #include <dirent.h>
@@ -50,17 +49,17 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 #endif
 
 /*
  * The send_file() system call is available in AIX 4.3.2 or later.
  * If this file is compiled on an older AIX system, it attempts to
  * look up the send_file symbol at run time to determine whether
- * we can use the faster PR_TransmitFile implementation based on
+ * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
  * send_file().  On AIX 4.3.2 or later, we can safely skip this
  * runtime function dispatching and just use the send_file based
  * implementation.
  */
 #ifdef AIX
 #ifdef SF_CLOSE
 #define HAVE_SEND_FILE
 #endif
@@ -235,17 +234,21 @@ struct pt_Continuation
     union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
     union {
         PRSize amount;                      /* #3 - size of 'buffer', or */
         pt_SockLen *addr_len;                  /*    - length of address */
 #ifdef HPUX11
         /*
          * For sendfile()
          */
-        off_t offset;                       /* offset in file to send */
+		struct file_spec {		
+        	off_t offset;                       /* offset in file to send */
+        	size_t nbytes;                      /* length of file data to send */
+        	size_t st_size;                     /* file size */
+		} file_spec;
 #endif
     } arg3;
     union { PRIntn flags; } arg4;           /* #4 - read/write flags */
     union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
 
 #ifdef HPUX11
     /*
      * For sendfile()
@@ -264,27 +267,35 @@ struct pt_Continuation
     ** These function can either return an int return code or a pointer to
     ** some object.
     */
     union { PRSize code; void *object; } result;
 
     PRIntn syserrno;                        /* in case it failed, why (errno) */
     pr_ContuationStatus status;             /* the status of the operation */
     PRCondVar *complete;                    /* to notify the initiating thread */
+	PRIntn io_tq_index;                     /* io-queue index */
 };
 
 static struct pt_TimedQueue
 {
     PRLock *ml;                             /* a little protection */
     PRThread *thread;                       /* internal thread's identification */
     PRUintn op_count;                       /* number of operations in the list */
     pt_Continuation *head, *tail;           /* head/tail of list of operations */
 
     pt_Continuation *op;                    /* timed operation furthest in future */
-} pt_tq;
+    struct pollfd *pollingList;             /* list built for polling */
+    PRIntn pollingSlotsAllocated;           /* # entries available in list */
+    pt_Continuation **pollingOps;           /* list paralleling polling list */
+} *pt_tqp;  /* an array */
+
+static PRIntn _pt_num_cpus;
+PRIntn _pt_tq_count;                        /* size of the pt_tqp array */
+static PRInt32 _pt_tq_index;                /* atomically incremented */
 
 #if defined(DEBUG)
 
 PTDebug pt_debug;  /* this is shared between several modules */
 
 PR_IMPLEMENT(void) PT_GetStats(PTDebug* here) { *here = pt_debug; }
 
 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
@@ -327,285 +338,297 @@ PR_IMPLEMENT(void) PT_FPrintStats(PRFile
         debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
         stats.cvars_notified, stats.delayed_cv_deletes);
 }  /* PT_FPrintStats */
 
 #endif  /* DEBUG */
 
 /*
  * The following two functions, pt_InsertTimedInternal and
- * pt_FinishTimedInternal, are always called with the pt_tq.ml
+ * pt_FinishTimedInternal, are always called with the tqp->ml
  * lock held.  The "internal" in the functions' names come from
  * the Mesa programming language.  Internal functions are always
  * called from inside a monitor.
  */
 
 static void pt_InsertTimedInternal(pt_Continuation *op)
 {
     pt_Continuation *t_op = NULL;
     PRIntervalTime now = PR_IntervalNow();
+	struct pt_TimedQueue *tqp = &pt_tqp[op->io_tq_index];
 
 #if defined(DEBUG)
     {
         PRIntn count;
         pt_Continuation *tmp;
-        PR_ASSERT((pt_tq.head == NULL) == (pt_tq.tail == NULL));
-        PR_ASSERT((pt_tq.head == NULL) == (pt_tq.op_count == 0));
-        for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
-        for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
+        PRThread *self = PR_GetCurrentThread();
+
+        PR_ASSERT(tqp == &pt_tqp[self->io_tq_index]);
+        PR_ASSERT((tqp->head == NULL) == (tqp->tail == NULL));
+        PR_ASSERT((tqp->head == NULL) == (tqp->op_count == 0));
+        for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+        PR_ASSERT(count == tqp->op_count);
+        for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+        PR_ASSERT(count == tqp->op_count);
+        for (tmp = tqp->head; tmp != NULL; tmp = tmp->next)
+            PR_ASSERT(tmp->io_tq_index == op->io_tq_index);
     }
 #endif /* defined(DEBUG) */
 
     /*
      * If this element operation isn't timed, it gets queued at the
-     * end of the list (just after pt_tq.tail) and we're
+     * end of the list (just after tqp->tail) and we're
      * finishd early.
      */
     if (PR_INTERVAL_NO_TIMEOUT == op->timeout)
     {
-        t_op = pt_tq.tail;  /* put it at the end */
+        t_op = tqp->tail;  /* put it at the end */
         goto done;
     }
 
     /*
      * The portion of this routine deals with timed ops.
      */
     op->absolute = now + op->timeout;  /* absolute ticks */
-    if (NULL == pt_tq.op) pt_tq.op = op;
+    if (NULL == tqp->op) tqp->op = op;
     else
     {
         /*
          * To find where in the list to put the new operation, based
          * on the absolute time the operation in question will expire.
          *
          * The new operation ('op') will expire at now() + op->timeout.
          *
          * This should be easy!
          */
 
-        for (t_op = pt_tq.op; NULL != t_op; t_op = t_op->prev)
+        for (t_op = tqp->op; NULL != t_op; t_op = t_op->prev)
         {
             /*
              * If 'op' expires later than t_op, then insert 'op' just
              * ahead of t_op. Otherwise, compute when operation[n-1]
              * expires and try again.
              *
-             * The actual different between the expiriation of 'op'
+             * The actual difference between the expiriation of 'op'
              * and the current operation what becomes the new operaton's
              * timeout interval. That interval is also subtracted from
              * the interval of the operation immediately following where
              * we stick 'op' (unless the next one isn't timed). The new
              * timeout assigned to 'op' takes into account the values of
              * now() and when the previous intervals were computed.
              */
             if ((PRInt32)(op->absolute - t_op->absolute) >= 0)
             {
-                if (t_op == pt_tq.op) pt_tq.op = op;
+                if (t_op == tqp->op) tqp->op = op;
                 break;
             }
         }
     }
 
 done:
 
     /*
      * Insert 'op' into the queue just after t_op or if t_op is null,
      * at the head of the list.
      *
      * We need to set up the 'next' and 'prev' pointers of 'op'
      * correctly before inserting 'op' into the queue.  Also, we insert
-     * 'op' by updating pt_tq.head or op->prev->next first, and then
+     * 'op' by updating tqp->head or op->prev->next first, and then
      * updating op->next->prev.  We want to make sure that the 'next'
      * pointers are linked up correctly at all times so that we can
-     * traverse the queue by starting with pt_tq.head and following
-     * the 'next' pointers, without having to acquire the pt_tq.ml lock.
+     * traverse the queue by starting with tqp->head and following
+     * the 'next' pointers, without having to acquire the tqp->ml lock.
      * (we do that in pt_ContinuationThreadInternal).  We traverse the 'prev'
      * pointers only in this function, which is called with the lock held.
      *
      * Similar care is taken in pt_FinishTimedInternal where we remove
      * an op from the queue.
      */
     if (NULL == t_op)
     {
         op->prev = NULL;
-        op->next = pt_tq.head;
-        pt_tq.head = op;
-        if (NULL == pt_tq.tail) pt_tq.tail = op;
+        op->next = tqp->head;
+        tqp->head = op;
+        if (NULL == tqp->tail) tqp->tail = op;
         else op->next->prev = op;
     }
     else
     {
         op->prev = t_op;
         op->next = t_op->next;
         if (NULL != op->prev)
             op->prev->next = op;
         if (NULL != op->next)
             op->next->prev = op;
-        if (t_op == pt_tq.tail)
-            pt_tq.tail = op;
+        if (t_op == tqp->tail)
+            tqp->tail = op;
     }
 
-    pt_tq.op_count += 1;
+    tqp->op_count += 1;
 
 #if defined(DEBUG)
     {
         PRIntn count;
         pt_Continuation *tmp;
-        PR_ASSERT(pt_tq.head != NULL);
-        PR_ASSERT(pt_tq.tail != NULL);
-        PR_ASSERT(pt_tq.op_count != 0);
-        PR_ASSERT(pt_tq.head->prev == NULL);
-        PR_ASSERT(pt_tq.tail->next == NULL);
-        if (pt_tq.op_count > 1)
+        PR_ASSERT(tqp->head != NULL);
+        PR_ASSERT(tqp->tail != NULL);
+        PR_ASSERT(tqp->op_count != 0);
+        PR_ASSERT(tqp->head->prev == NULL);
+        PR_ASSERT(tqp->tail->next == NULL);
+        if (tqp->op_count > 1)
         {
-            PR_ASSERT(pt_tq.head->next != NULL);
-            PR_ASSERT(pt_tq.tail->prev != NULL);
+            PR_ASSERT(tqp->head->next != NULL);
+            PR_ASSERT(tqp->tail->prev != NULL);
         }
         else
         {
-            PR_ASSERT(pt_tq.head->next == NULL);
-            PR_ASSERT(pt_tq.tail->prev == NULL);
+            PR_ASSERT(tqp->head->next == NULL);
+            PR_ASSERT(tqp->tail->prev == NULL);
         }
-        for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
-        for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
+        for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+        PR_ASSERT(count == tqp->op_count);
+        for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+        PR_ASSERT(count == tqp->op_count);
     }
 #endif /* defined(DEBUG) */
 
 }  /* pt_InsertTimedInternal */
 
 /*
  * function: pt_FinishTimedInternal
  *
  * Takes the finished operation out of the timed queue. It
  * notifies the initiating thread that the opertions is
  * complete and returns to the caller the value of the next
  * operation in the list (or NULL).
  */
 static pt_Continuation *pt_FinishTimedInternal(pt_Continuation *op)
 {
     pt_Continuation *next;
+	struct pt_TimedQueue *tqp = &pt_tqp[op->io_tq_index];
 
 #if defined(DEBUG)
     {
         PRIntn count;
         pt_Continuation *tmp;
-        PR_ASSERT(pt_tq.head != NULL);
-        PR_ASSERT(pt_tq.tail != NULL);
-        PR_ASSERT(pt_tq.op_count != 0);
-        PR_ASSERT(pt_tq.head->prev == NULL);
-        PR_ASSERT(pt_tq.tail->next == NULL);
-        if (pt_tq.op_count > 1)
+        PR_ASSERT(tqp->head != NULL);
+        PR_ASSERT(tqp->tail != NULL);
+        PR_ASSERT(tqp->op_count != 0);
+        PR_ASSERT(tqp->head->prev == NULL);
+        PR_ASSERT(tqp->tail->next == NULL);
+        if (tqp->op_count > 1)
         {
-            PR_ASSERT(pt_tq.head->next != NULL);
-            PR_ASSERT(pt_tq.tail->prev != NULL);
+            PR_ASSERT(tqp->head->next != NULL);
+            PR_ASSERT(tqp->tail->prev != NULL);
         }
         else
         {
-            PR_ASSERT(pt_tq.head->next == NULL);
-            PR_ASSERT(pt_tq.tail->prev == NULL);
+            PR_ASSERT(tqp->head->next == NULL);
+            PR_ASSERT(tqp->tail->prev == NULL);
         }
-        for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
-        for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
+        for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+        PR_ASSERT(count == tqp->op_count);
+        for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+        PR_ASSERT(count == tqp->op_count);
     }
 #endif /* defined(DEBUG) */
 
     /* remove this one from the list */
-    if (NULL == op->prev) pt_tq.head = op->next;
+    if (NULL == op->prev) tqp->head = op->next;
     else op->prev->next = op->next;
-    if (NULL == op->next) pt_tq.tail = op->prev;
+    if (NULL == op->next) tqp->tail = op->prev;
     else op->next->prev = op->prev;
 
     /* did we happen to hit the timed op? */
-    if (op == pt_tq.op) pt_tq.op = op->prev;
+    if (op == tqp->op) tqp->op = op->prev;
 
     next = op->next;
     op->next = op->prev = NULL;
     op->status = pt_continuation_done;
 
-    pt_tq.op_count -= 1;
+    tqp->op_count -= 1;
 
 #if defined(DEBUG)
     pt_debug.continuationsServed += 1;
 #endif
     PR_NotifyCondVar(op->complete);
 
 #if defined(DEBUG)
     {
         PRIntn count;
         pt_Continuation *tmp;
-        PR_ASSERT((pt_tq.head == NULL) == (pt_tq.tail == NULL));
-        PR_ASSERT((pt_tq.head == NULL) == (pt_tq.op_count == 0));
-        for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
-        for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
-        PR_ASSERT(count == pt_tq.op_count);
+        PR_ASSERT((tqp->head == NULL) == (tqp->tail == NULL));
+        PR_ASSERT((tqp->head == NULL) == (tqp->op_count == 0));
+        for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+        PR_ASSERT(count == tqp->op_count);
+        for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+        PR_ASSERT(count == tqp->op_count);
     }
 #endif /* defined(DEBUG) */
 
     return next;
 }  /* pt_FinishTimedInternal */
 
 static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
 {
     /* initialization */
     PRInt32 msecs, mx_poll_ticks;
     PRThreadPriority priority;              /* used to save caller's prio */
     PRIntn pollingListUsed;                 /* # entries used in the list */
     PRIntn pollingListNeeded;               /* # entries needed this time */
-    static struct pollfd *pollingList = 0;  /* list built for polling */
-    static PRIntn pollingSlotsAllocated = 0;/* # entries available in list */
-    static pt_Continuation **pollingOps = 0;/* list paralleling polling list */
+    PRIntn io_tq_index = my_op->io_tq_index;
+    struct pt_TimedQueue *tqp = &pt_tqp[my_op->io_tq_index];
+    struct pollfd *pollingList = tqp->pollingList;
+    PRIntn pollingSlotsAllocated = tqp->pollingSlotsAllocated;
+    pt_Continuation **pollingOps = tqp->pollingOps;
     
-    PR_Unlock(pt_tq.ml);  /* don't need that silly lock for a bit */
-
-    priority = PR_GetThreadPriority(pt_tq.thread);
-    PR_SetThreadPriority(pt_tq.thread, PR_PRIORITY_HIGH);
+    PR_Unlock(tqp->ml);  /* don't need that silly lock for a bit */
+
+    priority = PR_GetThreadPriority(tqp->thread);
+    PR_SetThreadPriority(tqp->thread, PR_PRIORITY_HIGH);
 
     mx_poll_ticks = (PRInt32)PR_MillisecondsToInterval(PT_DEFAULT_POLL_MSEC);
 
     /* do some real work */
     while (PR_TRUE)
     {
         PRIntn rv;
         PRInt32 timeout;
         PRIntn pollIndex;
         PRIntervalTime now;
         pt_Continuation *op, *next_op;
 
-        PR_ASSERT(NULL != pt_tq.head);
-
-        pollingListNeeded = pt_tq.op_count;
+        PR_ASSERT(NULL != tqp->head);
+
+        pollingListNeeded = tqp->op_count;
 
     /*
-     * We are not holding the pt_tq.ml lock now, so more items may
+     * We are not holding the tqp->ml lock now, so more items may
      * get added to pt_tq during this window of time.  We hope
      * that 10 more spaces in the polling list should be enough.
      *
      * The space allocated is for both a vector that parallels the
      * polling list, providing pointers directly into the operation's
      * table and the polling list itself. There is a guard element
      * between the two structures.
      */
         pollingListNeeded += 10;
         if (pollingListNeeded > pollingSlotsAllocated)
         {
             if (NULL != pollingOps) PR_Free(pollingOps);
             pollingOps = (pt_Continuation**)PR_Malloc(
                 sizeof(pt_Continuation**) + pollingListNeeded * 
                     (sizeof(struct pollfd) + sizeof(pt_Continuation*)));
             PR_ASSERT(NULL != pollingOps);
+			tqp->pollingOps = pollingOps;
             pollingSlotsAllocated = pollingListNeeded;
+			tqp->pollingSlotsAllocated = pollingSlotsAllocated;
             pollingOps[pollingSlotsAllocated] = (pt_Continuation*)-1;
             pollingList = (struct pollfd*)(&pollingOps[pollingSlotsAllocated + 1]);
+			tqp->pollingList = pollingList;
             
         }
 
 #if defined(DEBUG)
         if (pollingListNeeded > pt_debug.pollingListMax)
             pt_debug.pollingListMax = pollingListNeeded;
 #endif
 
@@ -614,82 +637,88 @@ static void pt_ContinuationThreadInterna
         ** the thread state will have the PT_THREAD_ABORTED bit set. This
         ** overrides good completions as well as timeouts.
         **
         ** BTW, it does no good to hold the lock here. This lock doesn't
         ** protect the thread structure in any way. Testing the bit and
         ** (perhaps) resetting it are safe 'cause it's the only modifiable
         ** bit in that word.
         */
-        if (pt_tq.thread->state & PT_THREAD_ABORTED)
+        if (tqp->thread->state & PT_THREAD_ABORTED)
         {
             my_op->status = pt_continuation_abort;
-            pt_tq.thread->state &= ~PT_THREAD_ABORTED;
+            tqp->thread->state &= ~PT_THREAD_ABORTED;
         }
 
 
         /*
          * Build up a polling list.
          * This list is sorted on time. Operations that have been
          * interrupted are completed and not included in the list.
          * There is an assertion that the operation is in progress.
          */
         pollingListUsed = 0;
-        PR_Lock(pt_tq.ml);
-
-        for (op = pt_tq.head; NULL != op;)
+        PR_Lock(tqp->ml);
+
+        for (op = tqp->head; NULL != op;)
         {
             if (pt_continuation_abort == op->status)
             {
                 op->result.code = -1;
                 op->syserrno = EINTR;
                 next_op = pt_FinishTimedInternal(op);
                 if (op == my_op) goto recycle;
                 else op = next_op;
-                PR_ASSERT(NULL != pt_tq.head);
+                PR_ASSERT(NULL != tqp->head);
             }
             else
             {
                 op->status = pt_continuation_pending;
                 if (pollingListUsed >= pollingSlotsAllocated)
                 {
 #if defined(DEBUG)
                     pt_debug.predictionsFoiled += 1;
 #endif
                     break;
                 }
                 PR_ASSERT((pt_Continuation*)-1 == pollingOps[pollingSlotsAllocated]);
-                op->fd->secret->eventMask = 0xffff;
+                /*
+                 * eventMask bitmasks are declared as PRIntn so that
+                 * each bitmask can be updated individually without
+                 * disturbing adjacent memory, but only the lower 16
+                 * bits of a bitmask are used.
+                 */
+                op->fd->secret->eventMask[io_tq_index] = 0xffff;
                 pollingOps[pollingListUsed] = op;
                 pollingList[pollingListUsed].revents = 0;
                 pollingList[pollingListUsed].fd = op->arg1.osfd;
                 pollingList[pollingListUsed].events = op->event;
                 pollingListUsed += 1;
                 op = op->next;
             }
         }
 
         /*
          * We don't want to wait forever on this poll. So keep
          * the interval down. The operations, if they are timed,
          * still have to timeout, while those that are not timed
          * should persist forever. But they may be aborted. That's
          * what this anxiety is all about.
          */
-        if (PR_INTERVAL_NO_TIMEOUT == pt_tq.head->timeout)
+        if (PR_INTERVAL_NO_TIMEOUT == tqp->head->timeout)
             msecs = PT_DEFAULT_POLL_MSEC;
         else
         {
-            timeout = pt_tq.head->absolute - PR_IntervalNow();
+            timeout = tqp->head->absolute - PR_IntervalNow();
             if (timeout <= 0) msecs = 0;  /* already timed out */
             else if (timeout >= mx_poll_ticks) msecs = PT_DEFAULT_POLL_MSEC;
             else msecs = (PRInt32)PR_IntervalToMilliseconds(timeout);
         }
 
-        PR_Unlock(pt_tq.ml);
+        PR_Unlock(tqp->ml);
 
         /*
          * If 'op' isn't NULL at this point, then we didn't get to
          * the end of the list. That means that more items got added
          * to the list than we anticipated. So, forget this iteration,
          * go around the horn again.
          *
          * One would hope this doesn't happen all that often.
@@ -726,40 +755,40 @@ static void pt_ContinuationThreadInterna
 
                 /* (ref: Bug #153459)
                 ** In case of POLLERR we let the operation retry in hope
                 ** of getting a more definitive OS error.
                 */
                 if ((revents & POLLNVAL)  /* busted in all cases */
                 || ((events & POLLOUT) && (revents & POLLHUP)))  /* write op & hup */
                 {
-                    PR_Lock(pt_tq.ml);
+                    PR_Lock(tqp->ml);
                     op->result.code = -1;
                     if (POLLNVAL & revents) op->syserrno = EBADF;
                     else if (POLLHUP & revents) op->syserrno = EPIPE;
                     (void)pt_FinishTimedInternal(op);
                     if (op == my_op) goto recycle;
-                    PR_Unlock(pt_tq.ml);
+                    PR_Unlock(tqp->ml);
                 }
-                else if ((0 != (revents & op->fd->secret->eventMask))
+                else if ((0 != (revents & op->fd->secret->eventMask[io_tq_index]))
                 && (pt_continuation_pending == op->status))
                 {
                 /*
                  * Only good?(?) revents left. Operations not pending
                  * will be pruned next time we build a list. This operation
                  * will be pruned if the continuation indicates it is
                  * finished.
                  */
 
                     if (op->function(op, revents))
                     {
-                        PR_Lock(pt_tq.ml);
+                        PR_Lock(tqp->ml);
                         (void)pt_FinishTimedInternal(op);
                         if (op == my_op) goto recycle;
-                        PR_Unlock(pt_tq.ml);
+                        PR_Unlock(tqp->ml);
                     }
                     else
                     {
                         /*
                          * If the continuation function returns
                          * PR_FALSE, it means available data have
                          * been read, output buffer space has been
                          * filled, or pending connections have been
@@ -768,129 +797,141 @@ static void pt_ContinuationThreadInterna
                          * invoked again, it will most likely
                          * return PR_FALSE.  So turn off these
                          * events in the event mask for this fd so
                          * that if this fd is encountered again in
                          * the polling list with these events on,
                          * we won't invoke the continuation
                          * function again.
                          */
-                        op->fd->secret->eventMask &= ~revents;
+                        op->fd->secret->eventMask[io_tq_index] &= ~revents;
                     }
                 }
             }
         }
 
         /*
          * This is timeout processing. It is done after checking
          * for good completions. Those that just made it under the
          * wire are lucky, but none the less, valid.
          */
         now = PR_IntervalNow();
-        PR_Lock(pt_tq.ml);
-        while ((NULL != pt_tq.head)
-        && (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout))
+        PR_Lock(tqp->ml);
+        while ((NULL != tqp->head)
+        && (PR_INTERVAL_NO_TIMEOUT != tqp->head->timeout))
         {
-            op = pt_tq.head;  /* get a copy of this before finishing it */
+            op = tqp->head;  /* get a copy of this before finishing it */
             if ((PRInt32)(op->absolute - now) > 0) break;
             /* 
              * The head element of the timed queue has timed out. Record
              * the reason for completion and take it out of the list.
              */
             op->result.code = -1;
             op->syserrno = ETIMEDOUT;
             (void)pt_FinishTimedInternal(op);
 
             /* 
              * If it's 'my_op' then we have to switch threads. Exit w/o
              * finishing the scan. The scan will be completed when another
              * thread calls in acting as the continuation thread. 
              */
             if (op == my_op) goto recycle;  /* exit w/o unlocking */
         }
-        PR_Unlock(pt_tq.ml);
+        PR_Unlock(tqp->ml);
     }
 
     PR_NOT_REACHED("This is a while(true) loop /w no breaks");
 
 recycle:
     /*
     ** Recycling the continuation thread.
     **
     ** The thread we were using for I/O continuations just completed 
     ** the I/O it submitted. It has to return to it's caller. We need
     ** another thread to act in the continuation role. We can do that
     ** by taking any operation off the timed queue, setting its state
     ** to 'recycle' and notifying the condition.
     **
     ** Selecting a likely thread seems like magic. I'm going to try
-    ** using one that has the longest (or no) timeout, pt_tq.tail.
+    ** using one that has the longest (or no) timeout, tqp->tail.
     ** If that slot's empty, then there's no outstanding I/O and we
     ** don't need a thread at all.
     **
     ** BTW, we're locked right now, and we'll be returning with the
     ** the lock held as well. Seems odd, doesn't it?
     */
 
     /* $$$ should this be called with the lock held? $$$ */
-    PR_SetThreadPriority(pt_tq.thread, priority);  /* reset back to caller's */
-
-    PR_ASSERT((NULL == pt_tq.head) == (0 == pt_tq.op_count));
-    PR_ASSERT((NULL == pt_tq.head) == (NULL == pt_tq.tail));
+    PR_SetThreadPriority(tqp->thread, priority);  /* reset back to caller's */
+
+    PR_ASSERT((NULL == tqp->head) == (0 == tqp->op_count));
+    PR_ASSERT((NULL == tqp->head) == (NULL == tqp->tail));
     PR_ASSERT(pt_continuation_done == my_op->status);
     
-    if (NULL != pt_tq.tail)
+    if (NULL != tqp->tail)
     {
-        if (pt_tq.tail->status != pt_continuation_abort)
+        if (tqp->tail->status != pt_continuation_abort)
         {
-            pt_tq.tail->status = pt_continuation_recycle;
+            tqp->tail->status = pt_continuation_recycle;
         }
-        PR_NotifyCondVar(pt_tq.tail->complete);
+        PR_NotifyCondVar(tqp->tail->complete);
 #if defined(DEBUG)
         pt_debug.recyclesNeeded += 1;
 #endif
     }
 #if defined(DEBUG)
      else pt_debug.quiescentIO += 1;
 #endif
 
 }  /* pt_ContinuationThreadInternal */
 
 static PRIntn pt_Continue(pt_Continuation *op)
 {
     PRStatus rv;
     PRThread *self = PR_GetCurrentThread();
+    struct pt_TimedQueue *tqp;
+
+    /* lazy assignment of the thread's ioq */
+    if (-1 == self->io_tq_index)
+    {
+        self->io_tq_index = (PR_AtomicIncrement(&_pt_tq_index)-1) % _pt_tq_count;
+    }
+
+    PR_ASSERT(self->io_tq_index >= 0);
+    tqp = &pt_tqp[self->io_tq_index];
+
     /* lazy allocation of the thread's cv */
     if (NULL == self->io_cv)
-        self->io_cv = PR_NewCondVar(pt_tq.ml);
+        self->io_cv = PR_NewCondVar(tqp->ml);
     /* Finish filling in the blank slots */
     op->complete = self->io_cv;
     op->status = pt_continuation_pending;  /* set default value */
-    PR_Lock(pt_tq.ml);  /* we provide the locking */
+	op->io_tq_index = self->io_tq_index;
+    PR_Lock(tqp->ml);  /* we provide the locking */
 
     pt_InsertTimedInternal(op);  /* insert in the structure */
 
     /*
     ** At this point, we try to decide whether there is a continuation
     ** thread, or whether we should assign this one to serve in that role.
     */
     do
     {
-        if (NULL == pt_tq.thread)
+        if (NULL == tqp->thread)
         {
             /*
             ** We're the one. Call the processing function with the lock
             ** held. It will return with it held as well, though there
             ** will certainly be times within the function when it gets
             ** released.
             */
-            pt_tq.thread = self;  /* I'm taking control */
+            tqp->thread = self;  /* I'm taking control */
             pt_ContinuationThreadInternal(op); /* go slash and burn */
             PR_ASSERT(pt_continuation_done == op->status);
-            pt_tq.thread = NULL;  /* I'm abdicating my rule */
+            tqp->thread = NULL;  /* I'm abdicating my rule */
         }
         else
         {
             rv = PR_WaitCondVar(op->complete, PR_INTERVAL_NO_TIMEOUT);
             /*
              * If we get interrupted, we set state the continuation thread will
              * see and allow it to finish the I/O operation w/ error. That way
              * the rule that only the continuation thread is removing elements
@@ -933,17 +974,17 @@ static PRIntn pt_Continue(pt_Continuatio
              * If we're to recycle, continue within this loop. This will
              * cause this thread to become the continuation thread.
              */
 
         }
     } while (pt_continuation_done != op->status);
 
 
-    PR_Unlock(pt_tq.ml);  /* we provided the locking */
+    PR_Unlock(tqp->ml);  /* we provided the locking */
 
     return op->result.code;  /* and the primary answer */
 }  /* pt_Continue */
 
 /*****************************************************************************/
 /*********************** specific continuation functions *********************/
 /*****************************************************************************/
 static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
@@ -1146,92 +1187,169 @@ static PRBool pt_recvfrom_cont(pt_Contin
         op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
     op->syserrno = errno;
     return ((-1 == op->result.code) && 
             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
         PR_FALSE : PR_TRUE;
 }  /* pt_recvfrom_cont */
 
 #ifdef AIX
-static PRBool pt_aix_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
+static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
 {
     struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
     int rv;
-
+	long long saved_file_offset;
+	long long saved_file_bytes;
+
+	saved_file_offset = sf_struct->file_offset;
+	saved_file_bytes = sf_struct->file_bytes;
+	sf_struct->bytes_sent = 0;
+
+	if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
+	PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
+									sf_struct->file_size);
     rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
     op->syserrno = errno;
 
     if (rv != -1) {
         op->result.code += sf_struct->bytes_sent;
+		/*
+		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
+		 * being updated. So, 'file_bytes' is maintained by NSPR to
+		 * avoid conflict when this bug is fixed in AIX, in the future.
+		 */
+		if (saved_file_bytes != -1)
+			saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
+		sf_struct->file_bytes = saved_file_bytes;
     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
         op->result.code = -1;
     } else {
         return PR_FALSE;
     }
 
     if (rv == 1) {    /* more data to send */
         return PR_FALSE;
     }
 
     return PR_TRUE;
 }
 #endif  /* AIX */
 
 #ifdef HPUX11
-static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
+static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
 {
     struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
     int count;
 
-    count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.offset, 0,
-            hdtrl, op->arg4.flags);
+    count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
+			op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
     PR_ASSERT(count <= op->nbytes_to_send);
     op->syserrno = errno;
 
     if (count != -1) {
         op->result.code += count;
     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
         op->result.code = -1;
     } else {
         return PR_FALSE;
     }
-
     if (count != -1 && count < op->nbytes_to_send) {
-        if (hdtrl[0].iov_len == 0) {
-            PR_ASSERT(hdtrl[0].iov_base == NULL);
-            op->arg3.offset += count;
-        } else if (count < hdtrl[0].iov_len) {
-            PR_ASSERT(op->arg3.offset == 0);
-            hdtrl[0].iov_base = (char *) hdtrl[0].iov_base + count;
+        if (count < hdtrl[0].iov_len) {
+			/* header not sent */
+
+            hdtrl[0].iov_base = ((char *) hdtrl[0].iov_len) + count;
             hdtrl[0].iov_len -= count;
-        } else {
-            op->arg3.offset = count - hdtrl[0].iov_len;
+
+        } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
+			/* header sent, file not sent */
+            PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
+
             hdtrl[0].iov_base = NULL;
             hdtrl[0].iov_len = 0;
-        }
+
+            op->arg3.file_spec.offset += file_nbytes_sent;
+            op->arg3.file_spec.nbytes -= file_nbytes_sent;
+        } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
+											hdtrl[1].iov_len)) {
+            PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
+                                         op->arg3.file_spec.nbytes);
+
+			/* header sent, file sent, trailer not sent */
+
+            hdtrl[0].iov_base = NULL;
+            hdtrl[0].iov_len = 0;
+			/*
+			 * set file offset and len so that no more file data is
+			 * sent
+			 */
+            op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
+            op->arg3.file_spec.nbytes = 0;
+
+            hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
+            hdtrl[1].iov_len -= trailer_nbytes_sent;
+		}
         op->nbytes_to_send -= count;
         return PR_FALSE;
     }
 
     return PR_TRUE;
 }
 #endif  /* HPUX11 */
 
+#define _MD_CPUS_ONLINE 2
+
 void _PR_InitIO()
 {
-    pt_tq.ml = PR_NewLock();
-    PR_ASSERT(NULL != pt_tq.ml);
+    PRIntn index;
+    char *num_io_queues;
+
+    if (num_io_queues = getenv("NSPR_NUM_IO_QUEUES"))
+    {
+        _pt_tq_count = atoi(num_io_queues);
+    }
+    else
+    {
+        /*
+         * Get the number of CPUs if the pthread
+         * library has kernel-scheduled entities that
+         * can run on multiple CPUs.
+         */
+#ifdef HPUX11
+        _pt_num_cpus = pthread_num_processors_np();
+#elif defined(IRIX) || defined(OSF1)
+        _pt_num_cpus = sysconf(_SC_NPROC_ONLN);
+#elif defined(AIX) || defined(LINUX) || defined(SOLARIS)
+        _pt_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+        /*
+         * A pure user-level (Mx1) pthread library can
+         * only use one CPU, even on a multiprocessor.
+         */
+        _pt_num_cpus = 1;
+#endif
+        if (_pt_num_cpus < 0)
+            _pt_num_cpus = _MD_CPUS_ONLINE;
+        _pt_tq_count = _pt_num_cpus;
+    }
+
+    pt_tqp = (struct pt_TimedQueue *)
+        PR_CALLOC(_pt_tq_count * sizeof(struct pt_TimedQueue));
+    PR_ASSERT(NULL != pt_tqp);
+
+    for (index = 0; index < _pt_tq_count; index++)
+    {
+        pt_tqp[index].ml = PR_NewLock();
+        PR_ASSERT(NULL != pt_tqp[index].ml);
+    }
 
 #if defined(DEBUG)
     memset(&pt_debug, 0, sizeof(PTDebug));
     pt_debug.timeStarted = PR_Now();
 #endif
 
-    pt_tq.thread = NULL;
-
     _pr_flock_lock = PR_NewLock();
     PR_ASSERT(NULL != _pr_flock_lock);
     _pr_rename_lock = PR_NewLock();
     PR_ASSERT(NULL != _pr_rename_lock); 
 
     _PR_InitFdCache();  /* do that */   
 
     _pr_stdin = pt_SetMethods(0, PR_DESC_FILE);
@@ -1379,101 +1497,101 @@ static PRInt32 pt_Write(PRFileDesc *fd, 
     if (bytes == -1)
         pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
     return bytes;
 }  /* pt_Write */
 
 static PRInt32 pt_Writev(
     PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
 {
-    PRIntn iov_index = 0;
+    PRIntn iov_index;
     PRBool fNeedContinue = PR_FALSE;
-    PRInt32 syserrno, bytes = -1, rv = -1;
+    PRInt32 syserrno, bytes, rv = -1;
+    struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
+    int osiov_len;
 
     if (pt_TestAbort()) return rv;
 
-    /*
-     * The first shot at this can use the client's iov directly.
-     * Only if we have to continue the operation do we have to
-     * make a copy that we can modify.
-     */
-    rv = bytes = writev(fd->secret->md.osfd, (const struct iovec*)iov, iov_len);
-    syserrno = errno;
+    /* Ensured by PR_Writev */
+    PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
 
     /*
-     * If we moved some bytes (ie., bytes > 0) how does that implicate
-     * the i/o vector list. In other words, exactly where are we within
-     * that array? What are the parameters for resumption? Maybe we're
-     * done!
+     * We can't pass iov to writev because PRIOVec and struct iovec
+     * may not be binary compatible.  Make osiov a copy of iov and
+     * pass osiov to writev.  We can modify osiov if we need to
+     * continue the operation.
      */
-    if ((bytes > 0) && (!fd->secret->nonblocking))
+    osiov = osiov_local;
+    osiov_len = iov_len;
+    for (iov_index = 0; iov_index < osiov_len; iov_index++)
     {
-        for (iov_index = 0; iov_index < iov_len; ++iov_index)
-        {
-            if (bytes < iov[iov_index].iov_len) break; /* continue w/ what's left */
-            bytes -= iov[iov_index].iov_len;  /* this one's done cooked */
-        }
+        osiov[iov_index].iov_base = iov[iov_index].iov_base;
+        osiov[iov_index].iov_len = iov[iov_index].iov_len;
     }
 
-    if ((bytes >= 0) && (iov_index < iov_len) && (!fd->secret->nonblocking))
+    rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
+    syserrno = errno;
+
+    if (!fd->secret->nonblocking)
     {
-        if (PR_INTERVAL_NO_WAIT == timeout)
+        if (bytes >= 0)
         {
-            rv = -1;
-            syserrno = ETIMEDOUT;
+            /*
+             * If we moved some bytes, how does that implicate the
+             * i/o vector list?  In other words, exactly where are
+             * we within that array?  What are the parameters for
+             * resumption?  Maybe we're done!
+             */
+            for ( ;osiov_len > 0; osiov++, osiov_len--)
+            {
+                if (bytes < osiov->iov_len)
+                {
+                    /* this one's not done yet */
+                    osiov->iov_base = (char*)osiov->iov_base + bytes;
+                    osiov->iov_len -= bytes;
+                    break;  /* go off and do that */
+                }
+                bytes -= osiov->iov_len;  /* this one's done cooked */
+            }
+            PR_ASSERT(osiov_len > 0 || bytes == 0);
+            if (osiov_len > 0)
+            {
+                if (PR_INTERVAL_NO_WAIT == timeout)
+                {
+                    rv = -1;
+                    syserrno = ETIMEDOUT;
+                }
+                else fNeedContinue = PR_TRUE;
+            }
         }
-        else fNeedContinue = PR_TRUE;
-    }
-    else if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
-        && (!fd->secret->nonblocking))
-    {
-        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
-        else
+        else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
         {
-            rv = bytes = 0;
-            fNeedContinue = PR_TRUE;
+            if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+            else
+            {
+                rv = 0;
+                fNeedContinue = PR_TRUE;
+            }
         }
     }
 
     if (fNeedContinue == PR_TRUE)
     {
         pt_Continuation op;
-        /*
-         * Okay. Now we need a modifiable copy of the array.
-         * Allocate some storage and copy the (already) modified
-         * bits into the new vector. The is copying only the
-         * part of the array that's still valid. The array may
-         * have a new length and the first element of the array may
-         * have different values.
-         */
-        struct iovec *osiov = NULL, *tiov;
-        PRIntn osiov_len = iov_len - iov_index;  /* recompute */
-        osiov = (struct iovec*)PR_MALLOC(osiov_len * sizeof(struct iovec));
-        PR_ASSERT(NULL != osiov);
-        for (tiov = osiov; iov_index < iov_len; ++iov_index)
-        {
-            tiov->iov_base = iov[iov_index].iov_base;
-            tiov->iov_len = iov[iov_index].iov_len;
-            tiov += 1;
-        }
-        osiov->iov_len -= bytes;  /* that may be partially done */
-        /* so advance the description */
-        osiov->iov_base = (char*)osiov->iov_base + bytes;
 
         op.fd = fd;
         op.arg1.osfd = fd->secret->md.osfd;
         op.arg2.buffer = (void*)osiov;
         op.arg3.amount = osiov_len;
         op.timeout = timeout;
         op.result.code = rv;
         op.function = pt_writev_cont;
         op.event = POLLOUT | POLLPRI;
         rv = pt_Continue(&op);
         syserrno = op.syserrno;
-        PR_DELETE(osiov);
     }
     if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
     return rv;
 }  /* pt_Writev */
 
 static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
 {
     return _PR_MD_LSEEK(fd, offset, whence);
@@ -2032,226 +2150,265 @@ static pthread_once_t pt_aix_sendfile_on
 static void pt_aix_sendfile_init_routine(void)
 {
     void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
     pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
     dlclose(handle);
 }
 
 /* 
- * pt_AIXDispatchTransmitFile
+ * pt_AIXDispatchSendFile
  */
-static PRInt32 pt_AIXDispatchTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
-      const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-      PRIntervalTime timeout)
+static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+	  PRTransmitFileFlags flags, PRIntervalTime timeout)
 {
     int rv;
 
     rv = pthread_once(&pt_aix_sendfile_once_block,
             pt_aix_sendfile_init_routine);
     PR_ASSERT(0 == rv);
     if (pt_aix_sendfile_fptr) {
-        return pt_AIXTransmitFile(sd, fd, headers, hlen, flags, timeout);
+        return pt_AIXSendFile(sd, sfd, flags, timeout);
     } else {
-        return _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
+        return _PR_UnixSendFile(sd, sfd, flags, timeout);
     }
 }
 #endif /* !HAVE_SEND_FILE */
 
+
 /*
- * pt_AIXTransmitFile
+ * pt_AIXSendFile
  *
- *    Send file fd across socket sd. If headers is non-NULL, 'hlen'
- *    bytes of headers is sent before sending the file.
+ *    Send file sfd->fd across socket sd. If specified, header and trailer
+ *    buffers are sent before and after the file, respectively. 
  *
  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  *    
  *    return number of bytes sent or -1 on error
  *
  *      This implementation takes advantage of the send_file() system
  *      call available in AIX 4.3.2.
  */
 
-static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
-        const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-        PRIntervalTime timeout)
+static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
+		PRTransmitFileFlags flags, PRIntervalTime timeout)
 {
     struct sf_parms sf_struct;
     uint_t send_flags;
     ssize_t rv;
     int syserrno;
     PRInt32 count;
-
-    sf_struct.header_data = (void *) headers;  /* cast away the 'const' */
-    sf_struct.header_length = hlen;
-    sf_struct.file_descriptor = fd->secret->md.osfd;
+	long long saved_file_offset;
+	long long saved_file_bytes;
+
+    sf_struct.header_data = (void *) sfd->header;  /* cast away the 'const' */
+    sf_struct.header_length = sfd->hlen;
+    sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
     sf_struct.file_size = 0;
-    sf_struct.file_offset = 0;
-    sf_struct.file_bytes = -1;
-    sf_struct.trailer_data = NULL;
-    sf_struct.trailer_length = 0;
+    sf_struct.file_offset = sfd->file_offset;
+    if (sfd->file_nbytes == 0)
+    	sf_struct.file_bytes = -1;
+	else
+    	sf_struct.file_bytes = sfd->file_nbytes;
+    sf_struct.trailer_data = (void *) sfd->trailer;
+    sf_struct.trailer_length = sfd->tlen;
     sf_struct.bytes_sent = 0;
 
-    send_flags = 0;
+	saved_file_offset = sf_struct.file_offset;
+    saved_file_bytes = sf_struct.file_bytes;
+
+    send_flags = 0;			/* flags processed at the end */
 
     do {
         rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
     } while (rv == -1 && (syserrno = errno) == EINTR);
 
     if (rv == -1) {
         if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
             count = 0; /* Not a real error.  Need to continue. */
         } else {
             count = -1;
         }
     } else {
         count = sf_struct.bytes_sent;
+		/*
+		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
+		 * being updated. So, 'file_bytes' is maintained by NSPR to
+		 * avoid conflict when this bug is fixed in AIX, in the future.
+		 */
+		if (saved_file_bytes != -1)
+			saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
+		sf_struct.file_bytes = saved_file_bytes;
     }
 
     if ((rv == 1) || ((rv == -1) && (count == 0))) {
         pt_Continuation op;
 
         op.fd = sd;
         op.arg1.osfd = sd->secret->md.osfd;
         op.arg2.buffer = &sf_struct;
         op.arg4.flags = send_flags;
         op.result.code = count;
         op.timeout = timeout;
-        op.function = pt_aix_transmitfile_cont;
+        op.function = pt_aix_sendfile_cont;
         op.event = POLLOUT | POLLPRI;