fixup commit for branch 'FASTLOAD_20010703_BRANCH' FASTLOAD_20010703_BRANCH FASTLOAD_20010703_BASE
authorcvs2hg
Wed, 27 Jun 2001 02:57:52 +0000
branchFASTLOAD_20010703_BRANCH
changeset 1979 a59dfe0487617ad9cfe23e76f0d047bc3dd682c6
parent 1978 ceeaccac0ceba1a128a0c012f90b87ddc4ad7899
child 1991 b840cbf51d9f5d054519d13ec74e1709f0b57b80
push idunknown
push userunknown
push dateunknown
fixup commit for branch 'FASTLOAD_20010703_BRANCH'
lib/tests/event.c
pr/src/md/mac/prgcleak.c
pr/src/md/unix/os_Linux_ia64.s
pr/src/md/unix/os_SunOS_sparcv9.s
pr/tests/acceptreademu.c
pr/tests/append.c
pr/tests/env.c
pr/tests/errset.c
pr/tests/freeif.c
pr/tests/intrio.c
pr/tests/obsints.c
pr/tests/peek.c
pr/tests/pipeping2.c
pr/tests/pipepong2.c
pr/tests/primblok.c
pr/tests/prpollml.c
pr/tests/rmdir.c
pr/tests/selintr.c
deleted file mode 100644
--- a/lib/tests/event.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/*
- * The contents of this file are subject to the Netscape Public License
- * Version 1.1 (the "NPL"); you may not use this file except in
- * compliance with the NPL.  You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- * 
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- * 
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation.  Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
- * Reserved.
- */
-
-/*
-** File:        event.c
-** Description: Test functions in plevent.c
-**
-** This test creates a number of threads. Each thread sends
-** an event to the next higher numbered (in creation order)
-** thread. On receipt of that event, that thread in turn
-** sends an event to the next thread until the event goes
-** around the circle of threads. The test self terminates
-** after a predetermined number of events have circled the
-** circle of threads.
-**
-**
-** Internal Design
-**
-** TState:
-** TState is the Event Handler State Strucuture. It
-** contains the state for an EventThread. There is one TState
-** structure per thread running in the EventThread()
-** function.
-**
-** TestEvents():
-** The TestEvent() function is the "real main()" function of
-** this test. The function creates 'numThreads' instances of
-** a thread running the EventThread() function. He then waits
-** for these threads to complete.
-**
-** EventThread():
-** The EventThread() function runs in the context of a thread
-** instance created by TestEvents(). The function processes
-** events from threads running the same function. An event is
-** created and sent around the ring 
-** 
-** EventHandler(): 
-** The EventHandler() function processes events received by
-** EventThread(). His job is to create and send a new event
-** to the next EventThread() thread in the ring of threads.
-**
-** EventDestructor():
-** The EventDestructor() function disposes of the event.
-** Required by the protocol for PLEvent.
-**
-**
-*/          
-
-#include "nspr.h"
-#include "plgetopt.h"
-#include "plevent.h"
-
-/*
-** TState -- Event Handler State Structure
-**
-*/
-typedef struct TState
-{
-    PRIntn  threadIndex;        /* thread number. [0..n] */
-    PRIntn  quitSwitch;         /* when 0, running; when 1, order to quit */
-    PLEventQueue *eventQueue;   /* event queue for this thread */
-} TState;
-
-/*
-** Thread Event structure
-*/
-typedef struct TEvent
-{
-    PLEvent plEvent;
-    PRIntn  tIndex;         /* Thread index of thread receiving event */
-    PRIntn  quitSwitch;     /* when 0, keep going; when 1 set TState[me].quitSwitch = 1 */
-} TEvent;
-
-static void PR_CALLBACK EventHandler( TEvent *ep );
-static void PR_CALLBACK EventDestructor( TEvent *ep );
-PR_EXTERN(PRIntn) TestEvents( void );
-
-/* --- Global data ---------------------------------------*/
-
-static PRIntn  failed = 0;          /* when 1, indicates test failed */
-static PRLogModuleInfo    *lm;      /* LogModule "test" */
-
-static PRIntn   numThreads = 4;     /* Number of threads in the ring */
-static PRIntn   iterations = 7;     /* Number of iterations per thread */
-
-static PRIntn   iterationCount = 0; /* Counting times around the ring */
-
-static PRIntn   activeThreads = 0;  /* Number of active threads */
-static TState   *tsa = NULL;         /* array of all TStates */
-static PRMonitor *mon;
-static PRBool   useMonitoredQueue = PR_FALSE;
-
-/*
-** SendEvent() -- Send an event to the next thread
-**
-*/
-static void SendEvent( 
-    PRIntn threadIndex, 
-    PRIntn quitSwitch 
-)
-{
-    PLEventQueue    *eq = (tsa+threadIndex)->eventQueue;
-    TEvent  *event = PR_NEWZAP( TEvent );
-    
-    PR_ASSERT( event != NULL );
-
-    PR_LOG( lm, PR_LOG_NOTICE, ("SendEvent: event: %p, threadIndex: %d quitSwitch: %d", event, threadIndex, quitSwitch ));
-    PL_ENTER_EVENT_QUEUE_MONITOR( eq );
-    
-    PL_InitEvent( &event->plEvent, 0,
-            (PLHandleEventProc)EventHandler, 
-            (PLDestroyEventProc)EventDestructor  );
-    event->quitSwitch = quitSwitch;
-    event->tIndex = threadIndex;
-
-    PL_PostEvent( eq, &event->plEvent );
-    PL_EXIT_EVENT_QUEUE_MONITOR( eq );
-    return;        
-} /* end SendEvent() */
- 
-
-/*
-** EventHandler() -- Handle events posted from EventThread()
-**
-** if message says quit
-**   Tell my thread to quit.
-** create an event, if I quit, pass it on.
-** PostEvent( TEvent.threadIndex+1)
-**
-*/
-static void PR_CALLBACK EventHandler( TEvent *ep )
-{
-    TState  *ts = tsa+(ep->tIndex);
-    PRIntn  ndx;
-
-    PR_LOG( lm, PR_LOG_NOTICE, ("EventHandler: %p, ti: %d", ep, ep->tIndex ));
-    if ( ep->quitSwitch == PR_TRUE )
-        ts->quitSwitch = PR_TRUE;
-
-    if ( ts->threadIndex == 0 )
-    {
-        if ( iterationCount++ >= iterations )
-            ep->quitSwitch = PR_TRUE;
-    }
-    /*
-    ** Calculate thread index of the next thread to get an event,
-    ** then send him the event.
-    */
-    ndx = ep->tIndex +1;
-    if ( ndx >= numThreads )
-        ndx = 0;
-
-    SendEvent( ndx, ep->quitSwitch );
-
-    return;    
-} /* end EventHandler() */
-
-/*
-** EventDestructor() -- Free  the event handled in EventHandler()
-**
-** free(the event)
-**
-*/
-static void PR_CALLBACK EventDestructor( TEvent *ep )
-{
-    PR_LOG( lm, PR_LOG_NOTICE, ("EventDestructor: event: %p", ep ));
-    PR_Free( ep );
-    return;
-} /* end EventDestructor() */
-
-/*
-** EventThread() -- Drive events around the ring of threads
-** 
-** do
-**   WaitforEvent()
-**   HandleEvent()
-**   PR_LOG( the event)
-** until told to quit
-** 
-*/
-static void EventThread( void *arg )
-{   
-    TEvent *ep;
-    TState *ts = (TState *)arg;
-
-
-   while ( ts->eventQueue == 0 )
-        PR_Sleep( PR_MillisecondsToInterval(100));
-
-    do {
-        ep = (TEvent *)PL_WaitForEvent( ts->eventQueue );
-        PL_HandleEvent( (PLEvent *)ep );
-        PR_LOG( lm, PR_LOG_NOTICE,("EventThread() Handled event: %d", ts->threadIndex ));
-    } while( ts->quitSwitch == 0 );
-
-    PR_EnterMonitor( mon );
-    activeThreads--;
-    PR_Notify( mon );
-    PR_ExitMonitor( mon );
-
-    PR_LOG( lm, PR_LOG_NOTICE,("EventThread() Exit: %d", ts->threadIndex ));
-
-    return;    
-} /* end EventThread() */
-
-/*
-** TestEvents() -- 
-**
-** Create array of TEvents
-** CreateThreads of EventThreads
-** PostEvent() to the first EventThread
-** monitor for completion.
-** report results.
-**
-*/
-PR_IMPLEMENT( PRIntn ) TestEvents( void )
-{
-    PRIntn  i;
-
-    lm = PR_NewLogModule( "test" );
-    PR_LOG( lm, PR_LOG_NOTICE,("TestEvent(): Starting" ));
-    mon = PR_NewMonitor();
-    
-    /*
-    ** Allocate array of all TEvents
-    */
-    tsa = PR_Calloc( numThreads ,sizeof(TState));
-
-    /*
-    ** Initialize this event queue and create its thead
-    */
-    PR_ASSERT( tsa != NULL );
-    activeThreads = numThreads;
-    for ( i = 0 ; i < numThreads; i++ )
-    {
-        PRThread *me;
-        PLEventQueue *eq;
-
-        (tsa +i)->threadIndex = i;
-        (tsa +i)->quitSwitch = 0;
-        me = PR_CreateThread( PR_USER_THREAD,
-                EventThread, 
-                (void *)(tsa +i),
-                PR_PRIORITY_NORMAL,
-                PR_LOCAL_THREAD,
-                PR_UNJOINABLE_THREAD,
-                0 );
-        if ( me == NULL )
-        {
-            PR_LOG( lm, PR_LOG_ERROR, ("TestEvents: Can't create thread %d", i ));
-            exit(1);
-        }
-
-        if ( useMonitoredQueue == PR_TRUE )
-            eq = PL_CreateMonitoredEventQueue( "EventThread", me );
-        else
-            eq = PL_CreateNativeEventQueue( "EventThread", me );
-        PR_ASSERT( eq != NULL );
-
-        (tsa+i)->eventQueue = eq;
-    }
-    
-
-    /*
-    ** Post and event to the first thread in the ring
-    ** to get things started.
-    */
-    SendEvent( 0, 0 );
-    /* 
-    ** Wait for all threads to exit 
-    */
-    PR_EnterMonitor( mon );
-    while ( activeThreads > 0 ) 
-    	PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
-    PR_ExitMonitor( mon );
-
-    /*
-    ** Release assets: event queue for each thread, the list of TStates.
-    */
-    for ( i = 0 ; i < numThreads; i++ )
-    {
-        PL_DestroyEventQueue( (tsa +i)->eventQueue );
-    }
-    PR_Free( tsa );
-    
-    /*
-    ** All done! Log completion and return
-    */
-    PR_LOG( lm, PR_LOG_NOTICE,("TestEvent(): Ending" ));
-    return 0;
-} /* end TestEvents() */
-
-
-
-
-static void Help( void )
-{
-    printf( "Event: Help\n"
-            "syntax: event [-d][-h]\n"
-            "where: -h gives this message\n"
-            "       -d sets debug mode (a no-op here)\n"
-        );    
-} /* end Help() */
-
-PRIntn main(PRIntn argc, char **argv )
-{
-    PLOptStatus os;
-  	PLOptState *opt = PL_CreateOptState(argc, argv, "dhmt:i:");
-
-
-	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
-    {
-		if (PL_OPT_BAD == os) continue;
-        switch (opt->option)
-        {
-        case 'm':  /* use monitored event queue */
-            useMonitoredQueue = PR_TRUE;
-            break;
-        case 'd':  /* debug mode (noop) */
-            break;
-        case 't':  /* needs guidance */
-            numThreads = atol(opt->value);
-            break;
-        case 'i':  /* needs guidance */
-            iterations = atol(opt->value);
-            break;
-        case 'h':  /* needs guidance */
-        default:
-            Help();
-            return 2;
-        }
-    }
-	PL_DestroyOptState(opt);
-
-    TestEvents();
-    /*
-    ** Evaluate results and exit
-    */
-    if (failed)
-      {
-        printf("FAILED\n");
-        return(1);
-      }
-    else
-      {
-        printf("PASSED\n");
-        return(0);
-      }
-}  /* end main() */
-
-/* end event.c */
deleted file mode 100644
--- a/pr/src/md/mac/prgcleak.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/*
- * The contents of this file are subject to the Netscape Public License
- * Version 1.1 (the "NPL"); you may not use this file except in
- * compliance with the NPL.  You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- * 
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- * 
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation.  Portions created by Netscape are
- * Copyright (C) 1999 Netscape Communications Corporation.  All Rights
- * Reserved.
- *
- * Contributor(s):
- *   Patrick Beard <beard@netscape.com>
- */
-
-/*
- * prgcleak.c
- */
-
-#ifdef GC_LEAK_DETECTOR
-
-/* for FILE */
-#include <stdio.h>
-
-/* NSPR stuff */
-#include "generic_threads.h"
-#include "primpl.h"
-
-extern FILE *GC_stdout, *GC_stderr;
-
-extern void GC_gcollect(void);
-extern void GC_clear_roots(void);
-
-static PRStatus PR_CALLBACK scanner(PRThread* t, void** baseAddr,
-                                    PRUword count, void* closure)
-{
-    char* begin = (char*)baseAddr;
-    char* end = (char*)(baseAddr + count);
-    GC_mark_range_proc marker = (GC_mark_range_proc) closure;
-    marker(begin, end);
-    return PR_SUCCESS;
-}
-
-static void mark_all_stacks(GC_mark_range_proc marker)
-{
-    PR_ScanStackPointers(&scanner, (void *)marker);
-}
-
-static void locker(void* mutex)
-{
-    if (_PR_MD_CURRENT_CPU())
-        PR_Lock(mutex);
-}
-
-static void unlocker(void* mutex)
-{
-    if (_PR_MD_CURRENT_CPU())
-        PR_Unlock(mutex);
-}
-
-static void stopper(void* unused)
-{
-    if (_PR_MD_CURRENT_CPU())
-        PR_SuspendAll();
-}
-
-static void starter(void* unused)
-{
-    if (_PR_MD_CURRENT_CPU())
-        PR_ResumeAll();
-}
-
-void _PR_InitGarbageCollector()
-{
-    void* mutex;
-
-    /* redirect GC's stderr to catch startup leaks. */
-    GC_stderr = fopen("StartupLeaks", "w");
-
-    mutex = PR_NewLock();
-    PR_ASSERT(mutex != NULL);
-
-    GC_generic_init_threads(&mark_all_stacks, mutex, 
-            &locker, &unlocker,
-            &stopper, &starter);
-}
-
-void _PR_ShutdownGarbageCollector()
-{
-    /* do anything you need to shut down the collector. */
-}
-
-#endif /* GC_LEAK_DETECTOR */
new file mode 100644
--- /dev/null
+++ b/pr/src/md/unix/os_Linux_ia64.s
@@ -0,0 +1,80 @@
+// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// 
+// The contents of this file are subject to the Mozilla Public
+// License Version 1.1 (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of
+// the License at http://www.mozilla.org/MPL/
+// 
+// Software distributed under the License is distributed on an "AS
+// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+// implied. See the License for the specific language governing
+// rights and limitations under the License.
+// 
+// The Original Code is the Netscape Portable Runtime (NSPR).
+// 
+// The Initial Developer of the Original Code is Netscape
+// Communications Corporation.  Portions created by Netscape are 
+// Copyright (C) 2000 Netscape Communications Corporation.  All
+// Rights Reserved.
+// 
+// Contributor(s):
+// 
+// Alternatively, the contents of this file may be used under the
+// terms of the GNU General Public License Version 2 or later (the
+// "GPL"), in which case the provisions of the GPL are applicable 
+// instead of those above.  If you wish to allow use of your 
+// version of this file only under the terms of the GPL and not to
+// allow others to use your version of this file under the MPL,
+// indicate your decision by deleting the provisions above and
+// replace them with the notice and other provisions required by
+// the GPL.  If you do not delete the provisions above, a recipient
+// may use your version of this file under either the MPL or the
+// GPL.
+//
+
+.text
+        .align 16
+        .global _PR_ia64_AtomicIncrement#
+        .proc _PR_ia64_AtomicIncrement#
+_PR_ia64_AtomicIncrement:
+        fetchadd4.acq r8 = [r32], 1
+        ;;
+        adds r8 = 1, r8
+        br.ret.sptk.many b0
+        .endp _PR_ia64_AtomicIncrement#
+//
+        .align 16
+        .global _PR_ia64_AtomicDecrement#
+        .proc _PR_ia64_AtomicDecrement#
+_PR_ia64_AtomicDecrement:
+        fetchadd4.rel r8 = [r32], -1
+        ;;
+        adds r8 = -1, r8
+        br.ret.sptk.many b0
+        .endp _PR_ia64_AtomicDecrement#
+//
+        .align 16
+        .global _PR_ia64_AtomicAdd#
+        .proc _PR_ia64_AtomicAdd#
+_PR_ia64_AtomicAdd:
+        ld4 r15 = [r32]
+        ;;
+.L3:
+        mov r14 = r15
+        mov ar.ccv = r15
+        add r8 = r15, r33
+        ;;
+        cmpxchg4.acq r15 = [r32], r8, ar.ccv
+        ;;
+        cmp4.ne p6, p7 =  r15, r14
+        (p6) br.cond.dptk .L3
+        br.ret.sptk.many b0
+        .endp _PR_ia64_AtomicAdd#
+//
+        .align 16
+        .global _PR_ia64_AtomicSet#
+        .proc _PR_ia64_AtomicSet#
+_PR_ia64_AtomicSet:
+        xchg4 r8 = [r32], r33
+        br.ret.sptk.many b0
+        .endp _PR_ia64_AtomicSet#
new file mode 100644
--- /dev/null
+++ b/pr/src/md/unix/os_SunOS_sparcv9.s
@@ -0,0 +1,201 @@
+! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+! 
+! The contents of this file are subject to the Mozilla Public
+! License Version 1.1 (the "License"); you may not use this file
+! except in compliance with the License. You may obtain a copy of
+! the License at http://www.mozilla.org/MPL/
+! 
+! Software distributed under the License is distributed on an "AS
+! IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+! implied. See the License for the specific language governing
+! rights and limitations under the License.
+! 
+! The Original Code is the Netscape Portable Runtime (NSPR).
+! 
+! The Initial Developer of the Original Code is Netscape
+! Communications Corporation.  Portions created by Netscape are 
+! Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+! Rights Reserved.
+! 
+! Contributor(s):
+! 
+! Alternatively, the contents of this file may be used under the
+! terms of the GNU General Public License Version 2 or later (the
+! "GPL"), in which case the provisions of the GPL are applicable 
+! instead of those above.  If you wish to allow use of your 
+! version of this file only under the terms of the GPL and not to
+! allow others to use your version of this file under the MPL,
+! indicate your decision by deleting the provisions above and
+! replace them with the notice and other provisions required by
+! the GPL.  If you do not delete the provisions above, a recipient
+! may use your version of this file under either the MPL or the
+! GPL.
+! 
+
+!
+!  atomic increment, decrement and swap routines for V8+ sparc (ultrasparc)
+!  using CAS (compare-and-swap) atomic instructions
+!
+!  this MUST be compiled with an ultrasparc-aware assembler
+!
+!  standard asm linkage macros; this module must be compiled
+!  with the -P option (use C preprocessor)
+
+#include <sys/asm_linkage.h>
+
+!  ======================================================================
+!
+!  Perform the sequence a = a + 1 atomically with respect to other
+!  fetch-and-adds to location a in a wait-free fashion.
+!
+!  usage : val = PR_AtomicIncrement(address)
+!  return: current value (you'd think this would be old val)
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created;
+!  we use the caller's stack frame so what would normally be %i (input)
+!  registers are actually %o (output registers).  Also, we must not
+!  overwrite the contents of %l (local) registers as they are not
+!  assumed to be volatile during calls.
+!
+!  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(_MD_AtomicIncrement)      ! 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(_MD_AtomicIncrement)   ! standard assembler/ELF epilogue
+
+!
+!  end
+!
+!  ======================================================================
+!
+
+!  ======================================================================
+!
+!  Perform the sequence a = a - 1 atomically with respect to other
+!  fetch-and-decs to location a in a wait-free fashion.
+!
+!  usage : val = PR_AtomicDecrement(address)
+!  return: current value (you'd think this would be old val)
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created;
+!  we use the caller's stack frame so what would normally be %i (input)
+!  registers are actually %o (output registers).  Also, we must not
+!  overwrite the contents of %l (local) registers as they are not
+!  assumed to be volatile during calls.
+!
+!  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(_MD_AtomicDecrement)      ! 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(_MD_AtomicDecrement)   ! standard assembler/ELF epilogue
+
+!
+!  end
+!
+!  ======================================================================
+!
+
+!  ======================================================================
+!
+!  Perform the sequence a = b atomically with respect to other
+!  fetch-and-stores to location a in a wait-free fashion.
+!
+!  usage : old_val = PR_AtomicSet(address, newval)
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created;
+!  we use the caller's stack frame so what would normally be %i (input)
+!  registers are actually %o (output registers).  Also, we must not
+!  overwrite the contents of %l (local) registers as they are not
+!  assumed to be volatile during calls.
+!
+!  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(_MD_AtomicSet)            ! 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(_MD_AtomicSet)         ! 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(_MD_AtomicAdd)      ! 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(_MD_AtomicAdd)    		! standard assembler/ELF epilogue
+
+!
+!  end
+!
new file mode 100644
--- /dev/null
+++ b/pr/tests/acceptreademu.c
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * This test is the same as acceptread.c except that it uses the
+ * emulated acceptread method instead of the regular acceptread.
+ */
+
+#include <prio.h>
+#include <prprf.h>
+#include <prinit.h>
+#include <prnetdb.h>
+#include <prinrval.h>
+#include <prthread.h>
+#include <pprio.h>
+
+#include <plerror.h>
+
+#include <stdlib.h>
+
+#define DEFAULT_PORT 12273
+#define GET "GET / HTTP/1.0\n\n"
+static PRFileDesc *std_out, *err_out;
+static PRIntervalTime write_dally, accept_timeout;
+static PRDescIdentity emu_layer_ident;
+static PRIOMethods emu_layer_methods;
+
+/* the acceptread method in emu_layer_methods */
+static PRInt32 PR_CALLBACK emu_AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
+    PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout)
+{
+    return PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
+}
+
+static PRStatus PrintAddress(const PRNetAddr* address)
+{
+    char buffer[100];
+    PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer));
+    if (PR_FAILURE == rv) PL_FPrintError(err_out, "PR_NetAddrToString");
+    else PR_fprintf(
+        std_out, "Accepted connection from (0x%p)%s:%d\n",
+        address, buffer, address->inet.port);
+    return rv;
+}  /* PrintAddress */
+
+static void ConnectingThread(void *arg)
+{
+    PRInt32 nbytes;
+    char buf[1024];
+    PRFileDesc *sock;
+    PRNetAddr peer_addr, *addr;
+
+    addr = (PRNetAddr*)arg;
+
+    sock = PR_NewTCPSocket();
+    if (sock == NULL)
+    {
+        PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed");
+        PR_ProcessExit(1);
+    }
+
+    if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE)
+    {
+        PL_FPrintError(err_out, "PR_Connect (client) failed");
+        PR_ProcessExit(1);
+    }
+    if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE)
+    {
+        PL_FPrintError(err_out, "PR_GetPeerName (client) failed");
+        PR_ProcessExit(1);
+    }
+
+    /*
+    ** Then wait between the connection coming up and sending the expected
+    ** data. At some point in time, the server should fail due to a timeou
+    ** on the AcceptRead() operation, which according to the document is
+    ** only due to the read() portion.
+    */
+    PR_Sleep(write_dally);
+
+    nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT);
+    if (nbytes == -1) PL_FPrintError(err_out, "PR_Send (client) failed");
+
+    nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
+    if (nbytes == -1) PL_FPrintError(err_out, "PR_Recv (client) failed");
+    else
+    {
+        PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes);
+        buf[sizeof(buf) - 1] = '\0';
+        PR_fprintf(std_out, "%s\n", buf);
+    }
+
+    if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH))
+        PL_FPrintError(err_out, "PR_Shutdown (client) failed");
+
+    if (PR_FAILURE == PR_Close(sock))
+        PL_FPrintError(err_out, "PR_Close (client) failed");
+
+    return;
+}  /* ConnectingThread */
+
+#define BUF_SIZE 117
+static void AcceptingThread(void *arg)
+{
+    PRStatus rv;
+    PRInt32 bytes;
+    PRSize buf_size = BUF_SIZE;
+    PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32];
+    PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg;
+    PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket();
+    PRFileDesc *layer;
+    PRSocketOptionData sock_opt;
+
+    if (NULL == listen_sock)
+    {
+        PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed");
+        PR_ProcessExit(1);        
+    }
+    layer = PR_CreateIOLayerStub(emu_layer_ident, &emu_layer_methods);
+    if (NULL == layer)
+    {
+        PL_FPrintError(err_out, "PR_CreateIOLayerStub (server) failed");
+        PR_ProcessExit(1);        
+    }
+    if (PR_PushIOLayer(listen_sock, PR_TOP_IO_LAYER, layer) == PR_FAILURE)
+    {
+        PL_FPrintError(err_out, "PR_PushIOLayer (server) failed");
+        PR_ProcessExit(1);        
+    }
+    sock_opt.option = PR_SockOpt_Reuseaddr;
+    sock_opt.value.reuse_addr = PR_TRUE;
+    rv = PR_SetSocketOption(listen_sock, &sock_opt);
+    if (PR_FAILURE == rv)
+    {
+        PL_FPrintError(err_out, "PR_SetSocketOption (server) failed");
+        PR_ProcessExit(1);        
+    }
+    rv = PR_Bind(listen_sock, listen_addr);
+    if (PR_FAILURE == rv)
+    {
+        PL_FPrintError(err_out, "PR_Bind (server) failed");
+        PR_ProcessExit(1);        
+    }
+    rv = PR_Listen(listen_sock, 10);
+    if (PR_FAILURE == rv)
+    {
+        PL_FPrintError(err_out, "PR_Listen (server) failed");
+        PR_ProcessExit(1);        
+    }
+    bytes = PR_AcceptRead(
+        listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout);
+
+    if (-1 == bytes) PL_FPrintError(err_out, "PR_AcceptRead (server) failed");
+    else
+    {
+        PrintAddress(accept_addr);
+        PR_fprintf(
+            std_out, "(Server) read [0x%p..0x%p) %s\n",
+            buf, &buf[BUF_SIZE], buf);
+        bytes = PR_Write(accept_sock, buf, bytes);
+        rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH);
+        if (PR_FAILURE == rv)
+            PL_FPrintError(err_out, "PR_Shutdown (server) failed");
+    }
+
+    if (-1 != bytes)
+    {
+        rv = PR_Close(accept_sock);
+        if (PR_FAILURE == rv)
+            PL_FPrintError(err_out, "PR_Close (server) failed");
+    }
+
+    rv = PR_Close(listen_sock);
+    if (PR_FAILURE == rv)
+        PL_FPrintError(err_out, "PR_Close (server) failed");
+}  /* AcceptingThread */
+
+PRIntn main(PRIntn argc, char **argv)
+{
+    PRHostEnt he;
+    PRStatus status;
+    PRIntn next_index;
+    PRUint16 port_number;
+    char netdb_buf[PR_NETDB_BUF_SIZE];
+    PRNetAddr client_addr, server_addr;
+    PRThread *client_thread, *server_thread;
+    PRIntervalTime delta = PR_MillisecondsToInterval(500);
+
+    err_out = PR_STDERR;
+    std_out = PR_STDOUT;
+    accept_timeout = PR_SecondsToInterval(2);
+    emu_layer_ident = PR_GetUniqueIdentity("Emulated AcceptRead");
+    emu_layer_methods = *PR_GetDefaultIOMethods();
+    emu_layer_methods.acceptread = emu_AcceptRead;
+
+    if (argc != 2 && argc != 3) port_number = DEFAULT_PORT;
+    else port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]);
+
+    status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr);
+    if (PR_SUCCESS != status)
+    {
+        PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
+        PR_ProcessExit(1);
+    }
+    if (argc < 3)
+    {
+        status = PR_InitializeNetAddr(
+            PR_IpAddrLoopback, port_number, &client_addr);
+        if (PR_SUCCESS != status)
+        {
+            PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
+            PR_ProcessExit(1);
+        }
+    }
+    else
+    {
+        status = PR_GetHostByName(
+            argv[1], netdb_buf, sizeof(netdb_buf), &he);
+        if (status == PR_FAILURE)
+        {
+            PL_FPrintError(err_out, "PR_GetHostByName failed");
+            PR_ProcessExit(1);
+        }
+        next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr);
+        if (next_index == -1)
+        {
+            PL_FPrintError(err_out, "PR_EnumerateHostEnt failed");
+            PR_ProcessExit(1);
+        }
+    }
+
+    for (
+        write_dally = 0;
+        write_dally < accept_timeout + (2 * delta);
+        write_dally += delta)
+    {
+        PR_fprintf(
+            std_out, "Testing w/ write_dally = %d msec\n",
+            PR_IntervalToMilliseconds(write_dally));
+        server_thread = PR_CreateThread(
+            PR_USER_THREAD, AcceptingThread, &server_addr,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (server_thread == NULL)
+        {
+            PL_FPrintError(err_out, "PR_CreateThread (server) failed");
+            PR_ProcessExit(1);
+        }
+
+        PR_Sleep(delta);  /* let the server pot thicken */
+
+        client_thread = PR_CreateThread(
+            PR_USER_THREAD, ConnectingThread, &client_addr,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+        if (client_thread == NULL)
+        {
+            PL_FPrintError(err_out, "PR_CreateThread (client) failed");
+            PR_ProcessExit(1);
+        }
+
+        if (PR_JoinThread(client_thread) == PR_FAILURE)
+            PL_FPrintError(err_out, "PR_JoinThread (client) failed");
+
+        if (PR_JoinThread(server_thread) == PR_FAILURE)
+            PL_FPrintError(err_out, "PR_JoinThread (server) failed");
+    }
+
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/append.c
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+** File:        append.c
+** Description: Testing File writes where PR_APPEND was used on open
+**
+** append attempts to verify that a file opened with PR_APPEND
+** will always append to the end of file, regardless where the
+** current file pointer is positioned. To do this, PR_Seek() is
+** called before each write with the position set to beginning of
+** file. Subsequent writes should always append.
+** The file is read back, summing the integer data written to the
+** file. If the expected result is equal, the test passes.
+**
+** See BugSplat: 4090
+*/
+#include "plgetopt.h"
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+PRIntn  debug = 0;
+PRIntn  verbose = 0;
+PRBool  failedAlready = PR_FALSE;
+const PRInt32 addedBytes = 1000;
+const PRInt32   buf = 1; /* constant written to fd, addedBytes times */
+PRInt32         inBuf;   /* read it back into here */
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+    PRStatus    rc;
+    PRInt32     rv;
+    PRFileDesc  *fd;
+    PRIntn      i;
+    PRInt32     sum = 0;
+
+    {   /* Get command line options */
+        PLOptStatus os;
+        PLOptState *opt = PL_CreateOptState(argc, argv, "vd");
+
+	    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+        {
+		    if (PL_OPT_BAD == os) continue;
+            switch (opt->option)
+            {
+            case 'd':  /* debug */
+                debug = 1;
+                break;
+            case 'v':  /* verbose */
+                verbose = 1;
+                break;
+             default:
+                break;
+            }
+        }
+	    PL_DestroyOptState(opt);
+    } /* end block "Get command line options" */
+/* ---------------------------------------------------------------------- */
+    fd = PR_Open( "/tmp/nsprAppend", (PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY), 0666 );
+    if ( NULL == fd )  {
+        if (debug) printf("PR_Open() failed for writing: %d\n", PR_GetError());
+        failedAlready = PR_TRUE;
+        goto Finished;
+    }
+
+    for ( i = 0; i < addedBytes ; i++ ) {
+        rv = PR_Write( fd, &buf, sizeof(buf));
+        if ( sizeof(buf) != rv )  {
+            if (debug) printf("PR_Write() failed: %d\n", PR_GetError());
+            failedAlready = PR_TRUE;
+            goto Finished;
+        }
+        rv = PR_Seek( fd, 0 , PR_SEEK_SET );
+        if ( -1 == rv )  {
+            if (debug) printf("PR_Seek() failed: %d\n", PR_GetError());
+            failedAlready = PR_TRUE;
+            goto Finished;
+        }
+    }
+    rc = PR_Close( fd );
+    if ( PR_FAILURE == rc ) {
+        if (debug) printf("PR_Close() failed after writing: %d\n", PR_GetError());
+        failedAlready = PR_TRUE;
+        goto Finished;
+    }
+/* ---------------------------------------------------------------------- */
+    fd = PR_Open( "/tmp/nsprAppend", PR_RDONLY, 0 );
+    if ( NULL == fd )  {
+        if (debug) printf("PR_Open() failed for reading: %d\n", PR_GetError());
+        failedAlready = PR_TRUE;
+        goto Finished;
+    }
+
+    for ( i = 0; i < addedBytes ; i++ ) {
+        rv = PR_Read( fd, &inBuf, sizeof(inBuf));
+        if ( sizeof(inBuf) != rv)  {
+            if (debug) printf("PR_Write() failed: %d\n", PR_GetError());
+            failedAlready = PR_TRUE;
+            goto Finished;
+        }
+        sum += inBuf;
+    }
+
+    rc = PR_Close( fd );
+    if ( PR_FAILURE == rc ) {
+        if (debug) printf("PR_Close() failed after reading: %d\n", PR_GetError());
+        failedAlready = PR_TRUE;
+        goto Finished;
+    }
+    if ( sum != addedBytes )  {
+        if (debug) printf("Uh Oh! addedBytes: %d. Sum: %d\n", addedBytes, sum);
+        failedAlready = PR_TRUE;
+        goto Finished;
+    }
+
+/* ---------------------------------------------------------------------- */
+Finished:
+    if (debug || verbose) printf("%s\n", (failedAlready)? "FAILED" : "PASSED" );
+    return( (failedAlready)? 1 : 0 );
+}  /* main() */
+
+/* append.c */
new file mode 100644
--- /dev/null
+++ b/pr/tests/env.c
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+** File:        env.c
+** Description: Testing environment variable operations
+**
+*/
+#include "prenv.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+PRIntn  debug = 0;
+PRIntn  verbose = 0;
+PRBool  failedAlready = PR_FALSE;
+
+#define  ENVNAME    "NSPR_ENVIRONMENT_TEST_VARIABLE"
+#define  ENVVALUE   "The expected result"
+#define  ENVBUFSIZE 256
+
+char    *envBuf; /* buffer pointer. We leak memory here on purpose! */
+
+static char * NewBuffer( size_t size )
+{
+    char *buf = malloc( size );
+    if ( NULL == buf ) {
+        printf("env: NewBuffer() failed\n");
+        exit(1);
+    }
+    return(buf);
+} /* end NewBuffer() */
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+    char    *value;
+    PRStatus    rc;
+
+    {   /* Get command line options */
+        PLOptStatus os;
+        PLOptState *opt = PL_CreateOptState(argc, argv, "vd");
+
+	    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+        {
+		    if (PL_OPT_BAD == os) continue;
+            switch (opt->option)
+            {
+            case 'd':  /* debug */
+                debug = 1;
+                break;
+            case 'v':  /* verbose */
+                verbose = 1;
+                break;
+             default:
+                break;
+            }
+        }
+	    PL_DestroyOptState(opt);
+    } /* end block "Get command line options" */
+
+#if 0 
+    {
+        /*
+        ** This uses Windows native environment manipulation
+        ** as an experiment. Note the separation of namespace!
+        */
+        BOOL rv;
+        DWORD   size;
+        rv = SetEnvironmentVariable( ENVNAME, ENVVALUE );
+        if ( rv == 0 )  {
+            if (debug) printf("env: Shit! SetEnvironmentVariable() failed\n");
+            failedAlready = PR_TRUE;
+        }
+        if (verbose) printf("env: SetEnvironmentVariable() worked\n");
+
+        size = GetEnvironmentVariable( ENVNAME, envBuf, ENVBUFSIZE );    
+        if ( size == 0 )  {
+            if (debug) printf("env: Shit! GetEnvironmentVariable() failed. Found: %s\n", envBuf );
+            failedAlready = PR_TRUE;
+        }
+        if (verbose) printf("env: GetEnvironmentVariable() worked. Found: %s\n", envBuf);
+
+        value = PR_GetEnv( ENVNAME );
+        if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
+            if (debug) printf( "env: PR_GetEnv() failed retrieving WinNative. Found: %s\n", value);
+            failedAlready = PR_TRUE;
+        }
+        if (verbose) printf("env: PR_GetEnv() worked. Found: %s\n", value);
+    }
+#endif
+
+    /* set an environment variable, read it back */
+    envBuf = NewBuffer( ENVBUFSIZE );
+    sprintf( envBuf, ENVNAME "=" ENVVALUE );
+    rc = PR_SetEnv( envBuf );
+    if ( PR_FAILURE == rc )  {
+        if (debug) printf( "env: PR_SetEnv() failed setting\n");
+        failedAlready = PR_TRUE;
+    } else {
+        if (verbose) printf("env: PR_SetEnv() worked.\n");
+    }
+
+    value = PR_GetEnv( ENVNAME );
+    if ( (NULL == value ) || (strcmp( value, ENVVALUE)))  {
+        if (debug) printf( "env: PR_GetEnv() Failed after setting\n" );
+        failedAlready = PR_TRUE;
+    } else {
+        if (verbose) printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value );
+    }
+
+/* ---------------------------------------------------------------------- */
+    /* un-set the variable, using RAW name... should not work */
+    envBuf = NewBuffer( ENVBUFSIZE );
+    sprintf( envBuf, ENVNAME );
+    rc = PR_SetEnv( envBuf );
+    if ( PR_FAILURE == rc )  {
+        if (verbose) printf( "env: PR_SetEnv() not un-set using RAW name. Good!\n");
+    } else {
+        if (debug) printf("env: PR_SetEnv() un-set using RAW name. Bad!\n" );
+        failedAlready = PR_TRUE;
+    }
+
+    value = PR_GetEnv( ENVNAME );
+    if ( NULL == value ) {
+        if (debug) printf("env: PR_GetEnv() after un-set using RAW name. Bad!\n" );
+        failedAlready = PR_TRUE;
+    } else {
+        if (verbose) printf( "env: PR_GetEnv() after RAW un-set found: %s\n", value );
+    }
+    
+/* ---------------------------------------------------------------------- */
+    /* set it again ... */
+    envBuf = NewBuffer( ENVBUFSIZE );
+    sprintf( envBuf, ENVNAME "=" ENVVALUE );
+    rc = PR_SetEnv( envBuf );
+    if ( PR_FAILURE == rc )  {
+        if (debug) printf( "env: PR_SetEnv() failed setting the second time.\n");
+        failedAlready = PR_TRUE;
+    } else {
+        if (verbose) printf("env: PR_SetEnv() worked.\n");
+    }
+
+    /* un-set the variable using the form name= */
+    envBuf = NewBuffer( ENVBUFSIZE );
+    sprintf( envBuf, ENVNAME "=" );
+    rc = PR_SetEnv( envBuf );
+    if ( PR_FAILURE == rc )  {
+        if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n");
+        failedAlready = PR_TRUE;
+    } else {
+        if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" );
+    }
+
+    value = PR_GetEnv( ENVNAME );
+    if (( NULL == value ) || ( 0x00 == *value )) {
+        if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" );
+    } else {
+        if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
+        failedAlready = PR_TRUE;
+    }
+/* ---------------------------------------------------------------------- */
+    /* un-set the variable using the form name= */
+    envBuf = NewBuffer( ENVBUFSIZE );
+    sprintf( envBuf, ENVNAME "999=" );
+    rc = PR_SetEnv( envBuf );
+    if ( PR_FAILURE == rc )  {
+        if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n");
+        failedAlready = PR_TRUE;
+    } else {
+        if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" );
+    }
+
+    value = PR_GetEnv( ENVNAME "999" );
+    if (( NULL == value ) || ( 0x00 == *value )) {
+        if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" );
+    } else {
+        if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value );
+        failedAlready = PR_TRUE;
+    }
+
+/* ---------------------------------------------------------------------- */
+    if (debug || verbose) printf("\n%s\n", (failedAlready)? "FAILED" : "PASSED" );
+    return( (failedAlready)? 1 : 0 );
+}  /* main() */
+
+/* env.c */
new file mode 100644
--- /dev/null
+++ b/pr/tests/errset.c
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape security libraries.
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/***********************************************************************
+**
+** Name: errset.c
+**
+** Description: errset.c exercises the functions in prerror.c.
+** This code is a unit test of the prerror.c capability.
+**
+** Note: There's some fluff in here. The guts of the test
+** were plagerized from another test. So, sue me.
+**
+**
+*/
+#include "prerror.h"
+#include "plgetopt.h"
+#include "prlog.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static int _debug_on = 0;
+
+struct errinfo {
+	PRErrorCode errcode;
+	char 		*errname;
+};
+
+struct errinfo errcodes[] = {
+{PR_OUT_OF_MEMORY_ERROR,			"PR_OUT_OF_MEMORY_ERROR"},
+{PR_UNKNOWN_ERROR, "An intentionally long error message text intended to force a delete of the current errorString buffer and get another one."},
+{PR_BAD_DESCRIPTOR_ERROR,			"PR_BAD_DESCRIPTOR_ERROR"},
+{PR_WOULD_BLOCK_ERROR,				"PR_WOULD_BLOCK_ERROR"},
+{PR_ACCESS_FAULT_ERROR,				"PR_ACCESS_FAULT_ERROR"},
+{PR_INVALID_METHOD_ERROR,			"PR_INVALID_METHOD_ERROR"},
+{PR_ILLEGAL_ACCESS_ERROR,			"PR_ILLEGAL_ACCESS_ERROR"},
+{PR_UNKNOWN_ERROR,					"PR_UNKNOWN_ERROR"},
+{PR_PENDING_INTERRUPT_ERROR,		"PR_PENDING_INTERRUPT_ERROR"},
+{PR_NOT_IMPLEMENTED_ERROR,			"PR_NOT_IMPLEMENTED_ERROR"},
+{PR_IO_ERROR,						"PR_IO_ERROR"},
+{PR_IO_TIMEOUT_ERROR,				"PR_IO_TIMEOUT_ERROR"},
+{PR_IO_PENDING_ERROR,				"PR_IO_PENDING_ERROR"},
+{PR_DIRECTORY_OPEN_ERROR,			"PR_DIRECTORY_OPEN_ERROR"},
+{PR_INVALID_ARGUMENT_ERROR,			"PR_INVALID_ARGUMENT_ERROR"},
+{PR_ADDRESS_NOT_AVAILABLE_ERROR,	"PR_ADDRESS_NOT_AVAILABLE_ERROR"},
+{PR_ADDRESS_NOT_SUPPORTED_ERROR,	"PR_ADDRESS_NOT_SUPPORTED_ERROR"},
+{PR_IS_CONNECTED_ERROR,				"PR_IS_CONNECTED_ERROR"},
+{PR_BAD_ADDRESS_ERROR,				"PR_BAD_ADDRESS_ERROR"},
+{PR_ADDRESS_IN_USE_ERROR,			"PR_ADDRESS_IN_USE_ERROR"},
+{PR_CONNECT_REFUSED_ERROR,			"PR_CONNECT_REFUSED_ERROR"},
+{PR_NETWORK_UNREACHABLE_ERROR,		"PR_NETWORK_UNREACHABLE_ERROR"},
+{PR_CONNECT_TIMEOUT_ERROR,			"PR_CONNECT_TIMEOUT_ERROR"},
+{PR_NOT_CONNECTED_ERROR,			"PR_NOT_CONNECTED_ERROR"},
+{PR_LOAD_LIBRARY_ERROR,				"PR_LOAD_LIBRARY_ERROR"},
+{PR_UNLOAD_LIBRARY_ERROR,			"PR_UNLOAD_LIBRARY_ERROR"},
+{PR_FIND_SYMBOL_ERROR,				"PR_FIND_SYMBOL_ERROR"},
+{PR_INSUFFICIENT_RESOURCES_ERROR,	"PR_INSUFFICIENT_RESOURCES_ERROR"},
+{PR_DIRECTORY_LOOKUP_ERROR,			"PR_DIRECTORY_LOOKUP_ERROR"},
+{PR_TPD_RANGE_ERROR,				"PR_TPD_RANGE_ERROR"},
+{PR_PROC_DESC_TABLE_FULL_ERROR,		"PR_PROC_DESC_TABLE_FULL_ERROR"},
+{PR_SYS_DESC_TABLE_FULL_ERROR,		"PR_SYS_DESC_TABLE_FULL_ERROR"},
+{PR_NOT_SOCKET_ERROR,				"PR_NOT_SOCKET_ERROR"},
+{PR_NOT_TCP_SOCKET_ERROR,			"PR_NOT_TCP_SOCKET_ERROR"},
+{PR_SOCKET_ADDRESS_IS_BOUND_ERROR,	"PR_SOCKET_ADDRESS_IS_BOUND_ERROR"},
+{PR_NO_ACCESS_RIGHTS_ERROR,			"PR_NO_ACCESS_RIGHTS_ERROR"},
+{PR_OPERATION_NOT_SUPPORTED_ERROR,	"PR_OPERATION_NOT_SUPPORTED_ERROR"},
+{PR_PROTOCOL_NOT_SUPPORTED_ERROR,	"PR_PROTOCOL_NOT_SUPPORTED_ERROR"},
+{PR_REMOTE_FILE_ERROR,				"PR_REMOTE_FILE_ERROR"},
+{PR_BUFFER_OVERFLOW_ERROR,			"PR_BUFFER_OVERFLOW_ERROR"},
+{PR_CONNECT_RESET_ERROR,			"PR_CONNECT_RESET_ERROR"},
+{PR_RANGE_ERROR,					"PR_RANGE_ERROR"},
+{PR_DEADLOCK_ERROR,					"PR_DEADLOCK_ERROR"},
+{PR_FILE_IS_LOCKED_ERROR,			"PR_FILE_IS_LOCKED_ERROR"},
+{PR_FILE_TOO_BIG_ERROR,				"PR_FILE_TOO_BIG_ERROR"},
+{PR_NO_DEVICE_SPACE_ERROR,			"PR_NO_DEVICE_SPACE_ERROR"},
+{PR_PIPE_ERROR,						"PR_PIPE_ERROR"},
+{PR_NO_SEEK_DEVICE_ERROR,			"PR_NO_SEEK_DEVICE_ERROR"},
+{PR_IS_DIRECTORY_ERROR,				"PR_IS_DIRECTORY_ERROR"},
+{PR_LOOP_ERROR,						"PR_LOOP_ERROR"},
+{PR_NAME_TOO_LONG_ERROR,			"PR_NAME_TOO_LONG_ERROR"},
+{PR_FILE_NOT_FOUND_ERROR,			"PR_FILE_NOT_FOUND_ERROR"},
+{PR_NOT_DIRECTORY_ERROR,			"PR_NOT_DIRECTORY_ERROR"},
+{PR_READ_ONLY_FILESYSTEM_ERROR,		"PR_READ_ONLY_FILESYSTEM_ERROR"},
+{PR_DIRECTORY_NOT_EMPTY_ERROR,		"PR_DIRECTORY_NOT_EMPTY_ERROR"},
+{PR_FILESYSTEM_MOUNTED_ERROR,		"PR_FILESYSTEM_MOUNTED_ERROR"},
+{PR_NOT_SAME_DEVICE_ERROR,			"PR_NOT_SAME_DEVICE_ERROR"},
+{PR_DIRECTORY_CORRUPTED_ERROR,		"PR_DIRECTORY_CORRUPTED_ERROR"},
+{PR_FILE_EXISTS_ERROR,				"PR_FILE_EXISTS_ERROR"},
+{PR_MAX_DIRECTORY_ENTRIES_ERROR,	"PR_MAX_DIRECTORY_ENTRIES_ERROR"},
+{PR_INVALID_DEVICE_STATE_ERROR,		"PR_INVALID_DEVICE_STATE_ERROR"},
+{PR_DEVICE_IS_LOCKED_ERROR,			"PR_DEVICE_IS_LOCKED_ERROR"},
+{PR_NO_MORE_FILES_ERROR,			"PR_NO_MORE_FILES_ERROR"},
+{PR_END_OF_FILE_ERROR,				"PR_END_OF_FILE_ERROR"},
+{PR_FILE_SEEK_ERROR,				"PR_FILE_SEEK_ERROR"},
+{PR_FILE_IS_BUSY_ERROR,				"PR_FILE_IS_BUSY_ERROR"},
+{PR_IN_PROGRESS_ERROR,				"PR_IN_PROGRESS_ERROR"},
+{PR_ALREADY_INITIATED_ERROR,		"PR_ALREADY_INITIATED_ERROR"},
+{PR_GROUP_EMPTY_ERROR,				"PR_GROUP_EMPTY_ERROR"},
+{PR_INVALID_STATE_ERROR,			"PR_INVALID_STATE_ERROR"},
+{PR_NETWORK_DOWN_ERROR,				"PR_NETWORK_DOWN_ERROR"},
+{PR_SOCKET_SHUTDOWN_ERROR,			"PR_SOCKET_SHUTDOWN_ERROR"},
+{PR_CONNECT_ABORTED_ERROR,			"PR_CONNECT_ABORTED_ERROR"},
+{PR_HOST_UNREACHABLE_ERROR,			"PR_HOST_UNREACHABLE_ERROR"}
+};
+
+int
+main(int argc, char **argv)
+{
+
+	int count, errnum;
+
+    /*
+     * -d           debug mode
+     */
+
+    PLOptStatus os;
+    PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+    {
+        if (PL_OPT_BAD == os) continue;
+        switch (opt->option)
+        {
+        case 'd':  /* debug mode */
+            _debug_on = 1;
+            break;
+        default:
+            break;
+        }
+    }
+    PL_DestroyOptState(opt);
+
+	count = sizeof(errcodes)/sizeof(errcodes[0]);
+	printf("\nNumber of error codes = %d\n\n",count);
+	for (errnum = 0; errnum < count; errnum++) {
+        PRInt32 len1, len2, err;
+        char    msg[256];
+
+        PR_SetError( errnum, -5 );
+        err = PR_GetError();
+        PR_ASSERT( err == errnum );
+        err = PR_GetOSError();
+        PR_ASSERT( err == -5 );
+        PR_SetErrorText( strlen(errcodes[errnum].errname), errcodes[errnum].errname );
+        len1 = PR_GetErrorTextLength();
+        len2 = PR_GetErrorText( msg );
+        PR_ASSERT( len1 == len2 );
+        printf("%5.5d -- %s\n", errnum, msg );
+    }
+
+	return 0;
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/freeif.c
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * A test to see if the macros PR_DELETE and PR_FREEIF are
+ * properly defined.  (See Bugzilla bug #39110.)
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void Noop(void) { }
+
+static void Fail(void)
+{
+    printf("FAIL\n");
+    exit(1);
+}
+
+int main()
+{
+    int foo = 1;
+    char *ptr = NULL;
+
+    /* this fails to compile with the old definition of PR_DELETE */
+    if (foo)
+        PR_DELETE(ptr);
+    else
+        Noop();
+
+    /* this nests incorrectly with the old definition of PR_FREEIF */
+    if (foo)
+        PR_FREEIF(ptr);
+    else
+        Fail();
+
+    printf("PASS\n");
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/intrio.c
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * File:        intrio.c
+ * Purpose:     testing i/o interrupts (see Bugzilla bug #31120)
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef XP_MAC
+#include "prlog.h"
+#define printf PR_LogPrint
+extern void SetupMacPrintfLog(char *logFile);
+#endif
+
+/* for synchronization between the main thread and iothread */
+static PRLock *lock;
+static PRCondVar *cvar;
+static PRBool iothread_ready;
+
+static void PR_CALLBACK AbortIO(void *arg)
+{
+    PRStatus rv;
+    PR_Sleep(PR_SecondsToInterval(2));
+    rv = PR_Interrupt((PRThread*)arg);
+    PR_ASSERT(PR_SUCCESS == rv);
+}  /* AbortIO */
+
+static void PR_CALLBACK IOThread(void *arg)
+{
+    PRFileDesc *sock, *newsock;
+    PRNetAddr addr;
+
+    sock = PR_OpenTCPSocket(PR_AF_INET6);
+    if (sock == NULL) {
+        fprintf(stderr, "PR_OpenTCPSocket failed\n");
+        exit(1);
+    }
+    memset(&addr, 0, sizeof(addr));
+    if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
+        fprintf(stderr, "PR_SetNetAddr failed\n");
+        exit(1);
+    }
+    if (PR_Bind(sock, &addr) == PR_FAILURE) {
+        fprintf(stderr, "PR_Bind failed\n");
+        exit(1);
+    }
+    if (PR_Listen(sock, 5) == PR_FAILURE) {
+        fprintf(stderr, "PR_Listen failed\n");
+        exit(1);
+    }
+    /* tell the main thread that we are ready */
+    PR_Lock(lock);
+    iothread_ready = PR_TRUE;
+    PR_NotifyCondVar(cvar);
+    PR_Unlock(lock);
+    newsock = PR_Accept(sock, NULL, PR_INTERVAL_NO_TIMEOUT);
+    if (newsock != NULL) {
+        fprintf(stderr, "PR_Accept shouldn't have succeeded\n");
+        exit(1);
+    }
+    if (PR_GetError() != PR_PENDING_INTERRUPT_ERROR) {
+        fprintf(stderr, "PR_Accept failed (%d, %d)\n",
+            PR_GetError(), PR_GetOSError());
+        exit(1);
+    }
+    printf("PR_Accept() is interrupted as expected\n");
+    if (PR_Close(sock) == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+}
+
+static void Test(PRThreadScope scope1, PRThreadScope scope2)
+{
+    PRThread *iothread, *abortio;
+
+    printf("A %s thread will be interrupted by a %s thread\n",
+        (scope1 == PR_LOCAL_THREAD ? "local" : "global"),
+        (scope2 == PR_LOCAL_THREAD ? "local" : "global"));
+    iothread_ready = PR_FALSE;
+    iothread = PR_CreateThread(
+        PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL,
+        scope1, PR_JOINABLE_THREAD, 0);
+    if (iothread == NULL) {
+        fprintf(stderr, "cannot create thread\n");
+        exit(1);
+    }
+    PR_Lock(lock);
+    while (!iothread_ready)
+        PR_WaitCondVar(cvar, PR_INTERVAL_NO_TIMEOUT);
+    PR_Unlock(lock);
+    abortio = PR_CreateThread(
+        PR_USER_THREAD, AbortIO, iothread, PR_PRIORITY_NORMAL,
+        scope2, PR_JOINABLE_THREAD, 0);
+    if (abortio == NULL) {
+        fprintf(stderr, "cannot create thread\n");
+        exit(1);
+    }
+    if (PR_JoinThread(iothread) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+    if (PR_JoinThread(abortio) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+}
+
+PRIntn main(PRIntn argc, char **argv)
+{
+    PR_STDIO_INIT();
+    lock = PR_NewLock();
+    if (lock == NULL) {
+        fprintf(stderr, "PR_NewLock failed\n");
+        exit(1);
+    }
+    cvar = PR_NewCondVar(lock);
+    if (cvar == NULL) {
+        fprintf(stderr, "PR_NewCondVar failed\n");
+        exit(1);
+    }
+    /* test all four combinations */
+    Test(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
+    Test(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
+    Test(PR_GLOBAL_THREAD, PR_LOCAL_THREAD);
+    Test(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
+    printf("PASSED\n");
+    return 0;
+}  /* main */
new file mode 100644
--- /dev/null
+++ b/pr/tests/obsints.c
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Test: obsints.c 
+ *
+ * Description: make sure that protypes.h defines the obsolete integer
+ * types intn, uintn, uint, int8, uint8, int16, uint16, int32, uint32,
+ * int64, and uint64.
+ */
+
+#include <stdio.h>
+
+#ifdef NO_NSPR_10_SUPPORT
+
+/* nothing to do */
+int main()
+{
+    printf("PASS\n");
+    return 0;
+}
+
+#else /* NO_NSPR_10_SUPPORT */
+
+#include "prtypes.h"  /* which includes protypes.h */
+
+int main()
+{
+    /*
+     * Compilation fails if any of these integer types are not
+     * defined by protypes.h.
+     */
+    intn in;
+    uintn uin;
+    uint ui;
+    int8 i8;
+    uint8 ui8;
+    int16 i16;
+    uint16 ui16;
+    int32 i32;
+    uint32 ui32;
+    int64 i64;
+    uint64 ui64;
+
+    printf("PASS\n");
+    return 0;
+}
+
+#endif /* NO_NSPR_10_SUPPORT */
new file mode 100644
--- /dev/null
+++ b/pr/tests/peek.c
@@ -0,0 +1,389 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1999-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * A test case for the PR_MSG_PEEK flag of PR_Recv().
+ *
+ * Test both blocking and non-blocking sockets.
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFFER_SIZE 1024
+
+static int iterations = 10;
+
+/*
+ * In iteration i, recv_amount[i] is the number of bytes we
+ * wish to receive, and send_amount[i] is the number of bytes
+ * we actually send.  Therefore, the number of elements in the
+ * recv_amount or send_amount array should equal to 'iterations'.
+ * For this test to pass we need to ensure that
+ *     recv_amount[i] <= BUFFER_SIZE,
+ *     send_amount[i] <= BUFFER_SIZE,
+ *     send_amount[i] <= recv_amount[i].
+ */
+static PRInt32 recv_amount[10] = {
+    16, 128, 256, 1024, 512, 512, 128, 256, 32, 32};
+static PRInt32 send_amount[10] = {
+    16,  64, 128, 1024, 512, 256, 128,  64, 16, 32};
+
+/* Blocking I/O */
+static void ServerB(void *arg)
+{
+    PRFileDesc *listenSock = (PRFileDesc *) arg;
+    PRFileDesc *sock;
+    char buf[BUFFER_SIZE];
+    PRInt32 nbytes;
+    int i;
+    int j;
+
+    sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+    if (NULL == sock) {
+        fprintf(stderr, "PR_Accept failed\n");
+        exit(1);
+    }
+
+    for (i = 0; i < iterations; i++) {
+        memset(buf, 0, sizeof(buf));
+        nbytes = PR_Recv(sock, buf, recv_amount[i],
+                PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == nbytes) {
+            fprintf(stderr, "PR_Recv failed\n");
+            exit(1);
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+        for (j = 0; j < nbytes; j++) {
+            if (buf[j] != 2*i) {
+                fprintf(stderr, "byte %d should be %d but is %d\n",
+                        j, 2*i, buf[j]);
+                exit(1);
+            }
+        }
+        fprintf(stderr, "server: peeked expected data\n");
+
+        memset(buf, 0, sizeof(buf));
+        nbytes = PR_Recv(sock, buf, recv_amount[i],
+                PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == nbytes) {
+            fprintf(stderr, "PR_Recv failed\n");
+            exit(1);
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+        for (j = 0; j < nbytes; j++) {
+            if (buf[j] != 2*i) {
+                fprintf(stderr, "byte %d should be %d but is %d\n",
+                        j, 2*i, buf[j]);
+                exit(1);
+            }
+        }
+        fprintf(stderr, "server: peeked expected data\n");
+
+        memset(buf, 0, sizeof(buf));
+        nbytes = PR_Recv(sock, buf, recv_amount[i],
+                0, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == nbytes) {
+            fprintf(stderr, "PR_Recv failed\n");
+            exit(1);
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+        for (j = 0; j < nbytes; j++) {
+            if (buf[j] != 2*i) {
+                fprintf(stderr, "byte %d should be %d but is %d\n",
+                        j, 2*i, buf[j]);
+                exit(1);
+            }
+        }
+        fprintf(stderr, "server: received expected data\n");
+
+        PR_Sleep(PR_SecondsToInterval(1));
+        memset(buf, 2*i+1, send_amount[i]);
+        nbytes = PR_Send(sock, buf, send_amount[i],
+                0, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == nbytes) {
+            fprintf(stderr, "PR_Send failed\n");
+            exit(1);
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+    }
+    if (PR_Close(sock) == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+}
+
+/* Non-blocking I/O */
+static void ClientNB(void *arg)
+{
+    PRFileDesc *sock;
+    PRSocketOptionData opt;
+    PRUint16 port = (PRUint16) arg;
+    PRNetAddr addr;
+    char buf[BUFFER_SIZE];
+    PRPollDesc pd;
+    PRInt32 npds;
+    PRInt32 nbytes;
+    int i;
+    int j;
+
+    sock = PR_OpenTCPSocket(PR_AF_INET6);
+    if (NULL == sock) {
+        fprintf(stderr, "PR_OpenTCPSocket failed\n");
+        exit(1);
+    }
+    opt.option = PR_SockOpt_Nonblocking;
+    opt.value.non_blocking = PR_TRUE;
+    if (PR_SetSocketOption(sock, &opt) == PR_FAILURE) {
+        fprintf(stderr, "PR_SetSocketOption failed\n");
+        exit(1);
+    }
+    memset(&addr, 0, sizeof(addr));
+    if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, port, &addr)
+            == PR_FAILURE) {
+        fprintf(stderr, "PR_SetNetAddr failed\n");
+        exit(1);
+    }
+    if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+        if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
+            fprintf(stderr, "PR_Connect failed\n");
+            exit(1);
+        }
+        pd.fd = sock;
+        pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+        npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == npds) {
+            fprintf(stderr, "PR_Poll failed\n");
+            exit(1);
+        }
+        if (1 != npds) {
+            fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
+            exit(1);
+        }
+        if (PR_GetConnectStatus(&pd) == PR_FAILURE) {
+            fprintf(stderr, "PR_GetConnectStatus failed\n");
+            exit(1);
+        }
+    }
+
+    for (i = 0; i < iterations; i++) {
+        PR_Sleep(PR_SecondsToInterval(1));
+        memset(buf, 2*i, send_amount[i]);
+        while ((nbytes = PR_Send(sock, buf, send_amount[i],
+                0, PR_INTERVAL_NO_TIMEOUT)) == -1) {
+            if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+                fprintf(stderr, "PR_Send failed\n");
+                exit(1);
+            }
+            pd.fd = sock;
+            pd.in_flags = PR_POLL_WRITE;
+            npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+            if (-1 == npds) {
+                fprintf(stderr, "PR_Poll failed\n");
+                exit(1);
+            }
+            if (1 != npds) {
+                fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
+                exit(1);
+            }
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+
+        memset(buf, 0, sizeof(buf));
+        while ((nbytes = PR_Recv(sock, buf, recv_amount[i],
+                PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT)) == -1) {
+            if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+                fprintf(stderr, "PR_Recv failed\n");
+                exit(1);
+            }
+            pd.fd = sock;
+            pd.in_flags = PR_POLL_READ;
+            npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT);
+            if (-1 == npds) {
+                fprintf(stderr, "PR_Poll failed\n");
+                exit(1);
+            }
+            if (1 != npds) {
+                fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds);
+                exit(1);
+            }
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+        for (j = 0; j < nbytes; j++) {
+            if (buf[j] != 2*i+1) {
+                fprintf(stderr, "byte %d should be %d but is %d\n",
+                        j, 2*i+1, buf[j]);
+                exit(1);
+            }
+        }
+        fprintf(stderr, "client: peeked expected data\n");
+
+        memset(buf, 0, sizeof(buf));
+        nbytes = PR_Recv(sock, buf, recv_amount[i],
+                PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == nbytes) {
+            fprintf(stderr, "PR_Recv failed\n");
+            exit(1);
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+        for (j = 0; j < nbytes; j++) {
+            if (buf[j] != 2*i+1) {
+                fprintf(stderr, "byte %d should be %d but is %d\n",
+                        j, 2*i+1, buf[j]);
+                exit(1);
+            }
+        }
+        fprintf(stderr, "client: peeked expected data\n");
+
+        memset(buf, 0, sizeof(buf));
+        nbytes = PR_Recv(sock, buf, recv_amount[i],
+                0, PR_INTERVAL_NO_TIMEOUT);
+        if (-1 == nbytes) {
+            fprintf(stderr, "PR_Recv failed\n");
+            exit(1);
+        }
+        if (send_amount[i] != nbytes) {
+            fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes);
+            exit(1);
+        }
+        for (j = 0; j < nbytes; j++) {
+            if (buf[j] != 2*i+1) {
+                fprintf(stderr, "byte %d should be %d but is %d\n",
+                        j, 2*i+1, buf[j]);
+                exit(1);
+            }
+        }
+        fprintf(stderr, "client: received expected data\n");
+    }
+    if (PR_Close(sock) == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+}
+
+static void
+RunTest(PRThreadScope scope, PRFileDesc *listenSock, PRUint16 port)
+{
+    PRThread *server, *client;
+
+    server = PR_CreateThread(PR_USER_THREAD, ServerB, listenSock,
+            PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
+    if (NULL == server) {
+        fprintf(stderr, "PR_CreateThread failed\n");
+        exit(1);
+    }
+    client = PR_CreateThread(
+            PR_USER_THREAD, ClientNB, (void *) port,
+            PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0);
+    if (NULL == client) {
+        fprintf(stderr, "PR_CreateThread failed\n");
+        exit(1);
+    }
+
+    if (PR_JoinThread(server) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+    if (PR_JoinThread(client) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    PRFileDesc *listenSock;
+    PRNetAddr addr;
+    PRUint16 port;
+
+    listenSock = PR_OpenTCPSocket(PR_AF_INET6);
+    if (NULL == listenSock) {
+        fprintf(stderr, "PR_OpenTCPSocket failed\n");
+        exit(1);
+    }
+    memset(&addr, 0, sizeof(addr));
+    if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
+        fprintf(stderr, "PR_SetNetAddr failed\n");
+        exit(1);
+    }
+    if (PR_Bind(listenSock, &addr) == PR_FAILURE) {
+        fprintf(stderr, "PR_Bind failed\n");
+        exit(1);
+    }
+    if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) {
+        fprintf(stderr, "PR_GetSockName failed\n");
+        exit(1);
+    }
+    port = PR_ntohs(addr.ipv6.port);
+    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+        fprintf(stderr, "PR_Listen failed\n");
+        exit(1);
+    }
+
+    fprintf(stderr, "Running the test with local threads\n");
+    RunTest(PR_LOCAL_THREAD, listenSock, port);
+    fprintf(stderr, "Running the test with global threads\n");
+    RunTest(PR_GLOBAL_THREAD, listenSock, port);
+
+    if (PR_Close(listenSock) == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    printf("PASS\n");
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/pipeping2.c
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * File: pipeping2.c
+ *
+ * Description:
+ * This test runs in conjunction with the pipepong2 test.
+ * This test creates two pipes and passes two pipe fd's
+ * to the pipepong2 test.  Then this test writes "ping" to
+ * to the pipepong2 test and the pipepong2 test writes "pong"
+ * back.  To run this pair of tests, just invoke pipeping2.
+ *
+ * Tested areas: process creation, pipes, file descriptor
+ * inheritance.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+#include "prproces.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+static char *child_argv[] = { "pipepong2", NULL };
+
+int main()
+{
+    PRFileDesc *in_pipe[2];
+    PRFileDesc *out_pipe[2];
+    PRStatus status;
+    PRProcess *process;
+    PRProcessAttr *attr;
+    char buf[1024];
+    PRInt32 nBytes;
+    PRInt32 exitCode;
+    int idx;
+
+    status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_CreatePipe failed\n");
+        exit(1);
+    }
+    status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_CreatePipe failed\n");
+        exit(1);
+    }
+
+    status = PR_SetFDInheritable(in_pipe[0], PR_FALSE);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_SetFDInheritable failed\n");
+        exit(1);
+    }
+    status = PR_SetFDInheritable(in_pipe[1], PR_TRUE);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_SetFDInheritable failed\n");
+        exit(1);
+    }
+    status = PR_SetFDInheritable(out_pipe[0], PR_TRUE);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_SetFDInheritable failed\n");
+        exit(1);
+    }
+    status = PR_SetFDInheritable(out_pipe[1], PR_FALSE);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_SetFDInheritable failed\n");
+        exit(1);
+    }
+
+    attr = PR_NewProcessAttr();
+    if (attr == NULL) {
+        fprintf(stderr, "PR_NewProcessAttr failed\n");
+        exit(1);
+    }
+
+    status = PR_ProcessAttrSetInheritableFD(attr, out_pipe[0], "PIPE_READ");
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n");
+        exit(1);
+    }
+    status = PR_ProcessAttrSetInheritableFD(attr, in_pipe[1], "PIPE_WRITE");
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n");
+        exit(1);
+    }
+
+    process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr);
+    if (process == NULL) {
+        fprintf(stderr, "PR_CreateProcess failed\n");
+        exit(1);
+    }
+    PR_DestroyProcessAttr(attr);
+    status = PR_Close(out_pipe[0]);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    status = PR_Close(in_pipe[1]);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+
+    for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+        strcpy(buf, "ping");
+        printf("ping process: sending \"%s\"\n", buf);
+        nBytes = PR_Write(out_pipe[1], buf, 5);
+        if (nBytes == -1) {
+            fprintf(stderr, "PR_Write failed: (%d, %d)\n",
+                    PR_GetError(), PR_GetOSError());
+            exit(1);
+        }
+        memset(buf, 0, sizeof(buf));
+        nBytes = PR_Read(in_pipe[0], buf, sizeof(buf));
+        if (nBytes == -1) {
+            fprintf(stderr, "PR_Read failed\n");
+            exit(1);
+        }
+        printf("ping process: received \"%s\"\n", buf);
+        if (nBytes != 5) {
+            fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n",
+                    nBytes);
+            exit(1);
+        }
+        if (strcmp(buf, "pong") != 0) {
+            fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n",
+                    buf);
+            exit(1);
+        }
+    }
+
+    status = PR_Close(in_pipe[0]);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    status = PR_Close(out_pipe[1]);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    status = PR_WaitProcess(process, &exitCode);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_WaitProcess failed\n");
+        exit(1);
+    }
+    if (exitCode == 0) {
+        printf("PASS\n");
+        return 0;
+    } else {
+        printf("FAIL\n");
+        return 1;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/pipepong2.c
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * File: pipepong2.c
+ *
+ * Description:
+ * This test runs in conjunction with the pipeping2 test.
+ * The pipeping2 test creates two pipes and passes two
+ * pipe fd's to this test.  Then the pipeping2 test writes
+ * "ping" to this test and this test writes "pong" back.
+ * To run this pair of tests, just invoke pipeping2.
+ *
+ * Tested areas: process creation, pipes, file descriptor
+ * inheritance.
+ */
+
+#include "prerror.h"
+#include "prio.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define NUM_ITERATIONS 10
+
+int main()
+{
+    PRFileDesc *pipe_read, *pipe_write;
+    PRStatus status;
+    char buf[1024];
+    PRInt32 nBytes;
+    int idx;
+
+    pipe_read = PR_GetInheritedFD("PIPE_READ");
+    if (pipe_read == NULL) {
+        fprintf(stderr, "PR_GetInheritedFD failed\n");
+        exit(1);
+    }
+    status = PR_SetFDInheritable(pipe_read, PR_FALSE);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_SetFDInheritable failed\n");
+        exit(1);
+    }
+    pipe_write = PR_GetInheritedFD("PIPE_WRITE");
+    if (pipe_write == NULL) {
+        fprintf(stderr, "PR_GetInheritedFD failed\n");
+        exit(1);
+    }
+    status = PR_SetFDInheritable(pipe_write, PR_FALSE);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_SetFDInheritable failed\n");
+        exit(1);
+    }
+
+    for (idx = 0; idx < NUM_ITERATIONS; idx++) {
+        memset(buf, 0, sizeof(buf));
+        nBytes = PR_Read(pipe_read, buf, sizeof(buf));
+        if (nBytes == -1) {
+            fprintf(stderr, "PR_Read failed: (%d, %d)\n",
+                    PR_GetError(), PR_GetOSError());
+            exit(1);
+        }
+        printf("pong process: received \"%s\"\n", buf);
+        if (nBytes != 5) {
+            fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n",
+                    nBytes);
+            exit(1);
+        }
+        if (strcmp(buf, "ping") != 0) {
+            fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n",
+                    buf);
+            exit(1);
+        }
+
+        strcpy(buf, "pong");
+        printf("pong process: sending \"%s\"\n", buf);
+        nBytes = PR_Write(pipe_write, buf, 5);
+        if (nBytes == -1) {
+            fprintf(stderr, "PR_Write failed\n");
+            exit(1);
+        }
+    }
+
+    status = PR_Close(pipe_read);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    status = PR_Close(pipe_write);
+    if (status == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/primblok.c
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * File:        primblok.c
+ * Purpose:     testing whether the primordial thread can block in a
+ *              native blocking function without affecting the correct
+ *              functioning of NSPR I/O functions (Bugzilla bug #30746)
+ */
+
+#if !defined(WINNT)
+
+#include <stdio.h>
+
+int main()
+{
+    printf("This test is not relevant on this platform\n");
+    return 0;
+}
+
+#else /* WINNT */
+
+#include "nspr.h"
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_FILE_NAME "primblok.dat"
+
+/* use InterlockedExchange to update this variable */
+static LONG iothread_done;
+
+static void PR_CALLBACK IOThread(void *arg)
+{
+    PRFileDesc *fd;
+    char buf[32];
+    PRInt32 nbytes;
+
+    /* Give the primordial thread one second to block */
+    Sleep(1000);
+
+    /*
+     * See if our PR_Write call will hang when the primordial
+     * thread is blocking in a native blocking function.
+     */
+    fd = PR_Open(TEST_FILE_NAME, PR_WRONLY|PR_CREATE_FILE, 0666);
+    if (NULL == fd) {
+        fprintf(stderr, "PR_Open failed\n");
+        exit(1);
+    }
+    memset(buf, 0xaf, sizeof(buf));
+    fprintf(stderr, "iothread: calling PR_Write\n");
+    nbytes = PR_Write(fd, buf, sizeof(buf));
+    fprintf(stderr, "iothread: PR_Write returned\n");
+    if (nbytes != sizeof(buf)) {
+        fprintf(stderr, "PR_Write returned %d\n", nbytes);
+        exit(1);
+    }
+    if (PR_Close(fd) == PR_FAILURE) {
+        fprintf(stderr, "PR_Close failed\n");
+        exit(1);
+    }
+    if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) {
+        fprintf(stderr, "PR_Delete failed\n");
+        exit(1);
+    }
+
+    /* Tell the main thread that we are done */
+    InterlockedExchange(&iothread_done, 1);
+}
+
+int main()
+{
+    PRThread *iothread;
+
+    /* Must be a global thread */
+    iothread = PR_CreateThread(
+        PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL,
+        PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+    if (iothread == NULL) {
+        fprintf(stderr, "cannot create thread\n");
+        exit(1);
+    }
+
+    /*
+     * Block in a native blocking function.
+     * Give iothread 5 seconds to finish its task.
+     */
+    Sleep(5000);
+
+    /*
+     * Is iothread done or is it hung?
+     *
+     * I'm actually only interested in reading the value
+     * of iothread_done.  I'm using InterlockedExchange as
+     * a thread-safe way to read iothread_done.
+     */
+    if (InterlockedExchange(&iothread_done, 1) == 0) {
+        fprintf(stderr, "iothread is hung\n");
+        fprintf(stderr, "FAILED\n");
+        exit(1);
+    }
+
+    if (PR_JoinThread(iothread) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+    printf("PASSED\n");
+    return 0;
+}  /* main */
+
+#endif /* WINNT */
new file mode 100644
--- /dev/null
+++ b/pr/tests/prpollml.c
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * This test exercises the code that allocates and frees the syspoll_list
+ * array of PRThread in the pthreads version.  This test is intended to be
+ * run under Purify to verify that there is no memory leak.
+ */
+
+#include "nspr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define POLL_DESC_COUNT 256  /* This should be greater than the
+                              * STACK_POLL_DESC_COUNT macro in
+                              * ptio.c to cause syspoll_list to
+                              * be created. */
+
+static PRPollDesc pd[POLL_DESC_COUNT];
+
+static void Test(void)
+{
+    int i;
+    PRInt32 rv;
+    PRIntervalTime timeout;
+
+    timeout = PR_MillisecondsToInterval(10);
+    /* cause syspoll_list to grow */
+    for (i = 1; i <= POLL_DESC_COUNT; i++) {
+        rv = PR_Poll(pd, i, timeout);
+        if (rv != 0) {
+            fprintf(stderr,
+                "PR_Poll should time out but returns %d (%d, %d)\n",
+                rv, PR_GetError(), PR_GetOSError());
+            exit(1);
+        }
+    }
+    /* syspoll_list should be large enough for all these */
+    for (i = POLL_DESC_COUNT; i >= 1; i--) {
+        rv = PR_Poll(pd, i, timeout);
+        if (rv != 0) {
+            fprintf(stderr, "PR_Poll should time out but returns %d\n", rv);
+            exit(1);
+        }
+    }
+}
+
+static void ThreadFunc(void *arg)
+{
+    Test();
+}
+
+int main(int argc, char **argv)
+{
+    int i;
+    PRThread *thread;
+    PRFileDesc *sock;
+    PRNetAddr addr;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.inet.family = PR_AF_INET;
+    addr.inet.port = PR_htons(0);
+    addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+    for (i = 0; i < POLL_DESC_COUNT; i++) {
+        sock = PR_NewTCPSocket();
+        if (sock == NULL) {
+            fprintf(stderr, "PR_NewTCPSocket failed\n");
+            exit(1);
+        }
+        if (PR_Bind(sock, &addr) == PR_FAILURE) {
+            fprintf(stderr, "PR_Bind failed\n");
+            exit(1);
+        }
+        if (PR_Listen(sock, 5) == PR_FAILURE) {
+            fprintf(stderr, "PR_Listen failed\n");
+            exit(1);
+        }
+    
+        pd[i].fd = sock;
+        pd[i].in_flags = PR_POLL_READ;
+    }
+
+    /* first run the test on the primordial thread */
+    Test();
+
+    /* then run the test on all three kinds of threads */
+    thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+            PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+    if (NULL == thread) {
+        fprintf(stderr, "PR_CreateThread failed\n");
+        exit(1);
+    }
+    if (PR_JoinThread(thread) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+    thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+    if (NULL == thread) {
+        fprintf(stderr, "PR_CreateThread failed\n");
+        exit(1);
+    }
+    if (PR_JoinThread(thread) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+    thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+            PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, PR_JOINABLE_THREAD, 0);
+    if (NULL == thread) {
+        fprintf(stderr, "PR_CreateThread failed\n");
+        exit(1);
+    }
+    if (PR_JoinThread(thread) == PR_FAILURE) {
+        fprintf(stderr, "PR_JoinThread failed\n");
+        exit(1);
+    }
+    for (i = 0; i < POLL_DESC_COUNT; i++) {
+        if (PR_Close(pd[i].fd) == PR_FAILURE) {
+            fprintf(stderr, "PR_Close failed\n");
+            exit(1);
+        }
+    }
+    PR_Cleanup();
+    printf("PASS\n");
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/pr/tests/rmdir.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+** File:        rmdir.c
+** Description: Demonstrate bugzilla 80884. 
+**
+** after fix to unix_errors.c, message should report correct 
+** failure of PR_Rmdir().
+**
+**
+**
+*/
+
+#include <prio.h>
+#include <stdio.h>
+#include <prerror.h>
+#include <prlog.h>
+#include "plgetopt.h"
+
+#define DIRNAME "xxxBug80884/"
+#define FILENAME "file80883"
+
+PRBool  failed_already = PR_FALSE;
+PRBool	debug_mode = PR_FALSE;
+
+PRLogModuleInfo     *lm;
+
+/*
+** Help() -- print Usage information
+*/
+static void Help( void )  {
+    fprintf(stderr, "template usage:\n"
+                    "\t-d     debug mode\n"
+                    );
+} /* --- end Help() */
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+    PLOptStatus os;
+    PLOptState *opt = PL_CreateOptState(argc, argv, "dh");
+    PRFileDesc* fd;
+    PRErrorCode err;
+
+    /* parse command line options */
+    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+        if (PL_OPT_BAD == os) continue;
+        switch (opt->option) {
+            case 'd':  /* debug mode */
+                debug_mode = PR_TRUE;
+                break;
+            case 'h':
+            default:
+                Help();
+                return 2;
+        }
+    }
+    PL_DestroyOptState(opt);
+
+    lm = PR_NewLogModule( "testcase" );
+
+    (void) PR_MkDir( DIRNAME, 0777);
+    fd = PR_Open( DIRNAME FILENAME, PR_CREATE_FILE|PR_RDWR, 0666);
+    if (fd == 0) {
+        PRErrorCode err = PR_GetError();
+        fprintf(stderr, "create file fails: %d: %s\n", err,
+            PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
+        failed_already = PR_TRUE;
+        goto Finished;
+    }
+ 
+    PR_Close(fd);
+
+    if (PR_RmDir( DIRNAME ) == PR_SUCCESS) {
+        fprintf(stderr, "remove directory succeeds\n");
+        failed_already = PR_TRUE;
+        goto Finished;
+    }
+ 
+    err = PR_GetError();
+    fprintf(stderr, "remove directory fails with: %d: %s\n", err,
+        PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
+
+    (void) PR_Delete( DIRNAME FILENAME);
+    (void) PR_RmDir( DIRNAME );
+
+    return 0;
+
+Finished:
+    if ( debug_mode ) printf("%s\n", ( failed_already ) ? "FAILED" : "PASS" );
+    return( (failed_already)? 1 : 0 );
+}  /* --- end main() */
+/* --- end template.c */
new file mode 100644
--- /dev/null
+++ b/pr/tests/selintr.c
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Test whether classic NSPR's select() wrapper properly blocks
+ * the periodic SIGALRM clocks.  On some platforms (such as
+ * HP-UX and SINIX) an interrupted select() system call is
+ * restarted with the originally specified timeout, ignoring
+ * the time that has elapsed.  If a select() call is interrupted
+ * repeatedly, it will never time out.  (See Bugzilla bug #39674.)
+ */
+
+#if !defined(XP_UNIX)
+
+/*
+ * This test is applicable to Unix only.
+ */
+
+int main()
+{
+    return 0;
+}
+
+#else /* XP_UNIX */
+
+#include "nspr.h"
+
+#include <sys/time.h>
+#include <stdio.h>
+
+int main()
+{
+    struct timeval timeout;
+    int rv;
+
+    PR_SetError(0, 0);  /* force NSPR to initialize */
+    PR_EnableClockInterrupts();
+
+    /* 2 seconds timeout */
+    timeout.tv_sec = 2;
+    timeout.tv_usec = 0;
+    rv = select(1, NULL, NULL, NULL, &timeout);
+    printf("select returned %d\n", rv);
+    return 0;
+}
+
+#endif /* XP_UNIX */