Merging NSPR v3.0 release from internal source repository to NSPRPUB_RELEASE_3_0_LANDING_BRANCH
authorwtc%netscape.com
Sat, 03 Oct 1998 00:21:02 +0000
branchNSPRPUB_RELEASE_3_0_LANDING_BRANCH
changeset 284 7d80110e1f4b0df9065a1c98a99b86a78844ac8c
parent 269 f11c0fb86beb64cb5b02dd08bf44b9f3c37b9aa6
push idunknown
push userunknown
push dateunknown
Merging NSPR v3.0 release from internal source repository to cvs.mozilla.org NSPRPUB_RELEASE_3_0_LANDING_BRANCH.
config/Linux.mk
config/nsinstall.c
lib/ds/plarena.c
lib/libc/src/plerror.c
lib/tests/arena.c
macbuild/NSPR20PPC.mcp
macbuild/NSPRConfig.h
pr/include/md/_dgux.h
pr/include/md/_linux.h
pr/include/md/_macos.h
pr/include/md/_solaris.h
pr/include/prinit.h
pr/include/private/pprmwait.h
pr/include/prsystem.h
pr/src/io/prfile.c
pr/src/io/prmwait.c
pr/src/io/prprf.c
pr/src/io/prsocket.c
pr/src/md/mac/macio.c
pr/src/md/unix/Makefile
pr/src/md/unix/irix.c
pr/src/md/unix/objs.mk
pr/src/md/unix/os_SunOS_ultrasparc.s
pr/src/md/unix/solaris.c
pr/src/md/unix/unix.c
pr/src/md/unix/unix_errors.c
pr/src/md/unix/uxpoll.c
pr/src/md/unix/uxwrap.c
pr/src/md/windows/ntdllmn.c
pr/src/md/windows/ntio.c
pr/src/md/windows/w95dllmain.c
pr/src/md/windows/w95io.c
pr/src/misc/prinit.c
pr/src/misc/prsystem.c
pr/src/pthreads/ptio.c
pr/src/pthreads/ptthread.c
pr/tests/Makefile
pr/tests/accept.c
pr/tests/bigfile.c
pr/tests/cltsrv.c
pr/tests/foreign.c
pr/tests/fsync.c
pr/tests/instrumt.c
pr/tests/ioconthr.c
pr/tests/layer.c
pr/tests/multiwait.c
pr/tests/nbconn.c
pr/tests/nblayer.c
pr/tests/nonblock.c
pr/tests/provider.c
pr/tests/socket.c
pr/tests/sockopt.c
pr/tests/tmocon.c
--- a/config/Linux.mk
+++ b/config/Linux.mk
@@ -74,18 +74,17 @@ OS_CFLAGS		= $(DSO_CFLAGS) $(PLATFORM_FL
 # Version-specific stuff
 ######################################################################
 
 ifeq ($(CPU_ARCH),alpha)
 PLATFORM_FLAGS		+= -D_ALPHA_ -D__alpha -mieee
 PORT_FLAGS		+= -D_XOPEN_SOURCE
 endif
 ifeq ($(CPU_ARCH),ppc)
-PLATFORM_FLAGS		+= -DMKLINUX
-OS_INCLUDES		+= -I/usr/local/include
+PORT_FLAGS		+= -D_XOPEN_SOURCE
 endif
 ifeq ($(CPU_ARCH),x86)
 PLATFORM_FLAGS		+= -mno-486 -Di386
 PORT_FLAGS		+= -D_XOPEN_SOURCE
 endif
 ifeq ($(CPU_ARCH),m68k)
 #
 # gcc on Linux/m68k either has a bug or triggers a code-sequence
@@ -94,17 +93,17 @@ ifeq ($(CPU_ARCH),m68k)
 #
 ifndef BUILD_OPT
 OPTIMIZER		+= -O
 endif
 PLATFORM_FLAGS		+= -m68020-40
 endif
 
 #
-# Linux ppc and 2.0 have shared libraries.
+# Linux 2.x has shared libraries.
 #
 
 MKSHLIB			= $(LD) $(DSO_LDOPTS) -soname $(@:$(OBJDIR)/%.so=%.so)
 ifdef BUILD_OPT
 OPTIMIZER		= -O2
 endif
 
 ######################################################################
--- a/config/nsinstall.c
+++ b/config/nsinstall.c
@@ -79,30 +79,35 @@ usage(void)
     exit(2);
 }
 
 static int
 mkdirs(char *path, mode_t mode)
 {
     char *cp;
     struct stat sb;
+    int res;
     
     while (*path == '/' && path[1] == '/')
 	path++;
     while ((cp = strrchr(path, '/')) && cp[1] == '\0')
 	*cp = '\0';
     if (cp && cp != path) {
 	*cp = '\0';
 	if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
 	    mkdirs(path, mode) < 0) {
 	    return -1;
 	}
 	*cp = '/';
     }
-    return mkdir(path, mode);
+    res = mkdir(path, mode);
+    if ((res != 0) && (errno == EEXIST))
+	return 0;
+     else
+	return res;
 }
 
 static uid_t
 touid(char *owner)
 {
     struct passwd *pw;
     uid_t uid;
     char *cp;
--- a/lib/ds/plarena.c
+++ b/lib/ds/plarena.c
@@ -22,29 +22,73 @@
  * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
  */
 #include <stdlib.h>
 #include <string.h>
 #include "plarena.h"
 #include "prmem.h"
 #include "prbit.h"
 #include "prlog.h"
+#include "prmon.h"
+#include "prinit.h"
 
 static PLArena *arena_freelist;
 
 #ifdef PL_ARENAMETER
 static PLArenaStats *arena_stats_list;
 
 #define COUNT(pool,what)  (pool)->stats.what++
 #else
 #define COUNT(pool,what)  /* nothing */
 #endif
 
 #define PL_ARENA_DEFAULT_ALIGN  sizeof(double)
 
+static PRMonitor    *arenaLock;
+static PRCallOnceType once;
+
+/*
+** InitializeArenas() -- Initialize arena operations.
+**
+** InitializeArenas() is called exactly once and only once from 
+** LockArena(). This function creates the arena protection 
+** monitor: arenaLock.
+**
+** Note: If the arenaLock cannot be created, InitializeArenas()
+** fails quietly, returning only PR_FAILURE. This percolates up
+** to the application using the Arena API. He gets no arena
+** from PL_ArenaAllocate(). It's up to him to fail gracefully
+** or recover.
+**
+*/
+static PRStatus InitializeArenas( void )
+{
+    PR_ASSERT( arenaLock == NULL );
+    arenaLock = PR_NewMonitor();
+    if ( arenaLock == NULL )
+        return PR_FAILURE;
+    else
+        return PR_SUCCESS;
+} /* end ArenaInitialize() */
+
+static PRStatus LockArena( void )
+{
+    PRStatus rc = PR_CallOnce( &once, InitializeArenas );
+
+    if ( PR_FAILURE != rc )
+        PR_EnterMonitor( arenaLock );
+    return(rc);
+} /* end LockArena() */
+
+static void UnlockArena( void )
+{
+    PR_ExitMonitor( arenaLock );
+    return;
+} /* end UnlockArena() */
+
 PR_IMPLEMENT(void) PL_InitArenaPool(
     PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
 {
 #if defined(XP_MAC)
 #pragma unused (name)
 #endif
 
     if (align == 0)
@@ -69,16 +113,18 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PL
     PRUint32 sz;
     void *p;
 
     PR_ASSERT((nb & pool->mask) == 0);
 #if defined(WIN16)
     if (nb >= 60000U)
         return 0;
 #endif  /* WIN16 */
+    if ( PR_FAILURE == LockArena())
+        return(0);
     ap = &arena_freelist;
     for (a = pool->current; a->avail + nb > a->limit; pool->current = a) {
         if (a->next) {                          /* move to next arena */
             a = a->next;
             continue;
         }
         while ((b = *ap) != 0) {                /* reclaim a free arena */
             if (b->limit - b->base == pool->arenasize) {
@@ -89,25 +135,29 @@ PR_IMPLEMENT(void *) PL_ArenaAllocate(PL
                 goto claim;
             }
             ap = &b->next;
         }
         sz = PR_MAX(pool->arenasize, nb);        /* allocate a new arena */
         sz += sizeof *a + pool->mask;           /* header and alignment slop */
         b = (PLArena*)PR_MALLOC(sz);
         if (!b)
+        {
+            UnlockArena();
             return 0;
+        }
         a = a->next = b;
         a->next = 0;
         a->limit = (PRUword)a + sz;
         PL_COUNT_ARENA(pool,++);
         COUNT(pool, nmallocs);
     claim:
         a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
     }
+    UnlockArena();
     p = (void *)a->avail;
     a->avail += nb;
     return p;
 }
 
 PR_IMPLEMENT(void *) PL_ArenaGrow(
     PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
 {
@@ -148,19 +198,21 @@ static void FreeArenaList(PLArenaPool *p
             PL_COUNT_ARENA(pool,--);
             PR_DELETE(a);
         } while ((a = *ap) != 0);
     } else {
         /* Insert the whole arena chain at the front of the freelist. */
         do {
             ap = &(*ap)->next;
         } while (*ap);
+        LockArena();
         *ap = arena_freelist;
         arena_freelist = a;
         head->next = 0;
+        UnlockArena();
     }
 
     pool->current = head;
 }
 
 PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
 {
     PLArena *a;
@@ -214,21 +266,23 @@ PR_IMPLEMENT(void) PL_CompactArenaPool(P
 #endif
 #endif
 }
 
 PR_IMPLEMENT(void) PL_ArenaFinish()
 {
     PLArena *a, *next;
 
+    LockArena();
     for (a = arena_freelist; a; a = next) {
         next = a->next;
         PR_DELETE(a);
     }
     arena_freelist = NULL;
+    UnlockArena();
 }
 
 #ifdef PL_ARENAMETER
 PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb)
 {
     pool->stats.nallocs++;
     pool->stats.nbytes += nb;
     if (nb > pool->stats.maxalloc)
--- a/lib/libc/src/plerror.c
+++ b/lib/libc/src/plerror.c
@@ -91,16 +91,17 @@ static const char *tags[] =
     "PR_FILE_EXISTS_ERROR",
     "PR_MAX_DIRECTORY_ENTRIES_ERROR",
     "PR_INVALID_DEVICE_STATE_ERROR", 
     "PR_DEVICE_IS_LOCKED_ERROR", 
     "PR_NO_MORE_FILES_ERROR",
     "PR_END_OF_FILE_ERROR",
     "PR_FILE_SEEK_ERROR",
     "PR_FILE_IS_BUSY_ERROR", 
+    "<unused error code>",
     "PR_IN_PROGRESS_ERROR",
     "PR_ALREADY_INITIATED_ERROR",
     "PR_GROUP_EMPTY_ERROR",
     "PR_INVALID_STATE_ERROR",
     "PR_NETWORK_DOWN_ERROR",
     "PR_SOCKET_SHUTDOWN_ERROR",
     "PR_CONNECT_ABORTED_ERROR",
     "PR_HOST_UNREACHABLE_ERROR",
new file mode 100644
--- /dev/null
+++ b/lib/tests/arena.c
@@ -0,0 +1,265 @@
+/* -*- 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.0 (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.
+ */
+
+/*
+** File:        arena.c
+** Description: Testing arenas
+**
+*/
+
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include "nspr.h"
+#include "plarena.h"
+#include "plgetopt.h"
+
+PRLogModuleInfo *tLM;
+PRIntn  threadCount = 0;
+PRMonitor   *tMon;
+PRBool failed_already = PR_FALSE;
+
+/* Arguments from the command line with default values */
+PRIntn debug_mode = 0;
+PRIntn  poolMin = 4096;
+PRIntn  poolMax = (100 * 4096);
+PRIntn  arenaMin = 40;
+PRIntn  arenaMax = (100 * 40);
+PRIntn  stressIterations = 15;
+PRIntn  maxAlloc = (1024 * 1024);
+PRIntn  stressThreads = 4;
+
+/*
+** Test arena Mark and Release.
+*/
+static void MarkAndRelease( void )
+{
+    PLArenaPool ap;
+    void    *ptr;
+    void    *mark;
+
+    PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double));
+    PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+
+    mark = PL_ARENA_MARK( &ap );
+
+    PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+    
+    PL_ARENA_RELEASE( &ap, mark );
+    PL_ARENA_ALLOCATE( ptr, &ap, 512 );
+
+    if ( ptr != mark )
+    {
+        failed_already = PR_TRUE;
+        PR_LOG( tLM, PR_LOG_ERROR, ("Mark and Release failed: expected %p, got %p\n", mark, ptr)); 
+    }
+    else
+        PR_LOG( tLM, PR_LOG_DEBUG, ("Mark and Release passed\n")); 
+    
+    return;
+} /* end MarkAndRelease() */
+
+/*
+** RandSize() returns a random number in the range 
+** min..max, rounded to the next doubleword
+**
+*/
+static PRIntn RandSize( PRIntn min, PRIntn max )
+{
+    PRIntn  sz = (rand() % (max -min)) + min + sizeof(double);
+
+    sz &= ~sizeof(double)-1;
+
+    return(sz);
+}
+
+
+/*
+** StressThread()
+** A bunch of these beat on individual arenas
+** This tests the free_list protection.
+**
+*/
+static void PR_CALLBACK StressThread( void *arg )
+{
+    PLArenaPool ap;
+    PRIntn i;
+    PRIntn sz;
+    void *ptr;
+    PRThread *tp = PR_GetCurrentThread();
+
+    PR_LOG( tLM, PR_LOG_DEBUG, ("Stress Thread %p started\n", PR_GetCurrentThread()));
+    PL_InitArenaPool( &ap, "TheArena", RandSize( poolMin, poolMax), sizeof(double));
+
+    for ( i = 0; i < stressIterations; i++ )
+    {
+        PRIntn allocated = 0;
+
+        while ( allocated < maxAlloc )
+        {
+            sz = RandSize( arenaMin, arenaMax );
+            PL_ARENA_ALLOCATE( ptr, &ap, sz );
+            if ( ptr == NULL )
+            {
+                PR_LOG( tLM, PR_LOG_ERROR, ("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated));
+                break;
+            }
+            allocated += sz;
+        }
+        PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished one iteration\n", tp));
+        PL_FreeArenaPool( &ap );
+    }
+    PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp));
+    PL_FinishArenaPool( &ap );
+    PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp));
+
+    /* That's all folks! let's quit */
+    PR_EnterMonitor(tMon);
+    threadCount--;
+    PR_Notify(tMon);
+    PR_ExitMonitor(tMon);    
+    return;
+}    
+
+/*
+** Stress()
+** Flog the hell out of arenas multi-threaded.
+** Do NOT pass an individual arena to another thread.
+** 
+*/
+static void Stress( void )
+{
+    PRThread    *tt;
+    PRIntn      i;
+
+    tMon = PR_NewMonitor();
+
+    for ( i = 0 ; i < stressThreads ; i++ )
+    {
+        PR_EnterMonitor(tMon);
+        tt = PR_CreateThread(PR_USER_THREAD,
+               StressThread,
+               NULL,
+               PR_PRIORITY_NORMAL,
+               PR_GLOBAL_THREAD,
+               PR_UNJOINABLE_THREAD,
+               0);
+        threadCount++;
+        PR_ExitMonitor(tMon);
+    }
+
+    /* Wait for all threads to exit */
+    PR_EnterMonitor(tMon);
+    while ( threadCount != 0 ) 
+    {
+        PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT);
+    }
+    PR_ExitMonitor(tMon);
+	PR_DestroyMonitor(tMon);
+
+    return;
+} /* end Stress() */
+
+/*
+** EvaluateResults()
+** uses failed_already to display results and set program
+** exit code.
+*/
+static PRIntn  EvaluateResults(void)
+{
+    PRIntn rc = 0;
+
+    if ( failed_already == PR_TRUE )
+    {
+        PR_LOG( tLM, PR_LOG_DEBUG, ("FAIL\n"));
+        rc =1;
+    } 
+    else
+    {
+        PR_LOG( tLM, PR_LOG_DEBUG, ("PASS\n"));
+    }
+    return(rc);
+} /* EvaluateResults() */
+
+void Help( void )
+{
+    printf("arena [options]\n");
+    printf("where options are:\n");
+    printf("-p <n>   minimum size of an arena pool. Default(%d)\n", poolMin);
+    printf("-P <n>   maximum size of an arena pool. Default(%d)\n", poolMax);
+    printf("-a <n>   minimum size of an arena allocation. Default(%d)\n", arenaMin);
+    printf("-A <n>   maximum size of an arena allocation. Default(%d)\n", arenaMax);
+    printf("-i <n>   number of iterations in a stress thread. Default(%d)\n", stressIterations);
+    printf("-s <n>   maximum allocation for a single stress thread. Default(%d)\n", maxAlloc);
+    printf("-t <n>   number of stress threads. Default(%d)\n", stressThreads );
+    printf("-d       enable debug mode\n");
+    printf("\n");
+    exit(1);
+}    
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+    PLOptStatus os;
+	PLOptState *opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:");
+	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+    {
+		if (PL_OPT_BAD == os) continue;
+        switch (opt->option)
+        {
+        case 'a':  /* arena Min size */
+            arenaMin = atol( opt->value );
+            break;
+        case 'A':  /* arena Max size  */
+            arenaMax = atol( opt->value );
+            break;
+        case 'p':  /* pool Min size */
+            poolMin = atol( opt->value );
+            break;
+        case 'P':  /* pool Max size */
+            poolMax = atol( opt->value );
+            break;
+        case 'i':  /* Iterations in stress tests */
+            stressIterations = atol( opt->value );
+            break;
+        case 's':  /* storage to get per iteration */
+            maxAlloc = atol( opt->value );
+            break;
+        case 't':  /* Number of stress threads to create */
+            stressThreads = atol( opt->value );
+            break;
+        case 'd':  /* debug mode */
+			debug_mode = 1;
+            break;
+        case 'h':  /* help */
+        default:
+            Help();
+        } /* end switch() */
+    } /* end while() */
+	PL_DestroyOptState(opt);
+
+    srand( (unsigned)time( NULL ) ); /* seed random number generator */
+    tLM = PR_NewLogModule("testcase");
+
+    MarkAndRelease();
+
+    Stress();
+
+    return(EvaluateResults());
+} /* end main() */
+
+/* arena.c */
index 57934998a127e5aaa6de709f6e928028a3f4f75d..f15a68a21d4c0a5b67922ed2c64b807c93405827
GIT binary patch
literal 85613
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
--- a/macbuild/NSPRConfig.h
+++ b/macbuild/NSPRConfig.h
@@ -11,16 +11,14 @@
  * 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.
  */
 
