fixup commit for branch 'OTIS_TEST_BRANCH' OTIS_TEST_BRANCH OTIS_TEST_BASE
authorcvs2hg
Thu, 18 Oct 2001 04:37:33 +0000
branchOTIS_TEST_BRANCH
changeset 2096 248300125cfa6e2a74ed91bd7b8b798d31039165
parent 2095 8064d257828e1f7069d9fdcd0ae8457ac1c22175
push idunknown
push userunknown
push dateunknown
fixup commit for branch 'OTIS_TEST_BRANCH'
pr/include/md/_solaris.h
pr/include/prlog.h
pr/src/io/prlog.c
pr/src/io/prsocket.c
pr/src/md/os2/os2io.c
new file mode 100644
--- /dev/null
+++ b/pr/include/md/_solaris.h
@@ -0,0 +1,784 @@
+/* -*- 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.
+ */
+
+#ifndef nspr_solaris_defs_h___
+#define nspr_solaris_defs_h___
+
+/*
+ * Internal configuration macros
+ */
+
+#define PR_LINKER_ARCH	"solaris"
+#define _PR_SI_SYSNAME	"SOLARIS"
+#define _PR_SI_ARCHITECTURE	"sparc"
+#define PR_DLL_SUFFIX		".so"
+
+#define _PR_VMBASE		0x30000000
+#define _PR_STACK_VMBASE	0x50000000
+#define _MD_DEFAULT_STACK_SIZE	(2*65536L)
+#define _MD_MMAP_FLAGS          MAP_SHARED
+
+#undef  HAVE_STACK_GROWING_UP
+
+#ifndef HAVE_WEAK_IO_SYMBOLS
+#define	HAVE_WEAK_IO_SYMBOLS
+#endif
+
+#undef	HAVE_WEAK_MALLOC_SYMBOLS
+#define	HAVE_DLL
+#define	USE_DLFCN
+#define NEED_STRFTIME_LOCK
+
+/*
+ * Intel x86 has atomic instructions.
+ *
+ * Sparc v8 does not have instructions to efficiently implement
+ * atomic increment/decrement operations.  In the local threads
+ * only and pthreads versions, we use the default atomic routine
+ * implementation in pratom.c.  The obsolete global threads only
+ * version uses a global mutex_t to implement the atomic routines
+ * in solaris.c, which is actually equivalent to the default
+ * implementation.
+ *
+ * 64-bit Solaris requires sparc v9, which has atomic instructions.
+ */
+#if defined(i386) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(IS_64)
+#define _PR_HAVE_ATOMIC_OPS
+#endif
+
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
+/*
+ * We have assembly language implementation of atomic
+ * stacks for the 32-bit sparc and x86 architectures only.
+ */
+#if !defined(sparc) || !defined(IS_64)
+#define _PR_HAVE_ATOMIC_CAS
+#endif
+#endif
+
+#define _PR_POLL_AVAILABLE
+#define _PR_USE_POLL
+#define _PR_STAT_HAS_ST_ATIM
+#ifdef SOLARIS2_5
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+#else
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+#endif
+#define _PR_HAVE_GETIPNODEBYNAME
+#define _PR_HAVE_GETIPNODEBYADDR
+#define _PR_INET6_PROBE
+#define _PR_ACCEPT_INHERIT_NONBLOCK
+#ifndef _PR_INET6
+#define AF_INET6 26
+#define AI_V4MAPPED 0x0001 
+#define AI_ALL      0x0002
+#define AI_ADDRCONFIG   0x0004
+#define _PR_HAVE_MD_SOCKADDR_IN6
+/* isomorphic to struct in6_addr on Solaris 8 */
+struct _md_in6_addr {
+    union {
+        PRUint8  _S6_u8[16];
+        PRUint32 _S6_u32[4];
+        PRUint32 __S6_align;
+    } _S6_un;
+};
+/* isomorphic to struct sockaddr_in6 on Solaris 8 */
+struct _md_sockaddr_in6 {
+    PRUint16 sin6_family;
+    PRUint16 sin6_port;
+    PRUint32 sin6_flowinfo;
+    struct _md_in6_addr sin6_addr;
+    PRUint32 sin6_scope_id;
+    PRUint32 __sin6_src_id;
+};
+#endif
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
+#define _PR_HAVE_GETHOST_R
+#define _PR_HAVE_GETHOST_R_POINTER
+#endif
+
+#include "prinrval.h"
+NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void);
+#define _MD_GET_INTERVAL                  _MD_Solaris_GetInterval
+NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void);
+#define _MD_INTERVAL_PER_SEC              _MD_Solaris_TicksPerSecond
+
+#if defined(_PR_HAVE_ATOMIC_OPS)
+/*
+** Atomic Operations
+*/
+#define _MD_INIT_ATOMIC()
+
+NSPR_API(PRInt32) _MD_AtomicIncrement(PRInt32 *val);
+#define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement
+
+NSPR_API(PRInt32) _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val);
+#define _MD_ATOMIC_ADD _MD_AtomicAdd
+
+NSPR_API(PRInt32) _MD_AtomicDecrement(PRInt32 *val);
+#define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement
+
+NSPR_API(PRInt32) _MD_AtomicSet(PRInt32 *val, PRInt32 newval);
+#define _MD_ATOMIC_SET _MD_AtomicSet
+#endif /* _PR_HAVE_ATOMIC_OPS */
+
+#if defined(_PR_PTHREADS)
+
+NSPR_API(void)		_MD_EarlyInit(void);
+
+#define _MD_EARLY_INIT		_MD_EarlyInit
+#define _MD_FINAL_INIT		_PR_UnixInit
+
+#elif defined(_PR_GLOBAL_THREADS_ONLY)
+
+#include "prthread.h"
+
+#include <ucontext.h>
+
+/*
+** Iinitialization Related definitions
+*/
+
+NSPR_API(void)		_MD_EarlyInit(void);
+
+#define _MD_EARLY_INIT		_MD_EarlyInit
+#define _MD_FINAL_INIT		_PR_UnixInit
+
+#define _MD_GET_SP(threadp)	threadp->md.sp
+
+/*
+** Clean-up the thread machine dependent data structure
+*/
+#define	_MD_INIT_THREAD				_MD_InitializeThread
+#define	_MD_INIT_ATTACHED_THREAD	_MD_InitializeThread
+
+NSPR_API(PRStatus) _MD_CreateThread(PRThread *thread, 
+					void (*start)(void *), 
+					PRThreadPriority priority,
+					PRThreadScope scope, 
+					PRThreadState state, 
+					PRUint32 stackSize);
+#define _MD_CREATE_THREAD _MD_CreateThread
+
+#define	_PR_CONTEXT_TYPE	ucontext_t
+
+#define CONTEXT(_thread) (&(_thread)->md.context)
+
+#include <thread.h>
+#include <sys/lwp.h>
+#include <synch.h>
+
+extern struct PRLock *_pr_schedLock;
+
+/*
+** Thread Local Storage 
+*/
+
+#define THREAD_KEY_T thread_key_t
+
+extern struct PRThread *_pr_current_thread_tls();
+extern struct _PRCPU *_pr_current_cpu_tls();
+extern struct PRThread *_pr_last_thread_tls();
+
+extern THREAD_KEY_T threadid_key;
+extern THREAD_KEY_T cpuid_key;
+extern THREAD_KEY_T last_thread_key;
+
+#define _MD_CURRENT_THREAD() _pr_current_thread_tls()
+#define _MD_CURRENT_CPU() _pr_current_cpu_tls()
+#define _MD_LAST_THREAD() _pr_last_thread_tls()
+	
+#define _MD_SET_CURRENT_THREAD(newval) 			\
+	PR_BEGIN_MACRO					\
+	thr_setspecific(threadid_key, (void *)newval);	\
+	PR_END_MACRO
+
+#define _MD_SET_CURRENT_CPU(newval) 			\
+	PR_BEGIN_MACRO					\
+	thr_setspecific(cpuid_key, (void *)newval);	\
+	PR_END_MACRO
+
+#define _MD_SET_LAST_THREAD(newval)	 			\
+	PR_BEGIN_MACRO						\
+	thr_setspecific(last_thread_key, (void *)newval);	\
+	PR_END_MACRO
+	
+#define	_MD_CLEAN_THREAD(_thread)	_MD_cleanup_thread(_thread)
+extern void _MD_exit_thread(PRThread *thread);
+#define _MD_EXIT_THREAD(thread)		_MD_exit_thread(thread)
+
+#define	_MD_SUSPEND_THREAD(thread)	_MD_Suspend(thread)
+#define	_MD_RESUME_THREAD(thread)	thr_continue((thread)->md.handle)
+
+/* XXXX Needs to be defined - Prashant */
+#define _MD_SUSPEND_CPU(cpu)
+#define _MD_RESUME_CPU(cpu)
+
+extern void _MD_Begin_SuspendAll(void);
+extern void _MD_End_SuspendAll(void);
+extern void _MD_End_ResumeAll(void);
+#define _MD_BEGIN_SUSPEND_ALL()		_MD_Begin_SuspendAll()
+#define _MD_BEGIN_RESUME_ALL()		
+#define	_MD_END_SUSPEND_ALL()		_MD_End_SuspendAll()
+#define	_MD_END_RESUME_ALL()		_MD_End_ResumeAll()
+
+#define _MD_INIT_LOCKS()
+#define _MD_NEW_LOCK(md_lockp) (mutex_init(&((md_lockp)->lock),USYNC_THREAD,NULL) ? PR_FAILURE : PR_SUCCESS)
+#define _MD_FREE_LOCK(md_lockp) mutex_destroy(&((md_lockp)->lock))
+#define _MD_UNLOCK(md_lockp) mutex_unlock(&((md_lockp)->lock))
+#define _MD_TEST_AND_LOCK(md_lockp) mutex_trylock(&((md_lockp)->lock))
+struct _MDLock;
+NSPR_API(void) _MD_lock(struct _MDLock *md_lock);
+#undef PROFILE_LOCKS
+#ifndef PROFILE_LOCKS
+#define _MD_LOCK(md_lockp) _MD_lock(md_lockp)
+#else
+#define _MD_LOCK(md_lockp)                 \
+    PR_BEGIN_MACRO \
+    int rv = _MD_TEST_AND_LOCK(md_lockp); \
+    if (rv == 0) { \
+        (md_lockp)->hitcount++; \
+    } else { \
+        (md_lockp)->misscount++; \
+        _MD_lock(md_lockp); \
+    } \
+    PR_END_MACRO
+#endif
+
+#define _PR_LOCK_HEAP() if (_pr_heapLock) _MD_LOCK(&_pr_heapLock->md)
+#define _PR_UNLOCK_HEAP() if (_pr_heapLock) _MD_UNLOCK(&_pr_heapLock->md)
+
+#define _MD_ATTACH_THREAD(threadp)
+
+
+#define THR_KEYCREATE thr_keycreate
+#define THR_SELF thr_self
+#define _MD_NEW_CV(condp) cond_init(&((condp)->cv), USYNC_THREAD, 0)
+#define COND_WAIT(condp, mutexp) cond_wait(condp, mutexp)
+#define COND_TIMEDWAIT(condp, mutexp, tspec) \
+                                     cond_timedwait(condp, mutexp, tspec)
+#define _MD_NOTIFY_CV(condp, lockp) cond_signal(&((condp)->cv))
+#define _MD_NOTIFYALL_CV(condp,unused) cond_broadcast(&((condp)->cv))	
+#define _MD_FREE_CV(condp) cond_destroy(&((condp)->cv))
+#define _MD_YIELD() thr_yield()
+#include <time.h>
+/* 
+ * Because clock_gettime() on Solaris/x86 2.4 always generates a
+ * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(),
+ * which is implemented using gettimeofday().
+ */
+#if defined(i386) && defined(SOLARIS2_4)
+extern int _pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp);
+#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt))
+#else
+#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt))
+#endif  /* i386 && SOLARIS2_4 */
+
+#define MUTEX_T mutex_t
+#define COND_T cond_t
+
+#define _MD_NEW_SEM(md_semp,_val)  sema_init(&((md_semp)->sem),_val,USYNC_THREAD,NULL)
+#define _MD_DESTROY_SEM(md_semp) sema_destroy(&((md_semp)->sem))
+#define _MD_WAIT_SEM(md_semp) sema_wait(&((md_semp)->sem))
+#define _MD_POST_SEM(md_semp) sema_post(&((md_semp)->sem))
+
+#define _MD_SAVE_ERRNO(_thread)
+#define _MD_RESTORE_ERRNO(_thread)
+#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu)
+
+extern struct _MDLock _pr_ioq_lock;
+#define _MD_IOQ_LOCK()		_MD_LOCK(&_pr_ioq_lock)
+#define _MD_IOQ_UNLOCK()	_MD_UNLOCK(&_pr_ioq_lock)
+
+extern PRStatus _MD_wait(struct PRThread *, PRIntervalTime timeout);
+#define _MD_WAIT _MD_wait
+
+extern PRStatus _MD_WakeupWaiter(struct PRThread *);
+#define _MD_WAKEUP_WAITER _MD_WakeupWaiter
+
+NSPR_API(void) _MD_InitIO(void);
+#define _MD_INIT_IO _MD_InitIO
+
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status)
+#define _MD_SWITCH_CONTEXT(_thread)
+#define _MD_RESTORE_CONTEXT(_newThread)
+
+struct _MDLock {
+    MUTEX_T lock;
+#ifdef PROFILE_LOCKS
+    PRInt32 hitcount;
+    PRInt32 misscount;
+#endif
+};
+
+struct _MDCVar {
+    COND_T cv;
+};
+
+struct _MDSemaphore {
+    sema_t sem;
+};
+
+struct _MDThread {
+    _PR_CONTEXT_TYPE context;
+    thread_t handle;
+    lwpid_t lwpid;
+    uint_t sp;		/* stack pointer */
+    uint_t threadID;	/* ptr to solaris-internal thread id structures */
+    struct _MDSemaphore waiter_sem;
+};
+
+struct _MDThreadStack {
+    PRInt8 notused;
+};
+
+struct _MDSegment {
+    PRInt8 notused;
+};
+
+/*
+ * md-specific cpu structure field, common to all Unix platforms
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+    PRCList ioQ;
+    PRUint32 ioq_timeout;
+    PRInt32 ioq_max_osfd;
+    PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+    fd_set fd_read_set, fd_write_set, fd_exception_set;
+    PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+				fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+	struct pollfd *ioq_pollfds;
+	int ioq_pollfds_size;
+#endif	/* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu)			((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu)		((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu)		((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu)		((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu)		((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu)	((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu)	((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu)		((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu)		((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu)		((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu)		((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu)	((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu)	32
+
+
+struct _MDCPU {
+	struct _MDCPU_Unix md_unix;
+};
+
+/* The following defines the unwrapped versions of select() and poll(). */
+extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
+	fd_set *exceptfds, struct timeval *timeout);
+#define _MD_SELECT	_select
+
+#include <poll.h>
+#define _MD_POLL _poll
+extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Missing function prototypes
+*/
+extern int gethostname (char *name, int namelen);
+
+PR_END_EXTERN_C
+
+#else /* _PR_GLOBAL_THREADS_ONLY */
+
+/*
+ * LOCAL_THREADS_ONLY implementation on Solaris
+ */
+
+#include "prthread.h"
+
+#include <errno.h>
+#include <ucontext.h>
+#include <sys/stack.h>
+#include <synch.h>
+
+/*
+** Iinitialization Related definitions
+*/
+
+NSPR_API(void)				_MD_EarlyInit(void);
+NSPR_API(void)				_MD_SolarisInit();
+#define _MD_EARLY_INIT		_MD_EarlyInit
+#define _MD_FINAL_INIT		_MD_SolarisInit
+#define	_MD_INIT_THREAD		_MD_InitializeThread
+
+#ifdef USE_SETJMP
+
+#include <setjmp.h>
+
+#define _PR_CONTEXT_TYPE	jmp_buf
+
+#ifdef sparc
+#define _MD_GET_SP(_t)		(_t)->md.context[2]
+#else
+#define _MD_GET_SP(_t)		(_t)->md.context[4]
+#endif
+
+#define PR_NUM_GCREGS		_JBLEN
+#define CONTEXT(_thread)	(_thread)->md.context
+
+#else  /* ! USE_SETJMP */
+
+#ifdef sparc
+#define	_PR_CONTEXT_TYPE	ucontext_t
+#define _MD_GET_SP(_t)		(_t)->md.context.uc_mcontext.gregs[REG_SP]
+/*
+** Sparc's use register windows. the _MD_GetRegisters for the sparc's
+** doesn't actually store anything into the argument buffer; instead the
+** register windows are homed to the stack. I assume that the stack
+** always has room for the registers to spill to...
+*/
+#define PR_NUM_GCREGS		0
+#else
+#define _PR_CONTEXT_TYPE	unsigned int edi; sigset_t oldMask, blockMask; ucontext_t
+#define _MD_GET_SP(_t)		(_t)->md.context.uc_mcontext.gregs[USP]
+#define PR_NUM_GCREGS		_JBLEN
+#endif
+
+#define CONTEXT(_thread)	(&(_thread)->md.context)
+
+#endif /* ! USE_SETJMP */
+
+#include <time.h>
+/* 
+ * Because clock_gettime() on Solaris/x86 always generates a
+ * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(),
+ * which is implemented using gettimeofday().
+ */
+#ifdef i386
+#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt))
+#else
+#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt))
+#endif  /* i386 */
+
+#define _MD_SAVE_ERRNO(_thread)			(_thread)->md.errcode = errno;
+#define _MD_RESTORE_ERRNO(_thread)		errno = (_thread)->md.errcode;
+
+#ifdef sparc
+
+#ifdef USE_SETJMP
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status)	      \
+    PR_BEGIN_MACRO				      \
+	int *context = (_thread)->md.context;	      \
+    *status = PR_TRUE;              \
+	(void) setjmp(context);			      \
+	(_thread)->md.context[1] = (int) ((_sp) - 64); \
+	(_thread)->md.context[2] = (int) _main;	      \
+	(_thread)->md.context[3] = (int) _main + 4; \
+    _thread->no_sched = 0; \
+    PR_END_MACRO
+
+#define _MD_SWITCH_CONTEXT(_thread)    \
+    if (!setjmp(CONTEXT(_thread))) { \
+	_MD_SAVE_ERRNO(_thread)    \
+	_MD_SET_LAST_THREAD(_thread);	 \
+    _MD_SET_CURRENT_THREAD(_thread);	 \
+	_PR_Schedule();		     \
+    }
+
+#define _MD_RESTORE_CONTEXT(_newThread)	    \
+{				     \
+	_MD_RESTORE_ERRNO(_newThread)	    \
+	_MD_SET_CURRENT_THREAD(_newThread); \
+    longjmp(CONTEXT(_newThread), 1);    \
+}
+
+#else
+/*
+** Initialize the thread context preparing it to execute _main.
+*/
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status)					\
+    PR_BEGIN_MACRO				      									\
+    ucontext_t *uc = CONTEXT(_thread);									\
+    *status = PR_TRUE;													\
+    getcontext(uc);														\
+    uc->uc_stack.ss_sp = (char *) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8);	\
+    uc->uc_stack.ss_size = _thread->stack->stackSize; 					\
+    uc->uc_stack.ss_flags = 0; 				/* ? */		        		\
+    uc->uc_mcontext.gregs[REG_SP] = (unsigned int) uc->uc_stack.ss_sp;	\
+    uc->uc_mcontext.gregs[REG_PC] = (unsigned int) _main;				\
+    uc->uc_mcontext.gregs[REG_nPC] = (unsigned int) ((char*)_main)+4;	\
+    uc->uc_flags = UC_ALL;												\
+    _thread->no_sched = 0;												\
+    PR_END_MACRO
+
+/*
+** Switch away from the current thread context by saving its state and
+** calling the thread scheduler. Reload cpu when we come back from the
+** context switch because it might have changed.
+*/
+#define _MD_SWITCH_CONTEXT(_thread)    				\
+    PR_BEGIN_MACRO                     				\
+		if (!getcontext(CONTEXT(_thread))) { 		\
+			_MD_SAVE_ERRNO(_thread);    			\
+			_MD_SET_LAST_THREAD(_thread);	 		\
+			_PR_Schedule();			 				\
+		}					 						\
+    PR_END_MACRO
+
+/*
+** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or
+** initialized by _MD_INIT_CONTEXT.
+*/
+#define _MD_RESTORE_CONTEXT(_newThread)	    				\
+    PR_BEGIN_MACRO			    							\
+    	ucontext_t *uc = CONTEXT(_newThread); 				\
+    	uc->uc_mcontext.gregs[11] = 1;     					\
+		_MD_RESTORE_ERRNO(_newThread);	    				\
+		_MD_SET_CURRENT_THREAD(_newThread); 				\
+    	setcontext(uc);		       							\
+    PR_END_MACRO
+#endif
+
+#else  /* x86 solaris */
+
+#ifdef USE_SETJMP
+
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \
+    PR_BEGIN_MACRO \
+    *status = PR_TRUE; \
+    if (setjmp(CONTEXT(_thread))) _main(); \
+    _MD_GET_SP(_thread) = (int) ((_sp) - 64); \
+    PR_END_MACRO
+
+#define _MD_SWITCH_CONTEXT(_thread) \
+    if (!setjmp(CONTEXT(_thread))) { \
+        _MD_SAVE_ERRNO(_thread) \
+        _PR_Schedule();	\
+    }
+
+#define _MD_RESTORE_CONTEXT(_newThread) \
+{ \
+    _MD_RESTORE_ERRNO(_newThread) \
+    _MD_SET_CURRENT_THREAD(_newThread); \
+    longjmp(CONTEXT(_newThread), 1); \
+}
+
+#else /* USE_SETJMP */
+
+#define WINDOWSIZE		0
+ 
+int getedi(void);
+void setedi(int);
+ 
+#define _MD_INIT_CONTEXT(_thread, _sp, _main, status)	      \
+	PR_BEGIN_MACRO					\
+	ucontext_t *uc = CONTEXT(_thread);		\
+        *status = PR_TRUE;              \
+	getcontext(uc);					\
+	/* Force sp to be double aligned! */		\
+    	uc->uc_mcontext.gregs[USP] = (int) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8);	\
+	uc->uc_mcontext.gregs[PC] = (int) _main;	\
+	(_thread)->no_sched = 0; \
+	PR_END_MACRO
+
+/* getcontext() may return 1, contrary to what the man page says */
+#define _MD_SWITCH_CONTEXT(_thread)			\
+	PR_BEGIN_MACRO					\
+	ucontext_t *uc = CONTEXT(_thread);		\
+	PR_ASSERT(_thread->no_sched);			\
+	sigfillset(&((_thread)->md.blockMask));		\
+	sigprocmask(SIG_BLOCK, &((_thread)->md.blockMask),	\
+		&((_thread)->md.oldMask));		\
+	(_thread)->md.edi = getedi();			\
+	if (! getcontext(uc)) {				\
+		sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \
+		uc->uc_mcontext.gregs[EDI] = (_thread)->md.edi;	\
+		_MD_SAVE_ERRNO(_thread)    		\
+	        _MD_SET_LAST_THREAD(_thread);	        \
+		_PR_Schedule();				\
+	} else {					\
+		sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \
+		setedi((_thread)->md.edi);		\
+		PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \
+		_MD_LAST_THREAD()->no_sched = 0;	\
+	}						\
+	PR_END_MACRO
+
+/*
+** Restore a thread context, saved by _PR_SWITCH_CONTEXT
+*/
+#define _MD_RESTORE_CONTEXT(_newthread)			\
+	PR_BEGIN_MACRO					\
+	ucontext_t *uc = CONTEXT(_newthread);		\
+	uc->uc_mcontext.gregs[EAX] = 1;			\
+	_MD_RESTORE_ERRNO(_newthread)  			\
+	_MD_SET_CURRENT_THREAD(_newthread);		\
+	(_newthread)->no_sched = 1;			\
+	setcontext(uc);					\
+	PR_END_MACRO
+#endif /* USE_SETJMP */
+
+#endif /* sparc */
+
+struct _MDLock {
+	PRInt8 notused;
+};
+
+struct _MDCVar {
+	PRInt8 notused;
+};
+
+struct _MDSemaphore {
+	PRInt8 notused;
+};
+
+struct _MDThread {
+    _PR_CONTEXT_TYPE context;
+    int errcode;
+    int id;
+};
+
+struct _MDThreadStack {
+    PRInt8 notused;
+};
+
+struct _MDSegment {
+    PRInt8 notused;
+};
+
+/*
+ * md-specific cpu structure field
+ */
+#define _PR_MD_MAX_OSFD FD_SETSIZE
+
+struct _MDCPU_Unix {
+    PRCList ioQ;
+    PRUint32 ioq_timeout;
+    PRInt32 ioq_max_osfd;
+    PRInt32 ioq_osfd_cnt;
+#ifndef _PR_USE_POLL
+    fd_set fd_read_set, fd_write_set, fd_exception_set;
+    PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD],
+				fd_exception_cnt[_PR_MD_MAX_OSFD];
+#else
+	struct pollfd *ioq_pollfds;
+	int ioq_pollfds_size;
+#endif	/* _PR_USE_POLL */
+};
+
+#define _PR_IOQ(_cpu)			((_cpu)->md.md_unix.ioQ)
+#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu))
+#define _PR_FD_READ_SET(_cpu)		((_cpu)->md.md_unix.fd_read_set)
+#define _PR_FD_READ_CNT(_cpu)		((_cpu)->md.md_unix.fd_read_cnt)
+#define _PR_FD_WRITE_SET(_cpu)		((_cpu)->md.md_unix.fd_write_set)
+#define _PR_FD_WRITE_CNT(_cpu)		((_cpu)->md.md_unix.fd_write_cnt)
+#define _PR_FD_EXCEPTION_SET(_cpu)	((_cpu)->md.md_unix.fd_exception_set)
+#define _PR_FD_EXCEPTION_CNT(_cpu)	((_cpu)->md.md_unix.fd_exception_cnt)
+#define _PR_IOQ_TIMEOUT(_cpu)		((_cpu)->md.md_unix.ioq_timeout)
+#define _PR_IOQ_MAX_OSFD(_cpu)		((_cpu)->md.md_unix.ioq_max_osfd)
+#define _PR_IOQ_OSFD_CNT(_cpu)		((_cpu)->md.md_unix.ioq_osfd_cnt)
+#define _PR_IOQ_POLLFDS(_cpu)		((_cpu)->md.md_unix.ioq_pollfds)
+#define _PR_IOQ_POLLFDS_SIZE(_cpu)	((_cpu)->md.md_unix.ioq_pollfds_size)
+
+#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu)	32
+
+struct _MDCPU {
+	struct _MDCPU_Unix md_unix;
+};
+
+#ifndef _PR_PTHREADS
+#define _MD_INIT_LOCKS()
+#endif
+#define _MD_NEW_LOCK(lock)				PR_SUCCESS
+#define _MD_FREE_LOCK(lock)
+#define _MD_LOCK(lock)
+#define _MD_UNLOCK(lock)
+#define _MD_INIT_IO()
+#define _MD_IOQ_LOCK()
+#define _MD_IOQ_UNLOCK()
+
+#define _MD_INIT_RUNNING_CPU(cpu)		_MD_unix_init_running_cpu(cpu)
+#define _MD_INIT_THREAD					_MD_InitializeThread
+#define _MD_EXIT_THREAD(thread)
+#define _MD_SUSPEND_THREAD(thread)
+#define _MD_RESUME_THREAD(thread)
+#define _MD_CLEAN_THREAD(_thread)
+
+extern PRStatus _MD_WAIT(struct PRThread *, PRIntervalTime timeout);
+extern PRStatus _MD_WAKEUP_WAITER(struct PRThread *);
+extern void     _MD_YIELD(void);
+extern PRStatus _MD_InitializeThread(PRThread *thread);
+extern void     _MD_SET_PRIORITY(struct _MDThread *thread,
+	PRThreadPriority newPri);
+extern PRStatus _MD_CREATE_THREAD(PRThread *thread, void (*start) (void *),
+	PRThreadPriority priority, PRThreadScope scope, PRThreadState state,
+        PRUint32 stackSize);
+
+NSPR_API(PRIntervalTime)				_MD_Solaris_GetInterval(void);
+#define _MD_GET_INTERVAL				_MD_Solaris_GetInterval
+NSPR_API(PRIntervalTime)				_MD_Solaris_TicksPerSecond(void);
+#define _MD_INTERVAL_PER_SEC			_MD_Solaris_TicksPerSecond
+
+/* The following defines the unwrapped versions of select() and poll(). */
+extern int _select(int nfds, fd_set *readfds, fd_set *writefds,
+	fd_set *exceptfds, struct timeval *timeout);
+#define _MD_SELECT	_select
+
+#include <stropts.h>
+#include <poll.h>
+#define _MD_POLL _poll
+extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout);
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Missing function prototypes
+*/
+extern int gethostname (char *name, int namelen);
+
+PR_END_EXTERN_C
+
+#endif /* _PR_GLOBAL_THREADS_ONLY */
+
+#endif /* nspr_solaris_defs_h___ */
+
new file mode 100644
--- /dev/null
+++ b/pr/include/prlog.h
@@ -0,0 +1,253 @@
+/* -*- 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.
+ */
+
+#ifndef prlog_h___
+#define prlog_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** prlog.h -- Declare interfaces to NSPR's Logging service
+**
+** NSPR provides a logging service that is used by NSPR itself and is
+** available to client programs.
+**
+** To use the service from a client program, you should create a
+** PRLogModuleInfo structure by calling PR_NewLogModule(). After
+** creating the LogModule, you can write to the log using the PR_LOG()
+** macro.
+**
+** Initialization of the log service is handled by NSPR initialization.
+**
+** At execution time, you must enable the log service. To enable the
+** log service, set the environment variable: NSPR_LOG_MODULES
+** variable.
+**
+** NSPR_LOG_MODULES variable has the form:
+**
+**     <moduleName>:<value>[, <moduleName>:<value>]*
+**
+** Where:
+**  <moduleName> is the name passed to PR_NewLogModule().
+**  <value> is a numeric constant, e.g. 5. This value is the maximum
+** value of a log event, enumerated by PRLogModuleLevel, that you want
+** written to the log.
+** 
+** For example: to record all events of greater value than or equal to
+** PR_LOG_ERROR for a LogModule names "gizmo", say:
+** 
+** set NSPR_LOG_MODULES=gizmo:2
+** 
+** Note that you must specify the numeric value of PR_LOG_ERROR.
+** 
+** Special LogModule names are provided for controlling NSPR's log
+** service at execution time. These controls should be set in the
+** NSPR_LOG_MODULES environment variable at execution time to affect
+** NSPR's log service for your application.
+** 
+** The special LogModule "all" enables all LogModules. To enable all
+** LogModule calls to PR_LOG(), say:
+** 
+** set NSPR_LOG_MODULES=all:5
+** 
+** The special LogModule name "sync" tells the NSPR log service to do
+** unbuffered logging.
+** 
+** The special LogModule name "bufsize:<size>" tells NSPR to set the
+** log buffer to <size>.
+**
+** The environment variable NSPR_LOG_FILE specifies the log file to use
+** unless the default of "stderr" is acceptable. For MS Windows
+** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug"
+** (case sensitive). This value causes PR_LOG() output to be written
+** using the Windows API OutputDebugString(). OutputDebugString()
+** writes to the debugger window; some people find this helpful.
+** 
+**
+** To put log messages in your programs, use the PR_LOG macro:
+**
+**     PR_LOG(<module>, <level>, (<printfString>, <args>*));
+**
+** Where <module> is the address of a PRLogModuleInfo structure, and
+** <level> is one of the levels defined by the enumeration:
+** PRLogModuleLevel. <args> is a printf() style of argument list. That
+** is: (fmtstring, ...).
+**
+** Example:
+** 
+** main() {
+**    PRIntn one = 1;
+**    PRLogModuleInfo * myLm = PR_NewLogModule("gizmo");
+**    PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one)); 
+**    return; 
+** }
+** 
+** Note the use of printf() style arguments as the third agrument(s) to
+** PR_LOG().
+** 
+** After compiling and linking you application, set the environment:
+** 
+** set NSPR_LOG_MODULES=gizmo:5
+** set NSPR_LOG_FILE=logfile.txt
+** 
+** When you execute your application, the string "Log this! 1" will be
+** written to the file "logfile.txt".
+** 
+** Note to NSPR engineers: a number of PRLogModuleInfo structures are
+** defined and initialized in prinit.c. See this module for ideas on
+** what to log where.
+** 
+*/
+
+typedef enum PRLogModuleLevel {
+    PR_LOG_NONE = 0,                /* nothing */
+    PR_LOG_ALWAYS = 1,              /* always printed */
+    PR_LOG_ERROR = 2,               /* error messages */
+    PR_LOG_WARNING = 3,             /* warning messages */
+    PR_LOG_DEBUG = 4,               /* debug messages */
+
+    PR_LOG_NOTICE = PR_LOG_DEBUG,   /* notice messages */
+    PR_LOG_WARN = PR_LOG_WARNING,   /* warning messages */
+    PR_LOG_MIN = PR_LOG_DEBUG,      /* minimal debugging messages */
+    PR_LOG_MAX = PR_LOG_DEBUG       /* maximal debugging messages */
+} PRLogModuleLevel;
+
+/*
+** One of these structures is created for each module that uses logging.
+**    "name" is the name of the module
+**    "level" is the debugging level selected for that module
+*/
+typedef struct PRLogModuleInfo {
+    const char *name;
+    PRLogModuleLevel level;
+    struct PRLogModuleInfo *next;
+} PRLogModuleInfo;
+
+/*
+** Create a new log module.
+*/
+NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name);
+
+/*
+** Set the file to use for logging. Returns PR_FALSE if the file cannot
+** be created
+*/
+NSPR_API(PRBool) PR_SetLogFile(const char *name);
+
+/*
+** Set the size of the logging buffer. If "buffer_size" is zero then the
+** logging becomes "synchronous" (or unbuffered).
+*/
+NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size);
+
+/*
+** Print a string to the log. "fmt" is a PR_snprintf format type. All
+** messages printed to the log are preceeded by the name of the thread
+** and a time stamp. Also, the routine provides a missing newline if one
+** is not provided.
+*/
+NSPR_API(void) PR_LogPrint(const char *fmt, ...);
+
+/*
+** Flush the log to its file.
+*/
+NSPR_API(void) PR_LogFlush(void);
+
+/*
+** Windoze 16 can't support a large static string space for all of the
+** various debugging strings so logging is not enabled for it.
+*/
+#if (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16)
+#define PR_LOGGING 1
+
+#define PR_LOG_TEST(_module,_level) \
+    ((_module)->level >= (_level))
+
+/*
+** Log something.
+**    "module" is the address of a PRLogModuleInfo structure
+**    "level" is the desired logging level
+**    "args" is a variable length list of arguments to print, in the following
+**       format:  ("printf style format string", ...)
+*/
+#define PR_LOG(_module,_level,_args)     \
+    PR_BEGIN_MACRO             \
+      if (PR_LOG_TEST(_module,_level)) { \
+      PR_LogPrint _args;         \
+      }                     \
+    PR_END_MACRO
+
+#else /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */
+
+#undef PR_LOGGING
+#define PR_LOG_TEST(module,level) 0
+#define PR_LOG(module,level,args)
+
+#endif /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#ifdef PR_LOGGING
+#define PR_LOG_BEGIN    PR_LOG
+#define PR_LOG_END      PR_LOG
+#define PR_LOG_DEFINE   PR_NewLogModule
+#else
+#define PR_LOG_BEGIN(module,level,args)
+#define PR_LOG_END(module,level,args)
+#define PR_LOG_DEFINE(_name)    NULL
+#endif /* PR_LOGGING */
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#if defined(DEBUG)
+
+NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln);
+#define PR_ASSERT(_expr) \
+    ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__))
+
+#define PR_NOT_REACHED(_reasonStr) \
+    PR_Assert(_reasonStr,__FILE__,__LINE__)
+
+#else
+
+#define PR_ASSERT(expr) ((void) 0)
+#define PR_NOT_REACHED(reasonStr)
+
+#endif /* defined(DEBUG) */
+
+PR_END_EXTERN_C
+
+#endif /* prlog_h___ */
new file mode 100644
--- /dev/null
+++ b/pr/src/io/prlog.c
@@ -0,0 +1,504 @@
+/* -*- 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.
+ */
+
+/*
+ * Contributors:
+ *
+ * This Original Code has been modified by IBM Corporation.
+ * Modifications made by IBM described herein are
+ * Copyright (c) International Business Machines Corporation, 2000.
+ * Modifications to Mozilla code or documentation identified per
+ * MPL Section 3.3
+ *
+ * Date         Modified by     Description of modification
+ * 04/10/2000   IBM Corp.       Added DebugBreak() definitions for OS/2
+ */
+
+#include "primpl.h"
+#include "prenv.h"
+#include "prprf.h"
+#include <string.h>
+
+/*
+ * Lock used to lock the log.
+ *
+ * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
+ * contain assertions.  We have to avoid assertions in _PR_LOCK_LOG
+ * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
+ * This can lead to infinite recursion.
+ */
+static PRLock *_pr_logLock;
+#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
+#define _PR_LOCK_LOG() PR_Lock(_pr_logLock);
+#define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock);
+#elif defined(_PR_GLOBAL_THREADS_ONLY)
+#define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
+#define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
+#else
+
+#define _PR_LOCK_LOG() \
+{ \
+    PRIntn _is; \
+    PRThread *_me = _PR_MD_CURRENT_THREAD(); \
+    if (!_PR_IS_NATIVE_THREAD(_me)) \
+        _PR_INTSOFF(_is); \
+    _PR_LOCK_LOCK(_pr_logLock)
+
+#define _PR_UNLOCK_LOG() \
+    _PR_LOCK_UNLOCK(_pr_logLock); \
+    PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
+    if (!_PR_IS_NATIVE_THREAD(_me)) \
+        _PR_INTSON(_is); \
+}
+
+#endif
+
+#if defined(XP_PC)
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+#endif
+
+/*
+ * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
+ * because every asynchronous file io operation leads to a fiber context
+ * switch.  So we define _PUT_LOG as fputs (from stdio.h).  A side
+ * benefit is that fputs handles the LF->CRLF translation.  This
+ * code can also be used on other platforms with file stream io.
+ */
+#if defined(WIN32) || defined(XP_OS2)
+#define _PR_USE_STDIO_FOR_LOGGING
+#endif
+
+/*
+** Coerce Win32 log output to use OutputDebugString() when
+** NSPR_LOG_FILE is set to "WinDebug".
+*/
+#if defined(XP_PC)
+#define WIN32_DEBUG_FILE (FILE*)-2
+#endif
+
+/* Macros used to reduce #ifdef pollution */
+
+#if defined(_PR_USE_STDIO_FOR_LOGGING)
+#define _PUT_LOG(fd, buf, nb) {fputs(buf, fd); fflush(fd);}
+#elif defined(_PR_PTHREADS)
+#define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
+#elif defined(XP_MAC)
+#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb)
+#else
+#define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
+#endif
+
+/************************************************************************/
+
+static PRLogModuleInfo *logModules;
+
+static char *logBuf = NULL;
+static char *logp;
+static char *logEndp;
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+static FILE *logFile = NULL;
+#else
+static PRFileDesc *logFile = 0;
+#endif
+
+#define LINE_BUF_SIZE           512
+#define DEFAULT_BUF_SIZE        16384
+
+#ifdef _PR_NEED_STRCASECMP
+
+/*
+ * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
+ * such as NCR and Unixware.  Linking with both libc and libucb
+ * may cause some problem, so I just provide our own implementation
+ * of strcasecmp here.
+ */
+
+static const unsigned char uc[] =
+{
+    '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+    '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+    '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+    '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+    ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
+    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
+    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
+    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
+    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
+    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+    'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
+};
+
+PRIntn strcasecmp(const char *a, const char *b)
+{
+    const unsigned char *ua = (const unsigned char *)a;
+    const unsigned char *ub = (const unsigned char *)b;
+
+    if( ((const char *)0 == a) || (const char *)0 == b ) 
+        return (PRIntn)(a-b);
+
+    while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
+    {
+        a++;
+        ua++;
+        ub++;
+    }
+
+    return (PRIntn)(uc[*ua] - uc[*ub]);
+}
+
+#endif /* _PR_NEED_STRCASECMP */
+
+void _PR_InitLog(void)
+{
+    char *ev;
+
+    _pr_logLock = PR_NewLock();
+
+    ev = PR_GetEnv("NSPR_LOG_MODULES");
+    if (ev && ev[0]) {
+        char module[64];
+        PRBool isSync = PR_FALSE;
+        PRIntn evlen = strlen(ev), pos = 0;
+        PRInt32 bufSize = DEFAULT_BUF_SIZE;
+        while (pos < evlen) {
+            PRIntn level = 1, count = 0, delta = 0;
+            count = sscanf(&ev[pos], "%64[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n",
+                           module, &delta, &level, &delta);
+            pos += delta;
+            if (count == 0) break;
+
+            /*
+            ** If count == 2, then we got module and level. If count
+            ** == 1, then level defaults to 1 (module enabled).
+            */
+            if (strcasecmp(module, "sync") == 0) {
+                isSync = PR_TRUE;
+            } else if (strcasecmp(module, "bufsize") == 0) {
+                if (level >= LINE_BUF_SIZE) {
+                    bufSize = level;
+                }
+            } else {
+                PRLogModuleInfo *lm = logModules;
+                PRBool skip_modcheck =
+                    (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE;
+
+                while (lm != NULL) {
+                    if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
+                    else if (strcasecmp(module, lm->name) == 0) {
+                        lm->level = (PRLogModuleLevel)level;
+                        break;
+                    }
+                    lm = lm->next;
+                }
+            }
+            /*found:*/
+            count = sscanf(&ev[pos], " , %n", &delta);
+            pos += delta;
+            if (count == -1) break;
+        }
+        PR_SetLogBuffering(isSync ? bufSize : 0);
+
+        ev = PR_GetEnv("NSPR_LOG_FILE");
+        if (ev && ev[0]) {
+            if (!PR_SetLogFile(ev)) {
+#ifdef XP_PC
+                char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev);
+                if (str) {
+                    OutputDebugString(str);
+                    PR_smprintf_free(str);
+                }
+#else
+                fprintf(stderr, "Unable to create nspr log file '%s'\n", ev);
+#endif
+            }
+        } else {
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+            logFile = stderr;
+#else
+            logFile = _pr_stderr;
+#endif
+        }
+    }
+}
+
+void _PR_LogCleanup(void)
+{
+    PR_LogFlush();
+
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+    if (logFile && logFile != stdout && logFile != stderr) {
+        fclose(logFile);
+    }
+#else
+    if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+        PR_Close(logFile);
+    }
+#endif
+}
+
+static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
+{
+    char *ev;
+
+    ev = PR_GetEnv("NSPR_LOG_MODULES");
+    if (ev && ev[0]) {
+        char module[64];
+        PRIntn evlen = strlen(ev), pos = 0;
+        while (pos < evlen) {
+            PRIntn level = 1, count = 0, delta = 0;
+
+            count = sscanf(&ev[pos], "%64[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n",
+                           module, &delta, &level, &delta);
+            pos += delta;
+            if (count == 0) break;
+
+            /*
+            ** If count == 2, then we got module and level. If count
+            ** == 1, then level defaults to 1 (module enabled).
+            */
+            if (lm != NULL)
+            {
+                if ((strcasecmp(module, "all") == 0)
+                    || (strcasecmp(module, lm->name) == 0))
+                {
+                    lm->level = (PRLogModuleLevel)level;
+                }
+            }
+            count = sscanf(&ev[pos], " , %n", &delta);
+            pos += delta;
+            if (count == -1) break;
+        }
+    }
+} /* end _PR_SetLogModuleLevel() */
+
+PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name)
+{
+    PRLogModuleInfo *lm;
+
+        if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    lm = PR_NEWZAP(PRLogModuleInfo);
+    if (lm) {
+        lm->name = strdup(name);
+        lm->level = PR_LOG_NONE;
+        lm->next = logModules;
+        logModules = lm;
+    }
+    _PR_SetLogModuleLevel(lm);
+    return lm;
+}
+
+PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
+{
+#ifdef _PR_USE_STDIO_FOR_LOGGING
+    FILE *newLogFile;
+
+#ifdef XP_PC
+    if ( strcmp( file, "WinDebug") == 0)
+    {
+        logFile = WIN32_DEBUG_FILE;
+        return(PR_TRUE);
+    }
+#endif
+    newLogFile = fopen(file, "w");
+    if (newLogFile) {
+        /* We do buffering ourselves. */
+        setvbuf(newLogFile, NULL, _IONBF, 0);
+        if (logFile && logFile != stdout && logFile != stderr) {
+            fclose(logFile);
+        }
+        logFile = newLogFile;
+    }
+    return (PRBool) (newLogFile != 0);
+#else
+    PRFileDesc *newLogFile;
+
+    newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE, 0666);
+    if (newLogFile) {
+        if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
+            PR_Close(logFile);
+        }
+        logFile = newLogFile;
+#if defined(XP_MAC)
+        SetLogFileTypeCreator(file);
+#endif
+    }
+    return (PRBool) (newLogFile != 0);
+#endif /* _PR_USE_STDIO_FOR_LOGGING */
+}
+
+PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size)
+{
+    PR_LogFlush();
+
+    if (logBuf)
+        PR_DELETE(logBuf);
+    logBuf = 0;
+
+    if (buffer_size >= LINE_BUF_SIZE) {
+        logp = logBuf = (char*) PR_MALLOC(buffer_size);
+        logEndp = logp + buffer_size;
+    }
+}
+
+PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...)
+{
+    va_list ap;
+    char line[LINE_BUF_SIZE];
+    PRUint32 nb;
+    PRThread *me;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    if (!logFile) {
+        return;
+    }
+
+    va_start(ap, fmt);
+    me = PR_GetCurrentThread();
+    nb = PR_snprintf(line, sizeof(line)-1, "%ld[%p]: ",
+#if defined(_PR_DCETHREADS)
+             /* The problem is that for _PR_DCETHREADS, pthread_t is not a 
+              * pointer, but a structure; so you can't easily print it...
+              */
+                     me ? &(me->id): 0L, me);
+#elif defined(_PR_BTHREADS)
+		     me, me);
+#else
+                     me ? me->id : 0L, me);
+#endif
+
+    nb += PR_vsnprintf(line+nb, sizeof(line)-nb-1, fmt, ap);
+    if (nb && (line[nb-1] != '\n')) {
+#ifndef XP_MAC
+        line[nb++] = '\n';
+#else
+        line[nb++] = '\015';
+#endif 
+        line[nb] = '\0';
+    } else {
+#ifdef XP_MAC
+        line[nb-1] = '\015';
+#endif
+    }
+    va_end(ap);
+
+    _PR_LOCK_LOG();
+    if (logBuf == 0) {
+#ifdef XP_PC
+        if ( logFile == WIN32_DEBUG_FILE)
+            OutputDebugString( line );
+        else
+            _PUT_LOG(logFile, line, nb);
+#else
+        _PUT_LOG(logFile, line, nb);
+#endif
+    } else {
+        if (logp + nb > logEndp) {
+            _PUT_LOG(logFile, logBuf, logp - logBuf);
+            logp = logBuf;
+        }
+        memcpy(logp, line, nb);
+        logp += nb;
+    }
+    _PR_UNLOCK_LOG();
+    PR_LogFlush();
+}
+
+PR_IMPLEMENT(void) PR_LogFlush(void)
+{
+    if (logBuf && logFile) {
+        _PR_LOCK_LOG();
+            if (logp > logBuf) {
+                _PUT_LOG(logFile, logBuf, logp - logBuf);
+                logp = logBuf;
+            }
+        _PR_UNLOCK_LOG();
+    }
+}
+
+PR_IMPLEMENT(void) PR_Abort(void)
+{
+    PR_LogPrint("Aborting");
+    abort();
+}
+
+#if defined(XP_OS2)
+/*
+ * Added definitions for DebugBreak() for 2 different OS/2 compilers.
+ * Doing the int3 on purpose for Visual Age so that a developer can
+ * step over the instruction if so desired.  Not always possible if
+ * trapping due to exception handling IBM-AKR
+ */
+#if defined(XP_OS2_VACPP)
+#include <builtin.h>
+static void DebugBreak(void) { _interrupt(3); }
+#elif defined(XP_OS2_EMX)
+/* Force a trap */
+static void DebugBreak(void) { int *pTrap=NULL; *pTrap = 1; }
+#else
+static void DebugBreak(void) { }
+#endif
+#endif /* XP_OS2 */
+
+PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
+{
+    PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+    fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
+#endif
+#ifdef XP_MAC
+    dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln);
+#endif
+#if defined(WIN32) || defined(XP_OS2)
+    DebugBreak();
+#endif
+#ifndef XP_MAC
+    abort();
+#endif
+}
+
+#ifdef XP_MAC
+PR_IMPLEMENT(void) PR_Init_Log(void)
+{
+	_PR_InitLog();
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/pr/src/io/prsocket.c
@@ -0,0 +1,1805 @@
+/* -*- 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.
+ */
+
+#include "primpl.h"
+
+#include <string.h>
+
+/************************************************************************/
+
+/* These two functions are only used in assertions. */
+#if defined(DEBUG)
+
+PRBool IsValidNetAddr(const PRNetAddr *addr)
+{
+    if ((addr != NULL)
+#ifdef XP_UNIX
+	    && (addr->raw.family != PR_AF_LOCAL)
+#endif
+	    && (addr->raw.family != PR_AF_INET6)
+	    && (addr->raw.family != PR_AF_INET)) {
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
+{
+    /*
+     * The definition of the length of a Unix domain socket address
+     * is not uniform, so we don't check it.
+     */
+    if ((addr != NULL)
+#ifdef XP_UNIX
+            && (addr->raw.family != AF_UNIX)
+#endif
+            && (PR_NETADDR_SIZE(addr) != addr_len)) {
+#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
+        /*
+         * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
+         * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
+         * field and is 28 bytes.  It is possible for socket functions
+         * to return an addr_len greater than sizeof(struct sockaddr_in6).
+         * We need to allow that.  (Bugzilla bug #77264)
+         */
+        if ((PR_AF_INET6 == addr->raw.family)
+                && (sizeof(addr->ipv6) == addr_len)) {
+            return PR_TRUE;
+        }
+#endif
+        /*
+         * The accept(), getsockname(), etc. calls on some platforms
+         * do not set the actual socket address length on return.
+         * In this case, we verifiy addr_len is still the value we
+         * passed in (i.e., sizeof(PRNetAddr)).
+         */
+#if defined(QNX)
+        if (sizeof(PRNetAddr) == addr_len) {
+            return PR_TRUE;
+        }
+#endif
+        return PR_FALSE;
+    }
+    return PR_TRUE;
+}
+
+#endif /* DEBUG */
+
+static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
+PRInt32 iov_size, PRIntervalTime timeout)
+{
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	int w = 0;
+	const PRIOVec *tmp_iov;
+#define LOCAL_MAXIOV    8
+	PRIOVec local_iov[LOCAL_MAXIOV];
+	PRIOVec *iov_copy = NULL;
+	int tmp_out;
+	int index, iov_cnt;
+	int count=0, sz = 0;    /* 'count' is the return value. */
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+    /*
+     * Assume the first writev will succeed.  Copy iov's only on
+     * failure.
+     */
+    tmp_iov = iov;
+    for (index = 0; index < iov_size; index++)
+        sz += iov[index].iov_len;
+
+	iov_cnt = iov_size;
+
+	while (sz > 0) {
+
+		w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
+		if (w < 0) {
+			count = -1;
+			break;
+		}
+		count += w;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		sz -= w;
+
+		if (sz > 0) {
+			/* find the next unwritten vector */
+			for ( index = 0, tmp_out = count;
+				tmp_out >= iov[index].iov_len;
+				tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
+
+			if (tmp_iov == iov) {
+				/*
+				 * The first writev failed so we
+				 * must copy iov's around.
+				 * Avoid calloc/free if there
+				 * are few enough iov's.
+				 */
+				if (iov_size - index <= LOCAL_MAXIOV)
+					iov_copy = local_iov;
+				else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
+					sizeof *iov_copy)) == NULL) {
+					PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+					return -1;
+				}
+				tmp_iov = iov_copy;
+			}
+
+			PR_ASSERT(tmp_iov == iov_copy);
+
+			/* fill in the first partial read */
+			iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
+			iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
+			index++;
+
+			/* copy the remaining vectors */
+			for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
+				iov_copy[iov_cnt].iov_base = iov[index].iov_base;
+				iov_copy[iov_cnt].iov_len = iov[index].iov_len;
+			}
+		}
+	}
+
+	if (iov_copy != local_iov)
+		PR_DELETE(iov_copy);
+	return count;
+}
+
+/************************************************************************/
+
+PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PRInt32 osfd)
+{
+PRFileDesc *fd;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	if (fd != NULL) {
+		_PR_MD_MAKE_NONBLOCK(fd);
+		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+	} else
+		_PR_MD_CLOSE_SOCKET(osfd);
+	return(fd);
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PRInt32 osfd)
+{
+PRFileDesc *fd;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
+	if (fd != NULL) {
+		_PR_MD_MAKE_NONBLOCK(fd);
+		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
+	} else
+		_PR_MD_CLOSE_SOCKET(osfd);
+	return(fd);
+}
+
+
+static const PRIOMethods* PR_GetSocketPollFdMethods(void);
+
+PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
+{
+    PRFileDesc *fd;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    fd = _PR_Getfd();
+
+    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    else
+    {
+        fd->secret->md.osfd = osfd;
+        fd->secret->inheritable = _PR_TRI_FALSE;
+    	fd->secret->state = _PR_FILEDESC_OPEN;
+        fd->methods = PR_GetSocketPollFdMethods();
+    }
+
+    return fd;
+}  /* PR_CreateSocketPollFD */
+
+PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
+{
+    if (NULL == fd)
+    {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    fd->secret->state = _PR_FILEDESC_CLOSED;
+    _PR_Putfd(fd);
+    return PR_SUCCESS;
+}  /* PR_DestroySocketPollFd */
+
+static PRStatus PR_CALLBACK SocketConnect(
+    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRInt32 rv;    /* Return value of _PR_MD_CONNECT */
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+	PRNetAddr addrCopy;
+#endif
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return PR_FAILURE;
+	}
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+	}
+#endif
+
+	rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
+	if (rv == 0)
+		return PR_SUCCESS;
+	else
+		return PR_FAILURE;
+}
+
+static PRStatus PR_CALLBACK SocketConnectContinue(
+    PRFileDesc *fd, PRInt16 out_flags)
+{
+    PRInt32 osfd;
+    int err;
+
+    if (out_flags & PR_POLL_NVAL) {
+        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+        return PR_FAILURE;
+    }
+    if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
+        PR_ASSERT(out_flags == 0);
+        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
+        return PR_FAILURE;
+    }
+
+    osfd = fd->secret->md.osfd;
+
+#if defined(XP_UNIX)
+
+    err = _MD_unix_get_nonblocking_connect_error(osfd);
+    if (err != 0) {
+        _PR_MD_MAP_CONNECT_ERROR(err);
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+
+#elif defined(WIN32) || defined(WIN16)
+
+#if defined(WIN32)
+    /*
+     * The sleep circumvents a bug in Win32 WinSock.
+     * See Microsoft Knowledge Base article ID: Q165989.
+     */
+    Sleep(0);
+#endif /* WIN32 */
+
+    if (out_flags & PR_POLL_EXCEPT) {
+        int len = sizeof(err);
+        if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
+                == SOCKET_ERROR) {
+            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
+            return PR_FAILURE;
+        }
+        if (err != 0) {
+            _PR_MD_MAP_CONNECT_ERROR(err);
+        } else {
+            PR_SetError(PR_UNKNOWN_ERROR, 0);
+        }
+        return PR_FAILURE;
+    }
+
+    PR_ASSERT(out_flags & PR_POLL_WRITE);
+    return PR_SUCCESS;
+
+#elif defined(XP_OS2)
+
+    if (out_flags & PR_POLL_EXCEPT) {
+        int len = sizeof(err);
+        if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len)
+                < 0) {
+            _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
+            return PR_FAILURE;
+        }
+        if (err != 0) {
+            _PR_MD_MAP_CONNECT_ERROR(err);
+        } else {
+            PR_SetError(PR_UNKNOWN_ERROR, 0);
+        }
+        return PR_FAILURE;
+    }
+
+    PR_ASSERT(out_flags & PR_POLL_WRITE);
+    return PR_SUCCESS;
+
+#elif defined(XP_MAC)
+
+    err = _MD_mac_get_nonblocking_connect_error(osfd);
+    if (err == -1)
+        return PR_FAILURE;
+	else     
+		return PR_SUCCESS;
+
+#elif defined(XP_BEOS)
+
+    err = _MD_beos_get_nonblocking_connect_error(fd);
+    if( err != 0 ) {
+	_PR_MD_MAP_CONNECT_ERROR(err);
+	return PR_FAILURE;
+    }
+    else
+	return PR_SUCCESS;
+
+#else
+    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+    return PR_FAILURE;
+#endif
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
+{
+    /* Find the NSPR layer and invoke its connectcontinue method */
+    PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+
+    if (NULL == bottom) {
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return PR_FAILURE;
+    }
+    return SocketConnectContinue(bottom, pd->out_flags);
+}
+
+static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+	PRInt32 osfd;
+	PRFileDesc *fd2;
+	PRUint32 al;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+#ifdef WINNT
+	PRNetAddr addrCopy;
+#endif
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return 0;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return 0;
+	}
+
+#ifdef WINNT
+	if (addr == NULL) {
+		addr = &addrCopy;
+	}
+#endif
+	al = sizeof(PRNetAddr);
+	osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
+	if (osfd == -1)
+		return 0;
+
+	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	if (!fd2) {
+		_PR_MD_CLOSE_SOCKET(osfd);
+		return NULL;
+	}
+
+	fd2->secret->nonblocking = fd->secret->nonblocking;
+	fd2->secret->inheritable = fd->secret->inheritable;
+#ifdef WINNT
+	if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
+		/*
+		 * The new socket has been associated with an I/O
+		 * completion port.  There is no going back.
+		 */
+		fd2->secret->md.io_model_committed = PR_TRUE;
+	}
+	PR_ASSERT(al == PR_NETADDR_SIZE(addr));
+	fd2->secret->md.accepted_socket = PR_TRUE;
+	memcpy(&fd2->secret->md.peer_addr, addr, al);
+#endif
+
+	/*
+	 * On some platforms, the new socket created by accept()
+	 * inherits the nonblocking (or overlapped io) attribute
+	 * of the listening socket.  As an optimization, these
+	 * platforms can skip the following _PR_MD_MAKE_NONBLOCK
+	 * call.
+	 * 
+	 * On Mac, we MUST make this call, because _PR_MD_MAKE_NONBLOCK
+	 * (which maps to _MD_makenonblock, see macsockotpt.c)
+	 * installs the async notifier routine needed to make blocking
+	 * I/O work properly.
+	 */
+#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
+	_PR_MD_MAKE_NONBLOCK(fd2);
+#endif
+
+#ifdef _PR_INET6
+	if (addr && (AF_INET6 == addr->raw.family))
+        addr->raw.family = PR_AF_INET6;
+#endif
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+	PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
+
+	return fd2;
+}
+
+#ifdef WINNT
+PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
+PRIntervalTime timeout)
+{
+	PRInt32 osfd;
+	PRFileDesc *fd2;
+	PRIntn al;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRNetAddr addrCopy;
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return 0;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return 0;
+	}
+
+		if (addr == NULL) {
+			addr = &addrCopy;
+		}
+		al = PR_NETADDR_SIZE(addr);
+		osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
+		if (osfd == -1) {
+			return 0;
+		}
+
+	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	if (!fd2) {
+		_PR_MD_CLOSE_SOCKET(osfd);
+	} else {
+		fd2->secret->nonblocking = fd->secret->nonblocking;
+		fd2->secret->md.io_model_committed = PR_TRUE;
+	        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
+        	fd2->secret->md.accepted_socket = PR_TRUE;
+        	memcpy(&fd2->secret->md.peer_addr, addr, al);
+#ifdef _PR_INET6
+		if (AF_INET6 == addr->raw.family)
+        	addr->raw.family = PR_AF_INET6;
+#endif
+	}
+	return fd2;
+}
+#endif /* WINNT */
+
+
+static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
+{
+	PRInt32 result;
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+	PRNetAddr addrCopy;
+#endif
+
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+
+#ifdef XP_UNIX
+	if (addr->raw.family == AF_UNIX) {
+		/* Disallow relative pathnames */
+		if (addr->local.path[0] != '/') {
+			PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+			return PR_FAILURE;
+		}
+	}
+#endif /* XP_UNIX */
+
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+	}
+#endif
+	result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
+{
+	PRInt32 result;
+
+	result = _PR_MD_LISTEN(fd, backlog);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
+{
+	PRInt32 result;
+
+	result = _PR_MD_SHUTDOWN(fd, how);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+	return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
+PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if ((flags != 0) && (flags != PR_MSG_PEEK)) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d flags=%d",
+		    						fd, fd->secret->md.osfd, buf, amount, flags));
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if (fd->secret->peekBytes != 0) {
+		rv = (amount < fd->secret->peekBytes) ?
+			amount : fd->secret->peekBytes;
+		memcpy(buf, fd->secret->peekBuffer, rv);
+		if (flags == 0) {
+			/* consume the bytes in the peek buffer */
+			fd->secret->peekBytes -= rv;
+			if (fd->secret->peekBytes != 0) {
+				memmove(fd->secret->peekBuffer,
+					fd->secret->peekBuffer + rv,
+					fd->secret->peekBytes);
+			}
+		}
+		return rv;
+	}
+
+	/* allocate peek buffer, if necessary */
+	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
+		PR_ASSERT(0 == fd->secret->peekBytes);
+		/* impose a max size on the peek buffer */
+		if (amount > _PR_PEEK_BUFFER_MAX) {
+			amount = _PR_PEEK_BUFFER_MAX;
+		}
+		if (fd->secret->peekBufSize < amount) {
+			if (fd->secret->peekBuffer) {
+				PR_Free(fd->secret->peekBuffer);
+			}
+			fd->secret->peekBufSize = amount;
+			fd->secret->peekBuffer = PR_Malloc(amount);
+			if (NULL == fd->secret->peekBuffer) {
+				fd->secret->peekBufSize = 0;
+				PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+				return -1;
+			}
+		}
+	}
+#endif
+
+	rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
+		rv, PR_GetError(), PR_GetOSError()));
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
+		if (rv > 0) {
+			memcpy(fd->secret->peekBuffer, buf, rv);
+			fd->secret->peekBytes = rv;
+		}
+	}
+#endif
+
+	return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+	return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}
+
+static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
+PRIntn flags, PRIntervalTime timeout)
+{
+	PRInt32 temp, count;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	count = 0;
+	while (amount > 0) {
+		PR_LOG(_pr_io_lm, PR_LOG_MAX,
+		    ("send: fd=%p osfd=%d buf=%p amount=%d",
+		    fd, fd->secret->md.osfd, buf, amount));
+		temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
+		if (temp < 0) {
+					count = -1;
+					break;
+				}
+
+		count += temp;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		buf = (const void*) ((const char*)buf + temp);
+
+		amount -= temp;
+	}
+	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
+	return count;
+}
+
+static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+	return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
+}
+
+static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
+{
+	if (!fd || !fd->secret
+			|| (fd->secret->state != _PR_FILEDESC_OPEN
+			&& fd->secret->state != _PR_FILEDESC_CLOSED)) {
+		PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+		return PR_FAILURE;
+	}
+
+	if (fd->secret->state == _PR_FILEDESC_OPEN) {
+		if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
+			return PR_FAILURE;
+		}
+		fd->secret->state = _PR_FILEDESC_CLOSED;
+	}
+
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if (fd->secret->peekBuffer) {
+		PR_ASSERT(fd->secret->peekBufSize > 0);
+		PR_DELETE(fd->secret->peekBuffer);
+		fd->secret->peekBufSize = 0;
+		fd->secret->peekBytes = 0;
+	}
+#endif
+
+	PR_FreeFileDesc(fd);
+	return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
+{
+	PRInt32 rv;
+#ifdef _PR_HAVE_PEEK_BUFFER
+	if (fd->secret->peekBytes != 0) {
+		return fd->secret->peekBytes;
+	}
+#endif
+	rv =  _PR_MD_SOCKETAVAILABLE(fd);
+	return rv;		
+}
+
+static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
+{
+    PRInt64 rv;
+#ifdef _PR_HAVE_PEEK_BUFFER
+    if (fd->secret->peekBytes != 0) {
+        LL_I2L(rv, fd->secret->peekBytes);
+        return rv;
+    }
+#endif
+    LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
+	return rv;		
+}
+
+static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
+{
+#if defined(XP_MAC)
+#pragma unused (fd)
+#endif
+
+	return PR_SUCCESS;
+}
+
+static PRInt32 PR_CALLBACK SocketSendTo(
+    PRFileDesc *fd, const void *buf, PRInt32 amount,
+    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRInt32 temp, count;
+    const PRNetAddr *addrp = addr;
+#if defined(_PR_INET6)
+	PRNetAddr addrCopy;
+#endif
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+#if defined(_PR_INET6)
+	if (addr->raw.family == PR_AF_INET6) {
+		addrCopy = *addr;
+		addrCopy.raw.family = AF_INET6;
+		addrp = &addrCopy;
+	}
+#endif
+
+	count = 0;
+	while (amount > 0) {
+		temp = _PR_MD_SENDTO(fd, buf, amount, flags,
+		    addrp, PR_NETADDR_SIZE(addr), timeout);
+		if (temp < 0) {
+					count = -1;
+					break;
+				}
+		count += temp;
+		if (fd->secret->nonblocking) {
+			break;
+		}
+		buf = (const void*) ((const char*)buf + temp);
+		amount -= temp;
+	}
+	return count;
+}
+
+static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRUint32 al;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+
+	al = sizeof(PRNetAddr);
+	rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
+#ifdef _PR_INET6
+	if (addr && (AF_INET6 == addr->raw.family))
+        addr->raw.family = PR_AF_INET6;
+#endif
+	return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	/* The socket must be in blocking mode. */
+	if (sd->secret->nonblocking) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+	*nd = NULL;
+
+#if defined(WINNT)
+	{
+	PRInt32 newSock;
+	PRNetAddr *raddrCopy;
+
+	if (raddr == NULL) {
+		raddr = &raddrCopy;
+	}
+	rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
+	if (rv < 0) {
+		rv = -1;
+	} else {
+		/* Successfully accepted and read; create the new PRFileDesc */
+		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+		if (*nd == 0) {
+			_PR_MD_CLOSE_SOCKET(newSock);
+			/* PR_AllocFileDesc() has invoked PR_SetError(). */
+			rv = -1;
+		} else {
+			(*nd)->secret->md.io_model_committed = PR_TRUE;
+			(*nd)->secret->md.accepted_socket = PR_TRUE;
+			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+				PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+			if (AF_INET6 == *raddr->raw.family)
+        		*raddr->raw.family = PR_AF_INET6;
+#endif
+		}
+	}
+	}
+#else
+	rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
+#endif
+	return rv;
+}
+
+#ifdef WINNT
+PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRInt32 newSock;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRNetAddr *raddrCopy;
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	*nd = NULL;
+
+	if (raddr == NULL) {
+		raddr = &raddrCopy;
+	}
+	rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, 
+	    timeout, PR_TRUE, NULL, NULL);
+	if (rv < 0) {
+		rv = -1;
+	} else {
+		/* Successfully accepted and read; create the new PRFileDesc */
+		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+		if (*nd == 0) {
+			_PR_MD_CLOSE_SOCKET(newSock);
+			/* PR_AllocFileDesc() has invoked PR_SetError(). */
+			rv = -1;
+		} else {
+			(*nd)->secret->md.io_model_committed = PR_TRUE;
+			(*nd)->secret->md.accepted_socket = PR_TRUE;
+			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+				PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+			if (AF_INET6 == *raddr->raw.family)
+        		*raddr->raw.family = PR_AF_INET6;
+#endif
+		}
+	}
+	return rv;
+}
+
+PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
+PRFileDesc *sd, PRFileDesc **nd, 
+PRNetAddr **raddr, void *buf, PRInt32 amount,
+PRIntervalTime timeout,
+_PR_AcceptTimeoutCallback callback,
+void *callbackArg)
+{
+	PRInt32 rv;
+	PRInt32 newSock;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+	PRNetAddr *raddrCopy;
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	*nd = NULL;
+
+	if (raddr == NULL) {
+		raddr = &raddrCopy;
+	}
+	rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
+	    timeout, PR_TRUE, callback, callbackArg);
+	if (rv < 0) {
+		rv = -1;
+	} else {
+		/* Successfully accepted and read; create the new PRFileDesc */
+		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
+		if (*nd == 0) {
+			_PR_MD_CLOSE_SOCKET(newSock);
+			/* PR_AllocFileDesc() has invoked PR_SetError(). */
+			rv = -1;
+		} else {
+			(*nd)->secret->md.io_model_committed = PR_TRUE;
+			(*nd)->secret->md.accepted_socket = PR_TRUE;
+			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
+				PR_NETADDR_SIZE(*raddr));
+#ifdef _PR_INET6
+			if (AF_INET6 == *raddr->raw.family)
+        		*raddr->raw.family = PR_AF_INET6;
+#endif
+		}
+	}
+	return rv;
+}
+#endif /* WINNT */
+
+#ifdef WINNT
+PR_IMPLEMENT(void)
+PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
+{
+	_PR_MD_UPDATE_ACCEPT_CONTEXT(
+		socket->secret->md.osfd, acceptSocket->secret->md.osfd);
+}
+#endif /* WINNT */
+
+static PRInt32 PR_CALLBACK SocketSendFile(
+    PRFileDesc *sd, PRSendFileData *sfd,
+    PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+	PRInt32 rv;
+	PRThread *me = _PR_MD_CURRENT_THREAD();
+
+	if (_PR_PENDING_INTERRUPT(me)) {
+		me->flags &= ~_PR_INTERRUPT;
+		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+		return -1;
+	}
+	if (_PR_IO_PENDING(me)) {
+		PR_SetError(PR_IO_PENDING_ERROR, 0);
+		return -1;
+	}
+	/* The socket must be in blocking mode. */
+	if (sd->secret->nonblocking) {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+#if defined(WINNT)
+	rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
+	if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
+		/*
+		 * This should be kept the same as SocketClose, except
+		 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
+		 * not be called because the socket will be recycled.
+		 */
+		PR_FreeFileDesc(sd);
+	}
+#else
+	rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
+#endif	/* WINNT */
+
+	return rv;
+}
+
+static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
+const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
+PRIntervalTime timeout)
+{
+	PRSendFileData sfd;
+
+	sfd.fd = fd;
+	sfd.file_offset = 0;
+	sfd.file_nbytes = 0;
+	sfd.header = headers;
+	sfd.hlen = hlen;
+	sfd.trailer = NULL;
+	sfd.tlen = 0;
+
+	return(SocketSendFile(sd, &sfd, flags, timeout));
+}
+
+static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
+{
+	PRInt32 result;
+	PRUint32 addrlen;
+
+	addrlen = sizeof(PRNetAddr);
+	result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+#ifdef _PR_INET6
+	if (AF_INET6 == addr->raw.family)
+        addr->raw.family = PR_AF_INET6;
+#endif
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+	PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
+	return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
+{
+	PRInt32 result;
+	PRUint32 addrlen;
+
+	addrlen = sizeof(PRNetAddr);
+	result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
+	if (result < 0) {
+		return PR_FAILURE;
+	}
+#ifdef _PR_INET6
+	if (AF_INET6 == addr->raw.family)
+        addr->raw.family = PR_AF_INET6;
+#endif
+	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
+	PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
+	return PR_SUCCESS;
+}
+
+static PRInt16 PR_CALLBACK SocketPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+#ifdef XP_MAC
+#pragma unused( fd, in_flags )
+#endif
+    *out_flags = 0;
+    return in_flags;
+}  /* SocketPoll */
+
+static PRIOMethods tcpMethods = {
+	PR_DESC_SOCKET_TCP,
+	SocketClose,
+	SocketRead,
+	SocketWrite,
+	SocketAvailable,
+	SocketAvailable64,
+	SocketSync,
+	(PRSeekFN)_PR_InvalidInt,
+	(PRSeek64FN)_PR_InvalidInt64,
+	(PRFileInfoFN)_PR_InvalidStatus,
+	(PRFileInfo64FN)_PR_InvalidStatus,
+	SocketWritev,
+	SocketConnect,
+	SocketAccept,
+	SocketBind,
+	SocketListen,
+	SocketShutdown,
+	SocketRecv,
+	SocketSend,
+	(PRRecvfromFN)_PR_InvalidInt,
+	(PRSendtoFN)_PR_InvalidInt,
+	SocketPoll,
+	SocketAcceptRead,
+	SocketTransmitFile,
+	SocketGetName,
+	SocketGetPeerName,
+	(PRReservedFN)_PR_InvalidInt,
+	(PRReservedFN)_PR_InvalidInt,
+	_PR_SocketGetSocketOption,
+	_PR_SocketSetSocketOption,
+    SocketSendFile, 
+    SocketConnectContinue,
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRIOMethods udpMethods = {
+	PR_DESC_SOCKET_UDP,
+	SocketClose,
+	SocketRead,
+	SocketWrite,
+	SocketAvailable,
+	SocketAvailable64,
+	SocketSync,
+	(PRSeekFN)_PR_InvalidInt,
+	(PRSeek64FN)_PR_InvalidInt64,
+	(PRFileInfoFN)_PR_InvalidStatus,
+	(PRFileInfo64FN)_PR_InvalidStatus,
+	SocketWritev,
+	SocketConnect,
+	(PRAcceptFN)_PR_InvalidDesc,
+	SocketBind,
+	SocketListen,
+	SocketShutdown,
+	SocketRecv,
+	SocketSend,
+	SocketRecvFrom,
+	SocketSendTo,
+	SocketPoll,
+	(PRAcceptreadFN)_PR_InvalidInt,
+	(PRTransmitfileFN)_PR_InvalidInt,
+	SocketGetName,
+	SocketGetPeerName,
+	(PRReservedFN)_PR_InvalidInt,
+	(PRReservedFN)_PR_InvalidInt,
+	_PR_SocketGetSocketOption,
+	_PR_SocketSetSocketOption,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+
+static PRIOMethods socketpollfdMethods = {
+    (PRDescType) 0,
+    (PRCloseFN)_PR_InvalidStatus,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+	SocketPoll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRConnectcontinueFN)_PR_InvalidStatus, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods()
+{
+	return &tcpMethods;
+}
+
+PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
+{
+	return &udpMethods;
+}
+
+static const PRIOMethods* PR_GetSocketPollFdMethods()
+{
+    return &socketpollfdMethods;
+}  /* PR_GetSocketPollFdMethods */
+
+#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
+PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
+
+#if defined(_PR_INET6_PROBE)
+
+PR_EXTERN(PRBool) _pr_ipv6_is_present;
+
+PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
+{
+PRInt32 osfd;
+
+	osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
+	if (osfd != -1) {
+		_PR_MD_CLOSE_SOCKET(osfd);
+		return PR_TRUE;
+	}
+	return PR_FALSE;
+}
+#endif	/* _PR_INET6_PROBE */
+
+#endif
+
+PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
+{
+	PRInt32 osfd;
+	PRFileDesc *fd;
+	PRInt32 tmp_domain = domain;
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+	if (PR_AF_INET != domain
+			&& PR_AF_INET6 != domain
+#if defined(XP_UNIX)
+			&& PR_AF_LOCAL != domain
+#endif
+			) {
+		PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return NULL;
+	}
+
+#if defined(_PR_INET6_PROBE)
+	if (PR_AF_INET6 == domain) {
+		if (_pr_ipv6_is_present == PR_FALSE) 
+			domain = AF_INET;
+		else
+			domain = AF_INET6;
+	}
+#elif defined(_PR_INET6)
+	if (PR_AF_INET6 == domain)
+		domain = AF_INET6;
+#else
+	if (PR_AF_INET6 == domain)
+		domain = AF_INET;
+#endif	/* _PR_INET6 */
+	osfd = _PR_MD_SOCKET(domain, type, proto);
+	if (osfd == -1) {
+		return 0;
+	}
+	if (type == SOCK_STREAM)
+		fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
+	else
+		fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
+	/*
+	 * Make the sockets non-blocking
+	 */
+	if (fd != NULL) {
+		_PR_MD_MAKE_NONBLOCK(fd);
+		_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
+#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
+		/*
+		 * For platforms with no support for IPv6 
+		 * create layered socket for IPv4-mapped IPv6 addresses
+		 */
+		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
+			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
+				PR_Close(fd);
+				fd = NULL;
+			}
+		}
+#endif
+	} else
+		_PR_MD_CLOSE_SOCKET(osfd);
+
+	return fd;
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
+{
+	PRInt32 domain = AF_INET;
+
+	return PR_Socket(domain, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
+{
+	PRInt32 domain = AF_INET;
+
+	return PR_Socket(domain, SOCK_DGRAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
+{
+	return PR_Socket(af, SOCK_STREAM, 0);
+}
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
+{
+	return PR_Socket(af, SOCK_DGRAM, 0);
+}
+
+PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
+{
+#ifdef XP_UNIX
+	PRInt32 rv, osfd[2];
+
+	if (!_pr_initialized) _PR_ImplicitInitialization();
+
+	rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
+	if (rv == -1) {
+		return PR_FAILURE;
+	}
+
+	f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+	if (!f[0]) {
+		_PR_MD_CLOSE_SOCKET(osfd[0]);
+		_PR_MD_CLOSE_SOCKET(osfd[1]);
+		/* PR_AllocFileDesc() has invoked PR_SetError(). */
+		return PR_FAILURE;
+	}
+	f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+	if (!f[1]) {
+		PR_Close(f[0]);
+		_PR_MD_CLOSE_SOCKET(osfd[1]);
+		/* PR_AllocFileDesc() has invoked PR_SetError(). */
+		return PR_FAILURE;
+	}
+	_PR_MD_MAKE_NONBLOCK(f[0]);
+	_PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
+	_PR_MD_MAKE_NONBLOCK(f[1]);
+	_PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
+	return PR_SUCCESS;
+#elif defined(WINNT)
+    /*
+     * A socket pair is often used for interprocess communication,
+     * so we need to make sure neither socket is associated with
+     * the I/O completion port; otherwise it can't be used by a
+     * child process.
+     *
+     * The default implementation below cannot be used for NT
+     * because PR_Accept would have associated the I/O completion
+     * port with the listening and accepted sockets.
+     */
+    SOCKET listenSock;
+    SOCKET osfd[2];
+    struct sockaddr_in selfAddr;
+    int addrLen;
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    osfd[0] = osfd[1] = INVALID_SOCKET;
+    listenSock = socket(AF_INET, SOCK_STREAM, 0);
+    if (listenSock == INVALID_SOCKET) {
+        goto failed;
+    }
+    selfAddr.sin_family = AF_INET;
+    selfAddr.sin_port = 0;
+    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
+    addrLen = sizeof(selfAddr);
+    if (bind(listenSock, (struct sockaddr *) &selfAddr,
+            addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
+            &addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    if (listen(listenSock, 5) == SOCKET_ERROR) {
+        goto failed;
+    }
+    osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
+    if (osfd[0] == INVALID_SOCKET) {
+        goto failed;
+    }
+    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    /*
+     * Only a thread is used to do the connect and accept.
+     * I am relying on the fact that connect returns
+     * successfully as soon as the connect request is put
+     * into the listen queue (but before accept is called).
+     * This is the behavior of the BSD socket code.  If
+     * connect does not return until accept is called, we
+     * will need to create another thread to call connect.
+     */
+    if (connect(osfd[0], (struct sockaddr *) &selfAddr,
+            addrLen) == SOCKET_ERROR) {
+        goto failed;
+    }
+    osfd[1] = accept(listenSock, NULL, NULL);
+    if (osfd[1] == INVALID_SOCKET) {
+        goto failed;
+    }
+    closesocket(listenSock);
+
+    f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
+    if (!f[0]) {
+        closesocket(osfd[0]);
+        closesocket(osfd[1]);
+        /* PR_AllocFileDesc() has invoked PR_SetError(). */
+        return PR_FAILURE;
+    }
+    f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
+    if (!f[1]) {
+        PR_Close(f[0]);
+        closesocket(osfd[1]);
+        /* PR_AllocFileDesc() has invoked PR_SetError(). */
+        return PR_FAILURE;
+    }
+    _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
+    _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
+    return PR_SUCCESS;
+
+failed:
+    if (listenSock != INVALID_SOCKET) {
+        closesocket(listenSock);
+    }
+    if (osfd[0] != INVALID_SOCKET) {
+        closesocket(osfd[0]);
+    }
+    if (osfd[1] != INVALID_SOCKET) {
+        closesocket(osfd[1]);
+    }
+    return PR_FAILURE;
+#else /* not Unix or NT */
+    /*
+     * default implementation
+     */
+    PRFileDesc *listenSock;
+    PRNetAddr selfAddr;
+    PRUint16 port;
+
+    f[0] = f[1] = NULL;
+    listenSock = PR_NewTCPSocket();
+    if (listenSock == NULL) {
+        goto failed;
+    }
+    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
+    if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
+        goto failed;
+    }
+    port = ntohs(selfAddr.inet.port);
+    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
+        goto failed;
+    }
+    f[0] = PR_NewTCPSocket();
+    if (f[0] == NULL) {
+        goto failed;
+    }
+    PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
+
+    /*
+     * Only a thread is used to do the connect and accept.
+     * I am relying on the fact that PR_Connect returns
+     * successfully as soon as the connect request is put
+     * into the listen queue (but before PR_Accept is called).
+     * This is the behavior of the BSD socket code.  If
+     * connect does not return until accept is called, we
+     * will need to create another thread to call connect.
+     */
+    if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
+            == PR_FAILURE) {
+        goto failed;
+    }
+    f[1] = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT);
+    if (f[1] == NULL) {
+        goto failed;
+    }
+    PR_Close(listenSock);
+    return PR_SUCCESS;
+
+failed:
+    if (listenSock) {
+        PR_Close(listenSock);
+    }
+    if (f[0]) {
+        PR_Close(f[0]);
+    }
+    return PR_FAILURE;
+#endif
+}
+
+PR_IMPLEMENT(PRInt32)
+PR_FileDesc2NativeHandle(PRFileDesc *fd)
+{
+	if (fd) {
+		/*
+		 * The fd may be layered.  Chase the links to the
+		 * bottom layer to get the osfd.
+		 */
+		PRFileDesc *bottom = fd;
+		while (bottom->lower != NULL) {
+			bottom = bottom->lower;
+		}
+		return bottom->secret->md.osfd;
+	} else {
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+	}
+}
+
+PR_IMPLEMENT(void)
+PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
+{
+	if (fd)
+		fd->secret->md.osfd = handle;
+}
+
+/*
+** Select compatibility
+**
+*/
+
+PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
+{
+	memset(set, 0, sizeof(PR_fd_set));
+}
+
+PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
+{
+	PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
+
+	set->harray[set->hsize++] = fh;
+}
+
+PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
+{
+	PRUint32 index, index2;
+
+	for (index = 0; index<set->hsize; index++)
+		if (set->harray[index] == fh) {
+			for (index2=index; index2 < (set->hsize-1); index2++) {
+				set->harray[index2] = set->harray[index2+1];
+			}
+			set->hsize--;
+			break;
+		}
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
+{
+	PRUint32 index;
+	for (index = 0; index<set->hsize; index++)
+		if (set->harray[index] == fh) {
+			return 1;
+		}
+	return 0;
+}
+
+PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
+{
+	PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
+
+	set->narray[set->nsize++] = fd;
+}
+
+PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
+{
+	PRUint32 index, index2;
+
+	for (index = 0; index<set->nsize; index++)
+		if (set->narray[index] == fd) {
+			for (index2=index; index2 < (set->nsize-1); index2++) {
+				set->narray[index2] = set->narray[index2+1];
+			}
+			set->nsize--;
+			break;
+		}
+}
+
+PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
+{
+	PRUint32 index;
+	for (index = 0; index<set->nsize; index++)
+		if (set->narray[index] == fd) {
+			return 1;
+		}
+	return 0;
+}
+
+
+#if !defined(NEED_SELECT)
+#if !defined(XP_MAC)
+#include "obsolete/probslet.h"
+#else
+#include "probslet.h"
+#endif
+
+#define PD_INCR 20
+
+static PRPollDesc *_pr_setfd(
+    PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
+{
+    PRUintn fsidx, pdidx;
+    PRPollDesc *poll = polldesc;
+
+    if (NULL == set) return poll;
+
+	/* First set the pr file handle osfds */
+	for (fsidx = 0; fsidx < set->hsize; fsidx++)
+	{
+	    for (pdidx = 0; 1; pdidx++)
+        {
+            if ((PRFileDesc*)-1 == poll[pdidx].fd)
+            {
+                /* our vector is full - extend and condition it */
+                poll = (PRPollDesc*)PR_Realloc(
+                    poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
+                if (NULL == poll) goto out_of_memory;
+                memset(
+                    poll + pdidx * sizeof(PRPollDesc),
+                    0, PD_INCR * sizeof(PRPollDesc));
+                poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
+            }
+            if ((NULL == poll[pdidx].fd)
+            || (poll[pdidx].fd == set->harray[fsidx]))
+            {
+                /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
+                /* either empty or prevously defined */
+                poll[pdidx].fd = set->harray[fsidx];  /* possibly redundant */
+                poll[pdidx].in_flags |= flags;  /* possibly redundant */
+                break;
+            }
+        }
+	}
+
+#if 0
+	/* Second set the native osfds */
+	for (fsidx = 0; fsidx < set->nsize; fsidx++)
+	{
+	    for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
+        {
+            if ((PRFileDesc*)-1 == poll[pdidx].fd)
+            {
+                /* our vector is full - extend and condition it */
+                poll = PR_Realloc(
+                    poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
+                if (NULL == poll) goto out_of_memory;
+                memset(
+                    poll + pdidx * sizeof(PRPollDesc),
+                    0, PD_INCR * sizeof(PRPollDesc));
+                poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
+            }
+            if ((NULL == poll[pdidx].fd)
+            || (poll[pdidx].fd == set->narray[fsidx]))
+            {
+                /* either empty or prevously defined */
+                poll[pdidx].fd = set->narray[fsidx];
+                PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
+                poll[pdidx].in_flags |= flags;
+                break;
+            }
+        }
+	}
+#endif /* 0 */
+
+	return poll;
+
+out_of_memory:
+    if (NULL != polldesc) PR_DELETE(polldesc);
+    return NULL;
+}  /* _pr_setfd */
+
+#endif /* !defined(NEED_SELECT) */
+
+PR_IMPLEMENT(PRInt32) PR_Select(
+    PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
+    PR_fd_set *pr_ex, PRIntervalTime timeout)
+{
+
+#if !defined(NEED_SELECT)
+    PRInt32 npds = 0; 
+    /*
+    ** Find out how many fds are represented in the three lists.
+    ** Then allocate a polling descriptor for the logical union
+    ** (there can't be any overlapping) and call PR_Poll().
+    */
+
+    PRPollDesc *copy, *poll;
+
+    static PRBool warning = PR_TRUE;
+    if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
+
+    /* try to get an initial guesss at how much space we need */
+    npds = 0;
+    if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
+        npds = pr_rd->hsize + pr_rd->nsize;
+    if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
+        npds = pr_wr->hsize + pr_wr->nsize;
+    if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
+        npds = pr_ex->hsize + pr_ex->nsize;
+
+    if (0 == npds)
+    {
+        PR_Sleep(timeout);
+        return 0;
+    }
+
+    copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
+    if (NULL == poll) goto out_of_memory;
+    poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
+
+    poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
+    if (NULL == poll) goto out_of_memory;
+    poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
+    if (NULL == poll) goto out_of_memory;
+    poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
+    if (NULL == poll) goto out_of_memory;
+    unused = 0;
+    while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
+    {
+        ++unused;
+    }
+
+    PR_ASSERT(unused > 0);
+    npds = PR_Poll(poll, unused, timeout);
+
+    if (npds > 0)
+    {
+        /* Copy the results back into the fd sets */
+        if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
+        if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
+        if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
+        for (copy = &poll[unused - 1]; copy >= poll; --copy)
+        {
+            if (copy->out_flags & PR_POLL_NVAL)
+            {
+                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
+                npds = -1;
+                break;
+            }
+            if (copy->out_flags & PR_POLL_READ)
+                if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
+            if (copy->out_flags & PR_POLL_WRITE)
+                if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
+            if (copy->out_flags & PR_POLL_EXCEPT)
+                if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
+        }
+    }
+    PR_DELETE(poll);
+
+    return npds;
+out_of_memory:
+    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+    return -1;    
+
+#endif /* !defined(NEED_SELECT) */
+    
+}
new file mode 100644
--- /dev/null
+++ b/pr/src/md/os2/os2io.c
@@ -0,0 +1,798 @@
+/* -*- 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 Original Code has been modified by IBM Corporation.
+ * Modifications made by IBM described herein are
+ * Copyright (c) International Business Machines
+ * Corporation, 2000
+ *
+ * Modifications to Mozilla code or documentation
+ * identified per MPL Section 3.3
+ *
+ * Date             Modified by     Description of modification
+ * 03/23/2000       IBM Corp.       Changed write() to DosWrite(). EMX i/o
+ *                                  calls cannot be intermixed with DosXXX
+ *                                  calls since EMX remaps file/socket
+ *                                  handles.
+ * 04/27/2000       IBM Corp.       Changed open file to be more like NT and
+ *                                  better handle PR_TRUNCATE | PR_CREATE_FILE
+ *                                  and also fixed _PR_MD_SET_FD_INHERITABLE
+ */
+
+/* OS2 IO module
+ *
+ * Assumes synchronous I/O.
+ *
+ */
+
+#include "primpl.h"
+#include "prio.h"
+#include <ctype.h>
+#ifdef XP_OS2_VACPP
+#include <direct.h>
+#else
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+struct _MDLock               _pr_ioq_lock;
+
+PRStatus
+_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
+{
+    PRInt32 rv;
+    ULONG count;
+
+    PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+        SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks);
+    rv = DosWaitEventSem(thread->md.blocked_sema.sem, msecs);
+    DosResetEventSem(thread->md.blocked_sema.sem, &count); 
+    switch(rv) 
+    {
+        case NO_ERROR:
+            return PR_SUCCESS;
+            break;
+        case ERROR_TIMEOUT:
+            _PR_THREAD_LOCK(thread);
+            if (thread->state == _PR_IO_WAIT) {
+			  ;
+            } else {
+                if (thread->wait.cvar != NULL) {
+                    thread->wait.cvar = NULL;
+                    _PR_THREAD_UNLOCK(thread);
+                } else {
+                    /* The CVAR was notified just as the timeout
+                     * occurred.  This led to us being notified twice.
+                     * call SemRequest() to clear the semaphore.
+                     */
+                    _PR_THREAD_UNLOCK(thread);
+                    rv = DosWaitEventSem(thread->md.blocked_sema.sem, 0);
+                    DosResetEventSem(thread->md.blocked_sema.sem, &count); 
+                    PR_ASSERT(rv == NO_ERROR);
+                }
+            }
+            return PR_SUCCESS;
+            break;
+        default:
+            break;
+    }
+    return PR_FAILURE;
+}
+PRStatus
+_PR_MD_WAKEUP_WAITER(PRThread *thread)
+{
+    if ( _PR_IS_NATIVE_THREAD(thread) ) 
+    {
+        if (DosPostEventSem(thread->md.blocked_sema.sem) != NO_ERROR)
+            return PR_FAILURE;
+        else
+			return PR_SUCCESS;
+	}
+}
+
+
+/* --- FILE IO ----------------------------------------------------------- */
+/*
+ *  _PR_MD_OPEN() -- Open a file
+ *
+ *  returns: a fileHandle
+ *
+ *  The NSPR open flags (osflags) are translated into flags for OS/2
+ *
+ *  Mode seems to be passed in as a unix style file permissions argument
+ *  as in 0666, in the case of opening the logFile. 
+ *
+ */
+PRInt32
+_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
+{
+    HFILE file;
+    PRInt32 access = OPEN_SHARE_DENYNONE;
+    PRInt32 flags = 0L;
+    PRInt32 rc;
+    PRUword actionTaken;
+
+    ULONG CurMaxFH = 0;
+    LONG ReqCount = 1;
+    ULONG fattr;
+
+    if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH;
+
+    if (osflags & PR_RDONLY)
+        access |= OPEN_ACCESS_READONLY;
+    else if (osflags & PR_WRONLY)
+        access |= OPEN_ACCESS_WRITEONLY;
+    else if(osflags & PR_RDWR)
+        access |= OPEN_ACCESS_READWRITE;
+
+    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
+    {
+        flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
+    }
+    else if (osflags & PR_CREATE_FILE)
+    {
+        if (osflags & PR_TRUNCATE)
+            flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
+        else
+            flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
+    } 
+    else
+    {
+        if (osflags & PR_TRUNCATE)
+            flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
+        else
+            flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
+    }
+
+    if (isxdigit(mode) == 0) /* file attribs are hex, UNIX modes octal */
+      fattr = ((ULONG)mode == FILE_HIDDEN) ? FILE_HIDDEN : FILE_NORMAL;
+    else fattr = FILE_NORMAL;
+
+    /* OS/2 sets the Max file handles per process to 20 by default */
+    DosSetRelMaxFH(&ReqCount, &CurMaxFH);
+
+    rc = DosOpen((char*)name,
+                 &file,            /* file handle if successful */
+                 &actionTaken,     /* reason for failure        */
+                 0,                /* initial size of new file  */
+                 fattr,            /* file system attributes    */
+                 flags,            /* Open flags                */
+                 access,           /* Open mode and rights      */
+                 0);               /* OS/2 Extended Attributes  */
+    if (rc != NO_ERROR) {
+		_PR_MD_MAP_OPEN_ERROR(rc);
+      return -1; 
+	}
+
+    return (PRInt32)file;
+}
+
+PRInt32
+_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
+{
+    ULONG bytes;
+    int rv;
+
+    rv = DosRead((HFILE)fd->secret->md.osfd,
+                 (PVOID)buf,
+                 len,
+                 &bytes);
+    
+    if (rv != NO_ERROR) 
+    {
+        /* ERROR_HANDLE_EOF can only be returned by async io */
+        PR_ASSERT(rv != ERROR_HANDLE_EOF);
+        if (rv == ERROR_BROKEN_PIPE)
+            return 0;
+		else {
+			_PR_MD_MAP_READ_ERROR(rv);
+        return -1;
+    }
+    }
+    return (PRInt32)bytes;
+}
+
+PRInt32
+_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
+{
+    PRInt32 bytes;
+    int rv; 
+
+    rv = DosWrite((HFILE)fd->secret->md.osfd,
+                  (PVOID)buf,
+                  len,
+                  (PULONG)&bytes);
+
+    if (rv != NO_ERROR) 
+    {
+        _PR_MD_MAP_WRITE_ERROR(rv);
+        return -1;
+    }
+
+    return bytes;
+} /* --- end _PR_MD_WRITE() --- */
+
+PRInt32
+_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
+{
+    PRInt32 rv;
+    PRUword newLocation;
+
+    rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation);
+
+	if (rv != NO_ERROR) {
+		_PR_MD_MAP_LSEEK_ERROR(rv);
+		return -1;
+	} else
+		return newLocation;
+}
+
+PRInt64
+_PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
+{
+#ifdef NO_LONG_LONG
+    PRInt64 result;
+    PRInt32 rv, low = offset.lo, hi = offset.hi;
+    PRUword newLocation;
+
+    rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation);
+    rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation);
+
+  	if (rv != NO_ERROR) {
+		_PR_MD_MAP_LSEEK_ERROR(rv);
+		hi = newLocation = -1;
+   }
+
+    result.lo = newLocation;
+    result.hi = hi;
+	return result;
+
+#else
+    PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32);
+    PRUint64 rv;
+    PRUint32 newLocation, uhi;
+
+    switch (whence)
+      {
+      case PR_SEEK_SET:
+        where = FILE_BEGIN;
+        break;
+      case PR_SEEK_CUR:
+        where = FILE_CURRENT;
+        break;
+      case PR_SEEK_END:
+        where = FILE_END;
+        break;
+      default:
+        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+        return -1;
+}
+
+    rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation);
+     
+    if (rc != NO_ERROR) {
+      _PR_MD_MAP_LSEEK_ERROR(rc);
+      return -1;
+    }
+    
+    uhi = (PRUint32)hi;
+    PR_ASSERT((PRInt32)uhi >= 0);
+    rv = uhi;
+    PR_ASSERT((PRInt64)rv >= 0);
+    rv = (rv << 32);
+    PR_ASSERT((PRInt64)rv >= 0);
+    rv += newLocation;
+    PR_ASSERT((PRInt64)rv >= 0);
+    return (PRInt64)rv;
+#endif
+}
+
+PRInt32
+_PR_MD_FSYNC(PRFileDesc *fd)
+{
+    PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd);
+
+    if (rc != NO_ERROR) {
+   	if (rc != ERROR_ACCESS_DENIED) {	
+   			_PR_MD_MAP_FSYNC_ERROR(rc);
+   	    return -1;
+   	}
+    }
+    return 0;
+}
+
+PRInt32
+_MD_CloseFile(PRInt32 osfd)
+{
+    PRInt32 rv;
+    
+    rv = DosClose((HFILE)osfd);
+ 	if (rv != NO_ERROR)
+		_PR_MD_MAP_CLOSE_ERROR(rv);
+    return rv;
+}
+
+
+/* --- DIR IO ------------------------------------------------------------ */
+#define GetFileFromDIR(d)       (d)->d_entry.achName
+#define GetFileAttr(d)          (d)->d_entry.attrFile
+
+void FlipSlashes(char *cp, int len)
+{
+    while (--len >= 0) {
+    if (cp[0] == '/') {
+        cp[0] = PR_DIRECTORY_SEPARATOR;
+    }
+    cp++;
+    }
+}
+
+/*
+**
+** Local implementations of standard Unix RTL functions which are not provided
+** by the VAC RTL.
+**
+*/
+
+PRInt32
+_PR_MD_CLOSE_DIR(_MDDir *d)
+{
+   PRInt32 rc;
+
+    if ( d ) {
+      rc = DosFindClose(d->d_hdl);
+      if(rc == NO_ERROR){
+        d->magic = (PRUint32)-1;
+        return PR_SUCCESS;
+		} else {
+			_PR_MD_MAP_CLOSEDIR_ERROR(rc);
+        	return PR_FAILURE;
+		}
+    }
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return PR_FAILURE;
+}
+
+
+PRStatus
+_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
+{
+    char filename[ CCHMAXPATH ];
+    PRUword numEntries, rc;
+
+    numEntries = 1;
+
+    PR_snprintf(filename, CCHMAXPATH, "%s%s%s",
+                name, PR_DIRECTORY_SEPARATOR_STR, "*.*");
+    FlipSlashes( filename, strlen(filename) );
+
+    d->d_hdl = HDIR_CREATE;
+
+    rc = DosFindFirst( filename,
+                       &d->d_hdl,
+                       FILE_DIRECTORY | FILE_HIDDEN,
+                       &(d->d_entry),
+                       sizeof(d->d_entry),
+                       &numEntries,
+                       FIL_STANDARD);
+    if ( rc != NO_ERROR ) {
+		_PR_MD_MAP_OPENDIR_ERROR(rc);
+        return PR_FAILURE;
+    }
+    d->firstEntry = PR_TRUE;
+    d->magic = _MD_MAGIC_DIR;
+    return PR_SUCCESS;
+}
+
+char *
+_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
+{
+    PRUword numFiles = 1;
+    BOOL rv;
+    char *fileName;
+    USHORT fileAttr;
+
+    if ( d ) {
+       while (1) {
+           if (d->firstEntry) {
+               d->firstEntry = PR_FALSE;
+               rv = NO_ERROR;
+           } else {
+               rv = DosFindNext(d->d_hdl,
+                                &(d->d_entry),
+                                sizeof(d->d_entry),
+                                &numFiles);
+           }
+           if (rv != NO_ERROR) {
+               break;
+           }
+           fileName = GetFileFromDIR(d);
+           fileAttr = GetFileAttr(d);
+           if ( (flags & PR_SKIP_DOT) &&
+                (fileName[0] == '.') && (fileName[1] == '\0'))
+                continue;
+           if ( (flags & PR_SKIP_DOT_DOT) &&
+                (fileName[0] == '.') && (fileName[1] == '.') &&
+                (fileName[2] == '\0'))
+                continue;
+			/*
+			 * XXX
+			 * Is this the correct definition of a hidden file on OS/2?
+			 */
+           if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN))
+                return fileName;
+           else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN))
+                continue;
+           return fileName;
+        }
+        PR_ASSERT(NO_ERROR != rv);
+			_PR_MD_MAP_READDIR_ERROR(rv);
+        return NULL;
+		}
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+    return NULL;
+}
+
+PRInt32
+_PR_MD_DELETE(const char *name)
+{
+    PRInt32 rc = DosDelete((char*)name);
+    if(rc == NO_ERROR) {
+        return 0;
+    } else {
+		_PR_MD_MAP_DELETE_ERROR(rc);
+        return -1;
+    }
+}
+
+PRInt32
+_PR_MD_STAT(const char *fn, struct stat *info)
+{
+    PRInt32 rv;
+    char filename[CCHMAXPATH];
+
+    PR_snprintf(filename, CCHMAXPATH, "%s", fn);
+    FlipSlashes(filename, strlen(filename));
+
+    rv = _stat((char*)filename, info);
+    if (-1 == rv) {
+        /*
+         * Check for MSVC runtime library _stat() bug.
+         * (It's really a bug in FindFirstFile().)
+         * If a pathname ends in a backslash or slash,
+         * e.g., c:\temp\ or c:/temp/, _stat() will fail.
+         * Note: a pathname ending in a slash (e.g., c:/temp/)
+         * can be handled by _stat() on NT but not on Win95.
+         *
+         * We remove the backslash or slash at the end and
+         * try again.  
+         *
+         * Not sure if this happens on OS/2 or not,
+         * but it doesn't hurt to be careful.
+         */
+
+        int len = strlen(fn);
+        if (len > 0 && len <= _MAX_PATH
+                && (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
+            char newfn[_MAX_PATH + 1];
+
+            strcpy(newfn, fn);
+            newfn[len - 1] = '\0';
+            rv = _stat(newfn, info);
+        }
+    }
+
+    if (-1 == rv) {
+        _PR_MD_MAP_STAT_ERROR(errno);
+    }
+    return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
+{
+    struct stat sb;
+    PRInt32 rv;
+    PRInt64 s, s2us;
+ 
+    if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) {
+        if (info) {
+            if (S_IFREG & sb.st_mode)
+                info->type = PR_FILE_FILE ;
+            else if (S_IFDIR & sb.st_mode)
+                info->type = PR_FILE_DIRECTORY;
+            else
+                info->type = PR_FILE_OTHER;
+            info->size = sb.st_size;
+            LL_I2L(s2us, PR_USEC_PER_SEC);
+            LL_I2L(s, sb.st_mtime);
+            LL_MUL(s, s, s2us);
+            info->modifyTime = s;
+            LL_I2L(s, sb.st_ctime);
+            LL_MUL(s, s, s2us);
+            info->creationTime = s;
+        }
+    }
+    return rv;
+}
+
+PRInt32
+_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
+{
+    PRFileInfo info32;
+    PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32);
+    if (0 == rv)
+    {
+        info->type = info32.type;
+        LL_UI2L(info->size,info32.size);
+        info->modifyTime = info32.modifyTime;
+        info->creationTime = info32.creationTime;
+    }
+    return rv;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
+{
+   /* For once, the VAC compiler/library did a nice thing.
+    * The file handle used by the C runtime is the same one
+    * returned by the OS when you call DosOpen().  This means
+    * that you can take an OS HFILE and use it with C file
+    * functions.  The only caveat is that you have to call
+    * _setmode() first to initialize some junk.  This is
+    * immensely useful because I did not have a clue how to
+    * implement this function otherwise.  The windows folks
+    * took the source from the Microsoft C library source, but
+    * IBM wasn't kind enough to ship the source with VAC.
+    * On second thought, the needed function could probably
+    * be gotten from the OS/2 GNU library source, but the
+    * point is now moot.
+    */
+   struct stat hinfo;
+    PRInt64 s, s2us;
+
+    _setmode(fd->secret->md.osfd, O_BINARY);
+    if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) {
+		_PR_MD_MAP_FSTAT_ERROR(errno);
+        return -1;
+	}
+
+    if (hinfo.st_mode & S_IFDIR)
+        info->type = PR_FILE_DIRECTORY;
+    else
+        info->type = PR_FILE_FILE;
+
+    info->size = hinfo.st_size;
+    LL_I2L(s2us, PR_USEC_PER_SEC);
+    LL_I2L(s, hinfo.st_mtime);
+    LL_MUL(s, s, s2us);
+    info->modifyTime = s;
+    LL_I2L(s, hinfo.st_ctime);
+    LL_MUL(s, s, s2us);
+    info->creationTime = s;
+
+    return 0;
+}
+
+PRInt32
+_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
+{
+   PRFileInfo info32;
+   PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32);
+   if (0 == rv)
+   {
+       info->type = info32.type;
+       LL_UI2L(info->size,info32.size);
+
+       info->modifyTime = info32.modifyTime;
+       info->creationTime = info32.creationTime;
+   }
+   return rv;
+}
+
+
+PRInt32
+_PR_MD_RENAME(const char *from, const char *to)
+{
+   PRInt32 rc;
+    /* Does this work with dot-relative pathnames? */
+    if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) {
+        return 0;
+    } else {
+		_PR_MD_MAP_RENAME_ERROR(rc);
+        return -1;
+    }
+}
+
+PRInt32
+_PR_MD_ACCESS(const char *name, PRAccessHow how)
+{
+  PRInt32 rv;
+    switch (how) {
+      case PR_ACCESS_WRITE_OK:
+        rv = access(name, 02);
+		break;
+      case PR_ACCESS_READ_OK:
+        rv = access(name, 04);
+		break;
+      case PR_ACCESS_EXISTS:
+        return access(name, 00);
+	  	break;
+      default:
+		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+		return -1;
+    }
+	if (rv < 0)
+		_PR_MD_MAP_ACCESS_ERROR(errno);
+    return rv;
+}
+
+PRInt32
+_PR_MD_MKDIR(const char *name, PRIntn mode)
+{
+   PRInt32 rc;
+    /* XXXMB - how to translate the "mode"??? */
+    if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) {
+        return 0;
+    } else {
+		_PR_MD_MAP_MKDIR_ERROR(rc);
+        return -1;
+    }
+}
+
+PRInt32
+_PR_MD_RMDIR(const char *name)
+{
+   PRInt32 rc;
+    if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) {
+        return 0;
+    } else {
+		_PR_MD_MAP_RMDIR_ERROR(rc);
+        return -1;
+    }
+}
+
+PRStatus
+_PR_MD_LOCKFILE(PRInt32 f)
+{
+	PRInt32   rv;
+   FILELOCK lock, unlock;
+
+   lock.lOffset = 0;
+   lock.lRange = 0xffffffff;
+   unlock.lOffset = 0;
+   unlock.lRange = 0;
+
+	/*
+     * loop trying to DosSetFileLocks(),
+     * pause for a few miliseconds when can't get the lock
+     * and try again
+     */
+    for( rv = FALSE; rv == FALSE; /* do nothing */ )
+    {
+    
+	    rv = DosSetFileLocks( (HFILE) f,
+			                    &unlock, &lock,
+			                    0, 0); 
+		if ( rv != NO_ERROR )
+        {
+            DosSleep( 50 );  /* Sleep() a few milisecs and try again. */
+        }            
+    } /* end for() */
+    return PR_SUCCESS;
+} /* end _PR_MD_LOCKFILE() */
+
+PRStatus
+_PR_MD_TLOCKFILE(PRInt32 f)
+{
+    return _PR_MD_LOCKFILE(f);
+} /* end _PR_MD_TLOCKFILE() */
+
+
+PRStatus
+_PR_MD_UNLOCKFILE(PRInt32 f)
+{
+	PRInt32   rv;
+   FILELOCK lock, unlock;
+
+   lock.lOffset = 0;
+   lock.lRange = 0;
+   unlock.lOffset = 0;
+   unlock.lRange = 0xffffffff;
+    
+   rv = DosSetFileLocks( (HFILE) f,
+                          &unlock, &lock,
+                          0, 0); 
+            
+    if ( rv != NO_ERROR )
+    {
+    	return PR_SUCCESS;
+    }
+    else
+    {
+		return PR_FAILURE;
+    }
+} /* end _PR_MD_UNLOCKFILE() */
+
+PRStatus
+_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
+{
+    int rv = 0;
+    ULONG flags;
+
+    rv = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags);
+    if (rv != 0) {
+        PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+
+    if (inheritable)
+      flags &= ~OPEN_FLAGS_NOINHERIT;
+    else
+      flags |= OPEN_FLAGS_NOINHERIT;
+
+    rv = DosSetFHState((HFILE)fd->secret->md.osfd, flags);
+    if (rv != 0) {
+        PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+void
+_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
+{
+    /* XXX this function needs to be implemented */
+    fd->secret->inheritable = _PR_TRI_UNKNOWN;
+}
+
+void
+_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
+{
+    /* XXX this function needs to be reviewed */
+    ULONG flags;
+
+    PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
+    if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) {
+        if (flags & OPEN_FLAGS_NOINHERIT) {
+            fd->secret->inheritable = _PR_TRI_FALSE;
+        } else {
+            fd->secret->inheritable = _PR_TRI_TRUE;
+        }
+    }
+}