-#define OLDROUTINELOCATIONS 0
+#include "DefinesMac.h"
+#include "DefinesMozilla.h"
 
-#define XP_MAC 1
 #define _PR_NO_PREEMPT 1
 #define _NO_FAST_STRING_INLINES_ 1
 #define FORCE_PR_LOG 1
-#define NSPR20 1
-
--- a/pr/include/md/_dgux.h
+++ b/pr/include/md/_dgux.h
@@ -41,16 +41,18 @@
 #define HAVE_NETCONFIG
 #define	HAVE_DLL
 #define	USE_DLFCN
 #define NEED_STRFTIME_LOCK
 #define NEED_TIME_R
 #define _PR_NEED_STRCASECMP
 #define _PR_POLL_AVAILABLE
 #define _PR_USE_POLL
+#define _PR_NO_LARGE_FILES
+#define _PR_STAT_HAS_ONLY_ST_ATIME
 
 #define USE_SETJMP
 
 #include <setjmp.h>
 
 #define _SETJMP setjmp
 #define _LONGJMP longjmp
 #define _PR_CONTEXT_TYPE         jmp_buf
@@ -110,18 +112,54 @@ struct _MDSemaphore {
 struct _MDCVar {
     PRInt8 notused;
 };
 
 struct _MDSegment {
     PRInt8 notused;
 };
 
+/*
+ * md-specific cpu structure field
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+    PRCList ioQ;
+    PRUint32 ioq_timeout;
+    PRInt32 ioq_max_osfd;
+    PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+    fd_set fd_read_set, fd_write_set, fd_exception_set;
+    PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+                fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+    struct pollfd *ioq_pollfds;
+    int ioq_pollfds_size;
+#endif  /* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu)               ((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu)       ((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu)       ((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu)      ((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu)      ((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu)  ((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu)  ((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu)       ((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu)      ((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu)      ((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu)       ((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu)  ((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu)  32
+
 struct _MDCPU {
-	struct _MDCPU_Unix md_unix;
+    struct _MDCPU_Unix md_unix;
 };
 
 #define _MD_INIT_LOCKS()
 #define _MD_NEW_LOCK(lock) PR_SUCCESS
 #define _MD_FREE_LOCK(lock)
 #define _MD_LOCK(lock)
 #define _MD_UNLOCK(lock)
 #define _MD_INIT_IO()
--- a/pr/include/md/_linux.h
+++ b/pr/include/md/_linux.h
@@ -54,23 +54,21 @@
 #undef	HAVE_STACK_GROWING_UP
 
 /*
  * Elf linux supports dl* functions
  */
 #define HAVE_DLL
 #define USE_DLFCN
 
-#if !defined(MKLINUX) && !defined(NEED_TIME_R)
-#define NEED_TIME_R
+#define USE_SETJMP
+#if defined(__GLIBC__) && __GLIBC__ >= 2
+#define _PR_POLL_AVAILABLE
 #endif
-
-#define USE_SETJMP
-#define _PR_POLL_AVAILABLE
-#define _PR_USE_POLL
+#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
 
 #ifdef _PR_PTHREADS
@@ -82,18 +80,27 @@ extern void _MD_CleanupBeforeExit(void);
 
 #include <setjmp.h>
 
 #define PR_CONTEXT_TYPE	sigjmp_buf
 
 #define CONTEXT(_th) ((_th)->md.context)
 
 #ifdef __powerpc__
-/* PowerPC based MkLinux */
+/*
+ * PowerPC based MkLinux
+ *
+ * On the PowerPC, the new style jmp_buf isn't used until glibc
+ * 2.1.
+ */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_GPR1]
+#else
 #define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__misc[0]
+#endif /* __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 */
 #define _MD_SET_FP(_t, val)
 #define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t))
 #define _MD_GET_FP_PTR(_t) ((void *) 0)
 /* aix = 64, macos = 70 */
 #define PR_NUM_GCREGS  64
 
 #elif defined(__alpha)
 /* Alpha based Linux */
@@ -187,16 +194,28 @@ extern void _MD_CleanupBeforeExit(void);
 #define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[0].__fp = (val))
 #define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t))
 #define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[0].__fp)
 #define _MD_SP_TYPE __ptr_t
 #else
 #error "Linux/MIPS pre-glibc2 not supported yet"
 #endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
 
+#elif defined(__arm__)
+/* ARM/Linux */
+#if defined(__GLIBC__) && __GLIBC__ >= 2
+#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[20]
+#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[19] = (val))
+#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t))
+#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[19])
+#define _MD_SP_TYPE __ptr_t
+#else
+#error "ARM/Linux pre-glibc2 not supported yet"
+#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
+
 #else
 
 #error "Unknown CPU architecture"
 
 #endif /*__powerpc__*/
 
 /*
 ** Initialize a thread context to run "_main()" when started
@@ -288,16 +307,17 @@ struct _MDCVar {
 
 struct _MDSegment {
     PRInt8 notused;
 };
 
 /*
  * md-specific cpu structure field
  */
+#include <sys/time.h>  /* for FD_SETSIZE */
 #define _PR_MD_MAX_OSFD FD_SETSIZE
 
 struct _MDCPU_Unix {
     PRCList ioQ;
     PRUint32 ioq_timeout;
     PRInt32 ioq_max_osfd;
     PRInt32 ioq_osfd_cnt;
 #ifndef _PR_USE_POLL
--- a/pr/include/md/_macos.h
+++ b/pr/include/md/_macos.h
@@ -458,36 +458,30 @@ typedef int (*FARPROC)();
 extern long gTimeSlicesOnNonPrimaryThread;
 extern struct PRThread *gPrimaryThread;
 
 typedef short PROSFD;
 
 // Errors not found in the Mac StdCLib
 #define EACCES  		13      	// Permission denied
 #define ENOENT			-43			// No such file or directory
-#define	EMFILE			24			// Too many open files
 #define _OS_INVALID_FD_VALUE -1
 
 #define	STDERR_FILENO	2
 
 #if !defined(MAC_NSPR_STANDALONE)
-#define MAC_PATH_SEPARATOR 				':'
 #define PATH_SEPARATOR 					':'
 #define PATH_SEPARATOR_STR		        ":"
 #define DIRECTORY_SEPARATOR				'/'
 #define DIRECTORY_SEPARATOR_STR			"/"
 #endif
 
 #define UNIX_THIS_DIRECTORY_STR			"./"
 #define UNIX_PARENT_DIRECTORY_STR		"../"
 
-#define MAX_PATH 			512
-#define MAX_MAC_FILENAME	31
-#define MAXPATHLEN			MAX_PATH
-
 
 // Alias a few names
 #define getenv	PR_GetEnv
 #define putenv	_MD_PutEnv
 
 #if defined(MAC_NSPR_STANDALONE)
 typedef unsigned char (*MemoryCacheFlusherProc)(size_t size);
 typedef void (*PreAllocationHookProc)(void);
@@ -529,20 +523,16 @@ extern FILE *_OS_FOPEN(const char *filen
 extern void dprintf(const char *format, ...);
 
 
 // Entry into the memory system's cache flushing
 #if defined(MAC_NSPR_STANDALONE)
 extern PRUint8 CallCacheFlushers(size_t blockSize);
 #endif
 
-enum {
-	kPrivateNSPREventType = 13
-};
-
 #if defined(MAC_NSPR_STANDALONE)
 extern void* reallocSmaller(void* block, size_t newSize);
 #endif
 
 
 /*
 ** PR_GetSystemInfo related definitions
 */
--- a/pr/include/md/_solaris.h
+++ b/pr/include/md/_solaris.h
@@ -335,17 +335,16 @@ struct _MDCPU {
 	struct _MDCPU_Unix md_unix;
 };
 
 /* The following defines the unwrapped versions of select() and poll(). */
 extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
 	fd_set *exceptfds, struct timeval *timeout);
 #define _MD_SELECT	_select
 
-#include <stropts.h>
 #include <poll.h>
 #define _MD_POLL _poll
 extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
 
 PR_BEGIN_EXTERN_C
 
 /*
 ** Missing function prototypes
--- a/pr/include/prinit.h
+++ b/pr/include/prinit.h
@@ -39,21 +39,21 @@ 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.0 yyyymmdd"
+#define PR_VERSION  "3.0 19981002"
 #define PR_VMAJOR   3
 #define PR_VMINOR   0
 #define PR_VPATCH   0
-#define PR_BETA     PR_TRUE
+#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
 ** that the underling library will perform as the caller expects.
 **
--- a/pr/include/private/pprmwait.h
+++ b/pr/include/private/pprmwait.h
@@ -20,24 +20,29 @@
 #else
 #define _PPRMWAIT_H
 
 #include "prlock.h"
 #include "prcvar.h"
 #include "prclist.h"
 #include "prthread.h"
 
-#define _PR_HASH_OFFSET 75013
 #define MAX_POLLING_INTERVAL 100
 #define _PR_POLL_COUNT_FUDGE 64
 #define MAX_POLLING_INTERVAL 100
 #define _PR_DEFAULT_HASH_LENGTH 59
 
-#define _MW_REHASH(a, i, m) _MW_HASH((PRUptrdiff)(a) + (i) + _PR_HASH_OFFSET, m)
+/*
+ * Our hash table resolves collisions by open addressing with
+ * double hashing.  See Cormen, Leiserson, and Rivest,
+ * Introduction to Algorithms, p. 232, The MIT Press, 1990.
+ */
+
 #define _MW_HASH(a, m) ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m))
+#define _MW_HASH2(a, m) (1 + ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m - 2)))
 #define _MW_ABORTED(_rv) \
     ((PR_FAILURE == (_rv)) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
 
 typedef enum {_prmw_success, _prmw_rehash, _prmw_error} _PR_HashStory;
 
 typedef struct _PRWaiterHash
 {
     PRUint16 count;             /* current number in hash table */
--- a/pr/include/prsystem.h
+++ b/pr/include/prsystem.h
@@ -27,16 +27,23 @@
 PR_BEGIN_EXTERN_C
 
 /*
 ** Get the host' directory separator.
 **  Pathnames are then assumed to be of the form:
 **      [<sep><root_component><sep>]*(<component><sep>)<leaf_name>
 */
 
+PR_EXTERN(char) PR_GetDirectorySeparator(void);
+
+/*
+** OBSOLETE -- the function name is misspelled.
+** Use PR_GetDirectorySeparator instead.
+*/
+
 PR_EXTERN(char) PR_GetDirectorySepartor(void);
 
 
 /* Types of information available via PR_GetSystemInfo(...) */
 typedef enum {
     PR_SI_HOSTNAME,
     PR_SI_SYSNAME,
     PR_SI_RELEASE,
--- a/pr/src/io/prfile.c
+++ b/pr/src/io/prfile.c
@@ -502,16 +502,18 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
 #if defined(XP_MAC)
 #pragma unused (readPipe, writePipe)
 #endif
 
 #ifdef WIN32
     HANDLE readEnd, writeEnd;
     SECURITY_ATTRIBUTES pipeAttributes;
 
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
     ZeroMemory(&pipeAttributes, sizeof(pipeAttributes));
     pipeAttributes.nLength = sizeof(pipeAttributes);
     pipeAttributes.bInheritHandle = TRUE;
     if (CreatePipe(&readEnd, &writeEnd, &pipeAttributes, 0) == 0) {
         PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
         return PR_FAILURE;
     }
     *readPipe = PR_AllocFileDesc((PRInt32)readEnd, &_pr_fileMethods);
@@ -529,16 +531,18 @@ PR_IMPLEMENT(PRStatus) PR_CreatePipe(
 #ifdef WINNT
     (*readPipe)->secret->md.nonoverlapped = PR_TRUE;
     (*writePipe)->secret->md.nonoverlapped = PR_TRUE;
 #endif
     return PR_SUCCESS;
 #elif defined(XP_UNIX)
     int pipefd[2];
 
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
     if (pipe(pipefd) == -1) {
         /* XXX map pipe error */
         PR_SetError(PR_UNKNOWN_ERROR, errno);
         return PR_FAILURE;
     }
     *readPipe = PR_AllocFileDesc(pipefd[0], &_pr_fileMethods);
     if (NULL == *readPipe) {
         close(pipefd[0]);
--- a/pr/src/io/prmwait.c
+++ b/pr/src/io/prmwait.c
@@ -263,16 +263,18 @@ static _PR_HashStory MW_AddHashInternal(
     ** We try to put the entry in by rehashing _MW_REHASH_MAX times. After
     ** that we declare defeat and force the table to be reconstructed.
     ** Since some fds might be added more than once, won't that cause
     ** collisions even in an empty table?
     */
     PRIntn rehash = _MW_REHASH_MAX;
     PRRecvWait **waiter;
     PRUintn hidx = _MW_HASH(desc->fd, hash->length);
+    PRUintn hoffset = 0;
+
     while (rehash-- > 0)
     {
         waiter = &hash->recv_wait;
         if (NULL == waiter[hidx])
         {
             waiter[hidx] = desc;
             hash->count += 1;
 #if 0
@@ -289,74 +291,94 @@ static _PR_HashStory MW_AddHashInternal(
             return _prmw_error;
         }
 #if 0
         printf("Failing 0x%x->0x%x ", desc, desc->fd);
         printf(
             "table[*%u:%u:%u]: 0x%x->0x%x\n",
             hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd);
 #endif
-        hidx = _MW_REHASH(desc->fd, hidx, hash->length);
+        if (0 == hoffset)
+        {
+            hoffset = _MW_HASH2(desc->fd, hash->length);
+            PR_ASSERT(0 != hoffset);
+        }
+        hidx = (hidx + hoffset) % (hash->length);
     }
     return _prmw_rehash;    
 }  /* MW_AddHashInternal */
 
 static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group)
 {
     PRRecvWait **desc;
-    PRUint32 pidx, length = 0;
+    PRUint32 pidx, length;
     _PRWaiterHash *newHash, *oldHash = group->waiter;
-    
+    PRBool retry;
+    _PR_HashStory hrv;
 
     static const PRInt32 prime_number[] = {
         _PR_DEFAULT_HASH_LENGTH, 179, 521, 907, 1427,
         2711, 3917, 5021, 8219, 11549, 18911, 26711, 33749, 44771};
-    PRUintn primes = (sizeof(prime_number) / sizeof(PRIntn));
+    PRUintn primes = (sizeof(prime_number) / sizeof(PRInt32));
 
     /* look up the next size we'd like to use for the hash table */
     for (pidx = 0; pidx < primes; ++pidx)
     {
         if (prime_number[pidx] == oldHash->length)
         {
-            length = prime_number[pidx + 1];
             break;
         }
     }
-    if (0 == length)
+    /* table size must be one of the prime numbers */
+    PR_ASSERT(pidx < primes);
+
+    /* if pidx == primes - 1, we can't expand the table any more */
+    while (pidx < primes - 1)
     {
-        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
-        return _prmw_error;  /* we're hosed */
-    }
+        /* next size */
+        ++pidx;
+        length = prime_number[pidx];
+
+        /* allocate the new hash table and fill it in with the old */
+        newHash = (_PRWaiterHash*)PR_CALLOC(
+            sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*)));
+        if (NULL == newHash)
+        {
+            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+            return _prmw_error;
+        }
 
-    /* allocate the new hash table and fill it in with the old */
-    newHash = (_PRWaiterHash*)PR_CALLOC(
-        sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*)));
-    if (NULL == newHash)
-    {
-        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
-        return _prmw_error;
+        newHash->length = length;
+        retry = PR_FALSE;
+        for (desc = &oldHash->recv_wait;
+            newHash->count < oldHash->count; ++desc)
+        {
+            PR_ASSERT(desc < &oldHash->recv_wait + oldHash->length);
+            if (NULL != *desc)
+            {
+                hrv = MW_AddHashInternal(*desc, newHash);
+                PR_ASSERT(_prmw_error != hrv);
+                if (_prmw_success != hrv)
+                {
+                    PR_DELETE(newHash);
+                    retry = PR_TRUE;
+                    break;
+                }
+            }
+        }
+        if (retry) continue;
+
+        PR_DELETE(group->waiter);
+        group->waiter = newHash;
+        group->p_timestamp += 1;
+        return _prmw_success;
     }
 
-    newHash->length = length;
-    for (desc = &oldHash->recv_wait; newHash->count < oldHash->count; ++desc)
-    {
-        if (NULL != *desc)
-        {
-            if (_prmw_success != MW_AddHashInternal(*desc, newHash))
-            {
-                PR_ASSERT(!"But, but, but ...");
-                PR_DELETE(newHash);
-                return _prmw_error;
-            }
-        }
-    }
-    PR_DELETE(group->waiter);
-    group->waiter = newHash;
-    group->p_timestamp += 1;
-    return _prmw_success;
+    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    return _prmw_error;  /* we're hosed */
 }  /* MW_ExpandHashInternal */
 
 #ifndef WINNT
 static void _MW_DoneInternal(
     PRWaitGroup *group, PRRecvWait **waiter, PRMWStatus outcome)
 {
     /*
     ** Add this receive wait object to the list of finished I/O
@@ -382,22 +404,28 @@ static PRRecvWait **_MW_LookupInternal(P
     /*
     ** Find the receive wait object corresponding to the file descriptor.
     ** Only search the wait group specified.
     */
     PRRecvWait **desc;
     PRIntn rehash = _MW_REHASH_MAX;
     _PRWaiterHash *hash = group->waiter;
     PRUintn hidx = _MW_HASH(fd, hash->length);
+    PRUintn hoffset = 0;
     
     while (rehash-- > 0)
     {
         desc = (&hash->recv_wait) + hidx;
         if ((*desc != NULL) && ((*desc)->fd == fd)) return desc;
-        hidx = _MW_REHASH(fd, hidx, hash->length);
+        if (0 == hoffset)
+        {
+            hoffset = _MW_HASH2(fd, hash->length);
+            PR_ASSERT(0 != hoffset);
+        }
+        hidx = (hidx + hoffset) % (hash->length);
     }
     return NULL;
 }  /* _MW_LookupInternal */
 
 #ifndef WINNT
 static PRStatus _MW_PollInternal(PRWaitGroup *group)
 {
     PRRecvWait **waiter;
@@ -844,16 +872,24 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvRea
         }
         _PR_THREAD_UNLOCK(me);
         _PR_MD_UNLOCK(&group->mdlock);
         PR_Unlock(group->ml);
         _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
         me->state = _PR_RUNNING;
         PR_Lock(group->ml);
         _PR_MD_LOCK(&group->mdlock);
+        if (_PR_PENDING_INTERRUPT(me)) {
+            PR_REMOVE_LINK(&me->waitQLinks);
+            _PR_MD_UNLOCK(&group->mdlock);
+            me->flags &= ~_PR_INTERRUPT;
+            me->io_suspended = PR_FALSE;
+            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+            goto aborted;
+        }
     }
     io_ready = PR_LIST_HEAD(&group->io_ready);
     PR_ASSERT(io_ready != NULL);
     PR_REMOVE_LINK(io_ready);
     _PR_MD_UNLOCK(&group->mdlock);
     overlapped = (_MDOverlapped *)
         ((char *)io_ready - offsetof(_MDOverlapped, data));
     io_ready = &overlapped->data.mw.desc->internal;
@@ -943,21 +979,22 @@ PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvRea
             PR_ASSERT(!PR_CLIST_IS_EMPTY(&group->io_ready));
         }
         io_ready = PR_LIST_HEAD(&group->io_ready);
         PR_NotifyCondVar(group->io_taken);
         PR_ASSERT(io_ready != NULL);
         PR_REMOVE_LINK(io_ready);
     } while (NULL == io_ready);
 
-aborted:
 failed_poll:
 
 #endif
 
+aborted:
+
     group->waiting_threads -= 1;
 invalid_state:
     (void)MW_TestForShutdownInternal(group);
     PR_Unlock(group->ml);
 
 failed_init:
     if (NULL != io_ready)
     {
@@ -1179,16 +1216,28 @@ PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitG
     else
     {
         PRCList *head = PR_LIST_HEAD(&group->io_ready);
         PR_REMOVE_AND_INIT_LINK(head);
 #ifdef WINNT
         overlapped = (_MDOverlapped *)
             ((char *)head - offsetof(_MDOverlapped, data));
         head = &overlapped->data.mw.desc->internal;
+        if (NULL != overlapped->data.mw.timer)
+        {
+            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+                != overlapped->data.mw.desc->timeout);
+            CancelTimer(overlapped->data.mw.timer);
+        }
+        else
+        {
+            PR_ASSERT(PR_INTERVAL_NO_TIMEOUT
+                == overlapped->data.mw.desc->timeout);
+        }
+        PR_DELETE(overlapped);
 #endif
         recv_wait = (PRRecvWait*)head;
     }
 #ifdef WINNT
 invalid_arg:
     _PR_MD_UNLOCK(&group->mdlock);
 #endif
     PR_Unlock(group->ml);
--- a/pr/src/io/prprf.c
+++ b/pr/src/io/prprf.c
@@ -30,21 +30,21 @@
 #include "prlong.h"
 #include "prlog.h"
 #include "prmem.h"
 
 /*
 ** Note: on some platforms va_list is defined as an array,
 ** and requires array notation.
 */
-#if defined(MKLINUX) || defined(WIN16)
+#if (defined(LINUX) && defined(__powerpc__)) || defined(WIN16)
 #define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
 #else
 #define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
-#endif /*MKLINUX*/
+#endif
 
 /*
 ** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
 */
 
 /*
 ** XXX This needs to be internationalized!
 */
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -1111,16 +1111,18 @@ PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocke
 	return PR_Socket(domain, 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);
 	if (rv == -1) {
 		return PR_FAILURE;
 	}
 
 	f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
 	if (!f[0]) {
 		_PR_MD_CLOSE_SOCKET(osfd[0]);
@@ -1351,17 +1353,16 @@ PRInt32 _PR_EmulateAcceptRead(
         /* copy the new info out where caller can see it */
         PRPtrdiff aligned = (PRPtrdiff)buf + amount + sizeof(void*) - 1;
         *raddr = (PRNetAddr*)(aligned & ~(sizeof(void*) - 1));
         memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
         *nd = accepted;
         return rv;
     }
 
-failed:
     PR_Close(accepted);
     return rv;
 }
 
 /*
 ** Select compatibility
 **
 */
--- a/pr/src/md/mac/macio.c
+++ b/pr/src/md/mac/macio.c
@@ -328,17 +328,17 @@ ErrorExit:
 
 /* File I/O functions called by PR I/O routines */
 PRInt32 _MD_Open(const char *path, PRIntn oflag, int mode)
 {
 // Macintosh doesnąt really have mode bits, just drop them
 #pragma unused (mode)
 
 	OSErr 				err;
- 	ParamBlockRec 		pb;
+ 	HParamBlockRec 		pb;
 	char	 			*macFileName = NULL;
 	Str255				pascalName;
 	PRInt8 				perm;
 	PRInt32				flags = oflag;
 
 	if (flags & PR_RDWR) {
 		oflag = O_RDWR;
 	} else if (flags & PR_WRONLY) {
@@ -370,23 +370,23 @@ open:
 	else if (perm == O_WRONLY)
 		perm = fsWrPerm;
 	else
 		perm = fsRdPerm;	
 	pb.ioParam.ioPermssn 		= perm;
 
 	pb.ioParam.ioMisc 			= NULL;
 	
-	err = PBOpenSync(&pb);
+	err = PBHOpenSync(&pb);
 	if (err == noErr)
 		return pb.ioParam.ioRefNum;
 	else if ((err != fnfErr) || ((oflag & O_CREAT) == 0))
 		goto ErrorExit;
 		
-	err = PBCreateSync(&pb);
+	err = PBHCreateSync(&pb);
 	if (err == noErr)
 		goto open;
 
 ErrorExit:
 	_PR_MD_CURRENT_THREAD()->md.osErrCode = err;
 	_MD_SetError(err);
     return -1;
 }
--- a/pr/src/md/unix/Makefile
+++ b/pr/src/md/unix/Makefile
@@ -190,17 +190,17 @@ ifeq ($(OS_ARCH), AIX)
 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
+		ASFILES += os_$(OS_ARCH).s
 	endif
 	endif
     endif
 endif
 
 ifeq ($(OS_ARCH), SINIX)
     ASFILES   = os_ReliantUNIX.s
 endif
@@ -221,22 +221,20 @@ ifneq ($(USE_PTHREADS), 1)
 #TARGETS		+= $(OBJDIR)/aixwrap.$(OBJ_SUFFIX)
 endif
 endif
 endif
 
 ifeq ($(OS_ARCH),SunOS)
 	ifneq ($(OS_RELEASE),4.1.3_U1)
 		ifeq ($(OS_TEST),sun4u)
-			LIBRARY_NAME = $(ULTRASPARC_LIBRARY)
-			LIBRARY_VERSION = $(MOD_VERSION)
 			ULTRASPARC_ASFILES = os_$(OS_ARCH)_ultrasparc.s
+			ASFILES += $(ULTRASPARC_ASFILES)
+			CFLAGS += -D_PR_ULTRASPARC
 			ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX)))
-			TARGETS		+= $(ULTRASPARC_ASOBJS) $(SHARED_LIBRARY)
-			RELEASE_LIBS = $(SHARED_LIBRARY)
 		endif
 	endif
 endif
 
 INCLUDES = -I$(DIST)/include/private -I$(DIST)/include
 
 include $(MOD_DEPTH)/config/rules.mk
 
@@ -247,19 +245,15 @@ export:: $(TARGETS)
 #	$(INSTALL) -m 444 $(OBJDIR)/aixwrap.$(OBJ_SUFFIX) $(DIST)/lib
 #endif
 #endif
 #endif
 
 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)
 	/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $<
 endif
 endif
 endif
 
 install:: export
--- a/pr/src/md/unix/irix.c
+++ b/pr/src/md/unix/irix.c
@@ -100,16 +100,17 @@ ulock_t _pr_heapLock;
 usema_t *_pr_irix_exit_sem;
 PRInt32 _pr_irix_exit_now = 0;
 PRInt32 _pr_irix_process_exit_code = 0;	/* exit code for PR_ProcessExit */
 PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to
 										   PR_ProcessExit */
 
 int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 };
 static void (*libc_exit)(int) = NULL;
+static void *libc_handle = NULL;
 
 #define _NSPR_DEF_INITUSERS		100	/* default value of CONF_INITUSERS */
 #define _NSPR_DEF_INITSIZE		(4 * 1024 * 1024)	/* 4 MB */
 
 int _irix_initusers = _NSPR_DEF_INITUSERS;
 int _irix_initsize = _NSPR_DEF_INITSIZE;
 
 PRIntn _pr_io_in_progress, _pr_clock_in_progress;
@@ -997,20 +998,30 @@ PRThread *me = _PR_MD_CURRENT_THREAD();
  * The exit code of the process is the exit code of the primordial
  * sproc.
  */
 
 void exit(int status)
 {
 PRThread *me, *thr;
 PRCList *qp;
-void __exit(int status);
+
+	if (!_pr_initialized)  {
+		if (!libc_exit) {
 
-	if (!_pr_initialized) 
-		__exit(status);
+			if (!libc_handle)
+				libc_handle = dlopen("libc.so",RTLD_NOW);
+			if (libc_handle)
+				libc_exit = (void (*)(int)) dlsym(libc_handle, "exit");
+		}
+		if (libc_exit)
+			(*libc_exit)(status);
+		else
+			_exit(status);
+	}
 
 	me = _PR_MD_CURRENT_THREAD();
 
 	if (me == NULL) 		/* detached thread */
 		(*libc_exit)(status);
 
 	PR_ASSERT(_PR_IS_NATIVE_THREAD(me) ||
 						(_PR_MD_CURRENT_CPU())->id == me->cpu->id);
@@ -1424,17 +1435,16 @@ void _MD_EarlyInit(void)
     _MD_IrixIntervalInit();
 }  /* _MD_EarlyInit */
 
 void _MD_IrixInit()
 {
 #if !defined(_PR_PTHREADS)
     struct sigaction sigact;
     PRThread *me = _PR_MD_CURRENT_THREAD();
-	void *libc_handle;
 	int rv;
 
 #ifndef IRIX5_3
 	/*
 	 * enable user-level processing of sigprocmask(); this is an undocumented
 	 * feature available in Irix 6.2, 6.3, 6.4 and 6.5
 	 */
 	__sgi_prda_procmask(USER_LEVEL);
--- a/pr/src/md/unix/objs.mk
+++ b/pr/src/md/unix/objs.mk
@@ -189,16 +189,24 @@ ifeq ($(OS_ARCH),SunOS)
 	ifneq ($(OS_RELEASE),4.1.3_U1)
 	ifneq ($(LOCAL_THREADS_ONLY),1)
             ASFILES = os_$(OS_ARCH).s
 	endif
 	endif
     endif
 endif
 
+ifeq ($(OS_ARCH),SunOS)
+	ifneq ($(OS_RELEASE),4.1.3_U1)
+		ifeq ($(OS_TEST),sun4u)
+			ASFILES += os_$(OS_ARCH)_ultrasparc.s
+		endif
+	endif
+endif
+
 ifeq ($(OS_ARCH), SINIX)
     ASFILES   = os_ReliantUNIX.s
 endif
 
 ifeq ($(OS_ARCH), IRIX)
     ASFILES   = os_Irix.s
 endif
 
--- a/pr/src/md/unix/os_SunOS_ultrasparc.s
+++ b/pr/src/md/unix/os_SunOS_ultrasparc.s
@@ -44,30 +44,30 @@
 !
 !  So, the registers used are:
 !     %o0  [input]   - the address of the value to increment
 !     %o1  [local]   - work register
 !     %o2  [local]   - work register
 !     %o3  [local]   - work register
 !  -----------------------
 
-        ENTRY(PR_AtomicIncrement)       ! standard assembler/ELF prologue
+        ENTRY(_pr_md_ultrasparc_inc)    ! standard assembler/ELF prologue
 
 retryAI:
         ld      [%o0], %o2              ! set o2 to the current value
         add     %o2, 0x1, %o3           ! calc the new value
         mov     %o3, %o1                ! save the return value
         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
         cmp     %o2, %o3                ! see if we set the value
         bne     retryAI                 ! if not, try again
         nop                             ! empty out the branch pipeline
         retl                            ! return back to the caller
         mov     %o1, %o0                ! set the return code to the new value
 
-        SET_SIZE(PR_AtomicIncrement)    ! standard assembler/ELF epilogue
+        SET_SIZE(_pr_md_ultrasparc_inc) ! standard assembler/ELF epilogue
 
 !
 !  end
 !
 !  ======================================================================
 !
 
 !  ======================================================================
@@ -88,30 +88,30 @@ retryAI:
 !
 !  So, the registers used are:
 !     %o0  [input]   - the address of the value to increment
 !     %o1  [local]   - work register
 !     %o2  [local]   - work register
 !     %o3  [local]   - work register
 !  -----------------------
 
-        ENTRY(PR_AtomicDecrement)       ! standard assembler/ELF prologue
+        ENTRY(_pr_md_ultrasparc_dec)       ! standard assembler/ELF prologue
 
 retryAD:
         ld      [%o0], %o2              ! set o2 to the current value
         sub     %o2, 0x1, %o3           ! calc the new value
         mov     %o3, %o1                ! save the return value
         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
         cmp     %o2, %o3                ! see if we set the value
         bne     retryAD                 ! if not, try again
         nop                             ! empty out the branch pipeline
         retl                            ! return back to the caller
         mov     %o1, %o0                ! set the return code to the new value
 
-        SET_SIZE(PR_AtomicDecrement)    ! standard assembler/ELF epilogue
+        SET_SIZE(_pr_md_ultrasparc_dec)    ! standard assembler/ELF epilogue
 
 !
 !  end
 !
 !  ======================================================================
 !
 
 !  ======================================================================
@@ -131,54 +131,54 @@ retryAD:
 !
 !  So, the registers used are:
 !     %o0  [input]   - the address of the value to increment
 !     %o1  [input]   - the new value to set for [%o0]
 !     %o2  [local]   - work register
 !     %o3  [local]   - work register
 !  -----------------------
 
-        ENTRY(PR_AtomicSet)             ! standard assembler/ELF prologue
+        ENTRY(_pr_md_ultrasparc_set)	! standard assembler/ELF prologue
 
 retryAS:
         ld      [%o0], %o2              ! set o2 to the current value
         mov     %o1, %o3                ! set up the new value
         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
         cmp     %o2, %o3                ! see if we set the value
         bne     retryAS                 ! if not, try again
         nop                             ! empty out the branch pipeline
         retl                            ! return back to the caller
         mov     %o3, %o0                ! set the return code to the prev value
 
-        SET_SIZE(PR_AtomicSet)          ! standard assembler/ELF epilogue
+        SET_SIZE(_pr_md_ultrasparc_set) ! standard assembler/ELF epilogue
 
 !
 !  end
 !
 !  ======================================================================
 !
 
 !  ======================================================================
 !
 !  Perform the sequence a = a + b atomically with respect to other
 !  fetch-and-adds to location a in a wait-free fashion.
 !
 !  usage : newval = PR_AtomicAdd(address, val)
 !  return: the value after addition
 !
-        ENTRY(PR_AtomicAdd)       ! standard assembler/ELF prologue
+        ENTRY(_pr_md_ultrasparc_add)       ! standard assembler/ELF prologue
 
 retryAA:
         ld      [%o0], %o2              ! set o2 to the current value
         add     %o2, %o1, %o3           ! calc the new value
         mov     %o3, %o4                ! save the return value
         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
         cmp     %o2, %o3                ! see if we set the value
         bne     retryAA                 ! if not, try again
         nop                             ! empty out the branch pipeline
         retl                            ! return back to the caller
         mov     %o4, %o0                ! set the return code to the new value
 
-        SET_SIZE(PR_AtomicAdd)    		! standard assembler/ELF epilogue
+        SET_SIZE(_pr_md_ultrasparc_add)	! standard assembler/ELF epilogue
 
 !
 !  end
 !
--- a/pr/src/md/unix/solaris.c
+++ b/pr/src/md/unix/solaris.c
@@ -14,16 +14,17 @@
  * Communications Corporation.  Portions created by Netscape are
  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  * Reserved.
  */
 
 #undef _FILE_OFFSET_BITS
 
 #include "primpl.h"
+#include <sys/systeminfo.h>
 
 
 extern PRBool suspendAllOn;
 extern PRThread *suspendAllThread;
 
 extern void _MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri);
 
 PRIntervalTime _MD_Solaris_TicksPerSecond(void)
@@ -53,18 +54,34 @@ PRIntervalTime _MD_Solaris_GetInterval(v
      */
     LL_I2L(resolution, 10000);
     LL_DIV(time.pr64, time.pr64, resolution);
     LL_L2UI(ticks, time.pr64);
     return ticks;
 }
 
 #ifdef _PR_PTHREADS
+
+static PRInt32 _md_ultrasparc = 0;
+
 void _MD_EarlyInit(void)
 {
+#define MACHINE_NAME_LEN	32
+#define ULTRASPARC			"sun4u"
+char machine[MACHINE_NAME_LEN];
+int rv;
+
+	rv = sysinfo(SI_MACHINE, machine, MACHINE_NAME_LEN);
+	/*
+	 * detect an ultrasparc (Sparc V9) system
+	 */
+	if ((rv > 0) && (rv <= MACHINE_NAME_LEN)) {
+		if (!strncmp(machine,ULTRASPARC, strlen(ULTRASPARC)))
+			_md_ultrasparc = 1;
+	}
 }
 
 PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
 {
 	*np = 0;
 	return NULL;
 }
 #endif /* _PR_PTHREADS */
@@ -85,70 +102,104 @@ PRWord *_MD_HomeGCRegisters(PRThread *t,
 #include <synch.h>
 
 static mutex_t _solaris_atomic = DEFAULTMUTEX;
 
 PRInt32
 _MD_AtomicIncrement(PRInt32 *val)
 {
     PRInt32 rv;
-    if (mutex_lock(&_solaris_atomic) != 0)
-        PR_ASSERT(0);
 
-    rv = ++(*val);
+#ifdef _PR_ULTRASPARC
+	if (_md_ultrasparc) {
+		rv = _pr_md_ultrasparc_inc(val);
+	} else {
+#endif
+		if (mutex_lock(&_solaris_atomic) != 0)
+			PR_ASSERT(0);
 
-    if (mutex_unlock(&_solaris_atomic) != 0)\
-        PR_ASSERT(0);
+		rv = ++(*val);
+
+		if (mutex_unlock(&_solaris_atomic) != 0)\
+			PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+	}
+#endif
 
 	return rv;
 }
 
 PRInt32
 _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val)
 {
     PRInt32 rv;
-    if (mutex_lock(&_solaris_atomic) != 0)
-        PR_ASSERT(0);
 
-    rv = ((*ptr) += val);
+#ifdef _PR_ULTRASPARC
+	if (_md_ultrasparc) {
+		rv = _pr_md_ultrasparc_add(ptr, val);
+	} else {
+#endif
+		if (mutex_lock(&_solaris_atomic) != 0)
+			PR_ASSERT(0);
 
-    if (mutex_unlock(&_solaris_atomic) != 0)\
-        PR_ASSERT(0);
+		rv = ((*ptr) += val);
+
+		if (mutex_unlock(&_solaris_atomic) != 0)\
+			PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+	}
+#endif
 
 	return rv;
 }
 
 PRInt32
 _MD_AtomicDecrement(PRInt32 *val)
 {
     PRInt32 rv;
-    if (mutex_lock(&_solaris_atomic) != 0)
-        PR_ASSERT(0);
 
-    rv = --(*val);
+#ifdef _PR_ULTRASPARC
+	if (_md_ultrasparc) {
+		rv = _pr_md_ultrasparc_dec(val);
+	} else {
+#endif
+		if (mutex_lock(&_solaris_atomic) != 0)
+			PR_ASSERT(0);
 
-    if (mutex_unlock(&_solaris_atomic) != 0)\
-        PR_ASSERT(0);
+		rv = --(*val);
 
+		if (mutex_unlock(&_solaris_atomic) != 0)\
+			PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+	}
+#endif
 	return rv;
 }
 
 PRInt32
 _MD_AtomicSet(PRInt32 *val, PRInt32 newval)
 {
     PRInt32 rv;
-    if (mutex_lock(&_solaris_atomic) != 0)
-        PR_ASSERT(0);
+
+#ifdef _PR_ULTRASPARC
+	if (_md_ultrasparc) {
+		rv = _pr_md_ultrasparc_set(val, newval);
+	} else {
+#endif
+		if (mutex_lock(&_solaris_atomic) != 0)
+			PR_ASSERT(0);
 
-    rv = *val;
-    *val = newval;
+		rv = *val;
+		*val = newval;
 
-    if (mutex_unlock(&_solaris_atomic) != 0)\
-        PR_ASSERT(0);
-
+		if (mutex_unlock(&_solaris_atomic) != 0)\
+			PR_ASSERT(0);
+#ifdef _PR_ULTRASPARC
+	}
+#endif
 	return rv;
 }
 #endif  /* _PR_HAVE_ATOMIC_OPS */
 
 #if defined(_PR_GLOBAL_THREADS_ONLY)
 #include <signal.h>
 #include <errno.h>
 #include <fcntl.h>
--- a/pr/src/md/unix/unix.c
+++ b/pr/src/md/unix/unix.c
@@ -25,17 +25,17 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 
 #ifdef _PR_POLL_AVAILABLE
-#include <sys/poll.h>
+#include <poll.h>
 #endif
 
 /* To get FIONREAD */
 #if defined(NCR) || defined(UNIXWARE) || defined(NEC) || defined(SNI) \
         || defined(SONY)
 #include <sys/filio.h>
 #endif
 
@@ -1424,26 +1424,25 @@ extern sigset_t ints_off;
 #endif
 	}
 
     /*
      * if the cpu's pollfd array is not big enough, release it and allocate a new one
      */
     if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) {
         if (_PR_IOQ_POLLFDS(me->cpu) != NULL)
-            PR_DELETE(pollfds);
+            PR_DELETE(_PR_IOQ_POLLFDS(me->cpu));
         pollfds_size =  PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds);
         pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd));
         _PR_IOQ_POLLFDS(me->cpu) = pollfds;
         _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size;
-        pollfdPtr = pollfds;
     } else {
         pollfds = _PR_IOQ_POLLFDS(me->cpu);
-        pollfdPtr = pollfds;
     }
+    pollfdPtr = pollfds;
 
     /*
      * If we need to poll the pipe for waking up a native thread,
      * the pipe's fd is the first element in the pollfds array.
      */
     if (_PR_IS_NATIVE_THREAD_SUPPORTED()) {
         pollfdPtr->fd = _pr_md_pipefd[0];
         pollfdPtr->events = POLLIN;
@@ -2517,17 +2516,22 @@ static PRIntn _MD_solaris25_stat64(const
     return rv;
 }  /* _MD_solaris25_stat64 */
 #endif /* defined(SOLARIS2_5) */
 
 #if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5)
 
 static PRIntn _MD_Unix_lockf64(PRIntn osfd, PRIntn function, PRInt64 size)
 {
-#if defined(RHAPSODY) || defined(BSDI)
+#if defined(HAVE_BSD_FLOCK)
+    /*
+     * XXX: HAVE_BSD_FLOCK is not really the appropriate macro
+     * to test for here.  We are trying to identify the platforms
+     * that don't have lockf, e.g., BSD/OS, FreeBSD, and Rhapsody.
+     */
     /* No lockf */
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
     return -1;
 #else
     PRInt64 desired, maxoff;
     PRInt32 current = lseek(osfd, SEEK_CUR, 0);
 
     LL_I2L(maxoff, 0x7fffffff);
--- a/pr/src/md/unix/unix_errors.c
+++ b/pr/src/md/unix/unix_errors.c
@@ -13,17 +13,17 @@
  * 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 "primpl.h"
 #if defined(_PR_POLL_AVAILABLE)
-#include <sys/poll.h>
+#include <poll.h>
 #endif
 #include <errno.h>
 
 void _MD_unix_map_opendir_error(int err)
 {
 	switch (err) {
 		case ENOTDIR:
 			PR_SetError(PR_NOT_DIRECTORY_ERROR, err);
--- a/pr/src/md/unix/uxpoll.c
+++ b/pr/src/md/unix/uxpoll.c
@@ -20,17 +20,17 @@
 #else  /* defined(_PR_PTHREADS) */
 
 #include "primpl.h"
 
 #include <sys/time.h>
 
 #include <fcntl.h>
 #ifdef _PR_USE_POLL
-#include <sys/poll.h>
+#include <poll.h>
 #endif
 
 #if defined(_PR_USE_POLL)
 static PRInt32 NativeThreadPoll(
     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
 {
     /*
      * This function is mostly duplicated from ptio.s's PR_Poll().
--- a/pr/src/md/unix/uxwrap.c
+++ b/pr/src/md/unix/uxwrap.c
@@ -298,17 +298,17 @@ int select(int width, fd_set *rd, fd_set
  *     -1:  fails, errno indicates the error.
  *      0:  timed out, the revents bitmasks are not set.
  *      positive value: the number of file descriptors for which poll()
  *          has set the revents bitmask.
  *
  *-----------------------------------------------------------------------
  */
 
-#include <sys/poll.h>
+#include <poll.h>
 
 #if defined(AIX4_1)
 int wrap_poll(void *listptr, unsigned long nfds, long timeout)
 #elif (defined(AIX) && !defined(AIX4_1))
 int poll(void *listptr, unsigned long nfds, long timeout)
 #elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9))
 int poll(struct pollfd filedes[], unsigned int nfds, int timeout)
 #elif defined(HPUX9)
--- a/pr/src/md/windows/ntdllmn.c
+++ b/pr/src/md/windows/ntdllmn.c
@@ -51,17 +51,19 @@ PRThread *me;
                 _pr_use_static_tls = FALSE;
             } else {
                 _pr_use_static_tls = TRUE;
             }
             break;
         case DLL_THREAD_ATTACH:
             break;
         case DLL_THREAD_DETACH:
-		me = _MD_GET_ATTACHED_THREAD();
-		if ((me != NULL) && (me->flags & _PR_ATTACHED))
-			_PRI_DetachThread();
+            if (_pr_initialized) {
+                me = _MD_GET_ATTACHED_THREAD();
+                if ((me != NULL) && (me->flags & _PR_ATTACHED))
+                    _PRI_DetachThread();
+            }
             break;
         case DLL_PROCESS_DETACH:
             break;
     }
     return TRUE;
 }
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -2096,18 +2096,17 @@ PRInt32
      * assume that 0, 1, and 2 are console, because if someone closes
      * System.out and then opens a file, they might get file descriptor
      * 1.  An error on *that* version of 1 should be reported, whereas
      * an error on System.out (which was the original 1) should be
      * ignored.  So I use isatty() to ensure that such an error was
      * because of this, and if it was, I ignore the error.
      */
 
-    long handle = _get_osfhandle(fd->secret->md.osfd);
-    BOOL ok = FlushFileBuffers((HANDLE)handle);
+    BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
 
     if (!ok) {
 	DWORD err = GetLastError();
 
 	if (err != ERROR_ACCESS_DENIED) {	/* from winerror.h */
 			_PR_MD_MAP_FSYNC_ERROR(err);
 	    return -1;
 	}
--- a/pr/src/md/windows/w95dllmain.c
+++ b/pr/src/md/windows/w95dllmain.c
@@ -34,17 +34,19 @@ BOOL WINAPI DllMain(
 PRThread *me;
 
     switch (fdwReason) {
         case DLL_PROCESS_ATTACH:
             break;
         case DLL_THREAD_ATTACH:
             break;
         case DLL_THREAD_DETACH:
-		me = _MD_GET_ATTACHED_THREAD();
-		if ((me != NULL) && (me->flags & _PR_ATTACHED))
-			_PRI_DetachThread();
+            if (_pr_initialized) {
+                me = _MD_GET_ATTACHED_THREAD();
+                if ((me != NULL) && (me->flags & _PR_ATTACHED))
+                    _PRI_DetachThread();
+            }
             break;
         case DLL_PROCESS_DETACH:
             break;
     }
     return TRUE;
 }
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -277,18 +277,17 @@ PRInt32
      * assume that 0, 1, and 2 are console, because if someone closes
      * System.out and then opens a file, they might get file descriptor
      * 1.  An error on *that* version of 1 should be reported, whereas
      * an error on System.out (which was the original 1) should be
      * ignored.  So I use isatty() to ensure that such an error was due
      * to this bogosity, and if it was, I ignore the error.
      */
 
-    long handle = _get_osfhandle(fd->secret->md.osfd);
-    BOOL ok = FlushFileBuffers((HANDLE)handle);
+    BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);
 
     if (!ok) {
 	DWORD err = GetLastError();
 	if (err != ERROR_ACCESS_DENIED) {	// from winerror.h
 			_PR_MD_MAP_FSYNC_ERROR(err);
 	    return -1;
 	}
     }
--- a/pr/src/misc/prinit.c
+++ b/pr/src/misc/prinit.c
@@ -350,16 +350,17 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup()
         /*
          * XXX: We are freeing the heap memory here so that Purify won't
          * complain, but we should also free other kinds of resources
          * that are allocated by the _PR_InitXXX() functions.
          * Ideally, for each _PR_InitXXX(), there should be a corresponding
          * _PR_XXXCleanup() that we can call here.
          */
         _PR_CleanupBeforeExit();
+        _pr_initialized = PR_FALSE;
         return PR_SUCCESS;
     }
     return PR_FAILURE;
 }
 #endif /* defined(_PR_PTHREADS) */
 
 /*
  *------------------------------------------------------------------------
--- a/pr/src/misc/prsystem.c
+++ b/pr/src/misc/prsystem.c
@@ -20,19 +20,34 @@
 #include "prsystem.h"
 #include "prprf.h"
 
 #if defined(XP_UNIX)
 #include <unistd.h>
 #include <sys/utsname.h>
 #endif
 
+PR_IMPLEMENT(char) PR_GetDirectorySeparator()
+{
+    return PR_DIRECTORY_SEPARATOR;
+}  /* PR_GetDirectorySeparator */
+
+/*
+** OBSOLETE -- the function name is misspelled.
+*/
 PR_IMPLEMENT(char) PR_GetDirectorySepartor()
 {
-    return PR_DIRECTORY_SEPARATOR;
+#if defined(DEBUG)
+    static PRBool warn = PR_TRUE;
+    if (warn) {
+        warn = _PR_Obsolete("PR_GetDirectorySepartor()",
+                "PR_GetDirectorySeparator()");
+    }
+#endif
+    return PR_GetDirectorySeparator();
 }  /* PR_GetDirectorySepartor */
 
 PR_IMPLEMENT(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen)
 {
     PRUintn len = 0;
 
     if (!_pr_initialized) _PR_ImplicitInitialization();
 
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -744,17 +744,20 @@ recycle:
     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_ASSERT(pt_continuation_done == my_op->status);
     
     if (NULL != pt_tq.tail)
     {
-        pt_tq.tail->status = pt_continuation_recycle;
+        if (pt_tq.tail->status != pt_continuation_abort)
+        {
+            pt_tq.tail->status = pt_continuation_recycle;
+        }
         PR_NotifyCondVar(pt_tq.tail->complete);
 #if defined(DEBUG)
         pt_debug.recyclesNeeded += 1;
 #endif
     }
 #if defined(DEBUG)
      else pt_debug.quiescentIO += 1;
 #endif
@@ -784,17 +787,17 @@ static PRIntn pt_Continue(pt_Continuatio
         if (NULL == pt_tq.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 = PR_GetCurrentThread();  /* I'm taking control */
+            pt_tq.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 */
         }
         else
         {
             rv = PR_WaitCondVar(op->complete, PR_INTERVAL_NO_TIMEOUT);
             /*
@@ -804,25 +807,46 @@ static PRIntn pt_Continue(pt_Continuatio
              * from the list is still valid.
              *
              * Don't call interrupt on the continuation thread. That'll just
              * irritate him. He's cycling around at least every mx_poll_ticks
              * anyhow and should notice the request in there. When he does
              * notice, this operation will be finished and the op's status
              * marked as pt_continuation_done.
              */
-            if ((PR_FAILURE == rv)  /* the wait failed */
-            && (pt_continuation_pending == op->status)  /* but the op hasn't */
-            && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))  /* was interrupted */
+            if ((PR_FAILURE == rv)  /* the wait was interrupted */
+            && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
             {
-                op->status = pt_continuation_abort;  /* go around the loop again */
+                if (pt_continuation_done == op->status)
+                {
+                    /*
+                     * The op is done and has been removed
+                     * from the timed queue.  We must not
+                     * change op->status, otherwise this
+                     * thread will go around the loop again.
+                     *
+                     * It's harsh to mark the op failed with
+                     * interrupt error when the io is already
+                     * done, but we should indicate the fact
+                     * that the thread was interrupted.  So
+                     * we set the aborted flag to abort the
+                     * thread's next blocking call.  Is this
+                     * the right thing to do?
+                     */
+                    self->state |= PT_THREAD_ABORTED;
+                }
+                else
+                {
+                    /* go around the loop again */
+                    op->status = pt_continuation_abort;
+                }
             }
             /*
              * If we're to recycle, continue within this loop. This will
-             * cause this thread to be come the continuation thread.
+             * cause this thread to become the continuation thread.
              */
 
         }
     } while (pt_continuation_done != op->status);
 
 
     PR_Unlock(pt_tq.ml);  /* we provided the locking */
 
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -194,34 +194,25 @@ static PRThread* pt_AttachThread(void)
     PRThread *thred = NULL;
     void *privateData = NULL;
 
     /*
      * NSPR must have been initialized when PR_AttachThread is called.
      * We cannot have PR_AttachThread call implicit initialization
      * because if multiple threads call PR_AttachThread simultaneously,
      * NSPR may be initialized more than once.
-     * We can't call PR_SetError() either.
+     * We can't call any function that calls PR_GetCurrentThread()
+     * either (e.g., PR_SetError()) as that will result in infinite
+     * recursion.
      */
     if (!_pr_initialized) return NULL;
 
-    /*
-     * If the thread is already known, it will have a non-NULL value
-     * in its private data. If that's the case, simply suppress the
-     * attach and note an error.
-     */
-    PTHREAD_GETSPECIFIC(pt_book.key, privateData);
-    if (NULL != privateData)
-    {
-        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
-        return NULL;
-    }
+    /* PR_NEWZAP must not call PR_GetCurrentThread() */
     thred = PR_NEWZAP(PRThread);
-    if (NULL == thred) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
-    else
+    if (NULL != thred)
     {
         int rv;
 
         thred->priority = PR_PRIORITY_NORMAL;
         thred->id = pthread_self();
         rv = pthread_setspecific(pt_book.key, thred);
         PR_ASSERT(0 == rv);
 
@@ -712,16 +703,27 @@ PR_IMPLEMENT(PRStatus) PR_Sleep(PRInterv
         PR_DestroyCondVar(cv);
     }
     return rv;
 }  /* PR_Sleep */
 
 static void _pt_thread_death(void *arg)
 {
     PRThread *thred = (PRThread*)arg;
+
+    if (thred->state & PT_THREAD_FOREIGN)
+    {
+        PR_Lock(pt_book.ml);
+        thred->prev->next = thred->next;
+        if (NULL == thred->next)
+            pt_book.last = thred->prev;
+        else
+            thred->next->prev = thred->prev;
+        PR_Unlock(pt_book.ml);
+    }
     _PR_DestroyThreadPrivate(thred);
     if (NULL != thred->errorString)
         PR_Free(thred->errorString);
     if (NULL != thred->io_cv)
         PR_DestroyCondVar(thred->io_cv);
     PR_Free(thred->stack);
 #if defined(DEBUG)
     memset(thred, 0xaf, sizeof(PRThread));
@@ -830,16 +832,17 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup()
          * problem.
          */
         if (0 == pt_book.system)
         {
             PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
             PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
         }
         _pt_thread_death(me);
+        _pr_initialized = PR_FALSE;
         return PR_SUCCESS;
     }
     return PR_FAILURE;
 }  /* PR_Cleanup */
 
 PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
 {
     _exit(status);
--- a/pr/tests/Makefile
+++ b/pr/tests/Makefile
@@ -32,17 +32,16 @@ else
 DIRS = dll
 endif
 
 ifeq ($(OS_TARGET),OS2)
 OS_CFLAGS = $(OS_EXE_CFLAGS)
 endif
 
 CSRCS =             \
-	acceptread.c    \
 	accept.c		\
 	alarm.c			\
 	atomic.c		\
 	attach.c		\
 	bigfile.c		\
 	cleanup.c		\
 	cltsrv.c		\
 	concur.c	    \
@@ -58,16 +57,17 @@ CSRCS =             \
 	fsync.c	        \
 	getproto.c		\
 	i2l.c		    \
 	initclk.c		\
 	inrval.c		\
 	instrumt.c      \
 	intrupt.c       \
 	io_timeout.c    \
+	ioconthr.c      \
 	ipv6.c          \
 	join.c    		\
 	joinkk.c        \
 	joinku.c        \
 	joinuk.c        \
 	joinuu.c        \
 	layer.c		    \
 	lazyinit.c		\
--- a/pr/tests/accept.c
+++ b/pr/tests/accept.c
@@ -43,30 +43,32 @@
 #include "prpriv.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "plgetopt.h"
 #include "plerror.h"
 
-#define BASE_PORT 8001
+#define BASE_PORT 10000
 
 #define CLIENT_DATA        128
 
 #define ACCEPT_NORMAL        0x1
 #define ACCEPT_FAST        0x2
 #define ACCEPT_READ        0x3
 #define ACCEPT_READ_FAST    0x4
 #define ACCEPT_READ_FAST_CB    0x5
 
 #define CLIENT_NORMAL        0x1
 #define CLIENT_TIMEOUT_ACCEPT    0x2
 #define CLIENT_TIMEOUT_SEND    0x3
 
+#define SERVER_MAX_BIND_COUNT        100
+
 #if defined(XP_MAC) || defined(XP_OS2)
 #define TIMEOUTSECS 10
 #else
 #define TIMEOUTSECS 2
 #endif
 PRIntervalTime timeoutTime;
 
 static PRInt32 count = 1;
@@ -180,36 +182,48 @@ static  PRThread *clientThread;
 static  PRNetAddr *raddr;
 static  char buf[4096 + 64];
 static  PRInt32 status;
 static  PRInt32 bytesRead;
 
 static void 
 RunTest(PRInt32 acceptType, PRInt32 clientAction)
 {
+int i;
 
     /* First bind to the socket */
     listenSock = PR_NewTCPSocket();
     if (!listenSock) {
         failed_already=1;
         if (debug_mode)
             PR_fprintf(output, "unable to create listen socket\n");
         return;
     }
+	memset(&listenAddr, 0 , sizeof(listenAddr));
     listenAddr.inet.family = PR_AF_INET;
     listenAddr.inet.port = PR_htons(BASE_PORT);
     listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
-    rv = PR_Bind(listenSock, &listenAddr);
-    if (rv == PR_FAILURE) {
+    /*
+     * try a few times to bind server's address, if addresses are in
+     * use
+     */
+    i = 0;
+    while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) {
+        if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
+            listenAddr.inet.port += 2;
+            if (i++ < SERVER_MAX_BIND_COUNT)
+                continue;
+        }
         failed_already=1;
         if (debug_mode)
-            PR_fprintf(output, "unable to bind\n");
-        return;
+        	PR_fprintf(output,"accept: ERROR - PR_Bind failed\n");
+		return;
     }
 
+
     rv = PR_Listen(listenSock, 100);
     if (rv == PR_FAILURE) {
         failed_already=1;
         if (debug_mode)
             PR_fprintf(output, "unable to listen\n");
         return;
     }
 
@@ -303,17 +317,17 @@ RunTest(PRInt32 acceptType, PRInt32 clie
                 /* Invalid test case */
                 TEST_ASSERT(0);
                 break;
             case CLIENT_NORMAL:
                 TEST_ASSERT(clientSock);
                 TEST_ASSERT(status == CLIENT_DATA);
                 break;
             case CLIENT_TIMEOUT_SEND:
-                TEST_ASSERT(clientSock);
+                TEST_ASSERT(clientSock == NULL);
                 TEST_ASSERT(status == -1);
                 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
                 break;
             }
             break;
         case ACCEPT_READ_FAST_CB:
             status = PR_NTFast_AcceptRead_WithTimeoutCallback(
                 listenSock, &clientSock, &raddr, buf, 4096,
@@ -325,17 +339,17 @@ RunTest(PRInt32 acceptType, PRInt32 clie
                 break;
             case CLIENT_NORMAL:
                 TEST_ASSERT(clientSock);
                 TEST_ASSERT(status == CLIENT_DATA);
                 break;
             case CLIENT_TIMEOUT_SEND:
                 if (debug_mode)
                     PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock);
-                TEST_ASSERT(clientSock);
+                TEST_ASSERT(clientSock == NULL);
                 TEST_ASSERT(status == -1);
                 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR);
                 break;
             }
             break;
 #endif
         }
         if (clientSock != NULL) {
--- a/pr/tests/bigfile.c
+++ b/pr/tests/bigfile.c
@@ -160,17 +160,17 @@ PRIntn main(PRIntn argc, char **argv)
     }
     PL_DestroyOptState(opt);
 
     if (0 == count) count = DEFAULT_COUNT;
     if (0 == filesize) filesize = DEFAULT_FILESIZE;
     if (NULL == filename)
     {
         if (DEFAULT_FILESIZE != filesize) return Usage();
-        else filename = "/usr/tmp/bigfile.dat";
+        else filename = "bigfile.dat";
     }
 
     if (PR_FAILURE == DeleteIfFound(filename)) return 1;
 
     test_result = 0;
 
     LL_I2L(zero_meg, 0);
     LL_I2L(one_meg, 1000000);
--- a/pr/tests/cltsrv.c
+++ b/pr/tests/cltsrv.c
@@ -508,19 +508,20 @@ static PRStatus ProcessRequest(PRFileDes
         TEST_ASSERT(bytes > 0);
     }
 
     PR_Lock(server->ml);
     server->operations += 1;
     server->bytesTransferred += filebytes;
     PR_Unlock(server->ml);
 
-    rv = PR_Close(file); file = NULL;
+    rv = PR_Close(file);
     if (Aborted(rv)) goto aborted;
     TEST_ASSERT(PR_SUCCESS == rv);
+    file = NULL;
 
     TEST_LOG(
         cltsrv_log_file, TEST_LOG_VERBOSE,
         ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename));
     file = PR_Open(descriptor->filename, PR_RDONLY, 0);
     if (NULL == file)
     {
         rv = PR_FAILURE;
@@ -591,19 +592,20 @@ static PRStatus ProcessRequest(PRFileDes
     
     PR_Lock(server->ml);
     server->bytesTransferred += filebytes;
     PR_Unlock(server->ml);
 
     rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH);
     if (Aborted(rv)) goto aborted;
 
-    rv = PR_Close(file); file = NULL;
+    rv = PR_Close(file);
     if (Aborted(rv)) goto aborted;
     TEST_ASSERT(PR_SUCCESS == rv);
+    file = NULL;
 
 aborted:
     PR_ClearInterrupt();
     if (NULL != file) PR_Close(file);
     drv = PR_Delete(descriptor->filename);
     TEST_ASSERT(PR_SUCCESS == drv);
 exit:
     TEST_LOG(
--- a/pr/tests/foreign.c
+++ b/pr/tests/foreign.c
@@ -207,64 +207,72 @@ static void PR_CALLBACK lazyEntry(void *
 {
     PR_ASSERT(NULL == arg);
 }  /* lazyEntry */
 
 
 static void OneShot(void *arg)
 {
     PRUintn pdkey;
+    PRLock *lock;
+    PRFileDesc *fd;
+    PRDir *dir;
     PRFileDesc *pair[2];
     PRIntn test = (PRIntn)arg;
 
 	for (test = 0; test < 11; ++test) {
 
     switch (test)
     {
         case 0:
-            (void)PR_NewLock(); 
+            lock = PR_NewLock(); 
 			DPRINTF((output,"Thread[0x%x] called PR_NewLock\n",
 			PR_GetCurrentThread()));
+            PR_DestroyLock(lock);
             break;
             
         case 1:
             (void)PR_SecondsToInterval(1);
 			DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n",
 			PR_GetCurrentThread()));
             break;
             
         case 2: (void)PR_CreateThread(
             PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL,
             PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); 
 			DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n",
 			PR_GetCurrentThread()));
             break;
             
         case 3:
-            (void)PR_Open("/usr/tmp/", PR_RDONLY, 0); 
+            fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666); 
 			DPRINTF((output,"Thread[0x%x] called PR_Open\n",
 			PR_GetCurrentThread()));
+            PR_Close(fd);
             break;
             
         case 4:
-            (void)PR_NewUDPSocket(); 
+            fd = PR_NewUDPSocket(); 
 			DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n",
 			PR_GetCurrentThread()));
+            PR_Close(fd);
             break;
             
         case 5:
-            (void)PR_NewTCPSocket(); 
+            fd = PR_NewTCPSocket(); 
 			DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n",
 			PR_GetCurrentThread()));
+            PR_Close(fd);
             break;
             
         case 6:
-            (void)PR_OpenDir("/usr/tmp/"); 
+            dir = PR_OpenDir("/usr/tmp/"); 
 			DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n",
 			PR_GetCurrentThread()));
+            PR_CloseDir(dir);
             break;
             
         case 7:
             (void)PR_NewThreadPrivateIndex(&pdkey, NULL);
 			DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n",
 			PR_GetCurrentThread()));
             break;
         
@@ -273,16 +281,18 @@ static void OneShot(void *arg)
 			DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n",
 			PR_GetCurrentThread()));
             break;
             
         case 9:
             (void)PR_NewTCPSocketPair(pair);
 			DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n",
 			PR_GetCurrentThread()));
+            PR_Close(pair[0]);
+            PR_Close(pair[1]);
             break;
             
         case 10:
             PR_SetConcurrency(2);
 			DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n",
 			PR_GetCurrentThread()));
             break;
             
--- a/pr/tests/fsync.c
+++ b/pr/tests/fsync.c
@@ -37,17 +37,17 @@ static void Help(void)
 }  /* Help */
 
 PRIntn main(PRIntn argc, char **argv)
 {
     PRStatus rv;
     PLOptStatus os;
     PRUint8 *buffer;
     PRFileDesc *file = NULL;
-    const char *filename = "/usr/tmp/sync.dat";
+    const char *filename = "sync.dat";
     PRUint32 index, loops, iterations = 10, filesize = 10;
     PRIntn flags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
     PLOptState *opt = PL_CreateOptState(argc, argv, "hSK:c:");
     PRIntervalTime time, total = 0, shortest = 0x7fffffff, longest = 0;
 
     err = PR_GetSpecialFD(PR_StandardError);
 
     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
--- a/pr/tests/instrumt.c
+++ b/pr/tests/instrumt.c
@@ -329,17 +329,16 @@ static void TraceTest( void )
     PRThread *t1, *t2;
     
     PR_LOG( lm, msgLevel,
         ("Begin TraceTest"));    
 
     size = SMALL_TRACE_BUFSIZE;
     PR_SET_TRACE_OPTION( PRTraceBufSize, &size );
     PR_GET_TRACE_OPTION( PRTraceBufSize, &i );
-    PR_ASSERT( i == size );
     
     PR_CREATE_TRACE( th, "TraceTest", "tt2", "A description for the trace test" );
     PR_CREATE_TRACE( th, "TraceTest", "tt3", "A description for the trace test" );
     PR_CREATE_TRACE( th, "TraceTest", "tt4", "A description for the trace test" );
     PR_CREATE_TRACE( th, "TraceTest", "tt5", "A description for the trace test" );
     PR_CREATE_TRACE( th, "TraceTest", "tt6", "A description for the trace test" );
     PR_CREATE_TRACE( th, "TraceTest", "tt7", "A description for the trace test" );
     PR_CREATE_TRACE( th, "TraceTest", "tt8", "A description for the trace test" );
new file mode 100644
--- /dev/null
+++ b/pr/tests/ioconthr.c
@@ -0,0 +1,123 @@
+/* -*- 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.0 (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.
+ */
+
+/*
+ * This is a test for the io continuation thread machinery
+ * in pthreads.
+ */
+
+#include "nspr.h"
+#include <stdio.h>
+
+int num_threads = 10;  /* must be an even number */
+PRThreadScope thread_scope = PR_GLOBAL_THREAD;
+
+void ThreadFunc(void *arg)
+{
+    PRFileDesc *fd = (PRFileDesc *) arg;
+    char buf[1024];
+    PRInt32 nbytes;
+    PRErrorCode err;
+
+    nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20));
+    if (nbytes == -1) {
+        err = PR_GetError();
+        if (err != PR_PENDING_INTERRUPT_ERROR) {
+            fprintf(stderr, "PR_Recv failed: (%d, %d)\n",
+                    err, PR_GetOSError());
+            PR_ProcessExit(1);
+        }
+        if (PR_Close(fd) == PR_FAILURE) {
+            fprintf(stderr, "PR_Close failed\n");
+            PR_ProcessExit(1);
+        }
+    } else {
+        fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes);
+        PR_ProcessExit(1);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    PRFileDesc **fds;
+    PRThread **threads;
+    PRIntervalTime start, elapsed;
+    int index;
+
+    fds = (PRFileDesc **) PR_MALLOC(num_threads * sizeof(PRFileDesc *));
+    PR_ASSERT(fds != NULL);
+    threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *));
+    PR_ASSERT(threads != NULL);
+
+    for (index = 0; index < (num_threads / 2); index++) {
+        if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) {
+            fprintf(stderr, "PR_NewTCPSocket failed\n");
+            PR_ProcessExit(1);
+        }
+
+        threads[2 * index] = PR_CreateThread(
+                PR_USER_THREAD, ThreadFunc, fds[2 * index],
+                PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
+        if (NULL == threads[2 * index]) {
+            fprintf(stderr, "PR_CreateThread failed\n");
+            PR_ProcessExit(1);
+        }
+        threads[2 * index + 1] = PR_CreateThread(
+                PR_USER_THREAD, ThreadFunc, fds[2 * index + 1],
+                PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
+        if (NULL == threads[2 * index + 1]) {
+            fprintf(stderr, "PR_CreateThread failed\n");
+            PR_ProcessExit(1);
+        }
+    }
+
+    /* Let the threads block in PR_Recv */
+    PR_Sleep(PR_SecondsToInterval(2));
+
+    printf("Interrupting the threads\n");
+    fflush(stdout);
+    start = PR_IntervalNow();
+    for (index = 0; index < num_threads; index++) {
+        if (PR_Interrupt(threads[index]) == PR_FAILURE) {
+            fprintf(stderr, "PR_Interrupt failed\n");
+            PR_ProcessExit(1);
+        }
+    }
+    for (index = 0; index < num_threads; index++) {
+        if (PR_JoinThread(threads[index]) == PR_FAILURE) {
+            fprintf(stderr, "PR_JoinThread failed\n");
+            PR_ProcessExit(1);
+        }
+    }
+    elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
+    printf("Threads terminated in %d milliseconds\n",
+            PR_IntervalToMilliseconds(elapsed));
+    fflush(stdout);
+    
+    /* We are being very generous and allow 10 seconds. */
+    if (elapsed >= PR_SecondsToInterval(10)) {
+        fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n");
+        PR_ProcessExit(1);
+    }
+
+    PR_DELETE(threads);
+    PR_DELETE(fds);
+    printf("PASS\n");
+    PR_Cleanup();
+    return 0;
+}
--- a/pr/tests/layer.c
+++ b/pr/tests/layer.c
@@ -79,16 +79,19 @@ static PRFileDesc *PopLayer(PRFileDesc *
 static void PR_CALLBACK Client(void *arg)
 {
     PRStatus rv;
     PRUint8 buffer[100];
     PRIntn empty_flags = 0;
     PRIntn bytes_read, bytes_sent;
     PRFileDesc *stack = (PRFileDesc*)arg;
 
+    /* Initialize the buffer so that Purify won't complain */
+    memset(buffer, 0, sizeof(buffer));
+
     rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
     PR_ASSERT(PR_SUCCESS == rv);
     while (minor_iterations-- > 0)
     {
         bytes_sent = PR_Send(
             stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
         PR_ASSERT(sizeof(buffer) == bytes_sent);
         if (verbosity > chatty)
@@ -152,17 +155,17 @@ static void PR_CALLBACK Server(void *arg
 }  /* Server */
 
 static PRInt32 PR_CALLBACK MyRecv(
     PRFileDesc *fd, void *buf, PRInt32 amount,
     PRIntn flags, PRIntervalTime timeout)
 {
     char *b = (char*)buf;
     PRFileDesc *lo = fd->lower;
-    PRInt32 rv, readin = 0, request;
+    PRInt32 rv, readin = 0, request = 0;
     rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
     if (verbosity > chatty) PR_fprintf(
         logFile, "MyRecv sending permission for %d bytes\n", request);
     if (0 < rv)
     {
         if (verbosity > chatty) PR_fprintf(
             logFile, "MyRecv received permission request for %d bytes\n", request);
         rv = lo->methods->send(
--- a/pr/tests/multiwait.c
+++ b/pr/tests/multiwait.c
@@ -151,16 +151,19 @@ static void PR_CALLBACK ClientThread(voi
     PRFileDesc *server = PR_NewTCPSocket();
     if ((NULL == server)
     && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) return;
     MW_ASSERT(NULL != server);
 
     if (verbosity > chatty)
         PR_fprintf(debug, "%s: Server socket @0x%x\n", shared->title, server);
 
+    /* Initialize the buffer so that Purify won't complain */
+    memset(buffer, 0, sizeof(buffer));
+
     rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address);
     MW_ASSERT(PR_SUCCESS == rv);
 
     if (verbosity > quiet)
         PR_fprintf(debug, "%s: Client opening connection\n", shared->title);
     rv = PR_Connect(server, &server_address, PR_INTERVAL_NO_TIMEOUT);
 
     if (PR_FAILURE == rv)
@@ -254,18 +257,16 @@ static void OneOpOneThread(Shared *share
 
 static void ManyOpOneThread(Shared *shared)
 {
     PRStatus rv;
     PRIntn index;
     PRRecvWait *desc_in;
     PRRecvWait *desc_out;
 
-    desc_in = (PRRecvWait*)PR_CALLOC(sizeof(PRRecvWait*) * wait_objects);
-
     if (verbosity > quiet)
         PR_fprintf(debug, "%s: adding %d descs\n", shared->title, wait_objects);
 
     for (index = 0; index < wait_objects; ++index)
     {
         desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout);
 
         rv = PR_AddWaitFileDesc(shared->group, desc_in);
@@ -599,16 +600,17 @@ static void RealOneGroupIO(Shared *share
         PR_fprintf(debug, "%s: interrupting/joining client_threads\n", shared->title);
     for (index = 0; index < client_threads; ++index)
     {
         rv = PR_Interrupt(client_thread[index]);
         MW_ASSERT(PR_SUCCESS == rv);
         rv = PR_JoinThread(client_thread[index]);
         MW_ASSERT(PR_SUCCESS == rv);
     }
+    PR_DELETE(client_thread);
 
     if (verbosity > quiet)
         PR_fprintf(debug, "%s: interrupting/joining enumeration_thread\n", shared->title);
     rv = PR_Interrupt(enumeration_thread);
     MW_ASSERT(PR_SUCCESS == rv);
     rv = PR_JoinThread(enumeration_thread);
     MW_ASSERT(PR_SUCCESS == rv);
 
--- a/pr/tests/nbconn.c
+++ b/pr/tests/nbconn.c
@@ -45,16 +45,17 @@
 #define printf PR_LogPrint
 extern void SetupMacPrintfLog(char *logFile);
 static char *hosts[4] = {"cynic", "warp", "gandalf", "neon"};
 #endif
 
 #define SERVER_MAX_BIND_COUNT        100
 #define DATA_BUF_SIZE        		 256
 #define TCP_SERVER_PORT            10000
+#define TCP_UNUSED_PORT            211
 
 typedef struct Server_Param {
     PRFileDesc *sp_fd;		/* server port */
 } Server_Param;
 static void PR_CALLBACK TCP_Server(void *arg);
 
 int _debug_on;
 #define DPRINTF(arg) if (_debug_on) printf arg
@@ -65,17 +66,17 @@ static PRIntn connection_failure_test();
 int main(int argc, char **argv)
 {
     PRHostEnt he;
     char buf[1024];
     PRNetAddr addr;
     PRPollDesc pd;
     PRStatus rv;
     PRSocketOptionData optData;
-	const char *hostname;
+	const char *hostname = NULL;
     PRIntn default_case, n, bytes_read, bytes_sent;
 	PRInt32 failed_already = 0;
 #ifdef XP_MAC
 	int index;
 	PRIntervalTime timeout;
 #endif
 
     /*
@@ -274,17 +275,17 @@ connection_success_test()
 	PRNetAddr netaddr;
 	PRInt32 i, rv;
     PRPollDesc pd;
     PRSocketOptionData optData;
 	PRThread *thr = NULL;
 	Server_Param sp;
 	char send_buf[DATA_BUF_SIZE], recv_buf[DATA_BUF_SIZE];
     PRIntn default_case, n, bytes_read, bytes_sent;
-    PRIntn failed_already;
+    PRIntn failed_already = 0;
 
 	/*
 	 * Create a tcp socket
 	 */
 	if ((sockfd = PR_NewTCPSocket()) == NULL) {
 		fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
 		failed_already=1;
 		goto def_exit;
@@ -336,21 +337,16 @@ connection_success_test()
 		if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
 			DPRINTF(("Connect in progress\n"));
 		} else  {
 			fprintf(stderr,"Error - PR_Connect failed: (%d, %d)\n",
 									PR_GetError(), PR_GetOSError());
 			failed_already=1;
 			goto def_exit;
 		}
-	} else {
-		PR_ASSERT(rv == PR_SUCCESS);
-		fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n");
-		failed_already=1;
-		goto def_exit;
 	}
 	/*
 	 * Now create a thread to accept a connection
 	 */
 	sp.sp_fd = sockfd;
 	thr = PR_CreateThread(PR_USER_THREAD, TCP_Server, (void *)&sp, 
 			PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
 	if (thr == NULL) {
@@ -368,22 +364,16 @@ connection_success_test()
 	n = PR_Poll(&pd, 1, timeout);
 #endif
 	if (n == -1) {
 		fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
 									PR_GetError(), PR_GetOSError());
 		failed_already=1;
 		goto def_exit;
 	}
-	if (pd.out_flags != PR_POLL_WRITE) {
-		fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n",
-									pd.out_flags);
-		failed_already=1;
-		goto def_exit;
-	}
 	if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
 		PRInt32 rv;
 
 		DPRINTF(("Connection successful\n"));
 
 		/*
 		 * Write some data, read it back and check data integrity to
 		 * make sure the connection is good
@@ -515,16 +505,22 @@ connection_failure_test()
 	}
 
 	if (PR_GetSockName(sockfd, &netaddr) < 0) {
 		fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n",
 									PR_GetError(), PR_GetOSError());
 		failed_already=1;
 		goto def_exit;
 	}
+#ifdef AIX
+	/*
+	 * On AIX, set to unused/reserved port
+	 */
+	netaddr.inet.port = PR_htons(TCP_UNUSED_PORT);
+#endif
 	if ((conn_fd = PR_NewTCPSocket()) == NULL) {
 		fprintf(stderr,"Error - PR_NewTCPSocket failed\n");
 		failed_already=1;
 		goto def_exit;
 	}
 	optData.option = PR_SockOpt_Nonblocking;
 	optData.value.non_blocking = PR_TRUE;
 	PR_SetSocketOption(conn_fd, &optData);
@@ -546,22 +542,16 @@ connection_failure_test()
 	n = PR_Poll(&pd, 1, timeout);
 #endif
 	if (n == -1) {
 		fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n",
 									PR_GetError(), PR_GetOSError());
 		failed_already=1;
 		goto def_exit;
 	}
-	if (pd.out_flags != PR_POLL_WRITE) {
-		fprintf(stderr,"Error - PR_Poll returned invalid outflags: 0x%x\n",
-									pd.out_flags);
-		failed_already=1;
-		goto def_exit;
-	}
 	if (PR_GetConnectStatus(&pd) == PR_SUCCESS) {
 		PRInt32 rv;
 		fprintf(stderr,"PR_GetConnectStatus succeeded, expected to fail\n");
 		failed_already = 1;
 		goto def_exit;
 	}
 	rv = PR_GetError();
 	DPRINTF(("Connection failed, successfully with PR_Error %d\n",rv));
--- a/pr/tests/nblayer.c
+++ b/pr/tests/nblayer.c
@@ -95,16 +95,19 @@ static void PR_CALLBACK Client(void *arg
     PRIntn mits;
     PRInt32 ready;
     PRUint8 buffer[100];
     PRPollDesc polldesc;
     PRIntn empty_flags = 0;
     PRIntn bytes_read, bytes_sent;
     PRFileDesc *stack = (PRFileDesc*)arg;
 
+    /* Initialize the buffer so that Purify won't complain */
+    memset(buffer, 0, sizeof(buffer));
+
     rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
     if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError()))
     {
         if (verbosity > quiet)
             PR_fprintf(logFile, "Client connect 'in progress'\n");
         do
         {
             polldesc.fd = stack;
@@ -294,19 +297,18 @@ static void PR_CALLBACK Server(void *arg
             } while (bytes_sent < bytes_read);
             PR_ASSERT(bytes_read == bytes_sent);
             if (verbosity > chatty)
                 PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent);
         }
     } while (0 != bytes_read);
 
     if (verbosity > quiet)
-        PR_fprintf(logFile, "Server shutting down and closing stack\n");
+        PR_fprintf(logFile, "Server shutting down stack\n");
     rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
-    rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
 
 }  /* Server */
 
 static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd)
 {
     PR_DELETE(fd->secret);  /* manage my secret file object */
     return (PR_GetDefaultIOMethods())->close(fd);  /* let him do all the work */
 }  /* MyClose */
@@ -625,9 +627,9 @@ PRIntn main(PRIntn argc, char **argv)
         rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv);
         rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv);
         if (verbosity > silent)
             PR_fprintf(logFile, "Ending layered test\n");
     }
     return 0;
 }  /* main */
 
-/* layer.c */
+/* nblayer.c */
--- a/pr/tests/nonblock.c
+++ b/pr/tests/nonblock.c
@@ -69,16 +69,19 @@ clientThreadFunc(void *arg)
     PRNetAddr addr;
     char buf[CHUNK_SIZE];
     int i;
     PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME);
     PRIntn optval = 1;
     PRStatus retVal;
     PRInt32 nBytes;
 
+    /* Initialize the buffer so that Purify won't complain */
+    memset(buf, 0, sizeof(buf));
+
     addr.inet.family = PR_AF_INET;
     addr.inet.port = PR_htons((PRUint16)port);
     addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
     PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip);
 
     /* time 1 */
     PR_Sleep(unitTime);
     sock = PR_NewTCPSocket();
--- a/pr/tests/provider.c
+++ b/pr/tests/provider.c
@@ -76,17 +76,17 @@
 /*
 ** This is the beginning of the test
 */
 
 #define RECV_FLAGS 0
 #define SEND_FLAGS 0
 #define BUFFER_SIZE 1024
 #define DEFAULT_BACKLOG 5
-#define DEFAULT_PORT 12848
+#define DEFAULT_PORT 13000
 #define DEFAULT_CLIENTS 1
 #define ALLOWED_IN_ACCEPT 1
 #define DEFAULT_CLIPPING 1000
 #define DEFAULT_WORKERS_MIN 1
 #define DEFAULT_WORKERS_MAX 1
 #define DEFAULT_SERVER "localhost"
 #define DEFAULT_EXECUTION_TIME 10
 #define DEFAULT_CLIENT_TIMEOUT 4000
@@ -701,17 +701,17 @@ static PRStatus NewThread(
 
     switch (thread_provider)
     {
     case thread_nspr:
         {
             PRThread *thread = PR_CreateThread(
                 PR_USER_THREAD, start, arg,
                 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
-                PR_UNJOINABLE_THREAD, 0);
+                PR_JOINABLE_THREAD, 0);
             rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS;
         }
         break;
     case thread_pthread:
 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
         {
             int rv;
             pthread_t id;
@@ -1065,16 +1065,17 @@ static Verbosity IncrementVerbosity(void
 
 PRIntn main(PRIntn argc, char** argv)
 {
     PRUintn index;
     PRBool boolean;
     CSClient_t *client;
     PRStatus rv, joinStatus;
     CSServer_t *server = NULL;
+	char *thread_type;
 
     PRUintn backlog = DEFAULT_BACKLOG;
     PRUintn clients = DEFAULT_CLIENTS;
     const char *serverName = DEFAULT_SERVER;
     PRBool serverIsLocal = PR_TRUE;
     PRUintn accepting = ALLOWED_IN_ACCEPT;
     PRUintn workersMin = DEFAULT_WORKERS_MIN;
     PRUintn workersMax = DEFAULT_WORKERS_MAX;
@@ -1090,16 +1091,26 @@ PRIntn main(PRIntn argc, char** argv)
      * -e <seconds> duration of the test in seconds
      * -s <string>  dsn name of server (implies no server here)
      * -v           verbosity
      */
 
     PLOptStatus os;
     PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp");
 
+#if defined(WIN32)
+	thread_provider = thread_win32;
+#elif defined(_PR_PTHREADS)
+	thread_provider = thread_pthread;
+#elif defined(IRIX)
+	thread_provider = thread_sproc;
+#else
+    thread_provider = thread_nspr;
+#endif
+
     debug_out = PR_GetSpecialFD(PR_StandardError);
 
     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
     {
         if (PL_OPT_BAD == os) continue;
         switch (opt->option)
         {
         case 'G':  /* use global threads */
@@ -1342,15 +1353,26 @@ PRIntn main(PRIntn argc, char** argv)
         PR_DestroyLock(server->ml);
         PR_DELETE(server);
     }
 
     TEST_LOG(
         cltsrv_log_file, TEST_LOG_ALWAYS, 
         ("main(0x%p): test complete\n", PR_CurrentThread()));
 
-    PT_FPrintStats(debug_out, "\nPThread Statistics\n");
+	if (thread_provider == thread_win32)
+		thread_type = "\nWin32 Thread Statistics\n";
+	else if (thread_provider == thread_pthread)
+		thread_type = "\npthread Statistics\n";
+	else if (thread_provider == thread_sproc)
+		thread_type = "\nsproc Statistics\n";
+    else {
+		PR_ASSERT(thread_provider == thread_nspr);
+		thread_type = "\nPRThread Statistics\nn";
+	}
+
+    PT_FPrintStats(debug_out, thread_type);
 
     TimeOfDayMessage("Test exiting at", PR_CurrentThread());
     return 0;
 }  /* main */
 
 /* cltsrv.c */
--- a/pr/tests/socket.c
+++ b/pr/tests/socket.c
@@ -53,17 +53,17 @@ extern void SetupMacPrintfLog(char *logF
 
 #ifdef XP_PC
 #define mode_t int
 #endif
 
 #define DPRINTF(arg) if (_debug_on) printf arg
 
 #ifdef XP_PC
-char *TEST_DIR = "C:\\tmp\\prdir";
+char *TEST_DIR = "prdir";
 char *SMALL_FILE_NAME = "prsmallf";
 char *LARGE_FILE_NAME = "prlargef";
 #else
 char *TEST_DIR = "/tmp/prsocket_test_dir";
 char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file";
 char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";
 #endif
 #define SMALL_FILE_SIZE        (8 * 1024)        /* 8 KB        */
--- a/pr/tests/sockopt.c
+++ b/pr/tests/sockopt.c
@@ -124,18 +124,20 @@ PRIntn main(PRIntn argc, char *argv)
                 break;
             case PR_SockOpt_NoDelay:         /* don't delay send to coalesce packets */
             case PR_SockOpt_Keepalive:       /* keep connections alive */
                 socket = tcp;
             case PR_SockOpt_Reuseaddr:       /* allow local address reuse */
                 value = &boolean;
                 size = &booleansize;
                 break;
+#ifndef WIN32
             case PR_SockOpt_MaxSegment:      /* maximum segment size */
                 socket = tcp;
+#endif
             case PR_SockOpt_RecvBufferSize:  /* send buffer size */
             case PR_SockOpt_SendBufferSize:  /* receive buffer size */
                 value = &segment;
                 size = &segmentsize;
                 break;
 
             case PR_SockOpt_IpTimeToLive:    /* time to live */
                 value = &ttl;
@@ -145,19 +147,30 @@ PRIntn main(PRIntn argc, char *argv)
             case PR_SockOpt_AddMember:       /* add an IP group membership */
             case PR_SockOpt_DropMember:      /* drop an IP group membership */
             case PR_SockOpt_McastInterface:  /* multicast interface address */
             case PR_SockOpt_McastTimeToLive: /* multicast timetolive */
             case PR_SockOpt_McastLoopback:   /* multicast loopback */
             default:
                 continue;
             }
-
-            rv = PR_SetSockOpt(socket, option, value, *size);
-            if (PR_FAILURE == rv) Failed("PR_SetSockOpt()", tag[option]);
+			/*
+			 * TCP_MAXSEG can only be read, not set
+			 */
+            if (option != PR_SockOpt_MaxSegment) {
+#ifdef WIN32
+            	if ((option != PR_SockOpt_McastTimeToLive) &&
+								(option != PR_SockOpt_McastLoopback))
+#endif
+				{
+            		rv = PR_SetSockOpt(socket, option, value, *size);
+            		if (PR_FAILURE == rv) Failed("PR_SetSockOpt()",
+														tag[option]);
+				}
+			}
             
             rv = PR_GetSockOpt(socket, option, &value, size);
             if (PR_FAILURE == rv) Failed("PR_GetSockOpt()", tag[option]);
         }
         for(option = PR_SockOpt_Linger; option < PR_SockOpt_Last; Incr(&option))
         {
             PRSocketOptionData data;
             PRFileDesc *fd = tcp;
@@ -195,24 +208,38 @@ PRIntn main(PRIntn argc, char *argv)
                     break;    
                 case PR_SockOpt_McastLoopback:
                     fd = udp; 
                     data.value.mcast_loopback = PR_TRUE; 
                     break;    
                 case PR_SockOpt_NoDelay:
                     data.value.no_delay = PR_TRUE;         
                     break;    
+#ifndef WIN32
                 case PR_SockOpt_MaxSegment:
                     data.value.max_segment = segment;      
                     break;    
+#endif
                 default: continue;
             }
 
-            rv = PR_SetSocketOption(fd, &data);
-            if (PR_FAILURE == rv) Failed("PR_SetSocketOption()", tag[option]);
+			/*
+			 * TCP_MAXSEG can only be read, not set
+			 */
+            if (option != PR_SockOpt_MaxSegment) {
+#ifdef WIN32
+            	if ((option != PR_SockOpt_McastTimeToLive) &&
+								(option != PR_SockOpt_McastLoopback))
+#endif
+				{
+            		rv = PR_SetSocketOption(fd, &data);
+            		if (PR_FAILURE == rv)
+							Failed("PR_SetSocketOption()", tag[option]);
+				}
+			}
 
             rv = PR_GetSocketOption(fd, &data);
             if (PR_FAILURE == rv) Failed("PR_GetSocketOption()", tag[option]);
         }
     }
 #ifndef XP_MAC
     PR_fprintf(err, "%s\n", (failed) ? "FAILED" : "PASSED");
 #else
--- a/pr/tests/tmocon.c
+++ b/pr/tests/tmocon.c
@@ -420,17 +420,17 @@ int Tmocon(int argc, char **argv)
     for (index = 0; index < threads; ++index)
         rv = PR_JoinThread(thread[index]);
 
     PR_DELETE(thread);
 
     PR_fprintf(
         PR_GetSpecialFD(PR_StandardError), "%s\n",
         ((shared->failed) ? "FAILED" : "PASSED"));
-    return (shared->failed) ? 0 : 1;
+    return (shared->failed) ? 1 : 0;
 }
 
 int main(int argc, char **argv)
 {
     return (PR_VersionCheck(PR_VERSION)) ?
         PR_Initialize(Tmocon, argc, argv, 4) : -1;
 }  /* main */