summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtc%netscape.com <devnull@localhost>1999-10-07 20:15:02 +0000
committerwtc%netscape.com <devnull@localhost>1999-10-07 20:15:02 +0000
commitd7d4e4868b40b7c959d87467338c7298a43f4a9c (patch)
tree23f471cb2147fc6766fdd390c834db92a462d32e
parent27228524386b4ce0566f4334253dc6fe6f7bf927 (diff)
downloadnspr-hg-d7d4e4868b40b7c959d87467338c7298a43f4a9c.tar.gz
Created NSPRPUB_RELEASE_3_5_LANDING_BRANCH, rooted at
NSPRPUB_RELEASE_3_5_BASE.
-rw-r--r--config/AIX.mk5
-rw-r--r--config/HP-UX.mk8
-rw-r--r--config/IRIX.mk8
-rw-r--r--config/Linux.mk2
-rw-r--r--config/Makefile8
-rw-r--r--config/OSF1.mk2
-rw-r--r--config/SINIX.mk2
-rw-r--r--config/SunOS4.mk2
-rw-r--r--config/SunOS5.mk16
-rw-r--r--config/WIN32.mk7
-rw-r--r--config/config.mk2
-rw-r--r--config/rules.mk18
-rw-r--r--lib/ds/plevent.c9
-rw-r--r--lib/ds/plvrsion.c11
-rw-r--r--lib/libc/src/plvrsion.c11
-rw-r--r--lib/prstreams/plvrsion.c11
-rw-r--r--pr/include/md/Makefile10
-rw-r--r--pr/include/md/_aix.h7
-rw-r--r--pr/include/md/_aix32in6.cfg125
-rw-r--r--pr/include/md/_aix64.cfg4
-rw-r--r--pr/include/md/_beos.h2
-rw-r--r--pr/include/md/_hpux.h2
-rw-r--r--pr/include/md/_irix.h2
-rw-r--r--pr/include/md/_linux.h2
-rw-r--r--pr/include/md/_os2.h1
-rw-r--r--pr/include/md/_osf1.h6
-rw-r--r--pr/include/md/_solaris.h24
-rw-r--r--pr/include/md/_solaris32.cfg (renamed from pr/include/md/_solaris.cfg)0
-rw-r--r--pr/include/md/_solaris64.cfg130
-rw-r--r--pr/include/md/_unix_errors.h4
-rw-r--r--pr/include/md/_unixos.h4
-rw-r--r--pr/include/md/_win16.h1
-rw-r--r--pr/include/md/_win32_errors.h3
-rw-r--r--pr/include/md/_win95.h10
-rw-r--r--pr/include/md/_winnt.h19
-rw-r--r--pr/include/nspr.h3
-rw-r--r--pr/include/prinit.h12
-rw-r--r--pr/include/prio.h101
-rw-r--r--pr/include/pripcsem.h113
-rw-r--r--pr/include/private/pprio.h7
-rw-r--r--pr/include/private/primpl.h182
-rw-r--r--pr/include/prnetdb.h119
-rw-r--r--pr/include/prshm.h269
-rw-r--r--pr/include/prshma.h252
-rw-r--r--pr/src/Makefile15
-rw-r--r--pr/src/io/prfdcach.c4
-rw-r--r--pr/src/io/prlayer.c2
-rw-r--r--pr/src/io/prlog.c15
-rw-r--r--pr/src/io/prmwait.c2
-rw-r--r--pr/src/io/prpolevt.c157
-rw-r--r--pr/src/io/prsocket.c238
-rw-r--r--pr/src/md/beos/bnet.c6
-rw-r--r--pr/src/md/unix/Makefile11
-rw-r--r--pr/src/md/unix/aix.c7
-rw-r--r--pr/src/md/unix/objs.mk4
-rw-r--r--pr/src/md/unix/os_Irix.s58
-rw-r--r--pr/src/md/unix/os_SunOS.s83
-rw-r--r--pr/src/md/unix/os_SunOS_32.s101
-rw-r--r--pr/src/md/unix/unix.c243
-rw-r--r--pr/src/md/unix/unix_errors.c2
-rw-r--r--pr/src/md/unix/uxproces.c2
-rw-r--r--pr/src/md/unix/uxshm.c639
-rw-r--r--pr/src/md/windows/Makefile4
-rw-r--r--pr/src/md/windows/ntio.c685
-rw-r--r--pr/src/md/windows/ntmisc.c22
-rw-r--r--pr/src/md/windows/ntthread.c23
-rw-r--r--pr/src/md/windows/w32ipcsem.c177
-rw-r--r--pr/src/md/windows/w32shm.c309
-rw-r--r--pr/src/md/windows/win32_errors.c2
-rw-r--r--pr/src/memory/Makefile2
-rw-r--r--pr/src/memory/prshm.c140
-rw-r--r--pr/src/memory/prshma.c114
-rw-r--r--pr/src/misc/Makefile7
-rw-r--r--pr/src/misc/pralarm.c4
-rw-r--r--pr/src/misc/prinit.c28
-rw-r--r--pr/src/misc/pripc.c113
-rw-r--r--pr/src/misc/pripcsem.c111
-rw-r--r--pr/src/misc/prnetdb.c419
-rw-r--r--pr/src/nspr.rc10
-rw-r--r--pr/src/prvrsion.c11
-rw-r--r--pr/src/pthreads/ptio.c736
-rw-r--r--pr/src/pthreads/ptmisc.c11
-rw-r--r--pr/src/pthreads/ptsynch.c313
-rw-r--r--pr/src/pthreads/ptthread.c5
-rw-r--r--pr/src/threads/combined/prucpu.c84
-rw-r--r--pr/src/threads/combined/prucv.c29
-rw-r--r--pr/src/threads/combined/prulock.c34
-rw-r--r--pr/src/threads/combined/pruthr.c24
-rw-r--r--pr/src/threads/prcthr.c23
-rw-r--r--pr/src/threads/prdump.c10
-rw-r--r--pr/src/threads/prtpd.c16
-rw-r--r--pr/tests/Makefile10
-rw-r--r--pr/tests/accept.c1
-rw-r--r--pr/tests/affinity.c94
-rw-r--r--pr/tests/anonfm.c324
-rw-r--r--pr/tests/concur.c1
-rw-r--r--pr/tests/gethost.c227
-rw-r--r--pr/tests/io_timeout.c5
-rw-r--r--pr/tests/ioconthr.c28
-rw-r--r--pr/tests/many_cv.c2
-rw-r--r--pr/tests/nameshm1.c580
-rw-r--r--pr/tests/parent.c3
-rw-r--r--pr/tests/poll_to.c14
-rw-r--r--pr/tests/pollable.c1
-rw-r--r--pr/tests/provider.c1
-rwxr-xr-xpr/tests/runtests.ksh9
-rw-r--r--pr/tests/runy2ktests.ksh241
-rw-r--r--pr/tests/sema.c161
-rw-r--r--pr/tests/semaerr.c123
-rw-r--r--pr/tests/semaerr1.c118
-rw-r--r--pr/tests/semaping.c182
-rw-r--r--pr/tests/semapong.c126
-rw-r--r--pr/tests/socket.c513
-rw-r--r--pr/tests/testfile.c12
-rw-r--r--pr/tests/tmoacc.c8
-rw-r--r--pr/tests/tmocon.c93
-rw-r--r--pr/tests/vercheck.c7
-rw-r--r--pr/tests/y2k.c116
-rw-r--r--pr/tests/y2ktmo.c527
119 files changed, 9070 insertions, 1048 deletions
diff --git a/config/AIX.mk b/config/AIX.mk
index 0e68d833..bd40a9be 100644
--- a/config/AIX.mk
+++ b/config/AIX.mk
@@ -57,6 +57,11 @@ else
endif
endif
+# IPv6 support part of the standard AIX 4.3 release.
+ifneq (,$(filter-out 3.2 4.1 4.2,$(OS_RELEASE)))
+USE_IPV6 = 1
+endif
+
ifeq ($(CLASSIC_NSPR),1)
CC = xlC
CCC = xlC
diff --git a/config/HP-UX.mk b/config/HP-UX.mk
index 5a23232b..371de60b 100644
--- a/config/HP-UX.mk
+++ b/config/HP-UX.mk
@@ -120,10 +120,10 @@ ifeq ($(OS_RELEASE),B.11.00)
ifndef NS_USE_GCC
CCC = /opt/aCC/bin/aCC -ext
ifeq ($(USE_64), 1)
- OS_CFLAGS += +DA2.0W +DChpux
+ OS_CFLAGS += +DA2.0W +DS2.0
COMPILER_TAG = _64
else
- OS_CFLAGS += +DAportable +DS1.1
+ OS_CFLAGS += +DAportable +DS2.0
COMPILER_TAG = _32
endif
endif
@@ -176,7 +176,7 @@ endif
MKSHLIB = $(LD) $(DSO_LDOPTS)
-DSO_LDOPTS = -b
+DSO_LDOPTS = -b +h $(notdir $@)
DSO_LDFLAGS =
# -fPIC or +Z generates position independent code for use in shared
@@ -186,5 +186,3 @@ DSO_CFLAGS = -fPIC
else
DSO_CFLAGS = +Z
endif
-
-HAVE_PURIFY = 1
diff --git a/config/IRIX.mk b/config/IRIX.mk
index db26b010..44b86fd1 100644
--- a/config/IRIX.mk
+++ b/config/IRIX.mk
@@ -134,12 +134,6 @@ endif
# -rdata_shared is an ld option that puts string constants and
# const data into the text segment, where they will be shared
# across processes and be read-only.
-MKSHLIB = $(LD) $(SHLIB_LD_OPTS) -rdata_shared -shared -soname $(@:$(OBJDIR)/%.so=%.so)
-
-HAVE_PURIFY = 1
+MKSHLIB = $(LD) $(SHLIB_LD_OPTS) -rdata_shared -shared -soname $(notdir $@)
DSO_LDOPTS = -elf -shared -all
-
-ifdef DSO_BACKEND
-DSO_LDOPTS += -soname $(DSO_NAME)
-endif
diff --git a/config/Linux.mk b/config/Linux.mk
index 5fd85a46..be18254c 100644
--- a/config/Linux.mk
+++ b/config/Linux.mk
@@ -101,7 +101,7 @@ endif
# Linux 2.x has shared libraries.
#
-MKSHLIB = $(LD) $(DSO_LDOPTS) -soname $(@:$(OBJDIR)/%.so=%.so)
+MKSHLIB = $(LD) $(DSO_LDOPTS) -soname $(notdir $@)
ifdef BUILD_OPT
OPTIMIZER = -O2
endif
diff --git a/config/Makefile b/config/Makefile
index e52ce589..36ac7809 100644
--- a/config/Makefile
+++ b/config/Makefile
@@ -84,11 +84,9 @@ PROGS += $(OBJDIR)/nsinstall$(PROG_SUFFIX)
TARGETS = $(PROGS) $(PLSRCS:.pl=)
endif
-OUTOPTION = -o
-ifeq ($(OS_ARCH), WINNT)
-ifeq ($(CPU_ARCH),ALPHA)
-OUTOPTION = /link /out:
-endif
+OUTOPTION = -o # end of the line
+ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET)))
+OUTOPTION = /Fe
endif
# Redefine MAKE_OBJDIR for just this directory
diff --git a/config/OSF1.mk b/config/OSF1.mk
index ba9cd22b..e1c80c5e 100644
--- a/config/OSF1.mk
+++ b/config/OSF1.mk
@@ -93,5 +93,5 @@ OS_CFLAGS += -pthread
endif
# The command to build a shared library on OSF1.
-MKSHLIB = ld -shared -all -expect_unresolved "*"
+MKSHLIB = ld -shared -all -expect_unresolved "*" -soname $(notdir $@)
DSO_LDOPTS = -shared
diff --git a/config/SINIX.mk b/config/SINIX.mk
index 664f6ae0..6f42e7d9 100644
--- a/config/SINIX.mk
+++ b/config/SINIX.mk
@@ -89,6 +89,4 @@ OS_CFLAGS = $(NOMD_OS_CFLAGS)
OS_LIBS = -lsocket -lnsl -lresolv -ldl -lc
NOSUCHFILE = /no-such-file
-HAVE_PURIFY = 0
-
DEFINES += -D_PR_LOCAL_THREADS_ONLY
diff --git a/config/SunOS4.mk b/config/SunOS4.mk
index 70273112..5f73db40 100644
--- a/config/SunOS4.mk
+++ b/config/SunOS4.mk
@@ -45,8 +45,6 @@ endif
MKSHLIB = $(LD) $(DSO_LDOPTS)
-HAVE_PURIFY = 1
-
NOSUCHFILE = /no-such-file
DSO_LDOPTS =
diff --git a/config/SunOS5.mk b/config/SunOS5.mk
index cf244de2..f7243bce 100644
--- a/config/SunOS5.mk
+++ b/config/SunOS5.mk
@@ -79,6 +79,18 @@ endif
endif
endif
+ifeq ($(USE_64),1)
+ifndef INTERNAL_TOOLS
+ifndef NS_USE_GCC
+CC += -xarch=v9
+CCC += -xarch=v9
+endif
+endif
+COMPILER_TAG = _64
+else
+COMPILER_TAG = _32
+endif
+
RANLIB = echo
OS_DEFINES = -DSVR4 -DSYSV -D__svr4 -D__svr4__ -DSOLARIS
@@ -132,7 +144,7 @@ MKSHLIB = $(LD) $(DSO_LDOPTS)
# ld options:
# -G: produce a shared object
# -z defs: no unresolved symbols allowed
-DSO_LDOPTS = -G
+DSO_LDOPTS = -G -h $(notdir $@)
# -KPIC generates position independent code for use in shared libraries.
# (Similarly for -fPIC in case of gcc.)
@@ -142,8 +154,6 @@ else
DSO_CFLAGS = -KPIC
endif
-HAVE_PURIFY = 1
-
NOSUCHFILE = /no-such-file
#
diff --git a/config/WIN32.mk b/config/WIN32.mk
index 8c4fc172..375c80c3 100644
--- a/config/WIN32.mk
+++ b/config/WIN32.mk
@@ -53,7 +53,14 @@ OS_CFLAGS = -W3 -nologo -GF -Gy
ifdef BUILD_OPT
OS_CFLAGS += -MD
+# The -O2 optimization of MSVC 6.0 SP3 appears to generate
+# code that is unsafe for our use of fibers and static thread
+# local storage. We temporarily work around this problem by
+# turning off global optimizations (-Og).
OPTIMIZER = -O2
+ifeq ($(OS_TARGET),WINNT)
+OPTIMIZER += -Og-
+endif
DEFINES = -UDEBUG -U_DEBUG -DNDEBUG
DLLFLAGS = -OUT:"$@"
OBJDIR_TAG = _OPT
diff --git a/config/config.mk b/config/config.mk
index 45fdf764..91bba205 100644
--- a/config/config.mk
+++ b/config/config.mk
@@ -130,7 +130,7 @@ endif
MDIST = /m/dist
ifeq ($(OS_ARCH),WINNT)
MDIST = //helium/dist
-MDIST_DOS = \\\\helium\\dist
+MDIST_DOS = $(subst /,\\,$(MDIST))
endif
# RELEASE_DIR is ns/dist/<module name>
diff --git a/config/rules.mk b/config/rules.mk
index 8aff5b8d..9be1c121 100644
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -58,7 +58,6 @@ endif
# - LIBRARY: a static (archival) library
# - SHARED_LIBRARY: a shared (dynamic link) library
# - IMPORT_LIBRARY: an import library, used only on Windows and OS/2
-# - PURE_LIBRARY: a library for Purify
#
# The names of these libraries can be generated by simply specifying
# LIBRARY_NAME and LIBRARY_VERSION.
@@ -91,13 +90,6 @@ ifdef MKSHLIB
SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
endif
endif
-ifdef HAVE_PURIFY
-ifdef DSO_BACKEND
-PURE_LIBRARY = $(OBJDIR)/purelib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
-else
-PURE_LIBRARY = $(OBJDIR)/purelib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX)
-endif
-endif
endif
endif
@@ -107,9 +99,6 @@ ifeq ($(OS_ARCH), WINNT)
TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY)
else
TARGETS = $(LIBRARY) $(SHARED_LIBRARY)
-ifdef HAVE_PURIFY
-TARGETS += $(PURE_LIBRARY)
-endif
endif
endif
@@ -334,13 +323,6 @@ endif # OpenVMS
endif # WINNT
endif # AIX 4.1
-$(PURE_LIBRARY):
- rm -f $@
-ifneq ($(OS_ARCH), WINNT)
- $(AR) $(OBJS)
-endif
- $(RANLIB) $@
-
ifeq ($(OS_ARCH), WINNT)
$(RES): $(RESNAME)
@$(MAKE_OBJDIR)
diff --git a/lib/ds/plevent.c b/lib/ds/plevent.c
index e337d7fb..de1302c7 100644
--- a/lib/ds/plevent.c
+++ b/lib/ds/plevent.c
@@ -22,10 +22,8 @@
typedef MPARAM WPARAM,LPARAM;
#endif /* XP_OS2 */
+#include "primpl.h"
#include "plevent.h"
-#include "prmem.h"
-#include "prcmon.h"
-#include "prlog.h"
#if !defined(WIN32)
#include <errno.h>
@@ -43,11 +41,6 @@ typedef MPARAM WPARAM,LPARAM;
#if defined(XP_MAC)
#include <AppleEvents.h>
-#include "pprthred.h"
-#include "primpl.h"
-#else
-#include "private/pprthred.h"
-#include "private/primpl.h"
#endif /* XP_MAC */
#if defined(VMS)
diff --git a/lib/ds/plvrsion.c b/lib/ds/plvrsion.c
index acdfac95..bc5ee7dd 100644
--- a/lib/ds/plvrsion.c
+++ b/lib/ds/plvrsion.c
@@ -36,6 +36,11 @@
#if !defined(_PRODUCTION)
#define _PRODUCTION ""
#endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
static PRVersionDescription prVersionDescription_libplds3 =
{
@@ -65,8 +70,10 @@ static PRVersionDescription prVersionDescription_libplds3 =
/*
* Version information for the 'ident' and 'what commands
*/
-static char rcsid[] = "$Version: NSPR " PR_VERSION " " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION " " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING;
#endif /* XP_UNIX */
diff --git a/lib/libc/src/plvrsion.c b/lib/libc/src/plvrsion.c
index c09e5363..70dff093 100644
--- a/lib/libc/src/plvrsion.c
+++ b/lib/libc/src/plvrsion.c
@@ -36,6 +36,11 @@
#if !defined(_PRODUCTION)
#define _PRODUCTION ""
#endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
static PRVersionDescription prVersionDescription_libplc3 =
{
@@ -65,8 +70,10 @@ static PRVersionDescription prVersionDescription_libplc3 =
/*
* Version information for the 'ident' and 'what commands
*/
-static char rcsid[] = "$Version: NSPR " PR_VERSION " " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION " " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING;
#endif /* XP_UNIX */
diff --git a/lib/prstreams/plvrsion.c b/lib/prstreams/plvrsion.c
index 66a953fd..9a187c97 100644
--- a/lib/prstreams/plvrsion.c
+++ b/lib/prstreams/plvrsion.c
@@ -36,6 +36,11 @@
#if !defined(_PRODUCTION)
#define _PRODUCTION ""
#endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
static PRVersionDescription prVersionDescription_libprstrms3 =
{
@@ -65,8 +70,10 @@ static PRVersionDescription prVersionDescription_libprstrms3 =
/*
* Version information for the 'ident' and 'what commands
*/
-static char rcsid[] = "$Version: NSPR " PR_VERSION " " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION " " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING;
#endif /* XP_UNIX */
diff --git a/pr/include/md/Makefile b/pr/include/md/Makefile
index 3acaa418..dfee019b 100644
--- a/pr/include/md/Makefile
+++ b/pr/include/md/Makefile
@@ -51,9 +51,13 @@ ifeq ($(OS_ARCH),AIX)
ifeq ($(USE_64),1)
MDCPUCFG_H = _aix64.cfg
else
+ifeq ($(USE_IPV6),1)
+MDCPUCFG_H = _aix32in6.cfg
+else
MDCPUCFG_H = _aix32.cfg
endif
endif
+endif
ifeq ($(OS_ARCH),BSD_OS)
MDCPUCFG_H = _bsdi.cfg
@@ -95,7 +99,11 @@ ifeq ($(OS_ARCH),SunOS)
ifeq ($(OS_RELEASE),4.1.3_U1)
MDCPUCFG_H = _sunos4.cfg
else
-MDCPUCFG_H = _solaris.cfg
+ifeq ($(USE_64),1)
+MDCPUCFG_H = _solaris64.cfg
+else
+MDCPUCFG_H = _solaris32.cfg
+endif
endif
endif
diff --git a/pr/include/md/_aix.h b/pr/include/md/_aix.h
index 011c756e..a80ccb06 100644
--- a/pr/include/md/_aix.h
+++ b/pr/include/md/_aix.h
@@ -54,6 +54,11 @@
#define _PR_POLL_AVAILABLE
#define _PR_USE_POLL
#define _PR_STAT_HAS_ONLY_ST_ATIME
+#ifdef _PR_INET6
+#define _PR_HAVE_GETHOSTBYNAME2
+#endif
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
/* Timer operations */
#if defined(AIX_TIMERS)
@@ -72,7 +77,9 @@ extern PRIntervalTime _MD_AixIntervalPerSec(void);
/* The atomic operations */
#include <sys/atomic_op.h>
#define _PR_HAVE_ATOMIC_OPS
+#ifndef IS_64
#define _PR_HAVE_ATOMIC_CAS
+#endif
#define _MD_INIT_ATOMIC()
#define _MD_ATOMIC_INCREMENT(val) ((PRInt32)fetch_and_add((atomic_p)val, 1) + 1)
#define _MD_ATOMIC_ADD(ptr, val) ((PRInt32)fetch_and_add((atomic_p)ptr, val) + val)
diff --git a/pr/include/md/_aix32in6.cfg b/pr/include/md/_aix32in6.cfg
new file mode 100644
index 00000000..05fe241f
--- /dev/null
+++ b/pr/include/md/_aix32in6.cfg
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef AIX
+#define AIX
+#endif
+
+#undef IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+
+#define PR_BYTES_PER_BYTE 1
+#define PR_BYTES_PER_SHORT 2
+#define PR_BYTES_PER_INT 4
+#define PR_BYTES_PER_INT64 8
+#define PR_BYTES_PER_LONG 4
+#define PR_BYTES_PER_FLOAT 4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD 4
+#define PR_BYTES_PER_DWORD 8
+
+#define PR_BYTES_PER_WORD_LOG2 2
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#define PR_BITS_PER_BYTE 8
+#define PR_BITS_PER_SHORT 16
+#define PR_BITS_PER_INT 32
+#define PR_BITS_PER_INT64 64
+#define PR_BITS_PER_LONG 32
+#define PR_BITS_PER_FLOAT 32
+#define PR_BITS_PER_DOUBLE 64
+#define PR_BITS_PER_WORD 32
+
+#define PR_BITS_PER_BYTE_LOG2 3
+#define PR_BITS_PER_SHORT_LOG2 4
+#define PR_BITS_PER_INT_LOG2 5
+#define PR_BITS_PER_INT64_LOG2 6
+#define PR_BITS_PER_LONG_LOG2 5
+#define PR_BITS_PER_FLOAT_LOG2 5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2 5
+
+#define PR_ALIGN_OF_SHORT 2
+#define PR_ALIGN_OF_INT 4
+#define PR_ALIGN_OF_LONG 4
+#define PR_ALIGN_OF_INT64 8
+#define PR_ALIGN_OF_FLOAT 4
+#define PR_ALIGN_OF_DOUBLE 4
+#define PR_ALIGN_OF_POINTER 4
+
+#define HAVE_LONG_LONG
+#undef HAVE_ALIGNED_DOUBLES
+#undef HAVE_ALIGNED_LONGLONGS
+
+#ifndef _PR_INET6
+#define _PR_INET6
+#endif
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT PR_BYTES_PER_SHORT
+#define BYTES_PER_INT PR_BYTES_PER_INT
+#define BYTES_PER_INT64 PR_BYTES_PER_INT64
+#define BYTES_PER_LONG PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE PR_BITS_PER_BYTE
+#define BITS_PER_SHORT PR_BITS_PER_SHORT
+#define BITS_PER_INT PR_BITS_PER_INT
+#define BITS_PER_INT64 PR_BITS_PER_INT64
+#define BITS_PER_LONG PR_BITS_PER_LONG
+#define BITS_PER_FLOAT PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/pr/include/md/_aix64.cfg b/pr/include/md/_aix64.cfg
index e93d0130..30ad04d9 100644
--- a/pr/include/md/_aix64.cfg
+++ b/pr/include/md/_aix64.cfg
@@ -74,6 +74,10 @@
#undef HAVE_ALIGNED_DOUBLES
#undef HAVE_ALIGNED_LONGLONGS
+#ifndef _PR_INET6
+#define _PR_INET6
+#endif
+
#ifndef NO_NSPR_10_SUPPORT
#define BYTES_PER_BYTE PR_BYTES_PER_BYTE
diff --git a/pr/include/md/_beos.h b/pr/include/md/_beos.h
index 310fe307..2e77f242 100644
--- a/pr/include/md/_beos.h
+++ b/pr/include/md/_beos.h
@@ -318,7 +318,6 @@ struct protoent* getprotobynumber(int number);
#define _MD_RECV _MD_recv
#define _MD_SEND _MD_send
#define _MD_ACCEPT_READ _MD_accept_read
-#define _MD_TRANSMITFILE _MD_transmitfile
#define _MD_GETSOCKNAME _MD_getsockname
#define _MD_GETPEERNAME _MD_getpeername
#define _MD_GETSOCKOPT _MD_getsockopt
@@ -514,7 +513,6 @@ PR_EXTERN(PRInt32) _MD_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr *
// PR_EXTERN(PRInt32) _MD_fast_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg);
// PR_EXTERN(PRInt32) _MD_fast_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg);
// PR_EXTERN(void) _MD_update_accept_context(PRInt32 s, PRInt32 ls);
-PR_EXTERN(PRInt32) _MD_transmitfile(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen, PRInt32 flags, PRIntervalTime timeout);
PR_EXTERN(PRStatus) _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
PR_EXTERN(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
PR_EXTERN(PRStatus) _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen);
diff --git a/pr/include/md/_hpux.h b/pr/include/md/_hpux.h
index 12895c63..0d45f6c3 100644
--- a/pr/include/md/_hpux.h
+++ b/pr/include/md/_hpux.h
@@ -46,6 +46,8 @@
#define _PR_POLL_AVAILABLE
#define _PR_USE_POLL
#define _PR_STAT_HAS_ONLY_ST_ATIME
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
#undef _PR_HAVE_ATOMIC_OPS
diff --git a/pr/include/md/_irix.h b/pr/include/md/_irix.h
index 720991ac..4da14559 100644
--- a/pr/include/md/_irix.h
+++ b/pr/include/md/_irix.h
@@ -58,6 +58,8 @@
#define _PR_STAT_HAS_ST_ATIM
#define _PR_HAVE_OFF64_T
#define HAVE_POINTER_LOCALTIME_R
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
/* Initialization entry points */
PR_EXTERN(void) _MD_EarlyInit(void);
diff --git a/pr/include/md/_linux.h b/pr/include/md/_linux.h
index 16a772b2..7980934c 100644
--- a/pr/include/md/_linux.h
+++ b/pr/include/md/_linux.h
@@ -70,6 +70,8 @@
#else
#define _PR_NO_LARGE_FILES
#endif
+#define _PR_HAVE_SYSV_SEMAPHORES
+#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY
#ifdef _PR_PTHREADS
diff --git a/pr/include/md/_os2.h b/pr/include/md/_os2.h
index f4fee3d3..5d7ef0fc 100644
--- a/pr/include/md/_os2.h
+++ b/pr/include/md/_os2.h
@@ -261,7 +261,6 @@ extern PRInt32 _MD_CloseSocket(PRInt32 osfd);
#define _MD_ATOMIC_SET(x,y) _PR_MD_ATOMIC_SET(x, y)
#define _MD_INIT_IO (_PR_MD_INIT_IO)
-#define _MD_TRANSMITFILE (_PR_MD_TRANSMITFILE)
#define _MD_PR_POLL (_PR_MD_PR_POLL)
/* win95 doesn't have async IO */
diff --git a/pr/include/md/_osf1.h b/pr/include/md/_osf1.h
index 04860b68..7947ec61 100644
--- a/pr/include/md/_osf1.h
+++ b/pr/include/md/_osf1.h
@@ -46,6 +46,12 @@
#define _PR_USE_POLL
#define _PR_STAT_HAS_ONLY_ST_ATIME
#define _PR_HAVE_LARGE_OFF_T
+#ifdef _PR_INET6
+#define _PR_HAVE_GETIPNODEBYNAME
+#define _PR_HAVE_GETIPNODEBYADDR
+#endif
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
#define USE_SETJMP
diff --git a/pr/include/md/_solaris.h b/pr/include/md/_solaris.h
index 467607ce..11681813 100644
--- a/pr/include/md/_solaris.h
+++ b/pr/include/md/_solaris.h
@@ -44,16 +44,34 @@
#define USE_DLFCN
#define NEED_STRFTIME_LOCK
-#ifdef _PR_LOCAL_THREADS_ONLY
-#undef _PR_HAVE_ATOMIC_OPS
-#else
+/*
+ * Sparc v8 does not have instructions to efficiently implement
+ * atomic increment/decrement operations. In the local threads
+ * only and pthreads versions, we use the default atomic routine
+ * implementation in pratom.c. The obsolete global threads only
+ * version uses a global mutex_t to implement the atomic routines
+ * in solaris.c, which is actually equivalent to the default
+ * implementation.
+ */
+#ifdef _PR_GLOBAL_THREADS_ONLY
#define _PR_HAVE_ATOMIC_OPS
+#endif
+
+#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
+/*
+ * We have assembly language implementation of atomic
+ * stacks for the 32-bit sparc and x86 architectures only.
+ */
+#if !defined(sparc) || !defined(IS_64)
#define _PR_HAVE_ATOMIC_CAS
#endif
+#endif
#define _PR_POLL_AVAILABLE
#define _PR_USE_POLL
#define _PR_STAT_HAS_ST_ATIM
+#define _PR_HAVE_POSIX_SEMAPHORES
+#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY
#include "prinrval.h"
PR_EXTERN(PRIntervalTime) _MD_Solaris_GetInterval(void);
diff --git a/pr/include/md/_solaris.cfg b/pr/include/md/_solaris32.cfg
index f6b988a1..f6b988a1 100644
--- a/pr/include/md/_solaris.cfg
+++ b/pr/include/md/_solaris32.cfg
diff --git a/pr/include/md/_solaris64.cfg b/pr/include/md/_solaris64.cfg
new file mode 100644
index 00000000..40832724
--- /dev/null
+++ b/pr/include/md/_solaris64.cfg
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_UNIX
+#define XP_UNIX
+#endif
+
+#ifndef SOLARIS
+#define SOLARIS
+#endif
+
+#ifdef sparc
+#undef IS_LITTLE_ENDIAN
+#define IS_BIG_ENDIAN 1
+#define PR_ALIGN_OF_INT64 8
+#define PR_ALIGN_OF_DOUBLE 8
+#elif defined(i386)
+#define IS_LITTLE_ENDIAN 1
+#undef IS_BIG_ENDIAN
+#define PR_ALIGN_OF_INT64 4
+#define PR_ALIGN_OF_DOUBLE 4
+#else
+#error unknown processor
+#endif
+#define IS_64
+
+#define PR_BYTES_PER_BYTE 1
+#define PR_BYTES_PER_SHORT 2
+#define PR_BYTES_PER_INT 4
+#define PR_BYTES_PER_INT64 8
+#define PR_BYTES_PER_LONG 8
+#define PR_BYTES_PER_FLOAT 4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD 8
+#define PR_BYTES_PER_DWORD 8
+#define PR_BYTES_PER_WORD_LOG2 3
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#define PR_BITS_PER_BYTE 8
+#define PR_BITS_PER_SHORT 16
+#define PR_BITS_PER_INT 32
+#define PR_BITS_PER_INT64 64
+#define PR_BITS_PER_LONG 64
+#define PR_BITS_PER_FLOAT 32
+#define PR_BITS_PER_DOUBLE 64
+#define PR_BITS_PER_WORD 64
+
+#define PR_BITS_PER_BYTE_LOG2 3
+#define PR_BITS_PER_SHORT_LOG2 4
+#define PR_BITS_PER_INT_LOG2 5
+#define PR_BITS_PER_INT64_LOG2 6
+#define PR_BITS_PER_LONG_LOG2 6
+#define PR_BITS_PER_FLOAT_LOG2 5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2 6
+
+#define PR_ALIGN_OF_SHORT 2
+#define PR_ALIGN_OF_INT 4
+#define PR_ALIGN_OF_LONG 8
+#define PR_ALIGN_OF_FLOAT 4
+#define PR_ALIGN_OF_POINTER 8
+
+#define HAVE_LONG_LONG
+#define HAVE_ALIGNED_DOUBLES
+#define HAVE_ALIGNED_LONGLONGS
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT PR_BYTES_PER_SHORT
+#define BYTES_PER_INT PR_BYTES_PER_INT
+#define BYTES_PER_INT64 PR_BYTES_PER_INT64
+#define BYTES_PER_LONG PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE PR_BITS_PER_BYTE
+#define BITS_PER_SHORT PR_BITS_PER_SHORT
+#define BITS_PER_INT PR_BITS_PER_INT
+#define BITS_PER_INT64 PR_BITS_PER_INT64
+#define BITS_PER_LONG PR_BITS_PER_LONG
+#define BITS_PER_FLOAT PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* ifndef nspr_cpucfg___ */
diff --git a/pr/include/md/_unix_errors.h b/pr/include/md/_unix_errors.h
index 23a6d84c..d911081e 100644
--- a/pr/include/md/_unix_errors.h
+++ b/pr/include/md/_unix_errors.h
@@ -24,8 +24,8 @@
PR_BEGIN_EXTERN_C
-PR_EXTERN(PRStatus) _MD_gethostname(char *name, PRUint32 namelen);
-#define _MD_GETHOSTNAME _MD_gethostname
+PR_EXTERN(void) _MD_unix_map_default_error(int err);
+#define _PR_MD_MAP_DEFAULT_ERROR _MD_unix_map_default_error
PR_EXTERN(void) _MD_unix_map_opendir_error(int err);
#define _PR_MD_MAP_OPENDIR_ERROR _MD_unix_map_opendir_error
diff --git a/pr/include/md/_unixos.h b/pr/include/md/_unixos.h
index 10b3c6be..53684bbe 100644
--- a/pr/include/md/_unixos.h
+++ b/pr/include/md/_unixos.h
@@ -324,8 +324,7 @@ extern PRInt32 _MD_mkdir(const char *name, PRIntn mode);
extern PRInt32 _MD_rmdir(const char *name);
extern PRInt32 _MD_accept_read(PRInt32 sock, PRInt32 *newSock,
PRNetAddr **raddr, void *buf, PRInt32 amount);
-extern PRInt32 _PR_UnixTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
- const void *headers, PRInt32 hlen,
+extern PRInt32 _PR_UnixSendFile(PRFileDesc *sd, PRSendFileData *sfd,
PRTransmitFileFlags flags, PRIntervalTime timeout);
extern PRStatus _MD_LockFile(PRInt32 osfd);
@@ -446,6 +445,7 @@ extern int _MD_unix_get_nonblocking_connect_error(int osfd);
struct _MDFileMap {
PRIntn prot;
PRIntn flags;
+ PRBool isAnonFM; /* when true, PR_CloseFileMap() must close the related fd */
};
extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size);
diff --git a/pr/include/md/_win16.h b/pr/include/md/_win16.h
index 49b34415..544b4564 100644
--- a/pr/include/md/_win16.h
+++ b/pr/include/md/_win16.h
@@ -302,7 +302,6 @@ extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process);
#define _MD_ATOMIC_SET(x,y) (*x, y)
#define _MD_INIT_IO _PR_MD_INIT_IO
-#define _MD_TRANSMITFILE _PR_MD_TRANSMITFILE
/* win95 doesn't have async IO */
#define _MD_SOCKET _PR_MD_SOCKET
diff --git a/pr/include/md/_win32_errors.h b/pr/include/md/_win32_errors.h
index 0601c06e..2ff0abe1 100644
--- a/pr/include/md/_win32_errors.h
+++ b/pr/include/md/_win32_errors.h
@@ -24,6 +24,9 @@
#include <errno.h>
+extern void _MD_win32_map_default_error(PRInt32 err);
+#define _PR_MD_MAP_DEFAULT_ERROR _MD_win32_map_default_error
+
extern void _MD_win32_map_opendir_error(PRInt32 err);
#define _PR_MD_MAP_OPENDIR_ERROR _MD_win32_map_opendir_error
diff --git a/pr/include/md/_win95.h b/pr/include/md/_win95.h
index f9ee38b0..89febac7 100644
--- a/pr/include/md/_win95.h
+++ b/pr/include/md/_win95.h
@@ -38,6 +38,7 @@
#define HAVE_SOCKET_REUSEADDR
#define HAVE_SOCKET_KEEPALIVE
#define _PR_HAVE_ATOMIC_OPS
+#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY
/* --- Common User-Thread/Native-Thread Definitions --------------------- */
@@ -240,7 +241,6 @@ extern PRInt32 _MD_CloseSocket(PRInt32 osfd);
#define _MD_ATOMIC_SET(x,y) InterlockedExchange((PLONG)x, (LONG)y)
#define _MD_INIT_IO _PR_MD_INIT_IO
-#define _MD_TRANSMITFILE _PR_MD_TRANSMITFILE
/* win95 doesn't have async IO */
@@ -436,4 +436,12 @@ extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size);
extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap);
#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap
+/* --- Named semaphores stuff --- */
+#define _PR_HAVE_NAMED_SEMAPHORES
+#define _MD_OPEN_SEMAPHORE _PR_MD_OPEN_SEMAPHORE
+#define _MD_WAIT_SEMAPHORE _PR_MD_WAIT_SEMAPHORE
+#define _MD_POST_SEMAPHORE _PR_MD_POST_SEMAPHORE
+#define _MD_CLOSE_SEMAPHORE _PR_MD_CLOSE_SEMAPHORE
+#define _MD_DELETE_SEMAPHORE(name) PR_SUCCESS /* no op */
+
#endif /* nspr_win32_defs_h___ */
diff --git a/pr/include/md/_winnt.h b/pr/include/md/_winnt.h
index 0c2f438e..c75aa9b5 100644
--- a/pr/include/md/_winnt.h
+++ b/pr/include/md/_winnt.h
@@ -51,6 +51,7 @@
#define HAVE_SOCKET_KEEPALIVE
#define _PR_HAVE_ATOMIC_OPS
#define _PR_HAVE_ATOMIC_CAS
+#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY
/* --- Common User-Thread/Native-Thread Definitions --------------------- */
@@ -85,7 +86,6 @@ typedef struct _MDOverlapped {
enum _MDIOModel ioModel; /* The I/O model to implement
* using overlapped I/O.
*/
-
union {
struct _MDThread *mdThread; /* For blocking I/O, this structure
* is embedded in the _MDThread
@@ -120,6 +120,10 @@ struct _MDThread {
void *sp; /* only valid when suspended */
PRUint32 magic; /* for debugging */
PR_CONTEXT_TYPE gcContext; /* Thread context for GC */
+ struct _PRCPU *thr_bound_cpu; /* thread bound to cpu */
+ PRBool interrupt_disabled;/* thread cannot be interrupted */
+ HANDLE thr_event; /* For native-threads-only support,
+ thread blocks on this event */
/* The following are used only if this is a fiber */
void *fiber_id; /* flag whether or not this is a fiber*/
@@ -194,6 +198,7 @@ struct _MDProcess {
DWORD id;
};
+
/* --- Misc stuff --- */
#define _MD_GET_SP(thread) (thread)->md.gcContext[6]
@@ -275,7 +280,7 @@ extern int _PR_NTFiberSafeSelect(int, fd_set *, fd_set *, fd_set *,
#define _MD_BIND _PR_MD_BIND
#define _MD_RECV _PR_MD_RECV
#define _MD_SEND _PR_MD_SEND
-#define _MD_TRANSMITFILE _PR_MD_TRANSMITFILE
+#define _MD_SENDFILE _PR_MD_SENDFILE
#define _MD_PR_POLL _PR_MD_PR_POLL
/* --- Scheduler stuff --- */
@@ -327,7 +332,7 @@ extern void _PR_Unblock_IO_Wait(PRThread *thr);
#define _MD_FREE_LOCK(lock) DeleteCriticalSection(&((lock)->mutex))
#ifndef PROFILE_LOCKS
#define _MD_LOCK(lock) EnterCriticalSection(&((lock)->mutex))
-#define _MD_TEST_AND_LOCK(lock) 0 /* XXXMB */
+#define _MD_TEST_AND_LOCK(lock) (TryEnterCriticalSection(&((lock)->mutex))== FALSE)
#define _MD_UNLOCK(lock) LeaveCriticalSection(&((lock)->mutex))
#else
#define _MD_LOCK(lock) \
@@ -505,4 +510,12 @@ extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size);
extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap);
#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap
+/* --- Named semaphores stuff --- */
+#define _PR_HAVE_NAMED_SEMAPHORES
+#define _MD_OPEN_SEMAPHORE _PR_MD_OPEN_SEMAPHORE
+#define _MD_WAIT_SEMAPHORE _PR_MD_WAIT_SEMAPHORE
+#define _MD_POST_SEMAPHORE _PR_MD_POST_SEMAPHORE
+#define _MD_CLOSE_SEMAPHORE _PR_MD_CLOSE_SEMAPHORE
+#define _MD_DELETE_SEMAPHORE(name) PR_SUCCESS /* no op */
+
#endif /* nspr_win32_defs_h___ */
diff --git a/pr/include/nspr.h b/pr/include/nspr.h
index 7dcffe63..691b6a5b 100644
--- a/pr/include/nspr.h
+++ b/pr/include/nspr.h
@@ -31,6 +31,7 @@
#include "prinit.h"
#include "prinrval.h"
#include "prio.h"
+#include "pripcsem.h"
#include "prlink.h"
#include "prlock.h"
#include "prlog.h"
@@ -42,6 +43,8 @@
#include "prprf.h"
#include "prproces.h"
#include "prrwlock.h"
+#include "prshm.h"
+#include "prshma.h"
#include "prsystem.h"
#include "prthread.h"
#include "prtime.h"
diff --git a/pr/include/prinit.h b/pr/include/prinit.h
index 329a5058..b2119119 100644
--- a/pr/include/prinit.h
+++ b/pr/include/prinit.h
@@ -44,9 +44,9 @@ PR_BEGIN_EXTERN_C
** The format of the version string is
** "<major version>.<minor version> <build date>"
*/
-#define PR_VERSION "3.1"
+#define PR_VERSION "3.5"
#define PR_VMAJOR 3
-#define PR_VMINOR 1
+#define PR_VMINOR 5
#define PR_VPATCH 0
#define PR_BETA PR_FALSE
@@ -213,11 +213,3 @@ PR_EXTERN(PRStatus) PR_CallOnce(
PR_END_EXTERN_C
#endif /* prinit_h___ */
-
-
-
-
-
-
-
-
diff --git a/pr/include/prio.h b/pr/include/prio.h
index 76575c2b..5ced4fb4 100644
--- a/pr/include/prio.h
+++ b/pr/include/prio.h
@@ -156,6 +156,7 @@ union PRNetAddr {
PRUint16 port; /* port number */
PRUint32 flowinfo; /* routing information */
PRIPv6Addr ip; /* the actual 128 bits of address */
+ PRUint32 scope_id; /* set of interfaces for a scope */
} ipv6;
#endif /* defined(_PR_INET6) */
#if defined(XP_UNIX)
@@ -1044,7 +1045,7 @@ PR_EXTERN(PRUintn) PR_NetAddrSize(const PRNetAddr* addr);
*************************************************************************
* FUNCTION: PR_NewUDPSocket
* DESCRIPTION:
- * Create a new UDP network connection.
+ * Create a new UDP socket.
* INPUTS:
* None
* OUTPUTS:
@@ -1052,7 +1053,7 @@ PR_EXTERN(PRUintn) PR_NetAddrSize(const PRNetAddr* addr);
* RETURN: PRFileDesc*
* Upon successful completion, PR_NewUDPSocket returns a pointer
* to the PRFileDesc created for the newly opened UDP socket.
- * Returns a NULL pointer if the create of a new UDP connection failed.
+ * Returns a NULL pointer if the creation of a new UDP socket failed.
*
**************************************************************************
*/
@@ -1063,7 +1064,7 @@ PR_EXTERN(PRFileDesc*) PR_NewUDPSocket(void);
*************************************************************************
* FUNCTION: PR_NewTCPSocket
* DESCRIPTION:
- * Create a new TCP network connection.
+ * Create a new TCP socket.
* INPUTS:
* None
* OUTPUTS:
@@ -1071,7 +1072,7 @@ PR_EXTERN(PRFileDesc*) PR_NewUDPSocket(void);
* RETURN: PRFileDesc*
* Upon successful completion, PR_NewTCPSocket returns a pointer
* to the PRFileDesc created for the newly opened TCP socket.
- * Returns a NULL pointer if the create of a new TCP connection failed.
+ * Returns a NULL pointer if the creation of a new TCP socket failed.
*
**************************************************************************
*/
@@ -1080,6 +1081,46 @@ PR_EXTERN(PRFileDesc*) PR_NewTCPSocket(void);
/*
*************************************************************************
+ * FUNCTION: PR_OpenUDPSocket
+ * DESCRIPTION:
+ * Create a new UDP socket of the specified address family.
+ * INPUTS:
+ * PRIntn af
+ * Address family
+ * OUTPUTS:
+ * None
+ * RETURN: PRFileDesc*
+ * Upon successful completion, PR_OpenUDPSocket returns a pointer
+ * to the PRFileDesc created for the newly opened UDP socket.
+ * Returns a NULL pointer if the creation of a new UDP socket failed.
+ *
+ **************************************************************************
+ */
+
+PR_EXTERN(PRFileDesc*) PR_OpenUDPSocket(PRIntn af);
+
+/*
+ *************************************************************************
+ * FUNCTION: PR_OpenTCPSocket
+ * DESCRIPTION:
+ * Create a new TCP socket of the specified address family.
+ * INPUTS:
+ * PRIntn af
+ * Address family
+ * OUTPUTS:
+ * None
+ * RETURN: PRFileDesc*
+ * Upon successful completion, PR_NewTCPSocket returns a pointer
+ * to the PRFileDesc created for the newly opened TCP socket.
+ * Returns a NULL pointer if the creation of a new TCP socket failed.
+ *
+ **************************************************************************
+ */
+
+PR_EXTERN(PRFileDesc*) PR_OpenTCPSocket(PRIntn af);
+
+/*
+ *************************************************************************
* FUNCTION: PR_Connect
* DESCRIPTION:
* Initiate a connection on a socket.
@@ -1402,6 +1443,58 @@ PR_EXTERN(PRInt32) PR_TransmitFile(
PRFileDesc *networkSocket, PRFileDesc *sourceFile,
const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
PRIntervalTime timeout);
+
+/*
+*************************************************************************
+** FUNCTION: PR_SendFile
+** DESCRIPTION:
+** PR_SendFile sends data from a file (sendData->fd) across a socket
+** (networkSocket). If specified, a header and/or trailer buffer are sent
+** before and after the file, respectively. The file offset, number of bytes
+** of file data to send, the header and trailer buffers are specified in the
+** sendData argument.
+**
+** Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the
+** socket is closed after successfully sending the data.
+**
+** INPUTS:
+** PRFileDesc *networkSocket
+** The socket to send data over
+** PRSendFileData *sendData
+** Contains the FD, file offset and length, header and trailer
+** buffer specifications.
+** PRTransmitFileFlags flags
+** If the flags indicate that the connection should be closed,
+** it will be done immediately after transferring the file, unless
+** the operation is unsuccessful.
+.* PRIntervalTime timeout
+ * Time limit for completion of the send operation.
+**
+** RETURNS:
+** Returns the number of bytes written or -1 if the operation failed.
+** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_
+** SOCKET flag is ignored. The reason for the failure is obtained
+** by calling PR_GetError().
+**************************************************************************
+*/
+
+typedef struct PRSendFileData {
+ PRFileDesc *fd; /* file to send */
+ PRUint32 file_offset; /* file offset */
+ PRSize file_nbytes; /* number of bytes of file data to send */
+ /* if 0, send data from file_offset to */
+ /* end-of-file. */
+ const void *header; /* header buffer */
+ PRInt32 hlen; /* header len */
+ const void *trailer; /* trailer buffer */
+ PRInt32 tlen; /* trailer len */
+} PRSendFileData;
+
+
+PR_EXTERN(PRInt32) PR_SendFile(
+ PRFileDesc *networkSocket, PRSendFileData *sendData,
+ PRTransmitFileFlags flags, PRIntervalTime timeout);
+
/*
*************************************************************************
** FUNCTION: PR_AcceptRead
diff --git a/pr/include/pripcsem.h b/pr/include/pripcsem.h
new file mode 100644
index 00000000..c123afea
--- /dev/null
+++ b/pr/include/pripcsem.h
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * File: pripcsem.h
+ *
+ * Description: named semaphores for interprocess
+ * synchronization
+ *
+ * Unrelated processes obtain access to a shared semaphore
+ * by specifying its name.
+ *
+ * Our goal is to support named semaphores on at least
+ * Unix and Win32 platforms. The implementation will use
+ * one of the three native semaphore APIs: POSIX, System V,
+ * and Win32.
+ *
+ * Because POSIX named semaphores have kernel persistence,
+ * we are forced to have a delete function in this API.
+ */
+
+#ifndef pripcsem_h___
+#define pripcsem_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * PRSem is an opaque structure that represents a named
+ * semaphore.
+ */
+typedef struct PRSem PRSem;
+
+/*
+ * PR_OpenSemaphore --
+ *
+ * Create or open a named semaphore with the specified name.
+ * A handle to the semaphore is returned.
+ *
+ * If the named semaphore doesn't exist and the PR_SEM_CREATE
+ * flag is specified, the named semaphore is created. The
+ * created semaphore needs to be removed from the system with
+ * a PR_DeleteSemaphore call.
+ *
+ * If PR_SEM_CREATE is specified, the third argument is the
+ * access permission bits of the new semaphore (same
+ * interpretation as the mode argument to PR_Open) and the
+ * fourth argument is the initial value of the new semaphore.
+ * If PR_SEM_CREATE is not specified, the third and fourth
+ * arguments are ignored.
+ */
+
+#define PR_SEM_CREATE 0x1 /* create if not exist */
+#define PR_SEM_EXCL 0x2 /* fail if already exists */
+
+PR_EXTERN(PRSem *) PR_OpenSemaphore(
+ const char *name, PRIntn flags, PRIntn mode, PRUintn value);
+
+/*
+ * PR_WaitSemaphore --
+ *
+ * If the value of the semaphore is > 0, decrement the value and return.
+ * If the value is 0, sleep until the value becomes > 0, then decrement
+ * the value and return.
+ *
+ * The "test and decrement" operation is performed atomically.
+ */
+
+PR_EXTERN(PRStatus) PR_WaitSemaphore(PRSem *sem);
+
+/*
+ * PR_PostSemaphore --
+ *
+ * Increment the value of the named semaphore by 1.
+ */
+
+PR_EXTERN(PRStatus) PR_PostSemaphore(PRSem *sem);
+
+/*
+ * PR_CloseSemaphore --
+ *
+ * Close a named semaphore handle.
+ */
+
+PR_EXTERN(PRStatus) PR_CloseSemaphore(PRSem *sem);
+
+/*
+ * PR_DeleteSemaphore --
+ *
+ * Remove a named semaphore from the system.
+ */
+
+PR_EXTERN(PRStatus) PR_DeleteSemaphore(const char *name);
+
+PR_END_EXTERN_C
+
+#endif /* pripcsem_h___ */
diff --git a/pr/include/private/pprio.h b/pr/include/private/pprio.h
index 08b44076..02dbcb9a 100644
--- a/pr/include/private/pprio.h
+++ b/pr/include/private/pprio.h
@@ -235,6 +235,13 @@ PR_EXTERN(void) PR_NTFast_UpdateAcceptContext(PRFileDesc *acceptSock,
*/
PR_EXTERN(void) PR_NT_UseNonblock();
+/* FUNCTION: PR_NT_CancelIo
+** DESCRIPTION:
+** Cancel IO operations on fd.
+*/
+PR_EXTERN(PRStatus) PR_NT_CancelIo(PRFileDesc *fd);
+
+
#endif /* WIN32 */
PR_END_EXTERN_C
diff --git a/pr/include/private/primpl.h b/pr/include/private/primpl.h
index 9716dd15..69a341ba 100644
--- a/pr/include/private/primpl.h
+++ b/pr/include/private/primpl.h
@@ -60,6 +60,12 @@ typedef struct PRSegment PRSegment;
#include "obsolete/probslet.h"
#endif /* XP_MAC */
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#include <semaphore.h>
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+#include <sys/sem.h>
+#endif
+
/*************************************************************************
***** A Word about Model Dependent Function Naming Convention ***********
*************************************************************************/
@@ -307,6 +313,8 @@ PR_EXTERN(PRInt32) _pr_intsOff;
#endif /* _PR_LOCAL_THREADS_ONLY */
+extern PRInt32 _native_threads_only;
+
#if defined(_PR_GLOBAL_THREADS_ONLY)
#define _MD_GET_INTSOFF() 0
@@ -973,6 +981,23 @@ extern char * _PR_MD_READ_DIR(_MDDir *md, PRIntn flags);
extern PRInt32 _PR_MD_CLOSE_DIR(_MDDir *md);
#define _PR_MD_CLOSE_DIR _MD_CLOSE_DIR
+/* Named semaphores related */
+extern PRSem * _PR_MD_OPEN_SEMAPHORE(
+ const char *osname, PRIntn flags, PRIntn mode, PRUintn value);
+#define _PR_MD_OPEN_SEMAPHORE _MD_OPEN_SEMAPHORE
+
+extern PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem);
+#define _PR_MD_WAIT_SEMAPHORE _MD_WAIT_SEMAPHORE
+
+extern PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem);
+#define _PR_MD_POST_SEMAPHORE _MD_POST_SEMAPHORE
+
+extern PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem);
+#define _PR_MD_CLOSE_SEMAPHORE _MD_CLOSE_SEMAPHORE
+
+extern PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname);
+#define _PR_MD_DELETE_SEMAPHORE _MD_DELETE_SEMAPHORE
+
/* I/O related */
extern void _PR_MD_INIT_FILEDESC(PRFileDesc *fd);
#define _PR_MD_INIT_FILEDESC _MD_INIT_FILEDESC
@@ -1084,14 +1109,12 @@ extern void _PR_MD_UPDATE_ACCEPT_CONTEXT(PRInt32 s, PRInt32 ls);
#define _PR_MD_UPDATE_ACCEPT_CONTEXT _MD_UPDATE_ACCEPT_CONTEXT
#endif /* WIN32 */
-extern PRInt32 _PR_MD_TRANSMITFILE(
- PRFileDesc *sock, PRFileDesc *file,
- const void *headers, PRInt32 hlen, PRInt32 flags,
- PRIntervalTime timeout);
-#define _PR_MD_TRANSMITFILE _MD_TRANSMITFILE
-extern PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
- const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
- PRIntervalTime timeout);
+extern PRInt32 _PR_MD_SENDFILE(
+ PRFileDesc *sock, PRSendFileData *sfd,
+ PRInt32 flags, PRIntervalTime timeout);
+#define _PR_MD_SENDFILE _MD_SENDFILE
+extern PRInt32 _PR_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout);
extern PRStatus _PR_MD_GETSOCKNAME(
PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen);
@@ -1294,6 +1317,20 @@ struct PRSemaphore {
PR_EXTERN(void) _PR_InitSem(void);
+/*************************************************************************/
+
+struct PRSem {
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+ sem_t *sem;
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+ int semid;
+#elif defined(WIN32)
+ HANDLE sem;
+#else
+ PRInt8 notused;
+#endif
+};
+
/************************************************************************/
/* XXX this needs to be exported (sigh) */
@@ -1355,6 +1392,7 @@ struct PRThread {
PRBool okToDelete; /* ok to delete the PRThread struct? */
PRCondVar *io_cv; /* a condition used to run i/o */
PRCondVar *waiting; /* where the thread is waiting | NULL */
+ PRIntn io_tq_index; /* the io-queue index for this thread */
void *sp; /* recorded sp for garbage collection */
PRThread *next, *prev; /* simple linked list of all threads */
PRUint32 suspend; /* used to store suspend and resume flags */
@@ -1462,20 +1500,39 @@ struct PRFilePrivate {
PRInt32 state;
PRBool nonblocking;
PRBool inheritable;
-#if defined(_PR_PTHREADS)
- PRInt16 eventMask; /* A bitmask in which a 0 means
- * the event should be ignored in
- * the revents returned by poll.
- * The eventMask field is only
- * accessed by the i/o continuation
- * thread.
- */
-#endif
PRFileDesc *next;
PRIntn lockCount;
_MDFileDesc md;
+#ifdef _PR_PTHREADS
+ PRIntn eventMask[1]; /* An array of _pt_tq_count bitmasks.
+ * eventMask[i] is only accessed by
+ * the i-th i/o continuation thread.
+ * A 0 in a bitmask means the event
+ * should be igored in the revents
+ * bitmask returned by poll.
+ *
+ * poll's revents bitmask is a short,
+ * but we need to declare eventMask
+ * as an array of PRIntn's so that
+ * each bitmask can be updated
+ * individually without disturbing
+ * adjacent memory. Only the lower
+ * 16 bits of each PRIntn are used. */
+#endif
+/* IMPORTANT: eventMask MUST BE THE LAST FIELD OF THIS STRUCTURE */
};
+/*
+ * The actual size of the PRFilePrivate structure,
+ * including the eventMask array at the end
+ */
+#ifdef _PR_PTHREADS
+extern PRIntn _pt_tq_count;
+#define PRFILEPRIVATE_SIZE (sizeof(PRFilePrivate) + (_pt_tq_count-1) * sizeof(PRIntn))
+#else
+#define PRFILEPRIVATE_SIZE sizeof(PRFilePrivate)
+#endif
+
struct PRDir {
PRDirEntry d;
_MDDir md;
@@ -1712,6 +1769,97 @@ extern PRStatus _PR_MD_MEM_UNMAP(void *addr, PRUint32 size);
extern PRStatus _PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap);
#define _PR_MD_CLOSE_FILE_MAP _MD_CLOSE_FILE_MAP
+/* Named Shared Memory */
+
+/*
+** Declare PRSharedMemory.
+*/
+struct PRSharedMemory
+{
+ char *ipcname; /* after conversion to native */
+ PRSize size; /* from open */
+ PRIntn mode; /* from open */
+ PRIntn flags; /* from open */
+#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY)
+ int id;
+#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY)
+ int id;
+#elif defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
+ HANDLE handle;
+#else
+ PRUint32 nothing; /* placeholder, nothing behind here */
+#endif
+ PRUint32 ident; /* guard word at end of struct */
+#define _PR_SHM_IDENT 0xdeadbad
+};
+
+extern PRSharedMemory * _MD_OpenSharedMemory(
+ const char *name,
+ PRSize size,
+ PRIntn flags,
+ PRIntn mode
+);
+#define _PR_MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags );
+#define _PR_MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr );
+#define _PR_MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm );
+#define _PR_MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name );
+#define _PR_MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory
+
+extern PRFileMap* _md_OpenAnonFileMap(
+ const char *dirName,
+ PRSize size,
+ PRFileMapProtect prot
+);
+#define _PR_MD_OPEN_ANON_FILE_MAP _md_OpenAnonFileMap
+
+extern PRStatus _md_ExportFileMapAsString(
+ PRFileMap *fm,
+ PRSize bufSize,
+ char *buf
+);
+#define _PR_MD_EXPORT_FILE_MAP_AS_STRING _md_ExportFileMapAsString
+
+extern PRFileMap * _md_ImportFileMapFromString(
+ const char *fmstring
+);
+#define _PR_MD_IMPORT_FILE_MAP_FROM_STRING _md_ImportFileMapFromString
+
+
+
+/* Interprocess communications (IPC) */
+
+/*
+ * The maximum length of an NSPR IPC name, including the
+ * terminating null byte.
+ */
+#define PR_IPC_NAME_SIZE 1024
+
+/*
+ * Types of NSPR IPC objects
+ */
+typedef enum {
+ _PRIPCSem, /* semaphores */
+ _PRIPCShm /* shared memory segments */
+} _PRIPCType;
+
+/*
+ * Make a native IPC name from an NSPR IPC name.
+ */
+extern PRStatus _PR_MakeNativeIPCName(
+ const char *name, /* NSPR IPC name */
+ char *result, /* result buffer */
+ PRIntn size, /* size of result buffer */
+ _PRIPCType type /* type of IPC object */
+);
+
/* Socket call error code */
PR_EXTERN(PRInt32) _PR_MD_GET_SOCKET_ERROR(void);
diff --git a/pr/include/prnetdb.h b/pr/include/prnetdb.h
index 2b67f4c8..4a282b69 100644
--- a/pr/include/prnetdb.h
+++ b/pr/include/prnetdb.h
@@ -92,6 +92,49 @@ PR_EXTERN(PRStatus) PR_GetHostByName(
/***********************************************************************
** FUNCTION:
+** DESCRIPTION: PR_GetIPNodeByName()
+** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT)
+** of RFC 2553.
+**
+** INPUTS:
+** char *hostname Character string defining the host name of interest
+** PRUint16 af Address family (either PR_AF_INET or PR_AF_INET6)
+** PRIntn flags Specifies the types of addresses that are searched
+** for and the types of addresses that are returned.
+** The only supported flag is PR_AI_DEFAULT.
+** char *buf A scratch buffer for the runtime to return result.
+** This buffer is allocated by the caller.
+** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to
+** use is PR_NETDB_BUF_SIZE.
+** OUTPUTS:
+** PRHostEnt *hostentry
+** This structure is filled in by the runtime if
+** the function returns PR_SUCCESS. This structure
+** is allocated by the caller.
+** RETURN:
+** PRStatus PR_SUCCESS if the lookup succeeds. If it fails
+** the result will be PR_FAILURE and the reason
+** for the failure can be retrieved by PR_GetError().
+***********************************************************************/
+
+/*
+ * #define PR_AI_ALL 0x08
+ * #define PR_AI_V4MAPPED 0x10
+ * #define PR_AI_ADDRCONFIG 0x20
+ * #define PR_AI_DEFAULT (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG)
+ */
+#define PR_AI_DEFAULT 0x30
+
+PR_EXTERN(PRStatus) PR_GetIPNodeByName(
+ const char *hostname,
+ PRUint16 af,
+ PRIntn flags,
+ char *buf,
+ PRIntn bufsize,
+ PRHostEnt *hostentry);
+
+/***********************************************************************
+** FUNCTION:
** DESCRIPTION: PR_GetHostByAddr()
** Lookup a host entry by its network address.
**
@@ -160,7 +203,7 @@ PR_EXTERN(PRIntn) PR_EnumerateHostEnt(
** special well known values that are equivalent to
** INADDR_ANY and INADDR_LOOPBACK.
**
-** PRUInt16 port The port number to be assigned in the structure.
+** PRUint16 port The port number to be assigned in the structure.
**
** OUTPUTS:
** PRNetAddr *addr The address to be manipulated.
@@ -181,6 +224,80 @@ PR_EXTERN(PRStatus) PR_InitializeNetAddr(
PRNetAddrValue val, PRUint16 port, PRNetAddr *addr);
/***********************************************************************
+** FUNCTION: PR_SetNetAddr(),
+** DESCRIPTION:
+** Set the fields of a PRNetAddr, assigning well known values as
+** appropriate. This function is similar to PR_InitializeNetAddr
+** but differs in that the address family is specified.
+**
+** INPUTS
+** PRNetAddrValue val The value to be assigned to the IP Address portion
+** of the network address. This can only specify the
+** special well known values that are equivalent to
+** INADDR_ANY and INADDR_LOOPBACK.
+**
+** PRUint16 af The address family (either PR_AF_INET or PR_AF_INET6)
+**
+** PRUint16 port The port number to be assigned in the structure.
+**
+** OUTPUTS:
+** PRNetAddr *addr The address to be manipulated.
+**
+** RETURN:
+** PRStatus To indicate success or failure. If the latter, the
+** reason for the failure can be retrieved by calling
+** PR_GetError();
+***********************************************************************/
+PR_EXTERN(PRStatus) PR_SetNetAddr(
+ PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr);
+
+/***********************************************************************
+** FUNCTION:
+** DESCRIPTION: PR_IsNetAddrType()
+** Determine if the network address is of the specified type.
+**
+** INPUTS:
+** const PRNetAddr *addr A network address.
+** PRNetAddrValue The type of network address
+**
+** RETURN:
+** PRBool PR_TRUE if the network address is of the
+** specified type, else PR_FALSE.
+***********************************************************************/
+PR_EXTERN(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val);
+
+/***********************************************************************
+** MACRO:
+** DESCRIPTION: PR_NetAddrFamily()
+** Get the 'family' field of a PRNetAddr union.
+**
+** INPUTS:
+** const PRNetAddr *addr A network address.
+**
+** RETURN:
+** PRUint16 The 'family' field of 'addr'.
+***********************************************************************/
+#define PR_NetAddrFamily(addr) ((addr)->raw.family)
+
+/***********************************************************************
+** MACRO:
+** DESCRIPTION: PR_NetAddrInetPort()
+** Get the 'port' field of a PRNetAddr union.
+**
+** INPUTS:
+** const PRNetAddr *addr A network address.
+**
+** RETURN:
+** PRUint16 The 'port' field of 'addr'.
+***********************************************************************/
+#ifdef _PR_INET6
+#define PR_NetAddrInetPort(addr) \
+ ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port)
+#else
+#define PR_NetAddrInetPort(addr) ((addr)->inet.port)
+#endif
+
+/***********************************************************************
** FUNCTION:
** DESCRIPTION: PR_GetProtoByName()
** Lookup a protocol entry based on protocol's name
diff --git a/pr/include/prshm.h b/pr/include/prshm.h
new file mode 100644
index 00000000..a6d5ff9b
--- /dev/null
+++ b/pr/include/prshm.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** prshm.h -- NSPR Shared Memory
+**
+** NSPR Named Shared Memory API provides a cross-platform named
+** shared-memory interface. NSPR Named Shared Memory is modeled on
+** similar constructs in Unix and Windows operating systems. Shared
+** memory allows multiple processes to access one or more common shared
+** memory regions, using it as an inter-process communication channel.
+**
+** Notes on Platform Independence:
+** NSPR Named Shared Memory is built on the native services offered
+** by most platforms. The NSPR Named Shared Memory API tries to
+** provide a least common denominator interface so that it works
+** across all supported platforms. To ensure that it works everywhere,
+** some platform considerations must be accomodated and the protocol
+** for using NSPR Shared Memory API must be observed.
+**
+** Protocol:
+** Multiple shared memories can be created using NSPR's Shared Memory
+** feature. For each named shared memory, as defined by the name
+** given in the PR_OpenSharedMemory() call, a protocol for using the
+** shared memory API is required to ensure desired behavior. Failing
+** to follow the protocol may yield unpredictable results.
+**
+** PR_OpenSharedMemory() will create the shared memory segment, if it
+** does not already exist, or open a connection that the existing
+** shared memory segment if it already exists.
+**
+** PR_AttachSharedMemory() should be called following
+** PR_OpenSharedMemory() to map the memory segment to an address in
+** the application's address space.
+**
+** PR_AttachSharedMemory() may be called to re-map a shared memory
+** segment after detaching the same PRSharedMemory object. Be
+** sure to detach it when done.
+**
+** PR_DetachSharedMemory() should be called to un-map the shared
+** memory segment from the application's address space.
+**
+** PR_CloseSharedMemory() should be called when no further use of the
+** PRSharedMemory object is required within a process. Following a
+** call to PR_CloseSharedMemory() the PRSharedMemory object is
+** invalid and cannot be reused.
+**
+** PR_DeleteSharedMemory() should be called before process
+** termination. After calling PR_DeleteSharedMemory() any further use
+** of the shared memory associated with the name may cause
+** unpredictable results.
+**
+** Files:
+** The name passed to PR_OpenSharedMemory() should be a valid filename
+** for a unix platform. PR_OpenSharedMemory() creates file using the
+** name passed in. Some platforms may mangle the name before creating
+** the file and the shared memory.
+**
+** The unix implementation may use SysV IPC shared memory, Posix
+** shared memory, or memory mapped files; the filename may used to
+** define the namespace. On Windows, the name is significant, but
+** there is no file associated with name.
+**
+** No assumptions about the persistence of data in the named file
+** should be made. Depending on platform, the shared memory may be
+** mapped onto system paging space and be discarded at process
+** termination.
+**
+** All names provided to PR_OpenSharedMemory() should be valid
+** filename syntax or name syntax for shared memory for the target
+** platform. Referenced directories should have permissions
+** appropriate for writing.
+**
+** Limits:
+** Different platforms have limits on both the number and size of
+** shared memory resources. The default system limits on some
+** platforms may be smaller than your requirements. These limits may
+** be adjusted on some platforms either via boot-time options or by
+** setting the size of the system paging space to accomodate more
+** and/or larger shared memory segment(s).
+**
+** Security:
+** On unix platforms, depending on implementation, contents of the
+** backing store for the shared memory can be exposed via the file
+** system. Set permissions and or access controls at create and attach
+** time to ensure you get the desired security.
+**
+** On windows platforms, no special security measures are provided.
+**
+** Example:
+** The test case pr/tests/nameshm1.c provides an example of use as
+** well as testing the operation of NSPR's Named Shared Memory.
+**
+** lth. 18-Aug-1999.
+*/
+
+#ifndef prshm_h___
+#define prshm_h___
+
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Declare opaque type PRSharedMemory.
+*/
+typedef struct PRSharedMemory PRSharedMemory;
+
+/*
+** FUNCTION: PR_OpenSharedMemory()
+**
+** DESCRIPTION:
+** PR_OpenSharedMemory() creates a new shared-memory segment or
+** associates a previously created memory segment with name.
+**
+** When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the
+** shared memory already exists, the function returns NULL with the
+** error set to PR_FILE_EXISTS_ERROR.
+**
+** When parameter create is PR_SHM_CREATE and the shared memory
+** already exists, a handle to that memory segment is returned. If
+** the segment does not exist, it is created and a pointer to the
+** related PRSharedMemory structure is returned.
+**
+** When parameter create is 0, and the shared memory exists, a
+** pointer to a PRSharedMemory is returned. If the shared memory does
+** not exist, NULL is returned with the error set to
+** PR_FILE_NOT_FOUND_ERROR.
+**
+** INPUTS:
+** name -- the name the shared-memory segment is known as.
+** size -- the size of the shared memory segment.
+** flags -- Options for creating the shared memory
+** mode -- Same as is passed to PR_Open()
+**
+** OUTPUTS:
+** The shared memory is allocated.
+**
+** RETURNS: Pointer to opaque structure PRSharedMemory or NULL.
+** NULL is returned on error. The reason for the error can be
+** retrieved via PR_GetError() and PR_GetOSError();
+**
+*/
+PR_EXTERN( PRSharedMemory * )
+ PR_OpenSharedMemory(
+ const char *name,
+ PRSize size,
+ PRIntn flags,
+ PRIntn mode
+);
+/* Define values for PR_OpenShareMemory(...,create) */
+#define PR_SHM_CREATE 0x1 /* create if not exist */
+#define PR_SHM_EXCL 0x2 /* fail if already exists */
+
+/*
+** FUNCTION: PR_AttachSharedMemory()
+**
+** DESCRIPTION:
+** PR_AttachSharedMemory() maps the shared-memory described by
+** shm to the current process.
+**
+** INPUTS:
+** shm -- The handle returned from PR_OpenSharedMemory().
+** flags -- options for mapping the shared memory.
+** PR_SHM_READONLY causes the memory to be attached
+** read-only.
+**
+** OUTPUTS:
+** On success, the shared memory segment represented by shm is mapped
+** into the process' address space.
+**
+** RETURNS: Address where shared memory is mapped, or NULL.
+** NULL is returned on error. The reason for the error can be
+** retrieved via PR_GetError() and PR_GetOSError();
+**
+**
+*/
+PR_EXTERN( void * )
+ PR_AttachSharedMemory(
+ PRSharedMemory *shm,
+ PRIntn flags
+);
+/* Define values for PR_AttachSharedMemory(...,flags) */
+#define PR_SHM_READONLY 0x01
+
+/*
+** FUNCTION: PR_DetachSharedMemory()
+**
+** DESCRIPTION:
+** PR_DetachSharedMemory() detaches the shared-memory described
+** by shm.
+**
+** INPUTS:
+** shm -- The handle returned from PR_OpenSharedMemory().
+** addr -- The address at which the memory was attached.
+**
+** OUTPUTS:
+** The shared memory mapped to an address via a previous call to
+** PR_AttachSharedMemory() is unmapped.
+**
+** RETURNS: PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+ PR_DetachSharedMemory(
+ PRSharedMemory *shm,
+ void *addr
+);
+
+/*
+** FUNCTION: PR_CloseSharedMemory()
+**
+** DESCRIPTION:
+** PR_CloseSharedMemory() closes the shared-memory described by
+** shm.
+**
+** INPUTS:
+** shm -- The handle returned from PR_OpenSharedMemory().
+**
+** OUTPUTS:
+** the shared memory represented by shm is closed
+**
+** RETURNS: PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+ PR_CloseSharedMemory(
+ PRSharedMemory *shm
+);
+
+/*
+** FUNCTION: PR_DeleteSharedMemory()
+**
+** DESCRIPTION:
+** The shared memory resource represented by name is released.
+**
+** INPUTS:
+** name -- the name the shared-memory segment
+**
+** OUTPUTS:
+** depending on platform, resources may be returned to the underlying
+** operating system.
+**
+** RETURNS: PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+ PR_DeleteSharedMemory(
+ const char *name
+);
+
+PR_END_EXTERN_C
+
+#endif /* prshm_h___ */
diff --git a/pr/include/prshma.h b/pr/include/prshma.h
new file mode 100644
index 00000000..55c0d396
--- /dev/null
+++ b/pr/include/prshma.h
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** prshma.h -- NSPR Anonymous Shared Memory
+**
+** NSPR provides an anonymous shared memory based on NSPR's PRFileMap
+** type. The anonymous file-mapped shared memory provides an inheritable
+** shared memory, as in: the child process inherits the shared memory.
+** Compare the file-mapped anonymous shared memory to to a named shared
+** memory described in prshm.h. The intent is to provide a shared
+** memory that is accessable only by parent and child processes. ...
+** It's a security thing.
+**
+** Depending on the underlying platform, the file-mapped shared memory
+** may be backed by a file. ... surprise! ... On some platforms, no
+** real file backs the shared memory. On platforms where the shared
+** memory is backed by a file, the file's name in the filesystem is
+** visible to other processes for only the duration of the creation of
+** the file, hopefully a very short time. This restricts processess
+** that do not inherit the shared memory from opening the file and
+** reading or writing its contents. Further, when all processes
+** using an anonymous shared memory terminate, the backing file is
+** deleted. ... If you are not paranoid, you're not paying attention.
+**
+** The file-mapped shared memory requires a protocol for the parent
+** process and child process to share the memory. NSPR provides two
+** protocols. Use one or the other; don't mix and match.
+**
+** In the first protocol, the job of passing the inheritable shared
+** memory is done via helper-functions with PR_CreateProcess(). In the
+** second protocol, the parent process is responsible for creating the
+** child process; the parent and child are mutually responsible for
+** passing a FileMap string. NSPR provides helper functions for
+** extracting data from the PRFileMap object. ... See the examples
+** below.
+**
+** Both sides should adhere strictly to the protocol for proper
+** operation. The pseudo-code below shows the use of a file-mapped
+** shared memory by a parent and child processes. In the examples, the
+** server creates the file-mapped shared memory, the client attaches to
+** it.
+**
+** First protocol.
+** Server:
+**
+** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt);
+** addr = PR_MemMap(fm);
+** attr = PR_NewProcessAttr();
+** PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname );
+** PR_CreateProcess(Client);
+** PR_DestroyProcessAttr(attr);
+** ... yadda ...
+** PR_MemUnmap( addr );
+** PR_CloseFileMap(fm);
+**
+**
+** Client:
+** ... started by server via PR_CreateProcess()
+** fm = PR_GetInheritedFileMap( shmname );
+** addr = PR_MemMap(fm);
+** ... yadda ...
+** PR_MemUnmap(addr);
+** PR_CloseFileMap(fm);
+**
+**
+** Second Protocol:
+** Server:
+**
+** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt);
+** fmstring = PR_ExportFileMapAsString( fm );
+** addr = PR_MemMap(fm);
+** ... application specific technique to pass fmstring to child
+** ... yadda ... Server uses his own magic to create child
+** PR_MemUnmap( addr );
+** PR_CloseFileMap(fm);
+**
+**
+** Client:
+** ... started by server via his own magic
+** ... application specific technique to find fmstring from parent
+** fm = PR_ImportFileMapFromString( fmstring )
+** addr = PR_MemMap(fm);
+** ... yadda ...
+** PR_MemUnmap(addr);
+** PR_CloseFileMap(fm);
+**
+**
+** lth. 2-Jul-1999.
+**
+** Note: The second protocol was requested by NelsonB (7/1999); this is
+** to accomodate servers which already create their own child processes
+** using platform native methods.
+**
+*/
+
+#ifndef prshma_h___
+#define prshma_h___
+
+#include "prtypes.h"
+#include "prio.h"
+#include "prproces.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory
+**
+** Description:
+** PR_OpenAnonFileMap() creates an anonymous shared memory. If the
+** shared memory already exists, a handle is returned to that shared
+** memory object.
+**
+** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a
+** directory name, without the trailing '/', to contain the anonymous
+** file. A filename is generated for the name.
+**
+** On Windows platforms, dirName is ignored.
+**
+** Inputs:
+** dirName -- A directory name to contain the anonymous file.
+** size -- The size of the shared memory
+** prot -- How the shared memory is mapped. See prio.h
+**
+** Outputs:
+** PRFileMap *
+**
+** Returns:
+** Pointer to PRFileMap or NULL on error.
+**
+*/
+PR_EXTERN( PRFileMap *)
+PR_OpenAnonFileMap(
+ const char *dirName,
+ PRSize size,
+ PRFileMapProtect prot
+);
+
+/*
+** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export
+** to my children processes via PR_CreateProcess()
+**
+** Description:
+** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to
+** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess()
+** makes the PRFileMap importable by the child process.
+**
+** Inputs:
+** attr -- PRProcessAttr, used to pass data to PR_CreateProcess()
+** fm -- PRFileMap structure to be passed to the child process
+** shmname -- The name for the PRFileMap; used by child.
+**
+** Outputs:
+** PRFileMap *
+**
+** Returns:
+** PRStatus
+**
+*/
+PR_EXTERN(PRStatus)
+PR_ProcessAttrSetInheritableFileMap(
+ PRProcessAttr *attr,
+ PRFileMap *fm,
+ const char *shmname
+);
+
+/*
+** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported
+** by my parent process via PR_CreateProcess()
+**
+** Description:
+** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from
+** its parent process via PR_CreateProcess().
+**
+** Inputs:
+** shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap()
+**
+** Outputs:
+** PRFileMap *
+**
+** Returns:
+** PRFileMap pointer or NULL.
+**
+*/
+PR_EXTERN( PRFileMap *)
+PR_GetInheritedFileMap(
+ const char *shmname
+);
+
+/*
+** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap
+**
+** Description:
+** Creates an identifier, as a string, from a PRFileMap object
+** previously created with PR_OpenAnonFileMap().
+**
+** Inputs:
+** fm -- PRFileMap pointer to be represented as a string.
+** bufsize -- sizeof(buf)
+** buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE
+**
+** Outputs:
+** buf contains the stringized PRFileMap identifier
+**
+** Returns:
+** PRStatus
+**
+*/
+PR_EXTERN( PRStatus )
+PR_ExportFileMapAsString(
+ PRFileMap *fm,
+ PRSize bufsize,
+ char *buf
+);
+#define PR_FILEMAP_STRING_BUFSIZE 128
+
+/*
+** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string
+**
+** Description:
+** PR_ImportFileMapFromString() creates a PRFileMap object from a
+** string previously created by PR_ExportFileMapAsString().
+**
+** Inputs:
+** fmstring -- string created by PR_ExportFileMapAsString()
+**
+** Returns:
+** PRFileMap pointer or NULL.
+**
+*/
+PR_EXTERN( PRFileMap * )
+PR_ImportFileMapFromString(
+ const char *fmstring
+);
+
+PR_END_EXTERN_C
+#endif /* prshma_h___ */
diff --git a/pr/src/Makefile b/pr/src/Makefile
index 3890b5dd..ff1ee292 100644
--- a/pr/src/Makefile
+++ b/pr/src/Makefile
@@ -98,9 +98,6 @@ endif
ifneq ($(OS_RELEASE),V2.0)
OS_LIBS += -lc_r
endif
-ifeq ($(USE_IPV6), 1)
-OS_LIBS += -lip6
-endif
endif
ifeq ($(OS_ARCH),Linux)
@@ -116,7 +113,7 @@ ifeq ($(USE_PTHREADS), 1)
ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE)))
OS_LIBS = -ldce
else
-OS_LIBS = -lpthread
+OS_LIBS = -lpthread -lrt
endif
endif
ifeq ($(PTHREADS_USER), 1)
@@ -171,6 +168,8 @@ OBJS = \
malloc/$(OBJDIR)/prmalloc.$(OBJ_SUFFIX) \
malloc/$(OBJDIR)/prmem.$(OBJ_SUFFIX) \
md/$(OBJDIR)/prosdep.$(OBJ_SUFFIX) \
+ memory/$(OBJDIR)/prshm.$(OBJ_SUFFIX) \
+ memory/$(OBJDIR)/prshma.$(OBJ_SUFFIX) \
memory/$(OBJDIR)/prseg.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/pralarm.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/pratom.$(OBJ_SUFFIX) \
@@ -182,6 +181,7 @@ OBJS = \
misc/$(OBJDIR)/prerrortable.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/prinit.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/prinrval.$(OBJ_SUFFIX) \
+ misc/$(OBJDIR)/pripc.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/prlog2.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/prlong.$(OBJ_SUFFIX) \
misc/$(OBJDIR)/prnetdb.$(OBJ_SUFFIX) \
@@ -202,7 +202,8 @@ OBJS += \
io/$(OBJDIR)/prdir.$(OBJ_SUFFIX) \
io/$(OBJDIR)/prfile.$(OBJ_SUFFIX) \
io/$(OBJDIR)/prio.$(OBJ_SUFFIX) \
- io/$(OBJDIR)/prsocket.$(OBJ_SUFFIX)
+ io/$(OBJDIR)/prsocket.$(OBJ_SUFFIX) \
+ misc/$(OBJDIR)/pripcsem.$(OBJ_SUFFIX)
ifndef USE_BTHREADS
OBJS += \
@@ -283,7 +284,9 @@ OBJS += md/windows/$(OBJDIR)/w95io.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/ntinrval.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/ntsem.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/win32_errors.$(OBJ_SUFFIX) \
+ md/windows/$(OBJDIR)/w32ipcsem.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/w32poll.$(OBJ_SUFFIX) \
+ md/windows/$(OBJDIR)/w32shm.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/w95dllmain.$(OBJ_SUFFIX)
else
ifeq ($(OS_TARGET),OS2)
@@ -306,6 +309,8 @@ OBJS += md/windows/$(OBJDIR)/ntdllmn.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/ntinrval.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/ntsem.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/win32_errors.$(OBJ_SUFFIX) \
+ md/windows/$(OBJDIR)/w32ipcsem.$(OBJ_SUFFIX) \
+ md/windows/$(OBJDIR)/w32shm.$(OBJ_SUFFIX) \
md/windows/$(OBJDIR)/w32poll.$(OBJ_SUFFIX)
endif
endif
diff --git a/pr/src/io/prfdcach.c b/pr/src/io/prfdcach.c
index 53f91935..64f164b8 100644
--- a/pr/src/io/prfdcach.c
+++ b/pr/src/io/prfdcach.c
@@ -116,14 +116,14 @@ finished:
fd->dtor = NULL;
fd->lower = fd->higher = NULL;
fd->identity = PR_NSPR_IO_LAYER;
- memset(fd->secret, 0, sizeof(PRFilePrivate));
+ memset(fd->secret, 0, PRFILEPRIVATE_SIZE);
return fd;
allocate:
fd = PR_NEW(PRFileDesc);
if (NULL != fd)
{
- fd->secret = PR_NEW(PRFilePrivate);
+ fd->secret = (PRFilePrivate *) PR_MALLOC(PRFILEPRIVATE_SIZE);
if (NULL == fd->secret) PR_DELETE(fd);
}
if (NULL != fd) goto finished;
diff --git a/pr/src/io/prlayer.c b/pr/src/io/prlayer.c
index d9f66174..43060295 100644
--- a/pr/src/io/prlayer.c
+++ b/pr/src/io/prlayer.c
@@ -443,8 +443,8 @@ PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
fd->lower = insert;
fd->higher = insert->higher;
- insert->higher = fd;
insert->higher->lower = fd;
+ insert->higher = fd;
}
return PR_SUCCESS;
diff --git a/pr/src/io/prlog.c b/pr/src/io/prlog.c
index 24dbfdde..9f13e44b 100644
--- a/pr/src/io/prlog.c
+++ b/pr/src/io/prlog.c
@@ -82,7 +82,7 @@ static PRLock *_pr_logLock;
/* Macros used to reduce #ifdef pollution */
#if defined(_PR_USE_STDIO_FOR_LOGGING)
-#define _PUT_LOG(fd, buf, nb) fputs(buf, fd)
+#define _PUT_LOG(fd, buf, nb) {fputs(buf, fd); fflush(fd);}
#elif defined(_PR_PTHREADS)
#define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
#elif defined(XP_MAC)
@@ -199,19 +199,6 @@ void _PR_InitLog(void)
}
lm = lm->next;
}
- if (( PR_FALSE == skip_modcheck) && (NULL == lm)) {
-#ifdef XP_PC
- char* str = PR_smprintf("Unrecognized NSPR_LOG_MODULE: %s=%d\n",
- module, level);
- if (str) {
- OutputDebugString(str);
- PR_smprintf_free(str);
- }
-#else
- fprintf(stderr, "Unrecognized NSPR_LOG_MODULE: %s=%d\n",
- module, level);
-#endif
- }
}
/*found:*/
count = sscanf(&ev[pos], " , %n", &delta);
diff --git a/pr/src/io/prmwait.c b/pr/src/io/prmwait.c
index a3bd1576..4843e7ba 100644
--- a/pr/src/io/prmwait.c
+++ b/pr/src/io/prmwait.c
@@ -176,6 +176,7 @@ static PRStatus TimerInit(void)
{
goto failed;
}
+ PR_INIT_CLIST(&tm_vars.timer_queue);
tm_vars.manager_thread = PR_CreateThread(
PR_SYSTEM_THREAD, TimerManager, NULL, PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0);
@@ -183,7 +184,6 @@ static PRStatus TimerInit(void)
{
goto failed;
}
- PR_INIT_CLIST(&tm_vars.timer_queue);
return PR_SUCCESS;
failed:
diff --git a/pr/src/io/prpolevt.c b/pr/src/io/prpolevt.c
index 5151afd1..589c0a77 100644
--- a/pr/src/io/prpolevt.c
+++ b/pr/src/io/prpolevt.c
@@ -21,16 +21,99 @@
*
* Pollable events
*
+ * Pollable events are implemented using layered I/O. The only
+ * I/O methods that are implemented for pollable events are poll
+ * and close. No other methods can be invoked on a pollable
+ * event.
+ *
+ * A pipe or socket pair is created and the pollable event layer
+ * is pushed onto the read end. A pointer to the write end is
+ * saved in the PRFilePrivate structure of the pollable event.
+ *
*********************************************************************
*/
-#include "primpl.h"
+#include "prinit.h"
+#include "prio.h"
+#include "prmem.h"
+#include "prerror.h"
+#include "prlog.h"
+
+/*
+ * These internal functions are declared in primpl.h,
+ * but we can't include primpl.h because the definition
+ * of struct PRFilePrivate in this file (for the pollable
+ * event layer) will conflict with the definition of
+ * struct PRFilePrivate in primpl.h (for the NSPR layer).
+ */
+extern PRIntn _PR_InvalidInt(void);
+extern PRInt64 _PR_InvalidInt64(void);
+extern PRStatus _PR_InvalidStatus(void);
+extern PRFileDesc *_PR_InvalidDesc(void);
-typedef struct MyFilePrivate {
- PRFilePrivate copy;
- PRFileDesc *writeEnd;
- PRFilePrivate *oldSecret;
-} MyFilePrivate;
+/*
+ * PRFilePrivate structure for the NSPR pollable events layer
+ */
+struct PRFilePrivate {
+ PRFileDesc *writeEnd; /* the write end of the pipe/socketpair */
+};
+
+static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd);
+
+static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
+ PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
+
+static PRIOMethods _pr_polevt_methods = {
+ PR_DESC_LAYERED,
+ _pr_PolEvtClose,
+ (PRReadFN)_PR_InvalidInt,
+ (PRWriteFN)_PR_InvalidInt,
+ (PRAvailableFN)_PR_InvalidInt,
+ (PRAvailable64FN)_PR_InvalidInt64,
+ (PRFsyncFN)_PR_InvalidStatus,
+ (PRSeekFN)_PR_InvalidInt,
+ (PRSeek64FN)_PR_InvalidInt64,
+ (PRFileInfoFN)_PR_InvalidStatus,
+ (PRFileInfo64FN)_PR_InvalidStatus,
+ (PRWritevFN)_PR_InvalidInt,
+ (PRConnectFN)_PR_InvalidStatus,
+ (PRAcceptFN)_PR_InvalidDesc,
+ (PRBindFN)_PR_InvalidStatus,
+ (PRListenFN)_PR_InvalidStatus,
+ (PRShutdownFN)_PR_InvalidStatus,
+ (PRRecvFN)_PR_InvalidInt,
+ (PRSendFN)_PR_InvalidInt,
+ (PRRecvfromFN)_PR_InvalidInt,
+ (PRSendtoFN)_PR_InvalidInt,
+ _pr_PolEvtPoll,
+ (PRAcceptreadFN)_PR_InvalidInt,
+ (PRTransmitfileFN)_PR_InvalidInt,
+ (PRGetsocknameFN)_PR_InvalidStatus,
+ (PRGetpeernameFN)_PR_InvalidStatus,
+ (PRGetsockoptFN)_PR_InvalidStatus,
+ (PRSetsockoptFN)_PR_InvalidStatus,
+ (PRGetsocketoptionFN)_PR_InvalidStatus,
+ (PRSetsocketoptionFN)_PR_InvalidStatus
+};
+
+static PRDescIdentity _pr_polevt_id;
+static PRCallOnceType _pr_polevt_once_control;
+static PRStatus PR_CALLBACK _pr_PolEvtInit(void);
+
+static PRInt16 PR_CALLBACK _pr_PolEvtPoll(
+ PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+ return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags);
+}
+
+static PRStatus PR_CALLBACK _pr_PolEvtInit(void)
+{
+ _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events");
+ if (PR_INVALID_IO_LAYER == _pr_polevt_id) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
#if !defined(XP_UNIX) || defined(VMS)
#define USE_TCP_SOCKETPAIR
@@ -38,11 +121,21 @@ typedef struct MyFilePrivate {
PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
{
+ PRFileDesc *event;
PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */
- MyFilePrivate *secret;
- secret = PR_NEW(MyFilePrivate);
- if (secret == NULL) {
+ fd[0] = fd[1] = NULL;
+
+ if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) {
+ return NULL;
+ }
+
+ event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods);
+ if (NULL == event) {
+ goto errorExit;
+ }
+ event->secret = PR_NEW(PRFilePrivate);
+ if (event->secret == NULL) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
goto errorExit;
}
@@ -57,38 +150,48 @@ PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
}
#endif
- secret->copy = *fd[0]->secret;
- secret->oldSecret = fd[0]->secret;
- secret->writeEnd = fd[1];
- fd[0]->secret = (PRFilePrivate *) secret;
+ event->secret->writeEnd = fd[1];
+ if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) {
+ goto errorExit;
+ }
return fd[0];
errorExit:
- PR_DELETE(secret);
+ if (fd[0]) {
+ PR_Close(fd[0]);
+ PR_Close(fd[1]);
+ }
+ if (event) {
+ PR_DELETE(event->secret);
+ event->dtor(event);
+ }
return NULL;
}
-PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
+static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd)
{
- MyFilePrivate *secret;
-
- secret = (MyFilePrivate *) event->secret;
- event->secret = secret->oldSecret;
- PR_Close(event);
- PR_Close(secret->writeEnd);
- PR_DELETE(secret);
+ PRFileDesc *event;
+
+ event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
+ PR_ASSERT(NULL == event->higher && NULL == event->lower);
+ PR_Close(fd);
+ PR_Close(event->secret->writeEnd);
+ PR_DELETE(event->secret);
+ event->dtor(event);
return PR_SUCCESS;
}
+PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
+{
+ return PR_Close(event);
+}
+
static const char magicChar = '\x38';
PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
{
- MyFilePrivate *secret;
-
- secret = (MyFilePrivate *) event->secret;
- if (PR_Write(secret->writeEnd, &magicChar, 1) != 1) {
+ if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) {
return PR_FAILURE;
}
return PR_SUCCESS;
@@ -102,7 +205,7 @@ PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
PRIntn i;
#endif
- nBytes = PR_Read(event, buf, sizeof(buf));
+ nBytes = PR_Read(event->lower, buf, sizeof(buf));
if (nBytes == -1) {
return PR_FAILURE;
}
diff --git a/pr/src/io/prsocket.c b/pr/src/io/prsocket.c
index 2f599d8a..5ebd6248 100644
--- a/pr/src/io/prsocket.c
+++ b/pr/src/io/prsocket.c
@@ -856,49 +856,17 @@ static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
PRIntervalTime timeout)
{
- PRInt32 rv;
- PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRSendFileData sfd;
- if (_PR_PENDING_INTERRUPT(me)) {
- me->flags &= ~_PR_INTERRUPT;
- PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
- return -1;
- }
- if (_PR_IO_PENDING(me)) {
- PR_SetError(PR_IO_PENDING_ERROR, 0);
- return -1;
- }
- /* The socket must be in blocking mode. */
- if (sd->secret->nonblocking) {
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return -1;
- }
-#if defined(WINNT)
- rv = _PR_MD_TRANSMITFILE(
- sd, fd,
- headers, hlen, flags, timeout);
- if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
- /*
- * This should be kept the same as SocketClose, except
- * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
- * not be called because the socket will be recycled.
- */
- PR_FreeFileDesc(sd);
- }
-#else
-#if defined(XP_UNIX)
- /*
- * On HPUX11, we could call _PR_HPUXTransmitFile(), but that
- * would require that we not override the malloc() functions.
- */
- rv = _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
-#else /* XP_UNIX */
- rv = _PR_EmulateTransmitFile(sd, fd, headers, hlen, flags,
- timeout);
-#endif /* XP_UNIX */
-#endif /* WINNT */
+ sfd.fd = fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ sfd.header = headers;
+ sfd.hlen = hlen;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
- return rv;
+ return(PR_SendFile(sd, &sfd, flags, timeout));
}
static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
@@ -1245,6 +1213,16 @@ PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
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
@@ -1452,10 +1430,11 @@ PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
}
/*
- * _PR_EmulateTransmitFile
+ * _PR_EmulateSendFile
*
- * Send file fd across socket sd. If headers is non-NULL, 'hlen'
- * bytes of headers is sent before sending the file.
+ * Send file sfd->fd across socket sd. The header and trailer buffers
+ * specified in the 'sfd' argument are sent before and after the file,
+ * respectively.
*
* PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
*
@@ -1463,15 +1442,18 @@ PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
*
*/
-PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
-const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-PRIntervalTime timeout)
+PRInt32 _PR_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+PRTransmitFileFlags flags, PRIntervalTime timeout)
{
PRInt32 rv, count = 0;
PRInt32 rlen;
+ const void *buffer;
+ PRInt32 buflen;
+ PRInt32 sendbytes, readbytes;
PRThread *me = _PR_MD_CURRENT_THREAD();
char *buf = NULL;
-#define _TRANSMITFILE_BUFSIZE (16 * 1024)
+
+#define _SENDFILE_BUFSIZE (16 * 1024)
if (_PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
@@ -1479,62 +1461,120 @@ PRIntervalTime timeout)
return -1;
}
- buf = (char*)PR_MALLOC(_TRANSMITFILE_BUFSIZE);
+ buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE);
if (buf == NULL) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return -1;
}
/*
- * send headers, first
+ * send header, first
*/
- while (hlen) {
- rv = PR_Send(sd, headers, hlen, 0, timeout);
+ buflen = sfd->hlen;
+ buffer = sfd->header;
+ while (buflen) {
+ rv = PR_Send(sd, buffer, buflen, 0, timeout);
if (rv < 0) {
/* PR_Send() has invoked PR_SetError(). */
rv = -1;
goto done;
} else {
count += rv;
- headers = (const void*) ((const char*)headers + rv);
- hlen -= rv;
+ buffer = (const void*) ((const char*)buffer + rv);
+ buflen -= rv;
}
}
/*
* send file, next
*/
- while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) {
- while (rlen) {
- char *bufptr = buf;
-
- rv = PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT);
- if (rv < 0) {
- /* PR_Send() has invoked PR_SetError(). */
- rv = -1;
- goto done;
- } else {
- count += rv;
- bufptr = ((char*)bufptr + rv);
- rlen -= rv;
+
+ if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) {
+ rv = -1;
+ goto done;
+ }
+ sendbytes = sfd->file_nbytes;
+ if (sendbytes == 0) {
+ /* send entire file */
+ while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) {
+ while (rlen) {
+ char *bufptr = buf;
+
+ rv = PR_Send(sd, bufptr, rlen, 0, timeout);
+ if (rv < 0) {
+ /* PR_Send() has invoked PR_SetError(). */
+ rv = -1;
+ goto done;
+ } else {
+ count += rv;
+ bufptr = ((char*)bufptr + rv);
+ rlen -= rv;
+ }
}
}
- }
- if (rlen == 0) {
- /*
- * end-of-file
- */
- if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
- PR_Close(sd);
- rv = count;
+ if (rlen < 0) {
+ /* PR_Read() has invoked PR_SetError(). */
+ rv = -1;
+ goto done;
+ }
} else {
- PR_ASSERT(rlen < 0);
- /* PR_Read() has invoked PR_SetError(). */
- rv = -1;
+ readbytes = sendbytes > _SENDFILE_BUFSIZE ? _SENDFILE_BUFSIZE :
+ sendbytes;
+ while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) {
+ while (rlen) {
+ char *bufptr = buf;
+
+ rv = PR_Send(sd, bufptr, rlen, 0, timeout);
+ if (rv < 0) {
+ /* PR_Send() has invoked PR_SetError(). */
+ rv = -1;
+ goto done;
+ } else {
+ count += rv;
+ sendbytes -= rv;
+ bufptr = ((char*)bufptr + rv);
+ rlen -= rv;
+ }
+ }
+ readbytes = sendbytes > _SENDFILE_BUFSIZE ?
+ _SENDFILE_BUFSIZE : sendbytes;
+ }
+ if (rlen < 0) {
+ /* PR_Read() has invoked PR_SetError(). */
+ rv = -1;
+ goto done;
+ } else if (sendbytes != 0) {
+ /*
+ * there are fewer bytes in file to send than specified
+ */
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ rv = -1;
+ goto done;
+ }
}
+ /*
+ * send trailer, last
+ */
+ buflen = sfd->tlen;
+ buffer = sfd->trailer;
+ while (buflen) {
+ rv = PR_Send(sd, buffer, buflen, 0, timeout);
+ if (rv < 0) {
+ /* PR_Send() has invoked PR_SetError(). */
+ rv = -1;
+ goto done;
+ } else {
+ count += rv;
+ buffer = (const void*) ((const char*)buffer + rv);
+ buflen -= rv;
+ }
+ }
+ rv = count;
done:
if (buf)
PR_DELETE(buf);
+ if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
+ PR_Close(sd);
return rv;
}
@@ -1830,3 +1870,45 @@ out_of_memory:
#endif /* !defined(NEED_SELECT) */
}
+
+PR_IMPLEMENT(PRInt32) PR_SendFile(
+ PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ PRInt32 rv;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ return -1;
+ }
+ if (_PR_IO_PENDING(me)) {
+ PR_SetError(PR_IO_PENDING_ERROR, 0);
+ return -1;
+ }
+ /* The socket must be in blocking mode. */
+ if (sd->secret->nonblocking) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+#if defined(WINNT)
+ rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
+ if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
+ /*
+ * This should be kept the same as SocketClose, except
+ * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
+ * not be called because the socket will be recycled.
+ */
+ PR_FreeFileDesc(sd);
+ }
+#else
+#if defined(XP_UNIX)
+ rv = _PR_UnixSendFile(sd, sfd, flags, timeout);
+#else /* XP_UNIX */
+ rv = _PR_EmulateSendFile(sd, sfd, flags, timeout);
+#endif /* XP_UNIX */
+#endif /* WINNT */
+
+ return rv;
+}
diff --git a/pr/src/md/beos/bnet.c b/pr/src/md/beos/bnet.c
index fdc9f18c..cf7ca73a 100644
--- a/pr/src/md/beos/bnet.c
+++ b/pr/src/md/beos/bnet.c
@@ -577,12 +577,6 @@ _MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
}
PRInt32
-_MD_transmitfile (PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen, PRInt32 flags, PRIntervalTime timeout)
-{
- return PR_NOT_IMPLEMENTED_ERROR;
-}
-
-PRInt32
_MD_socket (int af, int type, int flags)
{
PRInt32 osfd, err;
diff --git a/pr/src/md/unix/Makefile b/pr/src/md/unix/Makefile
index b38c9e6a..9a36af8f 100644
--- a/pr/src/md/unix/Makefile
+++ b/pr/src/md/unix/Makefile
@@ -32,6 +32,7 @@ CSRCS = \
uxproces.c \
uxwrap.c \
uxpoll.c \
+ uxshm.c \
$(NULL)
PTH_USER_CSRCS = \
@@ -225,6 +226,9 @@ ifeq ($(OS_ARCH),SunOS)
ifneq ($(OS_RELEASE),4.1.3_U1)
ifneq ($(LOCAL_THREADS_ONLY),1)
ASFILES = os_$(OS_ARCH).s
+ ifneq ($(USE_64),1)
+ ASFILES += os_$(OS_ARCH)_32.s
+ endif
endif
endif
endif
@@ -288,8 +292,15 @@ $(SHARED_LIBRARY): $(ULTRASPARC_ASOBJS)
$(INSTALL) -m 444 $(SHARED_LIBRARY) $(DIST)/lib
$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES)
+ifeq ($(USE_64),1)
+ /usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v9 $<
+else
/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $<
endif
+
+clean::
+ rm -rf $(ULTRASPARC_ASOBJS)
+endif
endif
endif
diff --git a/pr/src/md/unix/aix.c b/pr/src/md/unix/aix.c
index 0970ff81..b9409590 100644
--- a/pr/src/md/unix/aix.c
+++ b/pr/src/md/unix/aix.c
@@ -81,10 +81,12 @@ PRIntervalTime _MD_AixIntervalPerSec(void)
#include <dlfcn.h>
int (*_PT_aix_yield_fcn)() = NULL;
+int _pr_aix_send_file_use_disabled = 0;
void _MD_EarlyInit(void)
{
void *main_app_handle;
+ char *evp;
main_app_handle = dlopen(NULL, RTLD_NOW);
PR_ASSERT(NULL != main_app_handle);
@@ -96,6 +98,11 @@ void _MD_EarlyInit(void)
}
dlclose(main_app_handle);
+ if (evp = getenv("NSPR_AIX_SEND_FILE_USE_DISABLED")) {
+ if (1 == atoi(evp))
+ _pr_aix_send_file_use_disabled = 1;
+ }
+
#if defined(AIX_TIMERS)
_MD_AixIntervalInit();
#endif
diff --git a/pr/src/md/unix/objs.mk b/pr/src/md/unix/objs.mk
index 6ca4ca52..951d76b8 100644
--- a/pr/src/md/unix/objs.mk
+++ b/pr/src/md/unix/objs.mk
@@ -22,6 +22,7 @@ CSRCS = \
unix.c \
unix_errors.c \
uxproces.c \
+ uxshm.c \
uxwrap.c \
uxpoll.c \
$(NULL)
@@ -217,6 +218,9 @@ ifeq ($(OS_ARCH),SunOS)
ifneq ($(OS_RELEASE),4.1.3_U1)
ifneq ($(LOCAL_THREADS_ONLY),1)
ASFILES = os_$(OS_ARCH).s
+ ifneq ($(USE_64),1)
+ ASFILES += os_$(OS_ARCH)_32.s
+ endif
endif
endif
endif
diff --git a/pr/src/md/unix/os_Irix.s b/pr/src/md/unix/os_Irix.s
index 3296e419..277a00cd 100644
--- a/pr/src/md/unix/os_Irix.s
+++ b/pr/src/md/unix/os_Irix.s
@@ -47,6 +47,34 @@ retry_push:
sw v0,0(a1)
sync
sw t0,0(a0)
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
jr ra
nop
@@ -68,11 +96,13 @@ retry_pop:
lw v0,0(a0)
li t1,1
beq v0,0,done
+ nop
beq v0,t1,retry_pop
nop
ll v0,0(a0)
beq v0,0,done
+ nop
beq v0,t1,retry_pop
nop
sc t1,0(a0)
@@ -81,6 +111,34 @@ retry_pop:
lw t0,0(v0)
sw t0,0(a0)
done:
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
jr ra
nop
diff --git a/pr/src/md/unix/os_SunOS.s b/pr/src/md/unix/os_SunOS.s
index 0e6dab73..514cd8f5 100644
--- a/pr/src/md/unix/os_SunOS.s
+++ b/pr/src/md/unix/os_SunOS.s
@@ -49,86 +49,3 @@ _MD_FlushRegisterWindows:
ret
restore
-! ======================================================================
-!
-! Atomically add a new element to the top of the stack
-!
-! usage : PR_StackPush(listp, elementp);
-!
-! -----------------------
-! Note on REGISTER USAGE:
-! as this is a LEAF procedure, a new stack frame is not created.
-!
-! So, the registers used are:
-! %o0 [input] - the address of the stack
-! %o1 [input] - the address of the element to be added to the stack
-! -----------------------
-
- .section ".text"
- .global PR_StackPush
-
-PR_StackPush:
-
-pulock: ld [%o0],%o3 !
- cmp %o3,-1 ! check if stack is locked
- be pulock ! loop, if locked
- mov -1,%o3 ! use delay-slot
- swap [%o0],%o3 ! atomically lock the stack and get
- ! the pointer to stack head
- cmp %o3,-1 ! check, if the stack is locked
- be pulock ! loop, if so
- nop
- st %o3,[%o1]
- retl ! return back to the caller
- st %o1,[%o0] !
-
- .size PR_StackPush,(.-PR_StackPush)
-
-
-! end
-! ======================================================================
-
-! ======================================================================
-!
-! Atomically remove the element at the top of the stack
-!
-! usage : elemep = PR_StackPop(listp);
-!
-! -----------------------
-! Note on REGISTER USAGE:
-! as this is a LEAF procedure, a new stack frame is not created.
-!
-! So, the registers used are:
-! %o0 [input] - the address of the stack
-! %o1 [input] - work register (top element)
-! -----------------------
-
- .section ".text"
- .global PR_StackPop
-
-PR_StackPop:
-
-polock: ld [%o0],%o1 !
- cmp %o1,-1 ! check if stack is locked
- be polock ! loop, if locked
- mov -1,%o1 ! use delay-slot
- swap [%o0],%o1 ! atomically lock the stack and get
- ! the pointer to stack head
- cmp %o1,-1 ! check, if the stack is locked
- be polock ! loop, if so
- nop
- tst %o1 ! test for empty stack
- be,a empty ! is empty
- st %g0,[%o0]
- ld [%o1], %o2 ! load the second element
- st %o2,[%o0] ! set stack head to second
- st %g0,[%o1] ! reset the next pointer; for
- ! debugging
-empty:
- retl ! return back to the caller
- mov %o1, %o0 ! return the first element
-
- .size PR_StackPop,(.-PR_StackPop)
-
-! end
-! ======================================================================
diff --git a/pr/src/md/unix/os_SunOS_32.s b/pr/src/md/unix/os_SunOS_32.s
new file mode 100644
index 00000000..96f18103
--- /dev/null
+++ b/pr/src/md/unix/os_SunOS_32.s
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+! ======================================================================
+!
+! Atomically add a new element to the top of the stack
+!
+! usage : PR_StackPush(listp, elementp);
+!
+! -----------------------
+! Note on REGISTER USAGE:
+! as this is a LEAF procedure, a new stack frame is not created.
+!
+! So, the registers used are:
+! %o0 [input] - the address of the stack
+! %o1 [input] - the address of the element to be added to the stack
+! -----------------------
+
+ .section ".text"
+ .global PR_StackPush
+
+PR_StackPush:
+
+pulock: ld [%o0],%o3 !
+ cmp %o3,-1 ! check if stack is locked
+ be pulock ! loop, if locked
+ mov -1,%o3 ! use delay-slot
+ swap [%o0],%o3 ! atomically lock the stack and get
+ ! the pointer to stack head
+ cmp %o3,-1 ! check, if the stack is locked
+ be pulock ! loop, if so
+ nop
+ st %o3,[%o1]
+ retl ! return back to the caller
+ st %o1,[%o0] !
+
+ .size PR_StackPush,(.-PR_StackPush)
+
+
+! end
+! ======================================================================
+
+! ======================================================================
+!
+! Atomically remove the element at the top of the stack
+!
+! usage : elemep = PR_StackPop(listp);
+!
+! -----------------------
+! Note on REGISTER USAGE:
+! as this is a LEAF procedure, a new stack frame is not created.
+!
+! So, the registers used are:
+! %o0 [input] - the address of the stack
+! %o1 [input] - work register (top element)
+! -----------------------
+
+ .section ".text"
+ .global PR_StackPop
+
+PR_StackPop:
+
+polock: ld [%o0],%o1 !
+ cmp %o1,-1 ! check if stack is locked
+ be polock ! loop, if locked
+ mov -1,%o1 ! use delay-slot
+ swap [%o0],%o1 ! atomically lock the stack and get
+ ! the pointer to stack head
+ cmp %o1,-1 ! check, if the stack is locked
+ be polock ! loop, if so
+ nop
+ tst %o1 ! test for empty stack
+ be,a empty ! is empty
+ st %g0,[%o0]
+ ld [%o1], %o2 ! load the second element
+ st %o2,[%o0] ! set stack head to second
+ st %g0,[%o1] ! reset the next pointer; for
+ ! debugging
+empty:
+ retl ! return back to the caller
+ mov %o1, %o0 ! return the first element
+
+ .size PR_StackPop,(.-PR_StackPop)
+
+! end
+! ======================================================================
diff --git a/pr/src/md/unix/unix.c b/pr/src/md/unix/unix.c
index 4eb75d1b..fd871585 100644
--- a/pr/src/md/unix/unix.c
+++ b/pr/src/md/unix/unix.c
@@ -2139,7 +2139,20 @@ void _MD_UnblockClockInterrupts()
void _MD_InitFileDesc(PRFileDesc *fd)
{
/* By default, a Unix fd is not closed on exec. */
- PR_ASSERT(0 == fcntl(fd->secret->md.osfd, F_GETFD, 0));
+#ifdef DEBUG
+ {
+ int flags;
+
+ /*
+ * Ignore EBADF error on fd's 0, 1, 2 because they are
+ * not open in all processes.
+ */
+ flags = fcntl(fd->secret->md.osfd, F_GETFD, 0);
+ PR_ASSERT((0 == flags) || (-1 == flags
+ && (0 <= fd->secret->md.osfd && fd->secret->md.osfd <= 2)
+ && errno == EBADF));
+ }
+#endif
fd->secret->inheritable = PR_TRUE;
}
@@ -2918,107 +2931,160 @@ PRIntervalTime _PR_UNIX_TicksPerSecond()
}
/*
- * _PR_UnixTransmitFile
+ * _PR_UnixSendFile
*
- * Send file fd across socket sd. If headers is non-NULL, 'hlen'
- * bytes of headers is sent before sending the file.
+ * Send file sfd->fd across socket sd. If header/trailer are specified
+ * they are sent before and after the file, respectively.
*
* PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
*
* return number of bytes sent or -1 on error
*
*/
-#define TRANSMITFILE_MMAP_CHUNK (256 * 1024)
-PR_IMPLEMENT(PRInt32) _PR_UnixTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
-const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
-PRIntervalTime timeout)
+#define SENDFILE_MMAP_CHUNK (256 * 1024)
+
+PR_IMPLEMENT(PRInt32) _PR_UnixSendFile(PRFileDesc *sd,
+PRSendFileData *sfd,
+PRTransmitFileFlags flags, PRIntervalTime timeout)
{
PRInt32 rv, count = 0;
- PRInt32 len, index = 0;
+ PRInt32 len, file_bytes, index = 0;
struct stat statbuf;
- struct PRIOVec iov[2];
+ struct PRIOVec iov[3];
void *addr;
- PRInt32 err;
+ PRUint32 file_mmap_offset, pagesize;
+ PRUint32 addr_offset, mmap_len;
/* Get file size */
- if (fstat(fd->secret->md.osfd, &statbuf) == -1) {
- err = _MD_ERRNO();
- switch (err) {
- case EBADF:
- PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
- break;
- case EFAULT:
- PR_SetError(PR_ACCESS_FAULT_ERROR, err);
- break;
- case EINTR:
- PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
- break;
- case ETIMEDOUT:
-#ifdef ENOLINK
- case ENOLINK:
-#endif
- PR_SetError(PR_REMOTE_FILE_ERROR, err);
- break;
- default:
- PR_SetError(PR_UNKNOWN_ERROR, err);
- break;
- }
+ if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
+ _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO());
count = -1;
goto done;
}
- /*
- * If the file is large, mmap and send the file in chunks so as
- * to not consume too much virtual address space
- */
- len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size :
- TRANSMITFILE_MMAP_CHUNK;
- /*
- * Map in (part of) file. Take care of zero-length files.
- */
- if (len) {
- addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE,
- fd->secret->md.osfd, 0);
+ if (sfd->file_nbytes && (statbuf.st_size <
+ (sfd->file_offset + sfd->file_nbytes))) {
+ /*
+ * there are fewer bytes in file to send than specified
+ */
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ count = -1;
+ goto done;
+ }
+ if (sfd->file_nbytes)
+ file_bytes = sfd->file_nbytes;
+ else
+ file_bytes = statbuf.st_size - sfd->file_offset;
+
+ pagesize = PR_GetPageSize();
+ /*
+ * If the file is large, mmap and send the file in chunks so as
+ * to not consume too much virtual address space
+ */
+ if ((sfd->file_offset == 0) ||
+ (sfd->file_offset & (pagesize - 1) == 0)) {
+ /*
+ * case 1: page-aligned file offset
+ */
+ mmap_len = file_bytes < SENDFILE_MMAP_CHUNK ? file_bytes :
+ SENDFILE_MMAP_CHUNK;
+
+ len = mmap_len;
+ file_mmap_offset = sfd->file_offset;
+ addr_offset = 0;
+ } else {
+ /*
+ * case 2: non page-aligned file offset
+ */
+ /* find previous page boundary */
+ file_mmap_offset = (sfd->file_offset & ~(pagesize - 1));
+
+ /* number of initial bytes to skip in mmap'd segment */
+ addr_offset = sfd->file_offset - file_mmap_offset;
+ PR_ASSERT(addr_offset > 0);
+ mmap_len = (file_bytes + addr_offset) < SENDFILE_MMAP_CHUNK ?
+ (file_bytes + addr_offset) : SENDFILE_MMAP_CHUNK;
+ len = mmap_len - addr_offset;
+ }
+ /*
+ * Map in (part of) file. Take care of zero-length files.
+ */
+ if (len) {
+#ifdef OSF1
+ /*
+ * Use MAP_SHARED to work around a bug in OSF1 that results in
+ * corrupted data in the memory-mapped region
+ */
+ addr = mmap((caddr_t) 0, mmap_len, PROT_READ, MAP_SHARED,
+ sfd->fd->secret->md.osfd, file_mmap_offset);
+#else
+ addr = mmap((caddr_t) 0, mmap_len, PROT_READ, MAP_PRIVATE,
+ sfd->fd->secret->md.osfd, file_mmap_offset);
+#endif
- if (addr == (void*)-1) {
- _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
- count = -1;
- goto done;
- }
- }
- /*
- * send headers, first, followed by the file
- */
- if (hlen) {
- iov[index].iov_base = (char *) headers;
- iov[index].iov_len = hlen;
- index++;
- }
- iov[index].iov_base = (char*)addr;
- iov[index].iov_len = len;
- index++;
- rv = PR_Writev(sd, iov, index, timeout);
- if (len)
- munmap(addr,len);
- if (rv >= 0) {
- PR_ASSERT(rv == hlen + len);
- statbuf.st_size -= len;
- count += rv;
- } else {
- count = -1;
- goto done;
- }
+ if (addr == (void*)-1) {
+ _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
+ count = -1;
+ goto done;
+ }
+ }
+ /*
+ * send headers, first, followed by the file
+ */
+ if (sfd->hlen) {
+ iov[index].iov_base = (char *) sfd->header;
+ iov[index].iov_len = sfd->hlen;
+ index++;
+ }
+ if (len) {
+ iov[index].iov_base = (char*)addr + addr_offset;
+ iov[index].iov_len = len;
+ index++;
+ }
+ if ((file_bytes == len) && (sfd->tlen)) {
+ /*
+ * all file data is mapped in; send the trailer too
+ */
+ iov[index].iov_base = (char *) sfd->trailer;
+ iov[index].iov_len = sfd->tlen;
+ index++;
+ }
+ rv = PR_Writev(sd, iov, index, timeout);
+ if (len)
+ munmap(addr,mmap_len);
+ if (rv >= 0) {
+ PR_ASSERT((len == file_bytes) || (rv == sfd->hlen + len));
+ PR_ASSERT((len != file_bytes) ||
+ (rv == sfd->hlen + len + sfd->tlen));
+ file_bytes -= len;
+ count += rv;
+ if (0 == file_bytes) /* header, file and trailer are sent */
+ goto done;
+ } else {
+ count = -1;
+ goto done;
+ }
/*
* send remaining bytes of the file, if any
*/
- len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ? statbuf.st_size :
- TRANSMITFILE_MMAP_CHUNK;
+ len = file_bytes < SENDFILE_MMAP_CHUNK ? file_bytes :
+ SENDFILE_MMAP_CHUNK;
while (len > 0) {
/*
* Map in (part of) file
*/
- PR_ASSERT((count - hlen) % TRANSMITFILE_MMAP_CHUNK == 0);
+ file_mmap_offset = sfd->file_offset + count - sfd->hlen;
+ PR_ASSERT((file_mmap_offset % pagesize) == 0);
+#ifdef OSF1
+ /*
+ * Use MAP_SHARED to work around a bug in OSF1 that results in
+ * corrupted data in the memory-mapped region
+ */
+ addr = mmap((caddr_t) 0, len, PROT_READ, MAP_SHARED,
+ sfd->fd->secret->md.osfd, file_mmap_offset);
+#else
addr = mmap((caddr_t) 0, len, PROT_READ, MAP_PRIVATE,
- fd->secret->md.osfd, count - hlen);
+ sfd->fd->secret->md.osfd, file_mmap_offset);
+#endif
if (addr == (void*)-1) {
_PR_MD_MAP_MMAP_ERROR(_MD_ERRNO());
@@ -3029,15 +3095,24 @@ PRIntervalTime timeout)
munmap(addr,len);
if (rv >= 0) {
PR_ASSERT(rv == len);
- statbuf.st_size -= rv;
+ file_bytes -= rv;
count += rv;
- len = statbuf.st_size < TRANSMITFILE_MMAP_CHUNK ?
- statbuf.st_size : TRANSMITFILE_MMAP_CHUNK;
+ len = file_bytes < SENDFILE_MMAP_CHUNK ?
+ file_bytes : SENDFILE_MMAP_CHUNK;
} else {
count = -1;
goto done;
}
}
+ PR_ASSERT(0 == file_bytes);
+ if (sfd->tlen) {
+ rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
+ if (rv >= 0) {
+ PR_ASSERT(rv == sfd->tlen);
+ count += rv;
+ } else
+ count = -1;
+ }
done:
if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET))
PR_Close(sd);
@@ -3697,6 +3772,14 @@ PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
PRStatus _MD_CloseFileMap(PRFileMap *fmap)
{
+ if ( PR_TRUE == fmap->md.isAnonFM ) {
+ PRStatus rc = PR_Close( fmap->fd );
+ if ( PR_FAILURE == rc ) {
+ PR_LOG( _pr_io_lm, PR_LOG_DEBUG,
+ ("_MD_CloseFileMap(): error closing anonymnous file map osfd"));
+ return PR_FAILURE;
+ }
+ }
PR_DELETE(fmap);
return PR_SUCCESS;
}
diff --git a/pr/src/md/unix/unix_errors.c b/pr/src/md/unix/unix_errors.c
index c3321cf3..30ff1f51 100644
--- a/pr/src/md/unix/unix_errors.c
+++ b/pr/src/md/unix/unix_errors.c
@@ -22,7 +22,7 @@
#endif
#include <errno.h>
-static void _MD_unix_map_default_error(int err)
+void _MD_unix_map_default_error(int err)
{
PRErrorCode prError;
diff --git a/pr/src/md/unix/uxproces.c b/pr/src/md/unix/uxproces.c
index acdb3104..8c0a9b96 100644
--- a/pr/src/md/unix/uxproces.c
+++ b/pr/src/md/unix/uxproces.c
@@ -716,6 +716,7 @@ PRStatus _MD_DetachUnixProcess(PRProcess *process)
PR_DELETE(pRec);
}
}
+ PR_DELETE(process);
done:
PR_Unlock(pr_wp.ml);
@@ -775,6 +776,7 @@ PRStatus _MD_WaitUnixProcess(
}
PR_DELETE(pRec);
}
+ PR_DELETE(process);
done:
PR_Unlock(pr_wp.ml);
diff --git a/pr/src/md/unix/uxshm.c b/pr/src/md/unix/uxshm.c
new file mode 100644
index 00000000..fe03a192
--- /dev/null
+++ b/pr/src/md/unix/uxshm.c
@@ -0,0 +1,639 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** uxshm.c -- Unix Implementations NSPR Named Shared Memory
+**
+**
+** lth. Jul-1999.
+**
+*/
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+#include "primpl.h"
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+
+#define NSPR_IPC_SHM_KEY 'b'
+/*
+** Implementation for System V
+*/
+#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory
+
+extern PRSharedMemory * _MD_OpenSharedMemory(
+ const char *name,
+ PRSize size,
+ PRIntn flags,
+ PRIntn mode
+)
+{
+ PRStatus rc = PR_SUCCESS;
+ key_t key;
+ PRSharedMemory *shm;
+ char ipcname[PR_IPC_NAME_SIZE];
+
+ rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+ if ( PR_FAILURE == rc )
+ {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+ return( NULL );
+ }
+
+ shm = PR_NEWZAP( PRSharedMemory );
+ if ( NULL == shm )
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
+ return( NULL );
+ }
+
+ shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+ if ( NULL == shm->ipcname )
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
+ return( NULL );
+ }
+
+ /* copy args to struct */
+ strcpy( shm->ipcname, ipcname );
+ shm->size = size;
+ shm->mode = mode;
+ shm->flags = flags;
+ shm->ident = _PR_SHM_IDENT;
+
+ /* create the file first */
+ if ( flags & PR_SHM_CREATE ) {
+ int osfd = open( shm->ipcname, (O_RDWR | O_CREAT), shm->mode );
+ if ( -1 == osfd ) {
+ _PR_MD_MAP_OPEN_ERROR( errno );
+ PR_FREEIF( shm->ipcname );
+ PR_DELETE( shm );
+ return( NULL );
+ }
+ if ( close(osfd == -1 )) {
+ _PR_MD_MAP_CLOSE_ERROR( errno );
+ PR_FREEIF( shm->ipcname );
+ PR_DELETE( shm );
+ return( NULL );
+ }
+ }
+
+ /* hash the shm.name to an ID */
+ key = ftok( shm->ipcname, NSPR_IPC_SHM_KEY );
+ if ( -1 == key )
+ {
+ rc = PR_FAILURE;
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): ftok() failed on name: %s", shm->ipcname));
+ PR_FREEIF( shm->ipcname );
+ PR_DELETE( shm );
+ return( NULL );
+ }
+
+ /* get the shared memory */
+ if ( flags & PR_SHM_CREATE ) {
+ shm->id = shmget( key, shm->size, ( shm->mode | IPC_CREAT|IPC_EXCL));
+ if ( shm->id >= 0 ) {
+ return( shm );
+ }
+ if ((errno == EEXIST) && (flags & PR_SHM_EXCL)) {
+ PR_SetError( PR_FILE_EXISTS_ERROR, errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): shmget() exclusive failed, errno: %d", errno));
+ PR_FREEIF(shm->ipcname);
+ PR_DELETE(shm);
+ return(NULL);
+ }
+ }
+
+ shm->id = shmget( key, shm->size, shm->mode );
+ if ( -1 == shm->id ) {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): shmget() failed, errno: %d", errno));
+ PR_FREEIF(shm->ipcname);
+ PR_DELETE(shm);
+ return(NULL);
+ }
+
+ return( shm );
+} /* end _MD_OpenSharedMemory() */
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+ void *addr;
+ PRUint32 aFlags = shm->mode;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ aFlags |= (flags & PR_SHM_READONLY )? SHM_RDONLY : 0;
+
+ addr = shmat( shm->id, NULL, aFlags );
+ if ( (void*)-1 == addr )
+ {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_AttachSharedMemory(): shmat() failed on name: %s, OsError: %d",
+ shm->ipcname, PR_GetOSError() ));
+ addr = NULL;
+ }
+
+ return addr;
+}
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+ PRStatus rc = PR_SUCCESS;
+ PRIntn urc;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ urc = shmdt( addr );
+ if ( -1 == urc )
+ {
+ rc = PR_FAILURE;
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DetachSharedMemory(): shmdt() failed on name: %s", shm->ipcname ));
+ }
+
+ return rc;
+}
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ PR_FREEIF(shm->ipcname);
+ PR_DELETE(shm);
+
+ return PR_SUCCESS;
+}
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+ PRStatus rc = PR_SUCCESS;
+ key_t key;
+ int id;
+ PRIntn urc;
+ char ipcname[PR_IPC_NAME_SIZE];
+
+ rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_SetError( PR_UNKNOWN_ERROR , errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+ return(PR_FAILURE);
+ }
+
+ /* create the file first */
+ {
+ int osfd = open( ipcname, (O_RDWR | O_CREAT), 0666 );
+ if ( -1 == osfd ) {
+ _PR_MD_MAP_OPEN_ERROR( errno );
+ return( PR_FAILURE );
+ }
+ if ( close(osfd == -1 )) {
+ _PR_MD_MAP_CLOSE_ERROR( errno );
+ return( PR_FAILURE );
+ }
+ }
+
+ /* hash the shm.name to an ID */
+ key = ftok( ipcname, NSPR_IPC_SHM_KEY );
+ if ( -1 == key )
+ {
+ rc = PR_FAILURE;
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): ftok() failed on name: %s", ipcname));
+ }
+
+ id = shmget( key, 0, 0 );
+ if ( -1 == id ) {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno));
+ return(PR_FAILURE);
+ }
+
+ urc = shmctl( id, IPC_RMID, NULL );
+ if ( -1 == urc )
+ {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname ));
+ return(PR_FAILURE);
+ }
+
+ urc = unlink( ipcname );
+ if ( -1 == urc ) {
+ _PR_MD_MAP_UNLINK_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname ));
+ return(PR_FAILURE);
+ }
+
+ return rc;
+} /* end _MD_DeleteSharedMemory() */
+
+/*
+** Implementation for Posix
+*/
+#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
+#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
+#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
+#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
+#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory
+
+struct _MDSharedMemory {
+ int handle;
+};
+
+extern PRSharedMemory * _MD_OpenSharedMemory(
+ const char *name,
+ PRSize size,
+ PRIntn flags,
+ PRIntn mode
+)
+{
+ PRStatus rc = PR_SUCCESS;
+ PRIntn id;
+ PRInt32 end;
+ PRSharedMemory *shm;
+ char ipcname[PR_IPC_NAME_SIZE];
+
+ rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_SetError( PR_UNKNOWN_ERROR , errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+ return( NULL );
+ }
+
+ shm = PR_NEWZAP( PRSharedMemory );
+ if ( NULL == shm )
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
+ return( NULL );
+ }
+
+ shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+ if ( NULL == shm->ipcname )
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
+ return( NULL );
+ }
+
+ /* copy args to struct */
+ strcpy( shm->ipcname, ipcname );
+ shm->size = size;
+ shm->mode = mode;
+ shm->flags = flags;
+ shm->ident = _PR_SHM_IDENT;
+
+ /*
+ ** Create the shared memory
+ */
+ if ( flags & PR_SHM_CREATE ) {
+ int oflag = (O_CREAT | O_RDWR);
+
+ if ( flags & PR_SHM_EXCL )
+ oflag |= O_EXCL;
+ shm->id = shm_open( shm->ipcname, oflag, shm->mode );
+ } else {
+ shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode );
+ }
+
+ if ( -1 == shm->id ) {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d",
+ shm->ipcname, PR_GetOSError()));
+ PR_DELETE( shm->ipcname );
+ PR_DELETE( shm );
+ return(NULL);
+ }
+
+ end = ftruncate( shm->id, shm->size );
+ if ( -1 == end ) {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d",
+ PR_GetOSError()));
+ PR_DELETE( shm->ipcname );
+ PR_DELETE( shm );
+ return(NULL);
+ }
+
+ return(shm);
+} /* end _MD_OpenSharedMemory() */
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+ void *addr;
+ PRIntn prot = (PROT_READ | PROT_WRITE);
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ if ( PR_SHM_READONLY == flags)
+ prot ^= PROT_WRITE;
+
+ addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 );
+ if ((void*)-1 == addr )
+ {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d",
+ shm->ipcname, PR_GetOSError()));
+ addr = NULL;
+ } else {
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr));
+ }
+
+ return addr;
+}
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+ PRStatus rc = PR_SUCCESS;
+ PRIntn urc;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ urc = munmap( addr, shm->size );
+ if ( -1 == urc )
+ {
+ rc = PR_FAILURE;
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d",
+ shm->ipcname, PR_GetOSError()));
+ }
+ return rc;
+}
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+ int urc;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ urc = close( shm->id );
+ if ( -1 == urc ) {
+ _PR_MD_MAP_CLOSE_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError()));
+ return(PR_FAILURE);
+ }
+ PR_DELETE( shm->ipcname );
+ PR_DELETE( shm );
+ return PR_SUCCESS;
+}
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+ PRStatus rc = PR_SUCCESS;
+ PRUintn urc;
+ char ipcname[PR_IPC_NAME_SIZE];
+
+ rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_SetError( PR_UNKNOWN_ERROR , errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
+ return( NULL );
+ }
+
+ urc = shm_unlink( ipcname );
+ if ( -1 == urc ) {
+ rc = PR_FAILURE;
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d",
+ ipcname, PR_GetOSError()));
+ } else {
+ PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
+ ("_MD_DeleteSharedMemory(): %s, success", ipcname));
+ }
+
+ return rc;
+} /* end _MD_DeleteSharedMemory() */
+#endif
+
+
+
+/*
+** Unix implementation for anonymous memory (file) mapping
+*/
+extern PRLogModuleInfo *_pr_shma_lm;
+
+#include <unistd.h>
+
+extern PRFileMap* _md_OpenAnonFileMap(
+ const char *dirName,
+ PRSize size,
+ PRFileMapProtect prot
+)
+{
+ PRFileMap *fm = NULL;
+ PRFileDesc *fd;
+ int osfd;
+ PRIntn urc;
+ PRIntn mode = 0600;
+ char *genName;
+ pid_t pid = getpid(); /* for generating filename */
+ PRThread *tid = PR_GetCurrentThread(); /* for generating filename */
+ int incr; /* for generating filename */
+ const int maxTries = 20; /* maximum # attempts at a unique filename */
+
+ /*
+ ** generate a filename from input and runtime environment
+ ** open the file, unlink the file.
+ ** make maxTries number of attempts at uniqueness in the filename
+ */
+ for ( incr = 0; incr < maxTries ; incr++ ) {
+ genName = PR_smprintf( "%s/.NSPR-AFM-%d-%p.%d",
+ dirName, (int) pid, tid, incr );
+ if ( NULL == genName ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename"));
+ goto Finished;
+ }
+
+ /* create the file */
+ osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode );
+ if ( -1 == osfd ) {
+ if ( EEXIST == errno ) {
+ PR_smprintf_free( genName );
+ continue; /* name exists, try again */
+ } else {
+ _PR_MD_MAP_OPEN_ERROR( errno );
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d",
+ genName, PR_GetOSError()));
+ PR_smprintf_free( genName );
+ goto Finished;
+ }
+ }
+ break; /* name generation and open successful, break; */
+ } /* end for() */
+
+ if ( incr == maxTries ) {
+ PR_ASSERT( -1 == osfd );
+ PR_ASSERT( EEXIST == errno );
+ _PR_MD_MAP_OPEN_ERROR( errno );
+ goto Finished;
+ }
+
+ urc = unlink( genName );
+ if ( -1 == urc ) {
+ _PR_MD_MAP_UNLINK_ERROR( errno );
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno));
+ PR_smprintf_free( genName );
+ close( osfd );
+ goto Finished;
+ }
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): unlink(): %s", genName ));
+
+ PR_smprintf_free( genName );
+
+ fd = PR_ImportFile( osfd );
+ if ( NULL == fd ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): PR_ImportFile(): failed"));
+ goto Finished;
+ }
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): fd: %p", fd ));
+
+ urc = ftruncate( fd->secret->md.osfd, size );
+ if ( -1 == urc ) {
+ _PR_MD_MAP_DEFAULT_ERROR( errno );
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno));
+ PR_Close( fd );
+ goto Finished;
+ }
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): ftruncate(): size: %d", size ));
+
+ fm = PR_CreateFileMap( fd, size, prot );
+ if ( NULL == fm ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("PR_OpenAnonFileMap(): failed"));
+ PR_Close( fd );
+ goto Finished;
+ }
+ fm->md.isAnonFM = PR_TRUE; /* set fd close */
+
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm ));
+
+Finished:
+ return(fm);
+} /* end md_OpenAnonFileMap() */
+
+/*
+** _md_ExportFileMapAsString()
+**
+**
+*/
+extern PRStatus _md_ExportFileMapAsString(
+ PRFileMap *fm,
+ PRSize bufSize,
+ char *buf
+)
+{
+ PRIntn written;
+ PRIntn prot = (PRIntn)fm->prot;
+
+ written = PR_snprintf( buf, bufSize, "%ld:%d",
+ fm->fd->secret->md.osfd, prot );
+
+ return((written == -1)? PR_FAILURE : PR_SUCCESS);
+} /* end _md_ExportFileMapAsString() */
+
+
+extern PRFileMap * _md_ImportFileMapFromString(
+ const char *fmstring
+)
+{
+ PRStatus rc;
+ PRInt32 osfd;
+ PRIntn prot; /* really: a PRFileMapProtect */
+ PRFileDesc *fd;
+ PRFileMap *fm;
+ PRFileInfo info;
+
+ PR_sscanf( fmstring, "%ld:%d", &osfd, &prot );
+
+ /* import the os file descriptor */
+ fd = PR_ImportFile( osfd );
+ if ( NULL == fd ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_ImportFileMapFromString(): PR_ImportFile() failed"));
+ goto Finished;
+ }
+
+ rc = PR_GetOpenFileInfo( fd, &info );
+ if ( PR_FAILURE == rc ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_ImportFileMapFromString(): PR_GetOpenFileInfo() failed"));
+ goto Finished;
+ }
+
+ fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot );
+ if ( NULL == fm ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_ImportFileMapFromString(): PR_CreateFileMap() failed"));
+ }
+
+Finished:
+ return(fm);
+} /* end _md_ImportFileMapFromString() */
diff --git a/pr/src/md/windows/Makefile b/pr/src/md/windows/Makefile
index 32000dc9..36744849 100644
--- a/pr/src/md/windows/Makefile
+++ b/pr/src/md/windows/Makefile
@@ -48,7 +48,9 @@ CSRCS = \
w95cv.c \
w95sock.c \
win32_errors.c \
+ w32ipcsem.c \
w32poll.c \
+ w32shm.c \
w95dllmain.c \
$(NULL)
else
@@ -61,7 +63,9 @@ CSRCS = \
ntthread.c \
ntio.c \
win32_errors.c \
+ w32ipcsem.c \
w32poll.c \
+ w32shm.c \
$(NULL)
endif
endif
diff --git a/pr/src/md/windows/ntio.c b/pr/src/md/windows/ntio.c
index 3769d950..47c1efeb 100644
--- a/pr/src/md/windows/ntio.c
+++ b/pr/src/md/windows/ntio.c
@@ -369,11 +369,20 @@ _PR_MD_PAUSE_CPU(PRIntervalTime ticks)
_PR_THREAD_UNLOCK(completed_io);
- completed_io->cpu = lockedCPU;
+ /*
+ * If an I/O operation is suspended, the thread
+ * must be running on the same cpu on which the
+ * I/O operation was issued.
+ */
+ PR_ASSERT(!completed_io->md.thr_bound_cpu ||
+ (completed_io->cpu == completed_io->md.thr_bound_cpu));
+
+ if (!completed_io->md.thr_bound_cpu)
+ completed_io->cpu = lockedCPU;
completed_io->state = _PR_RUNNABLE;
- _PR_RUNQ_LOCK(lockedCPU);
- _PR_ADD_RUNQ(completed_io, lockedCPU, pri);
- _PR_RUNQ_UNLOCK(lockedCPU);
+ _PR_RUNQ_LOCK(completed_io->cpu);
+ _PR_ADD_RUNQ(completed_io, completed_io->cpu, pri);
+ _PR_RUNQ_UNLOCK(completed_io->cpu);
} else {
_PR_THREAD_UNLOCK(completed_io);
}
@@ -382,9 +391,6 @@ _PR_MD_PAUSE_CPU(PRIntervalTime ticks)
}
}
} else {
- int old_count;
- PRBool fNeedRelease = PR_FALSE;
-
/* For native threads, they are only notified through this loop
* when completing IO. So, don't worry about this being a CVAR
* notification, because that is not possible.
@@ -393,13 +399,12 @@ _PR_MD_PAUSE_CPU(PRIntervalTime ticks)
completed_io->io_pending = PR_FALSE;
if (completed_io->io_suspended == PR_FALSE) {
completed_io->state = _PR_RUNNABLE;
- fNeedRelease = PR_TRUE;
- }
- _PR_THREAD_UNLOCK(completed_io);
- if (fNeedRelease) {
+ _PR_THREAD_UNLOCK(completed_io);
rv = ReleaseSemaphore(completed_io->md.blocked_sema,
- 1, &old_count);
+ 1, NULL);
PR_ASSERT(0 != rv);
+ } else {
+ _PR_THREAD_UNLOCK(completed_io);
}
}
}
@@ -412,11 +417,57 @@ _PR_MD_PAUSE_CPU(PRIntervalTime ticks)
return 0;
}
+static PRStatus
+_native_thread_md_wait(PRThread *thread, PRIntervalTime ticks)
+{
+ DWORD rv;
+ PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+ INFINITE : PR_IntervalToMilliseconds(ticks);
+
+ /*
+ * thread waiting for a cvar or a joining thread
+ */
+ rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
+ switch(rv) {
+ case WAIT_OBJECT_0:
+ return PR_SUCCESS;
+ break;
+ case WAIT_TIMEOUT:
+ _PR_THREAD_LOCK(thread);
+ PR_ASSERT (thread->state != _PR_IO_WAIT);
+ if (thread->wait.cvar != NULL) {
+ PR_ASSERT(thread->state == _PR_COND_WAIT);
+ thread->wait.cvar = NULL;
+ thread->state = _PR_RUNNING;
+ _PR_THREAD_UNLOCK(thread);
+ } else {
+ /* The CVAR was notified just as the timeout
+ * occurred. This left the semaphore in the
+ * signaled state. Call WaitForSingleObject()
+ * to clear the semaphore.
+ */
+ _PR_THREAD_UNLOCK(thread);
+ rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
+ PR_ASSERT(rv == WAIT_OBJECT_0);
+ }
+ return PR_SUCCESS;
+ break;
+ default:
+ return PR_FAILURE;
+ break;
+ }
+
+ return PR_SUCCESS;
+}
+
PRStatus
_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
{
DWORD rv;
+ if (_native_threads_only) {
+ return(_native_thread_md_wait(thread, ticks));
+ }
if ( thread->flags & _PR_GLOBAL_SCOPE ) {
PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
INFINITE : PR_IntervalToMilliseconds(ticks);
@@ -429,12 +480,14 @@ _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
_PR_THREAD_LOCK(thread);
if (thread->state == _PR_IO_WAIT) {
if (thread->io_pending == PR_TRUE) {
+ thread->state = _PR_RUNNING;
thread->io_suspended = PR_TRUE;
_PR_THREAD_UNLOCK(thread);
} else {
/* The IO completed just at the same time the timeout
- * occurred. This led to us being notified twice.
- * call WaitForSingleObject() to clear the semaphore.
+ * occurred. This left the semaphore in the signaled
+ * state. Call WaitForSingleObject() to clear the
+ * semaphore.
*/
_PR_THREAD_UNLOCK(thread);
rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
@@ -442,13 +495,15 @@ _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
}
} else {
if (thread->wait.cvar != NULL) {
+ PR_ASSERT(thread->state == _PR_COND_WAIT);
thread->wait.cvar = NULL;
thread->state = _PR_RUNNING;
_PR_THREAD_UNLOCK(thread);
} else {
/* The CVAR was notified just as the timeout
- * occurred. This led to us being notified twice.
- * call WaitForSingleObject() to clear the semaphore.
+ * occurred. This left the semaphore in the
+ * signaled state. Call WaitForSingleObject()
+ * to clear the semaphore.
*/
_PR_THREAD_UNLOCK(thread);
rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
@@ -471,11 +526,150 @@ _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
return PR_SUCCESS;
}
+static void
+_native_thread_io_nowait(
+ PRThread *thread,
+ int rv,
+ int bytes)
+{
+ int rc;
+
+ PR_ASSERT(rv != 0);
+ _PR_THREAD_LOCK(thread);
+ if (thread->state == _PR_IO_WAIT) {
+ PR_ASSERT(thread->io_suspended == PR_FALSE);
+ PR_ASSERT(thread->io_pending == PR_TRUE);
+ thread->state = _PR_RUNNING;
+ thread->io_pending = PR_FALSE;
+ _PR_THREAD_UNLOCK(thread);
+ } else {
+ /* The IO completed just at the same time the
+ * thread was interrupted. This left the semaphore
+ * in the signaled state. Call WaitForSingleObject()
+ * to clear the semaphore.
+ */
+ PR_ASSERT(thread->io_suspended == PR_TRUE);
+ PR_ASSERT(thread->io_pending == PR_TRUE);
+ thread->io_pending = PR_FALSE;
+ _PR_THREAD_UNLOCK(thread);
+ rc = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
+ PR_ASSERT(rc == WAIT_OBJECT_0);
+ }
+
+ thread->md.blocked_io_status = rv;
+ thread->md.blocked_io_bytes = bytes;
+ rc = ResetEvent(thread->md.thr_event);
+ PR_ASSERT(rc != 0);
+ return;
+}
+
+static PRStatus
+_native_thread_io_wait(PRThread *thread, PRIntervalTime ticks)
+{
+ DWORD rv, bytes;
+#define _NATIVE_IO_WAIT_HANDLES 2
+#define _NATIVE_WAKEUP_EVENT_INDEX 0
+#define _NATIVE_IO_EVENT_INDEX 1
+
+ HANDLE wait_handles[_NATIVE_IO_WAIT_HANDLES];
+
+ PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
+ INFINITE : PR_IntervalToMilliseconds(ticks);
+
+ PR_ASSERT(thread->flags & _PR_GLOBAL_SCOPE);
+
+ wait_handles[0] = thread->md.blocked_sema;
+ wait_handles[1] = thread->md.thr_event;
+ rv = WaitForMultipleObjects(_NATIVE_IO_WAIT_HANDLES, wait_handles,
+ FALSE, msecs);
+
+ switch(rv) {
+ case WAIT_OBJECT_0 + _NATIVE_IO_EVENT_INDEX:
+ /*
+ * I/O op completed
+ */
+ _PR_THREAD_LOCK(thread);
+ if (thread->state == _PR_IO_WAIT) {
+
+ PR_ASSERT(thread->io_suspended == PR_FALSE);
+ PR_ASSERT(thread->io_pending == PR_TRUE);
+ thread->state = _PR_RUNNING;
+ thread->io_pending = PR_FALSE;
+ _PR_THREAD_UNLOCK(thread);
+ } else {
+ /* The IO completed just at the same time the
+ * thread was interrupted. This led to us being
+ * notified twice. Call WaitForSingleObject()
+ * to clear the semaphore.
+ */
+ PR_ASSERT(thread->io_suspended == PR_TRUE);
+ PR_ASSERT(thread->io_pending == PR_TRUE);
+ thread->io_pending = PR_FALSE;
+ _PR_THREAD_UNLOCK(thread);
+ rv = WaitForSingleObject(thread->md.blocked_sema,
+ INFINITE);
+ PR_ASSERT(rv == WAIT_OBJECT_0);
+ }
+
+ rv = GetOverlappedResult((HANDLE) thread->io_fd,
+ &thread->md.overlapped.overlapped, &bytes, FALSE);
+
+ thread->md.blocked_io_status = rv;
+ if (rv != 0) {
+ thread->md.blocked_io_bytes = bytes;
+ } else {
+ thread->md.blocked_io_error = GetLastError();
+ PR_ASSERT(ERROR_IO_PENDING != thread->md.blocked_io_error);
+ }
+ rv = ResetEvent(thread->md.thr_event);
+ PR_ASSERT(rv != 0);
+ break;
+ case WAIT_OBJECT_0 + _NATIVE_WAKEUP_EVENT_INDEX:
+ /*
+ * I/O interrupted;
+ */
+#ifdef DEBUG
+ _PR_THREAD_LOCK(thread);
+ PR_ASSERT(thread->io_suspended == PR_TRUE);
+ _PR_THREAD_UNLOCK(thread);
+#endif
+ break;
+ case WAIT_TIMEOUT:
+ _PR_THREAD_LOCK(thread);
+ if (thread->state == _PR_IO_WAIT) {
+ thread->state = _PR_RUNNING;
+ thread->io_suspended = PR_TRUE;
+ _PR_THREAD_UNLOCK(thread);
+ } else {
+ /*
+ * The thread was interrupted just as the timeout
+ * occurred. This left the semaphore in the signaled
+ * state. Call WaitForSingleObject() to clear the
+ * semaphore.
+ */
+ PR_ASSERT(thread->io_suspended == PR_TRUE);
+ _PR_THREAD_UNLOCK(thread);
+ rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
+ PR_ASSERT(rv == WAIT_OBJECT_0);
+ }
+ break;
+ default:
+ return PR_FAILURE;
+ break;
+ }
+
+ return PR_SUCCESS;
+}
+
+
static PRStatus
_NT_IO_WAIT(PRThread *thread, PRIntervalTime timeout)
{
PRBool fWait = PR_TRUE;
+ if (_native_threads_only) {
+ return(_native_thread_io_wait(thread, timeout));
+ }
if (!_PR_IS_NATIVE_THREAD(thread)) {
_PR_THREAD_LOCK(thread);
@@ -510,6 +704,16 @@ void _PR_Unblock_IO_Wait(PRThread *thr)
_PRCPU *cpu = thr->cpu;
PR_ASSERT(thr->state == _PR_IO_WAIT);
+ /*
+ * A thread for which an I/O timed out or was interrupted cannot be
+ * in an IO_WAIT state except as a result of calling PR_Close or
+ * PR_NT_CancelIo for the FD. For these two cases, _PR_IO_WAIT state
+ * is not interruptible
+ */
+ if (thr->md.interrupt_disabled == PR_TRUE) {
+ _PR_THREAD_UNLOCK(thr);
+ return;
+ }
thr->io_suspended = PR_TRUE;
thr->state = _PR_RUNNABLE;
@@ -519,6 +723,11 @@ void _PR_Unblock_IO_Wait(PRThread *thr)
_PR_SLEEPQ_LOCK(cpu);
_PR_DEL_SLEEPQ(thr, PR_TRUE);
_PR_SLEEPQ_UNLOCK(cpu);
+ /*
+ * this thread will continue to run on the same cpu until the
+ * I/O is aborted by closing the FD or calling CancelIO
+ */
+ thr->md.thr_bound_cpu = me->cpu;
PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD));
_PR_AddThreadToRunQ(me, thr);
@@ -555,8 +764,12 @@ _NT_ResumeIO(PRThread *thread, PRIntervalTime ticks)
*/
thread->sleep = ticks;
- if (fWait)
- return _PR_MD_WAIT(thread, ticks);
+ if (fWait) {
+ if (!_PR_IS_NATIVE_THREAD(thread))
+ return _PR_MD_WAIT(thread, ticks);
+ else
+ return _NT_IO_WAIT(thread, ticks);
+ }
return PR_SUCCESS;
}
@@ -738,13 +951,17 @@ _md_Associate(HANDLE file)
{
HANDLE port;
- port = CreateIoCompletionPort((HANDLE)file,
- _pr_completion_port,
- KEY_IO,
- 0);
+ if (!_native_threads_only) {
+ port = CreateIoCompletionPort((HANDLE)file,
+ _pr_completion_port,
+ KEY_IO,
+ 0);
- /* XXX should map error codes on failures */
- return (port == _pr_completion_port);
+ /* XXX should map error codes on failures */
+ return (port == _pr_completion_port);
+ } else {
+ return 1;
+ }
}
/*
@@ -1114,10 +1331,21 @@ _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
return -1;
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
-
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
- me->io_fd = osfd;
me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = osfd;
+
rv = AcceptEx((SOCKET)osfd,
accept_sock,
me->md.acceptex_buf,
@@ -1129,13 +1357,24 @@ _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen,
if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) {
/* Argh! The IO failed */
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
_PR_MD_MAP_ACCEPTEX_ERROR(err);
return -1;
}
- if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+ if (_native_threads_only && rv) {
+ _native_thread_io_nowait(me, rv, bytes);
+ } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
PR_ASSERT(0);
return -1;
}
@@ -1225,10 +1464,21 @@ _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
return -1;
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
-
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
- me->io_fd = sock;
me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = sock;
+
rv = AcceptEx((SOCKET)sock,
*newSock,
buf,
@@ -1239,13 +1489,24 @@ _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
&(me->md.overlapped.overlapped));
if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
_PR_MD_MAP_ACCEPTEX_ERROR(err);
return -1;
}
- if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+ if (_native_threads_only && rv) {
+ _native_thread_io_nowait(me, rv, bytes);
+ } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
PR_ASSERT(0);
return -1;
}
@@ -1343,8 +1604,8 @@ retry:
}
PRInt32
-_PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen,
- PRInt32 flags, PRIntervalTime timeout)
+_PR_MD_SENDFILE(PRFileDesc *sock, PRSendFileData *sfd,
+ PRInt32 flags, PRIntervalTime timeout)
{
PRThread *me = _PR_MD_CURRENT_THREAD();
PRInt32 tflags;
@@ -1356,7 +1617,7 @@ _PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRI
PR_ASSERT(0 != rv);
sock->secret->md.io_model_committed = PR_TRUE;
}
- return _PR_EmulateTransmitFile(sock, file, headers, hlen, flags, timeout);
+ return _PR_EmulateSendFile(sock, sfd, flags, timeout);
}
if (me->io_suspended) {
@@ -1376,30 +1637,51 @@ _PR_MD_TRANSMITFILE(PRFileDesc *sock, PRFileDesc *file, const void *headers, PRI
return -1;
}
}
- me->md.xmit_bufs->Head = (void *)headers;
- me->md.xmit_bufs->HeadLength = hlen;
- me->md.xmit_bufs->Tail = (void *)NULL;
- me->md.xmit_bufs->TailLength = 0;
+ me->md.xmit_bufs->Head = (void *)sfd->header;
+ me->md.xmit_bufs->HeadLength = sfd->hlen;
+ me->md.xmit_bufs->Tail = (void *)sfd->trailer;
+ me->md.xmit_bufs->TailLength = sfd->tlen;
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
+ me->md.overlapped.overlapped.Offset = sfd->file_offset;
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
tflags = 0;
if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
tflags = TF_DISCONNECT | TF_REUSE_SOCKET;
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
- me->io_fd = sock->secret->md.osfd;
me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = sock->secret->md.osfd;
+
rv = TransmitFile((SOCKET)sock->secret->md.osfd,
- (HANDLE)file->secret->md.osfd,
- (DWORD)0,
+ (HANDLE)sfd->fd->secret->md.osfd,
+ (DWORD)sfd->file_nbytes,
(DWORD)0,
(LPOVERLAPPED)&(me->md.overlapped.overlapped),
(TRANSMIT_FILE_BUFFERS *)me->md.xmit_bufs,
(DWORD)tflags);
if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
_PR_MD_MAP_TRANSMITFILE_ERROR(err);
return -1;
}
@@ -1465,25 +1747,47 @@ _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
}
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
- me->io_fd = osfd;
me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = osfd;
+
rv = ReadFile((HANDLE)osfd,
buf,
amount,
&bytes,
&(me->md.overlapped.overlapped));
if ( (rv == 0) && (GetLastError() != ERROR_IO_PENDING) ) {
+ _PR_THREAD_LOCK(me);
me->io_pending = PR_FALSE;
me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
if ((err = GetLastError()) == ERROR_HANDLE_EOF)
return 0;
_PR_MD_MAP_READ_ERROR(err);
return -1;
}
- if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+ if (_native_threads_only && rv) {
+ _native_thread_io_nowait(me, rv, bytes);
+ } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
PR_ASSERT(0);
return -1;
}
@@ -1542,23 +1846,45 @@ _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
}
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
- me->io_fd = osfd;
me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = osfd;
+
rv = WriteFile((HANDLE)osfd,
buf,
amount,
&bytes,
&(me->md.overlapped.overlapped));
if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
+ _PR_THREAD_LOCK(me);
me->io_pending = PR_FALSE;
me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
_PR_MD_MAP_WRITE_ERROR(err);
return -1;
}
- if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
+ if (_native_threads_only && rv) {
+ _native_thread_io_nowait(me, rv, bytes);
+ } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
PR_ASSERT(0);
return -1;
}
@@ -1845,7 +2171,6 @@ _PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode)
return -1;
}
- /* Note: we didn't bother putting it in nonblocking mode */
return (PRInt32)file;
}
}
@@ -1902,17 +2227,38 @@ _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
fd->secret->md.io_model_committed = PR_TRUE;
}
- me->io_pending = PR_TRUE;
- me->io_fd = f;
- me->state = _PR_IO_WAIT;
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ me->io_pending = PR_TRUE;
+ me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = f;
+
rv = ReadFile((HANDLE)f,
(LPVOID)buf,
len,
&bytes,
&me->md.overlapped.overlapped);
if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
if (err == ERROR_HANDLE_EOF) {
return 0;
}
@@ -1920,7 +2266,9 @@ _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
return -1;
}
- if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ if (_native_threads_only && rv) {
+ _native_thread_io_nowait(me, rv, bytes);
+ } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
PR_ASSERT(0);
return -1;
}
@@ -2020,23 +2368,45 @@ _PR_MD_WRITE(PRFileDesc *fd, void *buf, PRInt32 len)
PR_ASSERT(rv != 0);
fd->secret->md.io_model_committed = PR_TRUE;
}
+ if (_native_threads_only)
+ me->md.overlapped.overlapped.hEvent = me->md.thr_event;
+
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ me->io_pending = PR_TRUE;
+ me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+ me->io_fd = f;
- me->io_pending = PR_TRUE;
- me->io_fd = f;
- me->state = _PR_IO_WAIT;
rv = WriteFile((HANDLE)f,
buf,
len,
&bytes,
&(me->md.overlapped.overlapped));
if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
+ _PR_THREAD_UNLOCK(me);
+
_PR_MD_MAP_WRITE_ERROR(err);
return -1;
}
- if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ if (_native_threads_only && rv) {
+ _native_thread_io_nowait(me, rv, bytes);
+ } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
PR_ASSERT(0);
return -1;
}
@@ -2192,52 +2562,52 @@ PRInt32
_PR_MD_CLOSE(PRInt32 osfd, PRBool socket)
{
PRInt32 rv;
- PRInt32 err;
if (_nt_use_async) {
PRThread *me = _PR_MD_CURRENT_THREAD();
if (socket) {
rv = closesocket((SOCKET)osfd);
if (rv < 0)
- err = WSAGetLastError();
+ _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
} else {
rv = CloseHandle((HANDLE)osfd)?0:-1;
if (rv < 0)
- err = GetLastError();
+ _PR_MD_MAP_CLOSE_ERROR(GetLastError());
}
- if (rv == 0 && me->io_pending) {
+ if (rv == 0 && me->io_suspended) {
if (me->io_fd == osfd) {
PRBool fWait;
- PR_ASSERT(me->io_suspended == PR_TRUE);
_PR_THREAD_LOCK(me);
me->state = _PR_IO_WAIT;
/* The IO could have completed on another thread just after
* calling closesocket while the io_suspended flag was true.
* So we now grab the lock to do a safe check on io_pending to
- * see if we need to wait or not. At this point we can check
- * io_pending safely because we've reset io_suspended to FALSE.
- * XXXMB - 1-15-97 this seems fishy and begging for a race...
+ * see if we need to wait or not.
*/
fWait = me->io_pending;
me->io_suspended = PR_FALSE;
+ me->md.interrupt_disabled = PR_TRUE;
_PR_THREAD_UNLOCK(me);
if (fWait)
_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
PR_ASSERT(me->io_suspended == PR_FALSE);
PR_ASSERT(me->io_pending == PR_FALSE);
+ /*
+ * I/O operation is no longer pending; the thread can now
+ * run on any cpu
+ */
+ _PR_THREAD_LOCK(me);
+ me->md.interrupt_disabled = PR_FALSE;
+ me->md.thr_bound_cpu = NULL;
me->io_suspended = PR_FALSE;
me->io_pending = PR_FALSE;
me->state = _PR_RUNNING;
+ _PR_THREAD_UNLOCK(me);
}
- } else {
- me->io_suspended = PR_FALSE;
- if (rv < 0)
- _PR_MD_MAP_CLOSE_ERROR(err);
}
- return rv;
} else {
if (socket) {
rv = closesocket((SOCKET)osfd);
@@ -2249,6 +2619,7 @@ _PR_MD_CLOSE(PRInt32 osfd, PRBool socket)
_PR_MD_MAP_CLOSE_ERROR(GetLastError());
}
}
+ return rv;
}
PRStatus
@@ -2804,8 +3175,17 @@ _PR_MD_LOCKFILE(PRInt32 f)
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
- me->state = _PR_IO_WAIT;
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
+ me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+
rv = LockFileEx((HANDLE)f,
LOCKFILE_EXCLUSIVE_LOCK,
0,
@@ -2813,6 +3193,27 @@ _PR_MD_LOCKFILE(PRInt32 f)
0,
&me->md.overlapped.overlapped);
+ if (_native_threads_only) {
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return PR_FAILURE;
+ }
+ _PR_THREAD_UNLOCK(me);
+
+ if (rv == FALSE) {
+ err = GetLastError();
+ PR_ASSERT(err != ERROR_IO_PENDING);
+ _PR_MD_MAP_LOCKF_ERROR(err);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+ }
+
/* HACK AROUND NT BUG
* NT 3.51 has a bug. In NT 3.51, if LockFileEx returns true, you
* don't get any completion on the completion port. This is a bug.
@@ -2835,8 +3236,17 @@ _PR_MD_LOCKFILE(PRInt32 f)
*/
if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return PR_FAILURE;
+ }
+ _PR_THREAD_UNLOCK(me);
+
_PR_MD_MAP_LOCKF_ERROR(err);
return PR_FAILURE;
}
@@ -2856,8 +3266,10 @@ _PR_MD_LOCKFILE(PRInt32 f)
#endif /* _NEED_351_FILE_LOCKING_HACK */
if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
+ _PR_THREAD_LOCK(me);
me->io_pending = PR_FALSE;
me->state = _PR_RUNNING;
+ _PR_THREAD_UNLOCK(me);
return PR_FAILURE;
}
@@ -2882,18 +3294,56 @@ _PR_MD_TLOCKFILE(PRInt32 f)
memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
- me->state = _PR_IO_WAIT;
+ _PR_THREAD_LOCK(me);
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return -1;
+ }
me->io_pending = PR_TRUE;
+ me->state = _PR_IO_WAIT;
+ _PR_THREAD_UNLOCK(me);
+
rv = LockFileEx((HANDLE)f,
LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK,
0,
0x7fffffff,
0,
&me->md.overlapped.overlapped);
+ if (_native_threads_only) {
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return PR_FAILURE;
+ }
+ _PR_THREAD_UNLOCK(me);
+
+ if (rv == FALSE) {
+ err = GetLastError();
+ PR_ASSERT(err != ERROR_IO_PENDING);
+ _PR_MD_MAP_LOCKF_ERROR(err);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+ }
if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
- _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error);
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return PR_FAILURE;
+ }
+ _PR_THREAD_UNLOCK(me);
+
+ _PR_MD_MAP_LOCKF_ERROR(err);
return PR_FAILURE;
}
#ifdef _NEED_351_FILE_LOCKING_HACK
@@ -2903,8 +3353,17 @@ _PR_MD_TLOCKFILE(PRInt32 f)
*/
if (_nt_version_gets_lockfile_completion == PR_FALSE) {
if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return PR_FAILURE;
+ }
+ _PR_THREAD_UNLOCK(me);
+
return PR_SUCCESS;
}
}
@@ -2912,8 +3371,17 @@ _PR_MD_TLOCKFILE(PRInt32 f)
#endif /* _NEED_351_FILE_LOCKING_HACK */
if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
- me->io_pending = PR_FALSE;
- me->state = _PR_RUNNING;
+ _PR_THREAD_LOCK(me);
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ if (_PR_PENDING_INTERRUPT(me)) {
+ me->flags &= ~_PR_INTERRUPT;
+ PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
+ _PR_THREAD_UNLOCK(me);
+ return PR_FAILURE;
+ }
+ _PR_THREAD_UNLOCK(me);
+
return PR_FAILURE;
}
@@ -3180,6 +3648,49 @@ PR_IMPLEMENT(void) PR_NT_UseNonblock()
_nt_use_async = 0;
}
+PR_IMPLEMENT(PRStatus) PR_NT_CancelIo(PRFileDesc *fd)
+{
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRBool fWait;
+ PRFileDesc *bottom;
+
+ bottom = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
+ if (!me->io_suspended || (NULL == bottom) ||
+ (me->io_fd != bottom->secret->md.osfd)) {
+ PR_SetError(PR_INVALID_STATE_ERROR, 0);
+ return PR_FAILURE;
+ }
+ /*
+ * The CancelIO operation has to be issued by the same NT thread that
+ * issued the I/O operation
+ */
+ PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || (me->cpu == me->md.thr_bound_cpu));
+ if (me->io_pending) {
+ if (!CancelIo((HANDLE)bottom->secret->md.osfd)) {
+ PR_SetError(PR_INVALID_STATE_ERROR, GetLastError());
+ return PR_FAILURE;
+ }
+ }
+ _PR_THREAD_LOCK(me);
+ fWait = me->io_pending;
+ me->io_suspended = PR_FALSE;
+ me->state = _PR_IO_WAIT;
+ me->md.interrupt_disabled = PR_TRUE;
+ _PR_THREAD_UNLOCK(me);
+ if (fWait)
+ _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
+ me->md.thr_bound_cpu = NULL;
+ PR_ASSERT(me->io_suspended == PR_FALSE);
+ PR_ASSERT(me->io_pending == PR_FALSE);
+
+ _PR_THREAD_LOCK(me);
+ me->md.interrupt_disabled = PR_FALSE;
+ me->io_suspended = PR_FALSE;
+ me->io_pending = PR_FALSE;
+ me->state = _PR_RUNNING;
+ _PR_THREAD_UNLOCK(me);
+ return PR_SUCCESS;
+}
PRInt32 _nt_nonblock_accept(PRFileDesc *fd, struct sockaddr_in *addr, int *len, PRIntervalTime timeout)
{
diff --git a/pr/src/md/windows/ntmisc.c b/pr/src/md/windows/ntmisc.c
index c9aab0e7..e2fb696f 100644
--- a/pr/src/md/windows/ntmisc.c
+++ b/pr/src/md/windows/ntmisc.c
@@ -563,6 +563,9 @@ PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
{
DWORD dwHi, dwLo;
DWORD flProtect;
+ PRUint32 osfd;
+
+ osfd = ( fmap->fd == (PRFileDesc*)-1 )? -1 : fmap->fd->secret->md.osfd;
dwLo = (DWORD) (size & 0xffffffff);
dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff);
@@ -580,7 +583,7 @@ PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
}
fmap->md.hFileMap = CreateFileMapping(
- (HANDLE) fmap->fd->secret->md.osfd,
+ (HANDLE) osfd,
NULL,
flProtect,
dwHi,
@@ -593,7 +596,8 @@ PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
}
return PR_SUCCESS;
}
-
+#include "prlog.h"
+extern PRLogModuleInfo *_pr_shma_lm;
void * _MD_MemMap(
PRFileMap *fmap,
PRInt64 offset,
@@ -606,6 +610,20 @@ void * _MD_MemMap(
dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff);
if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess,
dwHi, dwLo, len)) == NULL) {
+ {
+ LPVOID lpMsgBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf ));
+ }
PR_SetError(PR_UNKNOWN_ERROR, GetLastError());
}
return addr;
diff --git a/pr/src/md/windows/ntthread.c b/pr/src/md/windows/ntthread.c
index cb4f82cf..b6b41ea5 100644
--- a/pr/src/md/windows/ntthread.c
+++ b/pr/src/md/windows/ntthread.c
@@ -159,6 +159,13 @@ _PR_MD_INIT_THREAD(PRThread *thread)
if (thread->md.blocked_sema == NULL) {
return PR_FAILURE;
}
+ if (_native_threads_only) {
+ /* Create the blocking IO semaphore */
+ thread->md.thr_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (thread->md.thr_event == NULL) {
+ return PR_FAILURE;
+ }
+ }
}
return PR_SUCCESS;
@@ -278,6 +285,13 @@ _PR_MD_CLEAN_THREAD(PRThread *thread)
PR_ASSERT(rv);
thread->md.blocked_sema = 0;
}
+ if (_native_threads_only) {
+ if (thread->md.thr_event) {
+ rv = CloseHandle(thread->md.thr_event);
+ PR_ASSERT(rv);
+ thread->md.thr_event = 0;
+ }
+ }
if (thread->md.handle) {
rv = CloseHandle(thread->md.handle);
@@ -317,6 +331,14 @@ _PR_MD_EXIT_THREAD(PRThread *thread)
thread->md.blocked_sema = 0;
}
+ if (_native_threads_only) {
+ if (thread->md.thr_event) {
+ rv = CloseHandle(thread->md.thr_event);
+ PR_ASSERT(rv);
+ thread->md.thr_event = 0;
+ }
+ }
+
if (thread->md.handle) {
rv = CloseHandle(thread->md.handle);
PR_ASSERT(rv);
@@ -368,7 +390,6 @@ _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *thread)
{
thread->md.fiber_id = ConvertThreadToFiber(NULL);
PR_ASSERT(thread->md.fiber_id);
- thread->flags &= (~_PR_GLOBAL_SCOPE);
_MD_SET_CURRENT_THREAD(thread);
_MD_SET_LAST_THREAD(thread);
thread->no_sched = 1;
diff --git a/pr/src/md/windows/w32ipcsem.c b/pr/src/md/windows/w32ipcsem.c
new file mode 100644
index 00000000..951b1cf8
--- /dev/null
+++ b/pr/src/md/windows/w32ipcsem.c
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * File: w32ipcsem.c
+ * Description: implements named semaphores for NT and WIN95.
+ */
+
+#include "primpl.h"
+
+#ifndef _PR_GLOBAL_THREADS_ONLY
+
+/*
+ * A fiber cannot call WaitForSingleObject because that
+ * will block the other fibers running on the same thread.
+ * If a fiber needs to wait on a (semaphore) handle, we
+ * create a native thread to call WaitForSingleObject and
+ * have the fiber join the native thread.
+ */
+
+/*
+ * Arguments, return value, and error code for WaitForSingleObject
+ */
+struct WaitSingleArg {
+ HANDLE handle;
+ DWORD timeout;
+ DWORD rv;
+ DWORD error;
+};
+
+static void WaitSingleThread(void *arg)
+{
+ struct WaitSingleArg *warg = (struct WaitSingleArg *) arg;
+
+ warg->rv = WaitForSingleObject(warg->handle, warg->timeout);
+ if (warg->rv == WAIT_FAILED) {
+ warg->error = GetLastError();
+ }
+}
+
+static DWORD FiberSafeWaitForSingleObject(
+ HANDLE hHandle,
+ DWORD dwMilliseconds
+)
+{
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+
+ if (_PR_IS_NATIVE_THREAD(me)) {
+ return WaitForSingleObject(hHandle, dwMilliseconds);
+ } else {
+ PRThread *waitThread;
+ struct WaitSingleArg warg;
+ PRStatus rv;
+
+ warg.handle = hHandle;
+ warg.timeout = dwMilliseconds;
+ waitThread = PR_CreateThread(
+ PR_USER_THREAD, WaitSingleThread, &warg,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (waitThread == NULL) {
+ return WAIT_FAILED;
+ }
+
+ rv = PR_JoinThread(waitThread);
+ PR_ASSERT(rv == PR_SUCCESS);
+ if (rv == PR_FAILURE) {
+ return WAIT_FAILED;
+ }
+ if (warg.rv == WAIT_FAILED) {
+ SetLastError(warg.error);
+ }
+ return warg.rv;
+ }
+}
+
+#endif /* !_PR_GLOBAL_THREADS_ONLY */
+
+PRSem *_PR_MD_OPEN_SEMAPHORE(
+ const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
+{
+ PRSem *sem;
+
+ sem = PR_NEW(PRSem);
+ if (sem == NULL) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
+ if (flags & PR_SEM_CREATE) {
+ sem->sem = CreateSemaphore(NULL, value, 0x7fffffff, osname);
+ if (sem->sem == NULL) {
+ _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+ PR_DELETE(sem);
+ return NULL;
+ }
+ if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) {
+ PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS);
+ CloseHandle(sem->sem);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ } else {
+ sem->sem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, osname);
+ if (sem->sem == NULL) {
+ DWORD err = GetLastError();
+
+ /*
+ * If we open a nonexistent named semaphore, NT
+ * returns ERROR_FILE_NOT_FOUND, while Win95
+ * returns ERROR_INVALID_NAME
+ */
+ if (err == ERROR_INVALID_NAME) {
+ PR_SetError(PR_FILE_NOT_FOUND_ERROR, err);
+ } else {
+ _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+ }
+ PR_DELETE(sem);
+ return NULL;
+ }
+ }
+ return sem;
+}
+
+PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
+{
+ DWORD rv;
+
+#ifdef _PR_GLOBAL_THREADS_ONLY
+ rv = WaitForSingleObject(sem->sem, INFINITE);
+#else
+ rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE);
+#endif
+ PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0);
+ if (rv == WAIT_FAILED) {
+ _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+ return PR_FAILURE;
+ }
+ if (rv != WAIT_OBJECT_0) {
+ /* Should not happen */
+ PR_SetError(PR_UNKNOWN_ERROR, 0);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
+{
+ if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) {
+ _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
+{
+ if (CloseHandle(sem->sem) == FALSE) {
+ _PR_MD_MAP_CLOSE_ERROR(GetLastError());
+ return PR_FAILURE;
+ }
+ PR_DELETE(sem);
+ return PR_SUCCESS;
+}
diff --git a/pr/src/md/windows/w32shm.c b/pr/src/md/windows/w32shm.c
new file mode 100644
index 00000000..4fb60e93
--- /dev/null
+++ b/pr/src/md/windows/w32shm.c
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include <private/primpl.h>
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+
+#if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY)
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+extern PRSharedMemory * _MD_OpenSharedMemory(
+ const char *name,
+ PRSize size,
+ PRIntn flags,
+ PRIntn mode
+)
+{
+ char ipcname[PR_IPC_NAME_SIZE];
+ PRStatus rc = PR_SUCCESS;
+ DWORD dwHi, dwLo;
+ PRSharedMemory *shm;
+ DWORD flProtect = ( PAGE_READWRITE );
+
+ rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_SetError(PR_UNKNOWN_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid"));
+ return(NULL);
+ }
+
+ shm = PR_NEWZAP( PRSharedMemory );
+ if ( NULL == shm )
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
+ return(NULL);
+ }
+
+ shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
+ if ( NULL == shm->ipcname )
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
+ PR_DELETE(shm);
+ return(NULL);
+ }
+
+ /* copy args to struct */
+ strcpy( shm->ipcname, ipcname );
+ shm->size = size;
+ shm->mode = mode;
+ shm->flags = flags;
+ shm->ident = _PR_SHM_IDENT;
+
+ if (flags & PR_SHM_CREATE ) {
+ /* XXX: Not 64bit safe. Fix when WinNT goes 64bit, if ever */
+ dwHi = 0;
+ dwLo = shm->size;
+
+ shm->handle = CreateFileMapping(
+ (HANDLE)-1 ,
+ NULL,
+ flProtect,
+ dwHi,
+ dwLo,
+ shm->ipcname);
+
+ if ( NULL == shm->handle ) {
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ( "PR_OpenSharedMemory: CreateFileMapping() failed: %s",
+ shm->ipcname ));
+ PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
+ PR_FREEIF( shm->ipcname )
+ PR_DELETE( shm );
+ return(NULL);
+ } else {
+ if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS )) {
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ( "PR_OpenSharedMemory: Request exclusive & already exists",
+ shm->ipcname ));
+ PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS );
+ CloseHandle( shm->handle );
+ PR_FREEIF( shm->ipcname )
+ PR_DELETE( shm );
+ return(NULL);
+ } else {
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d",
+ shm->ipcname, shm->handle ));
+ return(shm);
+ }
+ }
+ } else {
+ shm->handle = OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, shm->ipcname );
+ if ( NULL == shm->handle ) {
+ _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d",
+ shm->ipcname, PR_GetOSError()));
+ PR_FREEIF( shm->ipcname );
+ PR_DELETE( shm );
+ return(NULL);
+ } else {
+ PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
+ ( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d",
+ shm->ipcname, shm->handle ));
+ return(shm);
+ }
+ }
+ /* returns from separate paths */
+}
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+ PRUint32 access = FILE_MAP_WRITE;
+ void *addr;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ if ( PR_SHM_READONLY & flags )
+ access = FILE_MAP_READ;
+
+ addr = MapViewOfFile( shm->handle,
+ access,
+ 0, 0,
+ shm->size );
+
+ if ( NULL == addr ) {
+ _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+ PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
+ ("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
+ }
+
+ return( addr );
+} /* end _MD_ATTACH_SHARED_MEMORY() */
+
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+ PRStatus rc = PR_SUCCESS;
+ BOOL wrc;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ wrc = UnmapViewOfFile( addr );
+ if ( FALSE == wrc )
+ {
+ _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+ PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
+ ("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError()));
+ rc = PR_FAILURE;
+ }
+
+ return( rc );
+}
+
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+ PRStatus rc = PR_SUCCESS;
+ BOOL wrc;
+
+ PR_ASSERT( shm->ident == _PR_SHM_IDENT );
+
+ wrc = CloseHandle( shm->handle );
+ if ( FALSE == wrc )
+ {
+ _PR_MD_MAP_DEFAULT_ERROR( GetLastError());
+ PR_LOG( _pr_shm_lm, PR_LOG_ERROR,
+ ("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError()));
+ rc = PR_FAILURE;
+ }
+ PR_FREEIF( shm->ipcname );
+ PR_DELETE( shm );
+
+ return( rc );
+} /* end _MD_CLOSE_SHARED_MEMORY() */
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+ return( PR_SUCCESS );
+}
+
+
+/*
+** Windows implementation of anonymous memory (file) map
+*/
+extern PRLogModuleInfo *_pr_shma_lm;
+
+extern PRFileMap* _md_OpenAnonFileMap(
+ const char *dirName,
+ PRSize size,
+ PRFileMapProtect prot
+)
+{
+ PRFileMap *fm;
+ HANDLE hFileMap;
+
+ fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot );
+ if ( NULL == fm ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed"));
+ goto Finished;
+ }
+
+ /*
+ ** Make fm->md.hFileMap inheritable. We can't use
+ ** GetHandleInformation and SetHandleInformation
+ ** because these two functions fail with
+ ** ERROR_CALL_NOT_IMPLEMENTED on Win95.
+ */
+ if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap,
+ GetCurrentProcess(), &hFileMap,
+ 0, TRUE /* inheritable */,
+ DUPLICATE_SAME_ACCESS) == FALSE) {
+ PR_SetError( PR_UNKNOWN_ERROR, GetLastError() );
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_OpenAnonFileMap(): DuplicateHandle(): failed"));
+ PR_CloseFileMap( fm );
+ fm = NULL;
+ goto Finished;
+ }
+ CloseHandle(fm->md.hFileMap);
+ fm->md.hFileMap = hFileMap;
+
+Finished:
+ return(fm);
+} /* end md_OpenAnonFileMap() */
+
+/*
+** _md_ExportFileMapAsString()
+**
+*/
+extern PRStatus _md_ExportFileMapAsString(
+ PRFileMap *fm,
+ PRSize bufSize,
+ char *buf
+)
+{
+ PRIntn written;
+
+ written = PR_snprintf( buf, bufSize, "%d:%ld:%ld",
+ (PRIntn)fm->prot, (PRInt32)fm->md.hFileMap, (PRInt32)fm->md.dwAccess );
+ /* Watch out on the above snprintf(). Windows HANDLE assumes 32bits; windows calls it void* */
+
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x",
+ fm->prot, fm->md.hFileMap, fm->md.dwAccess ));
+
+ return((written == -1)? PR_FAILURE : PR_SUCCESS);
+} /* end _md_ExportFileMapAsString() */
+
+
+/*
+** _md_ImportFileMapFromString()
+**
+*/
+extern PRFileMap * _md_ImportFileMapFromString(
+ const char *fmstring
+)
+{
+ PRIntn prot;
+ PRInt32 hFileMap;
+ PRInt32 dwAccess;
+ PRFileMap *fm = NULL;
+
+ PR_sscanf( fmstring, "%d:%ld:%ld", &prot, &hFileMap, &dwAccess );
+
+ fm = PR_NEWZAP(PRFileMap);
+ if ( NULL == fm ) {
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed"));
+ return(fm);
+ }
+
+ fm->prot = (PRFileMapProtect)prot;
+ fm->md.hFileMap = (HANDLE)hFileMap; /* Assumes HANDLE is 32bit */
+ fm->md.dwAccess = (DWORD)dwAccess;
+ fm->fd = (PRFileDesc*)-1;
+
+ PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
+ ("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x",
+ fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd));
+ return(fm);
+} /* end _md_ImportFileMapFromString() */
+
+#else
+Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined?
+#endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */
+/* --- end w32shm.c --- */
diff --git a/pr/src/md/windows/win32_errors.c b/pr/src/md/windows/win32_errors.c
index 1d5ba6af..0e73c560 100644
--- a/pr/src/md/windows/win32_errors.c
+++ b/pr/src/md/windows/win32_errors.c
@@ -59,7 +59,7 @@ static void _MD_win32_map_default_errno(PRInt32 err)
PR_SetError(prError, err);
}
-static void _MD_win32_map_default_error(PRInt32 err)
+void _MD_win32_map_default_error(PRInt32 err)
{
PRErrorCode prError;
diff --git a/pr/src/memory/Makefile b/pr/src/memory/Makefile
index 70326e5a..dde16b2d 100644
--- a/pr/src/memory/Makefile
+++ b/pr/src/memory/Makefile
@@ -28,7 +28,7 @@ OPTIMIZER =
endif
endif
-CSRCS = prseg.c
+CSRCS = prseg.c prshm.c prshma.c
TARGETS = $(OBJS)
diff --git a/pr/src/memory/prshm.c b/pr/src/memory/prshm.c
new file mode 100644
index 00000000..697734e9
--- /dev/null
+++ b/pr/src/memory/prshm.c
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** prshm.c -- NSPR Named Shared Memory
+**
+** lth. Jul-1999.
+*/
+#include <string.h>
+#include <prshm.h>
+#include <prerr.h>
+#include <prmem.h>
+#include <private/primpl.h>
+
+extern PRLogModuleInfo *_pr_shm_lm;
+
+
+#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
+/* SysV implementation is in pr/src/md/unix/uxshm.c */
+#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
+/* Posix implementation is in pr/src/md/unix/uxshm.c */
+#elif defined PR_HAVE_WIN32_NAMED_SHARED_MEMORY
+/* Win32 implementation is in pr/src/md/windows/w32shm.c */
+#else
+/*
+** there is no named_shared_memory
+*/
+extern PRSharedMemory* _MD_OpenSharedMemory( PRSharedMemory *shm )
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return NULL;
+}
+
+extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+extern PRStatus _MD_DeleteSharedMemory( const char *name )
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+#endif /* HAVE_SYSV_NAMED_SHARED_MEMORY */
+
+/*
+** FUNCTION: PR_OpenSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRSharedMemory * )
+ PR_OpenSharedMemory(
+ const char *name,
+ PRSize size,
+ PRIntn flags,
+ PRIntn mode
+)
+{
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ return( _PR_MD_OPEN_SHARED_MEMORY( name, size, flags, mode ));
+} /* end PR_OpenSharedMemory() */
+
+/*
+** FUNCTION: PR_AttachSharedMemory()
+**
+*/
+PR_IMPLEMENT( void * )
+ PR_AttachSharedMemory(
+ PRSharedMemory *shm,
+ PRIntn flags
+)
+{
+ return( _PR_MD_ATTACH_SHARED_MEMORY( shm, flags ));
+} /* end PR_AttachSharedMemory() */
+
+/*
+** FUNCTION: PR_DetachSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRStatus )
+ PR_DetachSharedMemory(
+ PRSharedMemory *shm,
+ void *addr
+)
+{
+ return( _PR_MD_DETACH_SHARED_MEMORY( shm, addr ));
+} /* end PR_DetachSharedMemory() */
+
+/*
+** FUNCTION: PR_CloseSharedMemory()
+**
+*/
+PR_IMPLEMENT( PRStatus )
+ PR_CloseSharedMemory(
+ PRSharedMemory *shm
+)
+{
+ return( _PR_MD_CLOSE_SHARED_MEMORY( shm ));
+} /* end PR_CloseSharedMemory() */
+
+/*
+** FUNCTION: PR_DeleteSharedMemory()
+**
+*/
+PR_EXTERN( PRStatus )
+ PR_DeleteSharedMemory(
+ const char *name
+)
+{
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ return(_PR_MD_DELETE_SHARED_MEMORY( name ));
+} /* end PR_DestroySharedMemory() */
+/* end prshm.c */
diff --git a/pr/src/memory/prshma.c b/pr/src/memory/prshma.c
new file mode 100644
index 00000000..c546f667
--- /dev/null
+++ b/pr/src/memory/prshma.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** prshma.h -- NSPR Anonymous Shared Memory
+**
+**
+*/
+
+#include "prtypes.h"
+#include "prshma.h"
+#include "prlog.h"
+#include "prio.h"
+#include "prprf.h"
+#include "private/primpl.h"
+
+extern PRLogModuleInfo *_pr_shma_lm;
+
+#if defined(XP_UNIX)
+/* defined in pr/src/md/unix/uxshm.c */
+#elif defined(WIN32)
+/* defined in pr/src/md/windows/w32shm.c */
+#else
+ error! ... not supported on this platform
+#endif
+
+/*
+** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory
+**
+*/
+PR_IMPLEMENT(PRFileMap*)
+PR_OpenAnonFileMap(
+ const char *dirName,
+ PRSize size,
+ PRFileMapProtect prot
+)
+{
+ return(_PR_MD_OPEN_ANON_FILE_MAP( dirName, size, prot ));
+} /* end PR_OpenAnonFileMap() */
+
+/*
+** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export
+** to my children processes via PR_CreateProcess()
+**
+**
+*/
+PR_IMPLEMENT( PRStatus)
+PR_ProcessAttrSetInheritableFileMap(
+ PRProcessAttr *attr,
+ PRFileMap *fm,
+ const char *shmname
+)
+{
+ PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+ return( PR_FAILURE);
+} /* end PR_ProcessAttrSetInheritableFileMap() */
+
+/*
+** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported
+** by my parent process via PR_CreateProcess()
+**
+*/
+PR_IMPLEMENT( PRFileMap *)
+PR_GetInheritedFileMap(
+ const char *shmname
+)
+{
+ PRFileMap *fm = NULL;
+ PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
+ return( fm );
+} /* end PR_GetInhteritedFileMap() */
+
+/*
+** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap
+**
+*/
+PR_IMPLEMENT( PRStatus )
+PR_ExportFileMapAsString(
+ PRFileMap *fm,
+ PRSize bufSize,
+ char *buf
+)
+{
+ return( _PR_MD_EXPORT_FILE_MAP_AS_STRING( fm, bufSize, buf ));
+} /* end PR_ExportFileMapAsString() */
+
+/*
+** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string
+**
+**
+*/
+PR_IMPLEMENT( PRFileMap * )
+PR_ImportFileMapFromString(
+ const char *fmstring
+)
+{
+ return( _PR_MD_IMPORT_FILE_MAP_FROM_STRING(fmstring));
+} /* end PR_ImportFileMapFromString() */
+/* end prshma.c */
diff --git a/pr/src/misc/Makefile b/pr/src/misc/Makefile
index 5d70797b..963265dd 100644
--- a/pr/src/misc/Makefile
+++ b/pr/src/misc/Makefile
@@ -39,6 +39,7 @@ CSRCS = \
prerrortable.c \
prinit.c \
prinrval.c \
+ pripc.c \
prlog2.c \
prlong.c \
prnetdb.c \
@@ -49,6 +50,12 @@ CSRCS = \
prtrace.c \
$(NULL)
+ifndef USE_PTHREADS
+CSRCS += \
+ pripcsem.c \
+ $(NULL)
+endif
+
TARGETS = $(OBJS)
INCLUDES = -I$(DIST)/include -I$(MOD_DEPTH)/pr/include -I$(MOD_DEPTH)/pr/include/private
diff --git a/pr/src/misc/pralarm.c b/pr/src/misc/pralarm.c
index 8d8fef00..3cff68c6 100644
--- a/pr/src/misc/pralarm.c
+++ b/pr/src/misc/pralarm.c
@@ -71,7 +71,7 @@ static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id)
if (id != NULL) /* have to put this id back in */
{
PRIntervalTime idDelta = now - id->nextNotify;
- timer = &alarm->timers;
+ timer = alarm->timers.next;
do
{
result = (PRAlarmID*)timer;
@@ -81,7 +81,7 @@ static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id)
break;
}
timer = timer->next;
- } while (timer != alarm->timers.next);
+ } while (timer != &alarm->timers);
}
result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers));
PR_REMOVE_LINK(timer); /* remove it from the list */
diff --git a/pr/src/misc/prinit.c b/pr/src/misc/prinit.c
index 556e97a4..f84079f4 100644
--- a/pr/src/misc/prinit.c
+++ b/pr/src/misc/prinit.c
@@ -29,6 +29,8 @@ PRLogModuleInfo *_pr_linker_lm;
PRLogModuleInfo *_pr_sched_lm;
PRLogModuleInfo *_pr_thread_lm;
PRLogModuleInfo *_pr_gc_lm;
+PRLogModuleInfo *_pr_shm_lm;
+PRLogModuleInfo *_pr_shma_lm;
PRFileDesc *_pr_stdin;
PRFileDesc *_pr_stdout;
@@ -106,13 +108,14 @@ PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion)
if (vmajor > PR_VMAJOR) {
return PR_FALSE;
- } else if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
+ }
+ if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) {
return PR_FALSE;
- } else if (vminor == PR_VMINOR && vpatch > PR_VPATCH) {
+ }
+ if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) {
return PR_FALSE;
- } else {
- return PR_TRUE;
}
+ return PR_TRUE;
} /* PR_VersionCheck */
@@ -120,11 +123,24 @@ PR_IMPLEMENT(PRBool) PR_Initialized(void)
{
return _pr_initialized;
}
+PRInt32 _native_threads_only = 0;
+
static void _PR_InitStuff(void)
{
+#ifdef WINNT
+ char *envp;
+#endif
+
if (_pr_initialized) return;
_pr_initialized = PR_TRUE;
+#ifdef WINNT
+ if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) {
+ if (atoi(envp) == 1)
+ _native_threads_only = 1;
+ }
+#endif
+
(void) PR_GetPageSize();
@@ -137,6 +153,8 @@ static void _PR_InitStuff(void)
_pr_sched_lm = PR_NewLogModule("sched");
_pr_thread_lm = PR_NewLogModule("thread");
_pr_gc_lm = PR_NewLogModule("gc");
+ _pr_shm_lm = PR_NewLogModule("shm");
+ _pr_shma_lm = PR_NewLogModule("shma");
/* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */
_PR_MD_EARLY_INIT();
@@ -163,7 +181,7 @@ static void _PR_InitStuff(void)
#endif
#ifndef _PR_GLOBAL_THREADS_ONLY
- _PR_InitCPUs();
+ _PR_InitCPUs();
#endif
/*
diff --git a/pr/src/misc/pripc.c b/pr/src/misc/pripc.c
new file mode 100644
index 00000000..fb19ab68
--- /dev/null
+++ b/pr/src/misc/pripc.c
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * File: pripc.c
+ *
+ * Description: functions for IPC support
+ */
+
+#include "primpl.h"
+
+#include <string.h>
+
+/*
+ * A POSIX IPC name must begin with a '/'.
+ * A POSIX IPC name on Solaris cannot contain any '/' except
+ * the required leading '/'.
+ * A POSIX IPC name on HP-UX and OSF1 must be a valid pathname
+ * in the file system.
+ *
+ * The ftok() function for System V IPC requires a valid pathname
+ * in the file system.
+ *
+ * A Win32 IPC name cannot contain '\'.
+ */
+
+static void _pr_ConvertSemName(char *result)
+{
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#if defined(SOLARIS)
+ char *p;
+
+ /* Convert '/' to '_' except for the leading '/' */
+ for (p = result+1; *p; p++) {
+ if (*p == '/') {
+ *p = '_';
+ }
+ }
+ return;
+#else
+ return;
+#endif
+#elif defined(_PR_HAVE_SYSV_SEMAPHORES)
+ return;
+#elif defined(WIN32)
+ return;
+#endif
+}
+
+static void _pr_ConvertShmName(char *result)
+{
+#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY)
+#if defined(SOLARIS)
+ char *p;
+
+ /* Convert '/' to '_' except for the leading '/' */
+ for (p = result+1; *p; p++) {
+ if (*p == '/') {
+ *p = '_';
+ }
+ }
+ return;
+#else
+ return;
+#endif
+#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY)
+ return;
+#elif defined(WIN32)
+ return;
+#else
+ return;
+#endif
+}
+
+PRStatus _PR_MakeNativeIPCName(
+ const char *name,
+ char *result,
+ PRIntn size,
+ _PRIPCType type)
+{
+ if (strlen(name) >= (PRSize)size) {
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+ return PR_FAILURE;
+ }
+ strcpy(result, name);
+ switch (type) {
+ case _PRIPCSem:
+ _pr_ConvertSemName(result);
+ break;
+ case _PRIPCShm:
+ _pr_ConvertShmName(result);
+ break;
+ default:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
diff --git a/pr/src/misc/pripcsem.c b/pr/src/misc/pripcsem.c
new file mode 100644
index 00000000..7013ec18
--- /dev/null
+++ b/pr/src/misc/pripcsem.c
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * File: pripcsem.c
+ *
+ * Description: implements the named semaphores API in prsemipc.h
+ * for classic NSPR. If _PR_HAVE_NAMED_SEMAPHORES is not defined,
+ * the named semaphore functions all fail with the error code
+ * PR_NOT_IMPLEMENTED_ERROR.
+ */
+
+#include "primpl.h"
+
+#ifdef _PR_PTHREADS
+
+#error "This file should not be compiled for the pthreads version"
+
+#else
+
+#ifndef _PR_HAVE_NAMED_SEMAPHORES
+
+PRSem * _PR_MD_OPEN_SEMAPHORE(
+ const char *osname, PRIntn flags, PRIntn mode, PRUintn value)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return NULL;
+}
+
+PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname)
+{
+ PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+ return PR_FAILURE;
+}
+
+#endif /* !_PR_HAVE_NAMED_SEMAPHORES */
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+ const char *name, PRIntn flags, PRIntn mode, PRUintn value)
+{
+ char osname[PR_IPC_NAME_SIZE];
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+ == PR_FAILURE) {
+ return NULL;
+ }
+ return _PR_MD_OPEN_SEMAPHORE(osname, flags, mode, value);
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+ return _PR_MD_WAIT_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+ return _PR_MD_POST_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+ return _PR_MD_CLOSE_SEMAPHORE(sem);
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+ char osname[PR_IPC_NAME_SIZE];
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+ if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+ == PR_FAILURE) {
+ return PR_FAILURE;
+ }
+ return _PR_MD_DELETE_SEMAPHORE(osname);
+}
+
+#endif /* _PR_PTHREADS */
diff --git a/pr/src/misc/prnetdb.c b/pr/src/misc/prnetdb.c
index 47afc606..de869246 100644
--- a/pr/src/misc/prnetdb.c
+++ b/pr/src/misc/prnetdb.c
@@ -100,9 +100,6 @@ PRBool _pr_ipv6_enabled = PR_FALSE;
#if defined(AIX)
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
-#else
-extern const struct in6_addr in6addr_any;
-extern const struct in6_addr in6addr_loopback;
#endif /* AIX */
#endif /* _PR_INET6 */
@@ -177,19 +174,68 @@ static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
return buf;
}
+#if defined(_PR_INET6)
+
+typedef enum _PRIPAddrConversion {
+ _PRIPAddrNoConversion,
+ _PRIPAddrIPv4Mapped,
+ _PRIPAddrIPv4Compat
+} _PRIPAddrConversion;
+
+/*
+** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6).
+*/
+static void MakeIPv4MappedAddr(const char *v4, char *v6)
+{
+ memset(v6, 0, 10);
+ memset(v6 + 10, 0xff, 2);
+ memcpy(v6 + 12, v4, 4);
+ PR_ASSERT(IN6_IS_ADDR_V4MAPPED((struct in6_addr *) v6));
+}
+
+/*
+** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6).
+*/
+static void MakeIPv4CompatAddr(const char *v4, char *v6)
+{
+ memset(v6, 0, 12);
+ memcpy(v6 + 12, v4, 4);
+ PR_ASSERT(IN6_IS_ADDR_V4COMPAT((struct in6_addr *) v6));
+}
+
+#endif /* _PR_INET6 */
+
/*
** Copy a hostent, and all of the memory that it refers to into
** (hopefully) stacked buffers.
*/
static PRStatus CopyHostent(
- struct hostent *from, char *buf, PRIntn bufsize, PRHostEnt *to)
+ struct hostent *from,
+ char *buf,
+ PRIntn bufsize,
+#if defined(_PR_INET6)
+ _PRIPAddrConversion conversion,
+#endif
+ PRHostEnt *to)
{
PRIntn len, na;
char **ap;
/* Do the easy stuff */
+#if defined(_PR_INET6)
+ if (conversion != _PRIPAddrNoConversion
+ && from->h_addrtype == AF_INET) {
+ PR_ASSERT(from->h_length == 4);
+ to->h_addrtype = AF_INET6;
+ to->h_length = 16;
+ } else {
+ to->h_addrtype = from->h_addrtype;
+ to->h_length = from->h_length;
+ }
+#else
to->h_addrtype = from->h_addrtype;
to->h_length = from->h_length;
+#endif
/* Copy the official name */
if (!from->h_name) return PR_FAILURE;
@@ -223,7 +269,21 @@ static PRStatus CopyHostent(
for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) {
to->h_addr_list[na] = Alloc(to->h_length, &buf, &bufsize, 0);
if (!to->h_addr_list[na]) return PR_FAILURE;
+#if defined(_PR_INET6)
+ if (conversion != _PRIPAddrNoConversion
+ && from->h_addrtype == AF_INET) {
+ if (conversion == _PRIPAddrIPv4Mapped) {
+ MakeIPv4MappedAddr(*ap, to->h_addr_list[na]);
+ } else {
+ PR_ASSERT(conversion == _PRIPAddrIPv4Compat);
+ MakeIPv4CompatAddr(*ap, to->h_addr_list[na]);
+ }
+ } else {
+ memcpy(to->h_addr_list[na], *ap, to->h_length);
+ }
+#else
memcpy(to->h_addr_list[na], *ap, to->h_length);
+#endif
}
to->h_addr_list[na] = 0;
return PR_SUCCESS;
@@ -277,6 +337,9 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByName(
#ifdef XP_UNIX
sigset_t oldset;
#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ int error_num;
+#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
@@ -288,11 +351,17 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByName(
#ifdef _PR_INET6
if (_pr_ipv6_enabled)
{
+#ifdef _PR_HAVE_GETHOSTBYNAME2
h = gethostbyname2(name, AF_INET6);
if (NULL == h)
{
h = gethostbyname2(name, AF_INET);
}
+#elif defined(_PR_HAVE_GETIPNODEBYNAME)
+ h = getipnodebyname(name, AF_INET6, AI_DEFAULT, &error_num);
+#else
+#error "Unknown name-to-address translation function"
+#endif
}
else
{
@@ -311,12 +380,129 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByName(
#endif /* _PR_INET6 */
if (NULL == h)
+ {
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#else
PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+ }
+ else
+ {
+#if defined(_PR_INET6)
+ _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+
+ if (_pr_ipv6_enabled) conversion = _PRIPAddrIPv4Mapped;
+ rv = CopyHostent(h, buf, bufsize, conversion, hp);
+#else
+ rv = CopyHostent(h, buf, bufsize, hp);
+#endif
+ if (PR_SUCCESS != rv)
+ PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ freehostent(h);
+#endif
+ }
+ UNLOCK_DNS();
+#ifdef XP_UNIX
+ ENABLECLOCK(&oldset);
+#endif
+ return rv;
+}
+
+PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName(
+ const char *name, PRUint16 af, PRIntn flags,
+ char *buf, PRIntn bufsize, PRHostEnt *hp)
+{
+ struct hostent *h;
+ PRStatus rv = PR_FAILURE;
+#ifdef XP_UNIX
+ sigset_t oldset;
+#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ int error_num;
+#endif
+
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+#if defined(_PR_INET6)
+ PR_ASSERT(af == AF_INET || af == AF_INET6);
+ if (af != AF_INET && af != AF_INET6) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+#else
+ PR_ASSERT(af == AF_INET);
+ if (af != AF_INET) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+#endif
+
+ /*
+ * Flags other than PR_AI_DEFAULT are not yet supported.
+ */
+ PR_ASSERT(flags == PR_AI_DEFAULT);
+ if (flags != PR_AI_DEFAULT) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+#ifdef XP_UNIX
+ DISABLECLOCK(&oldset);
+#endif
+ LOCK_DNS();
+
+#ifdef _PR_INET6
+#ifdef _PR_HAVE_GETHOSTBYNAME2
+ if (af == AF_INET6)
+ {
+ h = gethostbyname2(name, af);
+ if (NULL == h)
+ {
+ h = gethostbyname2(name, AF_INET);
+ }
+ }
+ else
+ {
+ h = gethostbyname2(name, af);
+ }
+#elif defined(_PR_HAVE_GETIPNODEBYNAME)
+ h = getipnodebyname(name, af, AI_DEFAULT, &error_num);
+#else
+#error "Unknown name-to-address translation function"
+#endif
+#else /* _PR_INET6 */
+#ifdef XP_OS2_VACPP
+ h = gethostbyname((char *)name);
+#else
+ h = gethostbyname(name);
+#endif
+#endif /* _PR_INET6 */
+
+ if (NULL == h)
+ {
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#else
+ PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+ }
else
{
+#if defined(_PR_INET6)
+ _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+
+ if (af == AF_INET6) conversion = _PRIPAddrIPv4Mapped;
+ rv = CopyHostent(h, buf, bufsize, conversion, hp);
+#else
rv = CopyHostent(h, buf, bufsize, hp);
+#endif
if (PR_SUCCESS != rv)
PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
+ freehostent(h);
+#endif
}
UNLOCK_DNS();
#ifdef XP_UNIX
@@ -335,6 +521,9 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
#ifdef XP_UNIX
sigset_t oldset;
#endif
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+ int error_num;
+#endif
if (!_pr_initialized) _PR_ImplicitInitialization();
@@ -355,18 +544,44 @@ PR_IMPLEMENT(PRStatus) PR_GetHostByAddr(
addr = &hostaddr->inet.ip;
addrlen = sizeof(hostaddr->inet.ip);
}
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+ h = getipnodebyaddr(addr, addrlen, hostaddr->raw.family, &error_num);
+#else
#ifdef XP_OS2_VACPP
h = gethostbyaddr((char *)addr, addrlen, hostaddr->raw.family);
#else
h = gethostbyaddr(addr, addrlen, hostaddr->raw.family);
#endif
- if (NULL == h) PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif /* _PR_INET6 && _PR_HAVE_GETIPNODEBYADDR */
+ if (NULL == h)
+ {
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+ PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num);
+#else
+ PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO());
+#endif
+ }
else
{
+#if defined(_PR_INET6)
+ _PRIPAddrConversion conversion = _PRIPAddrNoConversion;
+ if (hostaddr->raw.family == AF_INET6) {
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr*)addr)) {
+ conversion = _PRIPAddrIPv4Mapped;
+ } else if (IN6_IS_ADDR_V4COMPAT((struct in6_addr*)addr)) {
+ conversion = _PRIPAddrIPv4Compat;
+ }
+ }
+ rv = CopyHostent(h, buf, bufsize, conversion, hostentry);
+#else
rv = CopyHostent(h, buf, bufsize, hostentry);
+#endif
if (PR_SUCCESS != rv) {
PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
}
+#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR)
+ freehostent(h);
+#endif
}
UNLOCK_DNS();
#ifdef XP_UNIX
@@ -574,11 +789,19 @@ PR_IMPLEMENT(PRUintn) PR_NetAddrSize(const PRNetAddr* addr)
{
PRUintn addrsize;
+ /*
+ * RFC 2553 added a new field (sin6_scope_id) to
+ * struct sockaddr_in6. PRNetAddr's ipv6 member has a
+ * scope_id field to match the new field. In order to
+ * work with older implementations supporting RFC 2133,
+ * we take the size of struct sockaddr_in6 instead of
+ * addr->ipv6.
+ */
if (AF_INET == addr->raw.family)
addrsize = sizeof(addr->inet);
#if defined(_PR_INET6)
else if (AF_INET6 == addr->raw.family)
- addrsize = sizeof(addr->ipv6);
+ addrsize = sizeof(struct sockaddr_in6);
#endif
#if defined(XP_UNIX)
else if (AF_UNIX == addr->raw.family)
@@ -597,28 +820,17 @@ PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt(
if (NULL == addr) enumIndex = 0;
else
{
+ address->raw.family = hostEnt->h_addrtype;
#if defined(_PR_INET6)
- if (_pr_ipv6_enabled)
+ if (AF_INET6 == hostEnt->h_addrtype)
{
- address->ipv6.family = AF_INET6;
address->ipv6.port = htons(port);
- if (AF_INET6 == hostEnt->h_addrtype)
- memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
- else
- {
- unsigned char *start = (unsigned char *) &address->ipv6.ip;
- PR_ASSERT(AF_INET == hostEnt->h_addrtype);
- memset(start, 0, 10);
- memset(start + 10, 0xff, 2);
- memcpy(start + 12, addr, hostEnt->h_length);
- PR_ASSERT(IN6_IS_ADDR_V4MAPPED(&address->ipv6.ip));
- }
+ memcpy(&address->ipv6.ip, addr, hostEnt->h_length);
}
else
#endif /* defined(_PR_INET6) */
{
PR_ASSERT(AF_INET == hostEnt->h_addrtype);
- address->inet.family = hostEnt->h_addrtype;
address->inet.port = htons(port);
memcpy(&address->inet.ip, addr, hostEnt->h_length);
}
@@ -675,6 +887,82 @@ PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr(
return rv;
} /* PR_InitializeNetAddr */
+PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
+ PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr)
+{
+ PRStatus rv = PR_SUCCESS;
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ addr->raw.family = af;
+#if defined(_PR_INET6)
+ if (af == AF_INET6)
+ {
+ addr->ipv6.port = htons(port);
+ switch (val)
+ {
+ case PR_IpAddrNull:
+ break; /* don't overwrite the address */
+ case PR_IpAddrAny:
+ addr->ipv6.ip = in6addr_any;
+ break;
+ case PR_IpAddrLoopback:
+ addr->ipv6.ip = in6addr_loopback;
+ break;
+ default:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ rv = PR_FAILURE;
+ }
+ }
+ else
+#endif /* defined(_PR_INET6) */
+ {
+ addr->inet.port = htons(port);
+ switch (val)
+ {
+ case PR_IpAddrNull:
+ break; /* don't overwrite the address */
+ case PR_IpAddrAny:
+ addr->inet.ip = htonl(INADDR_ANY);
+ break;
+ case PR_IpAddrLoopback:
+ addr->inet.ip = htonl(INADDR_LOOPBACK);
+ break;
+ default:
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ rv = PR_FAILURE;
+ }
+ }
+ return rv;
+} /* PR_SetNetAddr */
+
+PR_IMPLEMENT(PRBool)
+PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
+{
+#if defined(_PR_INET6)
+ if (addr->raw.family == AF_INET6) {
+ if (val == PR_IpAddrAny
+ && IN6_IS_ADDR_UNSPECIFIED((struct in6_addr*)&addr->ipv6.ip)) {
+ return PR_TRUE;
+ } else if (val == PR_IpAddrLoopback
+ && IN6_IS_ADDR_LOOPBACK((struct in6_addr*)&addr->ipv6.ip)) {
+ return PR_TRUE;
+ }
+ }
+ else
+#endif
+ {
+ if (addr->raw.family == AF_INET) {
+ if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) {
+ return PR_TRUE;
+ } else if (val == PR_IpAddrLoopback
+ && addr->inet.ip == htonl(INADDR_LOOPBACK)) {
+ return PR_TRUE;
+ }
+ }
+ }
+ return PR_FALSE;
+}
+
PR_IMPLEMENT(PRNetAddr*) PR_CreateNetAddr(PRNetAddrValue val, PRUint16 port)
{
PRNetAddr *addr = NULL;
@@ -700,80 +988,69 @@ PR_IMPLEMENT(PRStatus) PR_DestroyNetAddr(PRNetAddr *addr)
PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr)
{
- /*
- ** If we're built to support IPv6 addressing AND it's currently enabled,
- ** then all addresses are of the IPv6 addressing family. Both are required
- ** before anything overt happens.
- */
- PRStatus status = PR_InitializeNetAddr(PR_IpAddrNull, 0, addr);
-
- PR_ASSERT(PR_SUCCESS == status);
- if (PR_SUCCESS != status) return status;
+ PRIntn rv;
+ PRStatus status = PR_SUCCESS;
#if defined(_PR_INET6)
-
- if (_pr_ipv6_enabled)
+ rv = inet_pton(AF_INET6, string, &addr->ipv6.ip);
+ if (1 == rv)
{
- /*
- ** Okay, we're doing it.
- */
- PRIntn rv = inet_pton(AF_INET6, string, &addr->ipv6.ip);
- if (1 != rv)
- {
- /*
- * rv is 0 if the string argument is not a valid IPv4 or IPv6
- * address string.
- * rv is -1 with errno set to EADNOSUPPORT if the af argument is
- * not a known address family.
- */
- PRIntn syserrno = (-1 == rv) ? errno : 0;
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, syserrno);
- status = PR_FAILURE;
- }
+ addr->raw.family = AF_INET6;
}
else
-#endif
{
- PRUint32 *ip = (PRUint32*)&addr->inet.ip;
-
-#ifdef XP_OS2_VACPP
- *ip = inet_addr((char *)string);
-#else
- *ip = inet_addr(string);
-#endif
- if ((PRUint32) -1 == *ip)
+ PR_ASSERT(0 == rv);
+ rv = inet_pton(AF_INET, string, &addr->inet.ip);
+ if (1 == rv)
+ {
+ addr->raw.family = AF_INET;
+ }
+ else
{
- /*
- * Either the af argument is not AF_INET, or the string argument
- * is a malformed address string.
- */
+ PR_ASSERT(0 == rv);
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
status = PR_FAILURE;
}
}
+#else /* _PR_INET6 */
+#ifdef XP_OS2_VACPP
+ addr->inet.ip = inet_addr((char *)string);
+#else
+ addr->inet.ip = inet_addr(string);
+#endif
+ if ((PRUint32) -1 == addr->inet.ip)
+ {
+ /*
+ * Either the af argument is not AF_INET, or the string argument
+ * is a malformed address string.
+ */
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ status = PR_FAILURE;
+ }
+#endif /* _PR_INET6 */
- return status;
+ return status;
}
PR_IMPLEMENT(PRStatus) PR_NetAddrToString(
const PRNetAddr *addr, char *string, PRUint32 size)
{
- PR_ASSERT(size >= 16);
- if (size < 16) goto failed;
-
#if defined(_PR_INET6)
- if (_pr_ipv6_enabled)
+ if (AF_INET6 == addr->raw.family)
{
- PR_ASSERT(AF_INET6 == addr->ipv6.family);
- if ((AF_INET6 != addr->ipv6.family)
- || (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)))
- goto failed;
+ if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size))
+ {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno);
+ return PR_FAILURE;
+ }
}
else
#endif /* defined(_PR_INET6) */
{
- PR_ASSERT(AF_INET == addr->inet.family);
- if (AF_INET != addr->inet.family) goto failed;
+ PR_ASSERT(AF_INET == addr->raw.family);
+ PR_ASSERT(size >= 16);
+ if (size < 16) goto failed;
+ if (AF_INET != addr->raw.family) goto failed;
else
{
unsigned char *byte = (unsigned char*)&addr->inet.ip;
diff --git a/pr/src/nspr.rc b/pr/src/nspr.rc
index 7188a8c2..73d704b5 100644
--- a/pr/src/nspr.rc
+++ b/pr/src/nspr.rc
@@ -45,8 +45,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 3,2,0,0
- PRODUCTVERSION 3,1,0,0
+ FILEVERSION 3,5,0,0
+ PRODUCTVERSION 3,5,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -54,7 +54,7 @@ VS_VERSION_INFO VERSIONINFO
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
- FILETYPE 0x1L
+ FILETYPE 0x2L
FILESUBTYPE 0x0L
// end win16
@@ -67,7 +67,7 @@ BEGIN
BEGIN
VALUE "CompanyName", "Netscape Communications Corporation\0"
VALUE "FileDescription", "Netscape Portable Run Time\0"
- VALUE "FileVersion", "3, 1, 0, 0\0"
+ VALUE "FileVersion", "3.5\0"
#ifdef WINNT
VALUE "InternalName", "libnspr3\0"
VALUE "OriginalFilename", "libnspr3.dll\0"
@@ -77,7 +77,7 @@ BEGIN
#endif
VALUE "LegalCopyright", "Copyright © 1996\0"
VALUE "ProductName", "Netscape Communication Corporation NSPR20\0"
- VALUE "ProductVersion", "3, 1, 0, 0\0"
+ VALUE "ProductVersion", "3.5\0"
END
END
BLOCK "VarFileInfo"
diff --git a/pr/src/prvrsion.c b/pr/src/prvrsion.c
index b538235f..6c5e59a3 100644
--- a/pr/src/prvrsion.c
+++ b/pr/src/prvrsion.c
@@ -36,6 +36,11 @@
#if !defined(_PRODUCTION)
#define _PRODUCTION ""
#endif
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
static PRVersionDescription prVersionDescription_libnspr3 =
{
@@ -65,8 +70,10 @@ static PRVersionDescription prVersionDescription_libnspr3 =
/*
* Version information for the 'ident' and 'what commands
*/
-static char rcsid[] = "$Version: NSPR " PR_VERSION " " _BUILD_STRING " $";
-static char sccsid[] = "@(#)NSPR " PR_VERSION " " _BUILD_STRING;
+static char rcsid[] = "$Version: NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING " $";
+static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING
+ " " _BUILD_STRING;
#endif /* XP_UNIX */
diff --git a/pr/src/pthreads/ptio.c b/pr/src/pthreads/ptio.c
index eabf762a..3b2fa4c8 100644
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -19,7 +19,6 @@
/*
** File: ptio.c
** Descritpion: Implemenation of I/O methods for pthreads
-** Exports: ptio.h
*/
#if defined(_PR_PTHREADS)
@@ -55,7 +54,7 @@
* The send_file() system call is available in AIX 4.3.2 or later.
* If this file is compiled on an older AIX system, it attempts to
* look up the send_file symbol at run time to determine whether
- * we can use the faster PR_TransmitFile implementation based on
+ * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
* send_file(). On AIX 4.3.2 or later, we can safely skip this
* runtime function dispatching and just use the send_file based
* implementation.
@@ -240,7 +239,11 @@ struct pt_Continuation
/*
* For sendfile()
*/
- off_t offset; /* offset in file to send */
+ struct file_spec {
+ off_t offset; /* offset in file to send */
+ size_t nbytes; /* length of file data to send */
+ size_t st_size; /* file size */
+ } file_spec;
#endif
} arg3;
union { PRIntn flags; } arg4; /* #4 - read/write flags */
@@ -269,6 +272,7 @@ struct pt_Continuation
PRIntn syserrno; /* in case it failed, why (errno) */
pr_ContuationStatus status; /* the status of the operation */
PRCondVar *complete; /* to notify the initiating thread */
+ PRIntn io_tq_index; /* io-queue index */
};
static struct pt_TimedQueue
@@ -279,7 +283,14 @@ static struct pt_TimedQueue
pt_Continuation *head, *tail; /* head/tail of list of operations */
pt_Continuation *op; /* timed operation furthest in future */
-} pt_tq;
+ struct pollfd *pollingList; /* list built for polling */
+ PRIntn pollingSlotsAllocated; /* # entries available in list */
+ pt_Continuation **pollingOps; /* list paralleling polling list */
+} *pt_tqp; /* an array */
+
+static PRIntn _pt_num_cpus;
+PRIntn _pt_tq_count; /* size of the pt_tqp array */
+static PRInt32 _pt_tq_index; /* atomically incremented */
#if defined(DEBUG)
@@ -332,7 +343,7 @@ PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
/*
* The following two functions, pt_InsertTimedInternal and
- * pt_FinishTimedInternal, are always called with the pt_tq.ml
+ * pt_FinishTimedInternal, are always called with the tqp->ml
* lock held. The "internal" in the functions' names come from
* the Mesa programming language. Internal functions are always
* called from inside a monitor.
@@ -342,28 +353,34 @@ static void pt_InsertTimedInternal(pt_Continuation *op)
{
pt_Continuation *t_op = NULL;
PRIntervalTime now = PR_IntervalNow();
+ struct pt_TimedQueue *tqp = &pt_tqp[op->io_tq_index];
#if defined(DEBUG)
{
PRIntn count;
pt_Continuation *tmp;
- PR_ASSERT((pt_tq.head == NULL) == (pt_tq.tail == NULL));
- PR_ASSERT((pt_tq.head == NULL) == (pt_tq.op_count == 0));
- for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
- for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
+ PRThread *self = PR_GetCurrentThread();
+
+ PR_ASSERT(tqp == &pt_tqp[self->io_tq_index]);
+ PR_ASSERT((tqp->head == NULL) == (tqp->tail == NULL));
+ PR_ASSERT((tqp->head == NULL) == (tqp->op_count == 0));
+ for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+ PR_ASSERT(count == tqp->op_count);
+ for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+ PR_ASSERT(count == tqp->op_count);
+ for (tmp = tqp->head; tmp != NULL; tmp = tmp->next)
+ PR_ASSERT(tmp->io_tq_index == op->io_tq_index);
}
#endif /* defined(DEBUG) */
/*
* If this element operation isn't timed, it gets queued at the
- * end of the list (just after pt_tq.tail) and we're
+ * end of the list (just after tqp->tail) and we're
* finishd early.
*/
if (PR_INTERVAL_NO_TIMEOUT == op->timeout)
{
- t_op = pt_tq.tail; /* put it at the end */
+ t_op = tqp->tail; /* put it at the end */
goto done;
}
@@ -371,7 +388,7 @@ static void pt_InsertTimedInternal(pt_Continuation *op)
* The portion of this routine deals with timed ops.
*/
op->absolute = now + op->timeout; /* absolute ticks */
- if (NULL == pt_tq.op) pt_tq.op = op;
+ if (NULL == tqp->op) tqp->op = op;
else
{
/*
@@ -383,14 +400,14 @@ static void pt_InsertTimedInternal(pt_Continuation *op)
* This should be easy!
*/
- for (t_op = pt_tq.op; NULL != t_op; t_op = t_op->prev)
+ for (t_op = tqp->op; NULL != t_op; t_op = t_op->prev)
{
/*
* If 'op' expires later than t_op, then insert 'op' just
* ahead of t_op. Otherwise, compute when operation[n-1]
* expires and try again.
*
- * The actual different between the expiriation of 'op'
+ * The actual difference between the expiriation of 'op'
* and the current operation what becomes the new operaton's
* timeout interval. That interval is also subtracted from
* the interval of the operation immediately following where
@@ -400,7 +417,7 @@ static void pt_InsertTimedInternal(pt_Continuation *op)
*/
if ((PRInt32)(op->absolute - t_op->absolute) >= 0)
{
- if (t_op == pt_tq.op) pt_tq.op = op;
+ if (t_op == tqp->op) tqp->op = op;
break;
}
}
@@ -414,11 +431,11 @@ done:
*
* We need to set up the 'next' and 'prev' pointers of 'op'
* correctly before inserting 'op' into the queue. Also, we insert
- * 'op' by updating pt_tq.head or op->prev->next first, and then
+ * 'op' by updating tqp->head or op->prev->next first, and then
* updating op->next->prev. We want to make sure that the 'next'
* pointers are linked up correctly at all times so that we can
- * traverse the queue by starting with pt_tq.head and following
- * the 'next' pointers, without having to acquire the pt_tq.ml lock.
+ * traverse the queue by starting with tqp->head and following
+ * the 'next' pointers, without having to acquire the tqp->ml lock.
* (we do that in pt_ContinuationThreadInternal). We traverse the 'prev'
* pointers only in this function, which is called with the lock held.
*
@@ -428,9 +445,9 @@ done:
if (NULL == t_op)
{
op->prev = NULL;
- op->next = pt_tq.head;
- pt_tq.head = op;
- if (NULL == pt_tq.tail) pt_tq.tail = op;
+ op->next = tqp->head;
+ tqp->head = op;
+ if (NULL == tqp->tail) tqp->tail = op;
else op->next->prev = op;
}
else
@@ -441,35 +458,35 @@ done:
op->prev->next = op;
if (NULL != op->next)
op->next->prev = op;
- if (t_op == pt_tq.tail)
- pt_tq.tail = op;
+ if (t_op == tqp->tail)
+ tqp->tail = op;
}
- pt_tq.op_count += 1;
+ tqp->op_count += 1;
#if defined(DEBUG)
{
PRIntn count;
pt_Continuation *tmp;
- PR_ASSERT(pt_tq.head != NULL);
- PR_ASSERT(pt_tq.tail != NULL);
- PR_ASSERT(pt_tq.op_count != 0);
- PR_ASSERT(pt_tq.head->prev == NULL);
- PR_ASSERT(pt_tq.tail->next == NULL);
- if (pt_tq.op_count > 1)
+ PR_ASSERT(tqp->head != NULL);
+ PR_ASSERT(tqp->tail != NULL);
+ PR_ASSERT(tqp->op_count != 0);
+ PR_ASSERT(tqp->head->prev == NULL);
+ PR_ASSERT(tqp->tail->next == NULL);
+ if (tqp->op_count > 1)
{
- PR_ASSERT(pt_tq.head->next != NULL);
- PR_ASSERT(pt_tq.tail->prev != NULL);
+ PR_ASSERT(tqp->head->next != NULL);
+ PR_ASSERT(tqp->tail->prev != NULL);
}
else
{
- PR_ASSERT(pt_tq.head->next == NULL);
- PR_ASSERT(pt_tq.tail->prev == NULL);
+ PR_ASSERT(tqp->head->next == NULL);
+ PR_ASSERT(tqp->tail->prev == NULL);
}
- for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
- for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
+ for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+ PR_ASSERT(count == tqp->op_count);
+ for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+ PR_ASSERT(count == tqp->op_count);
}
#endif /* defined(DEBUG) */
@@ -486,47 +503,48 @@ done:
static pt_Continuation *pt_FinishTimedInternal(pt_Continuation *op)
{
pt_Continuation *next;
+ struct pt_TimedQueue *tqp = &pt_tqp[op->io_tq_index];
#if defined(DEBUG)
{
PRIntn count;
pt_Continuation *tmp;
- PR_ASSERT(pt_tq.head != NULL);
- PR_ASSERT(pt_tq.tail != NULL);
- PR_ASSERT(pt_tq.op_count != 0);
- PR_ASSERT(pt_tq.head->prev == NULL);
- PR_ASSERT(pt_tq.tail->next == NULL);
- if (pt_tq.op_count > 1)
+ PR_ASSERT(tqp->head != NULL);
+ PR_ASSERT(tqp->tail != NULL);
+ PR_ASSERT(tqp->op_count != 0);
+ PR_ASSERT(tqp->head->prev == NULL);
+ PR_ASSERT(tqp->tail->next == NULL);
+ if (tqp->op_count > 1)
{
- PR_ASSERT(pt_tq.head->next != NULL);
- PR_ASSERT(pt_tq.tail->prev != NULL);
+ PR_ASSERT(tqp->head->next != NULL);
+ PR_ASSERT(tqp->tail->prev != NULL);
}
else
{
- PR_ASSERT(pt_tq.head->next == NULL);
- PR_ASSERT(pt_tq.tail->prev == NULL);
+ PR_ASSERT(tqp->head->next == NULL);
+ PR_ASSERT(tqp->tail->prev == NULL);
}
- for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
- for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
+ for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+ PR_ASSERT(count == tqp->op_count);
+ for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+ PR_ASSERT(count == tqp->op_count);
}
#endif /* defined(DEBUG) */
/* remove this one from the list */
- if (NULL == op->prev) pt_tq.head = op->next;
+ if (NULL == op->prev) tqp->head = op->next;
else op->prev->next = op->next;
- if (NULL == op->next) pt_tq.tail = op->prev;
+ if (NULL == op->next) tqp->tail = op->prev;
else op->next->prev = op->prev;
/* did we happen to hit the timed op? */
- if (op == pt_tq.op) pt_tq.op = op->prev;
+ if (op == tqp->op) tqp->op = op->prev;
next = op->next;
op->next = op->prev = NULL;
op->status = pt_continuation_done;
- pt_tq.op_count -= 1;
+ tqp->op_count -= 1;
#if defined(DEBUG)
pt_debug.continuationsServed += 1;
@@ -537,12 +555,12 @@ static pt_Continuation *pt_FinishTimedInternal(pt_Continuation *op)
{
PRIntn count;
pt_Continuation *tmp;
- PR_ASSERT((pt_tq.head == NULL) == (pt_tq.tail == NULL));
- PR_ASSERT((pt_tq.head == NULL) == (pt_tq.op_count == 0));
- for (tmp = pt_tq.head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
- for (tmp = pt_tq.tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
- PR_ASSERT(count == pt_tq.op_count);
+ PR_ASSERT((tqp->head == NULL) == (tqp->tail == NULL));
+ PR_ASSERT((tqp->head == NULL) == (tqp->op_count == 0));
+ for (tmp = tqp->head, count = 0; tmp != NULL; tmp = tmp->next) count += 1;
+ PR_ASSERT(count == tqp->op_count);
+ for (tmp = tqp->tail, count = 0; tmp != NULL; tmp = tmp->prev) count += 1;
+ PR_ASSERT(count == tqp->op_count);
}
#endif /* defined(DEBUG) */
@@ -556,14 +574,16 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
PRThreadPriority priority; /* used to save caller's prio */
PRIntn pollingListUsed; /* # entries used in the list */
PRIntn pollingListNeeded; /* # entries needed this time */
- static struct pollfd *pollingList = 0; /* list built for polling */
- static PRIntn pollingSlotsAllocated = 0;/* # entries available in list */
- static pt_Continuation **pollingOps = 0;/* list paralleling polling list */
+ PRIntn io_tq_index = my_op->io_tq_index;
+ struct pt_TimedQueue *tqp = &pt_tqp[my_op->io_tq_index];
+ struct pollfd *pollingList = tqp->pollingList;
+ PRIntn pollingSlotsAllocated = tqp->pollingSlotsAllocated;
+ pt_Continuation **pollingOps = tqp->pollingOps;
- PR_Unlock(pt_tq.ml); /* don't need that silly lock for a bit */
+ PR_Unlock(tqp->ml); /* don't need that silly lock for a bit */
- priority = PR_GetThreadPriority(pt_tq.thread);
- PR_SetThreadPriority(pt_tq.thread, PR_PRIORITY_HIGH);
+ priority = PR_GetThreadPriority(tqp->thread);
+ PR_SetThreadPriority(tqp->thread, PR_PRIORITY_HIGH);
mx_poll_ticks = (PRInt32)PR_MillisecondsToInterval(PT_DEFAULT_POLL_MSEC);
@@ -576,12 +596,12 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
PRIntervalTime now;
pt_Continuation *op, *next_op;
- PR_ASSERT(NULL != pt_tq.head);
+ PR_ASSERT(NULL != tqp->head);
- pollingListNeeded = pt_tq.op_count;
+ pollingListNeeded = tqp->op_count;
/*
- * We are not holding the pt_tq.ml lock now, so more items may
+ * We are not holding the tqp->ml lock now, so more items may
* get added to pt_tq during this window of time. We hope
* that 10 more spaces in the polling list should be enough.
*
@@ -598,9 +618,12 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
sizeof(pt_Continuation**) + pollingListNeeded *
(sizeof(struct pollfd) + sizeof(pt_Continuation*)));
PR_ASSERT(NULL != pollingOps);
+ tqp->pollingOps = pollingOps;
pollingSlotsAllocated = pollingListNeeded;
+ tqp->pollingSlotsAllocated = pollingSlotsAllocated;
pollingOps[pollingSlotsAllocated] = (pt_Continuation*)-1;
pollingList = (struct pollfd*)(&pollingOps[pollingSlotsAllocated + 1]);
+ tqp->pollingList = pollingList;
}
@@ -619,10 +642,10 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
** (perhaps) resetting it are safe 'cause it's the only modifiable
** bit in that word.
*/
- if (pt_tq.thread->state & PT_THREAD_ABORTED)
+ if (tqp->thread->state & PT_THREAD_ABORTED)
{
my_op->status = pt_continuation_abort;
- pt_tq.thread->state &= ~PT_THREAD_ABORTED;
+ tqp->thread->state &= ~PT_THREAD_ABORTED;
}
@@ -633,9 +656,9 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
* There is an assertion that the operation is in progress.
*/
pollingListUsed = 0;
- PR_Lock(pt_tq.ml);
+ PR_Lock(tqp->ml);
- for (op = pt_tq.head; NULL != op;)
+ for (op = tqp->head; NULL != op;)
{
if (pt_continuation_abort == op->status)
{
@@ -644,7 +667,7 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
next_op = pt_FinishTimedInternal(op);
if (op == my_op) goto recycle;
else op = next_op;
- PR_ASSERT(NULL != pt_tq.head);
+ PR_ASSERT(NULL != tqp->head);
}
else
{
@@ -657,7 +680,13 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
break;
}
PR_ASSERT((pt_Continuation*)-1 == pollingOps[pollingSlotsAllocated]);
- op->fd->secret->eventMask = 0xffff;
+ /*
+ * eventMask bitmasks are declared as PRIntn so that
+ * each bitmask can be updated individually without
+ * disturbing adjacent memory, but only the lower 16
+ * bits of a bitmask are used.
+ */
+ op->fd->secret->eventMask[io_tq_index] = 0xffff;
pollingOps[pollingListUsed] = op;
pollingList[pollingListUsed].revents = 0;
pollingList[pollingListUsed].fd = op->arg1.osfd;
@@ -674,17 +703,17 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
* should persist forever. But they may be aborted. That's
* what this anxiety is all about.
*/
- if (PR_INTERVAL_NO_TIMEOUT == pt_tq.head->timeout)
+ if (PR_INTERVAL_NO_TIMEOUT == tqp->head->timeout)
msecs = PT_DEFAULT_POLL_MSEC;
else
{
- timeout = pt_tq.head->absolute - PR_IntervalNow();
+ timeout = tqp->head->absolute - PR_IntervalNow();
if (timeout <= 0) msecs = 0; /* already timed out */
else if (timeout >= mx_poll_ticks) msecs = PT_DEFAULT_POLL_MSEC;
else msecs = (PRInt32)PR_IntervalToMilliseconds(timeout);
}
- PR_Unlock(pt_tq.ml);
+ PR_Unlock(tqp->ml);
/*
* If 'op' isn't NULL at this point, then we didn't get to
@@ -731,15 +760,15 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
if ((revents & POLLNVAL) /* busted in all cases */
|| ((events & POLLOUT) && (revents & POLLHUP))) /* write op & hup */
{
- PR_Lock(pt_tq.ml);
+ PR_Lock(tqp->ml);
op->result.code = -1;
if (POLLNVAL & revents) op->syserrno = EBADF;
else if (POLLHUP & revents) op->syserrno = EPIPE;
(void)pt_FinishTimedInternal(op);
if (op == my_op) goto recycle;
- PR_Unlock(pt_tq.ml);
+ PR_Unlock(tqp->ml);
}
- else if ((0 != (revents & op->fd->secret->eventMask))
+ else if ((0 != (revents & op->fd->secret->eventMask[io_tq_index]))
&& (pt_continuation_pending == op->status))
{
/*
@@ -751,10 +780,10 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
if (op->function(op, revents))
{
- PR_Lock(pt_tq.ml);
+ PR_Lock(tqp->ml);
(void)pt_FinishTimedInternal(op);
if (op == my_op) goto recycle;
- PR_Unlock(pt_tq.ml);
+ PR_Unlock(tqp->ml);
}
else
{
@@ -773,7 +802,7 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
* we won't invoke the continuation
* function again.
*/
- op->fd->secret->eventMask &= ~revents;
+ op->fd->secret->eventMask[io_tq_index] &= ~revents;
}
}
}
@@ -785,11 +814,11 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
* wire are lucky, but none the less, valid.
*/
now = PR_IntervalNow();
- PR_Lock(pt_tq.ml);
- while ((NULL != pt_tq.head)
- && (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout))
+ PR_Lock(tqp->ml);
+ while ((NULL != tqp->head)
+ && (PR_INTERVAL_NO_TIMEOUT != tqp->head->timeout))
{
- op = pt_tq.head; /* get a copy of this before finishing it */
+ op = tqp->head; /* get a copy of this before finishing it */
if ((PRInt32)(op->absolute - now) > 0) break;
/*
* The head element of the timed queue has timed out. Record
@@ -806,7 +835,7 @@ static void pt_ContinuationThreadInternal(pt_Continuation *my_op)
*/
if (op == my_op) goto recycle; /* exit w/o unlocking */
}
- PR_Unlock(pt_tq.ml);
+ PR_Unlock(tqp->ml);
}
PR_NOT_REACHED("This is a while(true) loop /w no breaks");
@@ -822,7 +851,7 @@ recycle:
** to 'recycle' and notifying the condition.
**
** Selecting a likely thread seems like magic. I'm going to try
- ** using one that has the longest (or no) timeout, pt_tq.tail.
+ ** using one that has the longest (or no) timeout, tqp->tail.
** If that slot's empty, then there's no outstanding I/O and we
** don't need a thread at all.
**
@@ -831,19 +860,19 @@ recycle:
*/
/* $$$ should this be called with the lock held? $$$ */
- PR_SetThreadPriority(pt_tq.thread, priority); /* reset back to caller's */
+ PR_SetThreadPriority(tqp->thread, priority); /* reset back to caller's */
- PR_ASSERT((NULL == pt_tq.head) == (0 == pt_tq.op_count));
- PR_ASSERT((NULL == pt_tq.head) == (NULL == pt_tq.tail));
+ PR_ASSERT((NULL == tqp->head) == (0 == tqp->op_count));
+ PR_ASSERT((NULL == tqp->head) == (NULL == tqp->tail));
PR_ASSERT(pt_continuation_done == my_op->status);
- if (NULL != pt_tq.tail)
+ if (NULL != tqp->tail)
{
- if (pt_tq.tail->status != pt_continuation_abort)
+ if (tqp->tail->status != pt_continuation_abort)
{
- pt_tq.tail->status = pt_continuation_recycle;
+ tqp->tail->status = pt_continuation_recycle;
}
- PR_NotifyCondVar(pt_tq.tail->complete);
+ PR_NotifyCondVar(tqp->tail->complete);
#if defined(DEBUG)
pt_debug.recyclesNeeded += 1;
#endif
@@ -858,13 +887,25 @@ static PRIntn pt_Continue(pt_Continuation *op)
{
PRStatus rv;
PRThread *self = PR_GetCurrentThread();
+ struct pt_TimedQueue *tqp;
+
+ /* lazy assignment of the thread's ioq */
+ if (-1 == self->io_tq_index)
+ {
+ self->io_tq_index = (PR_AtomicIncrement(&_pt_tq_index)-1) % _pt_tq_count;
+ }
+
+ PR_ASSERT(self->io_tq_index >= 0);
+ tqp = &pt_tqp[self->io_tq_index];
+
/* lazy allocation of the thread's cv */
if (NULL == self->io_cv)
- self->io_cv = PR_NewCondVar(pt_tq.ml);
+ self->io_cv = PR_NewCondVar(tqp->ml);
/* Finish filling in the blank slots */
op->complete = self->io_cv;
op->status = pt_continuation_pending; /* set default value */
- PR_Lock(pt_tq.ml); /* we provide the locking */
+ op->io_tq_index = self->io_tq_index;
+ PR_Lock(tqp->ml); /* we provide the locking */
pt_InsertTimedInternal(op); /* insert in the structure */
@@ -874,7 +915,7 @@ static PRIntn pt_Continue(pt_Continuation *op)
*/
do
{
- if (NULL == pt_tq.thread)
+ if (NULL == tqp->thread)
{
/*
** We're the one. Call the processing function with the lock
@@ -882,10 +923,10 @@ static PRIntn pt_Continue(pt_Continuation *op)
** will certainly be times within the function when it gets
** released.
*/
- pt_tq.thread = self; /* I'm taking control */
+ tqp->thread = self; /* I'm taking control */
pt_ContinuationThreadInternal(op); /* go slash and burn */
PR_ASSERT(pt_continuation_done == op->status);
- pt_tq.thread = NULL; /* I'm abdicating my rule */
+ tqp->thread = NULL; /* I'm abdicating my rule */
}
else
{
@@ -938,7 +979,7 @@ static PRIntn pt_Continue(pt_Continuation *op)
} while (pt_continuation_done != op->status);
- PR_Unlock(pt_tq.ml); /* we provided the locking */
+ PR_Unlock(tqp->ml); /* we provided the locking */
return op->result.code; /* and the primary answer */
} /* pt_Continue */
@@ -1151,16 +1192,33 @@ static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
} /* pt_recvfrom_cont */
#ifdef AIX
-static PRBool pt_aix_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
+static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
{
struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
int rv;
+ long long saved_file_offset;
+ long long saved_file_bytes;
+ saved_file_offset = sf_struct->file_offset;
+ saved_file_bytes = sf_struct->file_bytes;
+ sf_struct->bytes_sent = 0;
+
+ if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
+ PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
+ sf_struct->file_size);
rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
op->syserrno = errno;
if (rv != -1) {
op->result.code += sf_struct->bytes_sent;
+ /*
+ * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
+ * being updated. So, 'file_bytes' is maintained by NSPR to
+ * avoid conflict when this bug is fixed in AIX, in the future.
+ */
+ if (saved_file_bytes != -1)
+ saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
+ sf_struct->file_bytes = saved_file_bytes;
} else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
op->result.code = -1;
} else {
@@ -1176,13 +1234,13 @@ static PRBool pt_aix_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
#endif /* AIX */
#ifdef HPUX11
-static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
+static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
{
struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
int count;
- count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.offset, 0,
- hdtrl, op->arg4.flags);
+ count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
+ op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
PR_ASSERT(count <= op->nbytes_to_send);
op->syserrno = errno;
@@ -1193,20 +1251,41 @@ static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
} else {
return PR_FALSE;
}
-
if (count != -1 && count < op->nbytes_to_send) {
- if (hdtrl[0].iov_len == 0) {
- PR_ASSERT(hdtrl[0].iov_base == NULL);
- op->arg3.offset += count;
- } else if (count < hdtrl[0].iov_len) {
- PR_ASSERT(op->arg3.offset == 0);
- hdtrl[0].iov_base = (char *) hdtrl[0].iov_base + count;
+ if (count < hdtrl[0].iov_len) {
+ /* header not sent */
+
+ hdtrl[0].iov_base = ((char *) hdtrl[0].iov_len) + count;
hdtrl[0].iov_len -= count;
- } else {
- op->arg3.offset = count - hdtrl[0].iov_len;
+
+ } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
+ /* header sent, file not sent */
+ PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
+
hdtrl[0].iov_base = NULL;
hdtrl[0].iov_len = 0;
- }
+
+ op->arg3.file_spec.offset += file_nbytes_sent;
+ op->arg3.file_spec.nbytes -= file_nbytes_sent;
+ } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
+ hdtrl[1].iov_len)) {
+ PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
+ op->arg3.file_spec.nbytes);
+
+ /* header sent, file sent, trailer not sent */
+
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = 0;
+ /*
+ * set file offset and len so that no more file data is
+ * sent
+ */
+ op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
+ op->arg3.file_spec.nbytes = 0;
+
+ hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
+ hdtrl[1].iov_len -= trailer_nbytes_sent;
+ }
op->nbytes_to_send -= count;
return PR_FALSE;
}
@@ -1215,18 +1294,57 @@ static PRBool pt_hpux_transmitfile_cont(pt_Continuation *op, PRInt16 revents)
}
#endif /* HPUX11 */
+#define _MD_CPUS_ONLINE 2
+
void _PR_InitIO()
{
- pt_tq.ml = PR_NewLock();
- PR_ASSERT(NULL != pt_tq.ml);
+ PRIntn index;
+ char *num_io_queues;
+
+ if (num_io_queues = getenv("NSPR_NUM_IO_QUEUES"))
+ {
+ _pt_tq_count = atoi(num_io_queues);
+ }
+ else
+ {
+ /*
+ * Get the number of CPUs if the pthread
+ * library has kernel-scheduled entities that
+ * can run on multiple CPUs.
+ */
+#ifdef HPUX11
+ _pt_num_cpus = pthread_num_processors_np();
+#elif defined(IRIX) || defined(OSF1)
+ _pt_num_cpus = sysconf(_SC_NPROC_ONLN);
+#elif defined(AIX) || defined(LINUX) || defined(SOLARIS)
+ _pt_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ /*
+ * A pure user-level (Mx1) pthread library can
+ * only use one CPU, even on a multiprocessor.
+ */
+ _pt_num_cpus = 1;
+#endif
+ if (_pt_num_cpus < 0)
+ _pt_num_cpus = _MD_CPUS_ONLINE;
+ _pt_tq_count = _pt_num_cpus;
+ }
+
+ pt_tqp = (struct pt_TimedQueue *)
+ PR_CALLOC(_pt_tq_count * sizeof(struct pt_TimedQueue));
+ PR_ASSERT(NULL != pt_tqp);
+
+ for (index = 0; index < _pt_tq_count; index++)
+ {
+ pt_tqp[index].ml = PR_NewLock();
+ PR_ASSERT(NULL != pt_tqp[index].ml);
+ }
#if defined(DEBUG)
memset(&pt_debug, 0, sizeof(PTDebug));
pt_debug.timeStarted = PR_Now();
#endif
- pt_tq.thread = NULL;
-
_pr_flock_lock = PR_NewLock();
PR_ASSERT(NULL != _pr_flock_lock);
_pr_rename_lock = PR_NewLock();
@@ -1384,79 +1502,80 @@ static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
static PRInt32 pt_Writev(
PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
{
- PRIntn iov_index = 0;
+ PRIntn iov_index;
PRBool fNeedContinue = PR_FALSE;
- PRInt32 syserrno, bytes = -1, rv = -1;
+ PRInt32 syserrno, bytes, rv = -1;
+ struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
+ int osiov_len;
if (pt_TestAbort()) return rv;
- /*
- * The first shot at this can use the client's iov directly.
- * Only if we have to continue the operation do we have to
- * make a copy that we can modify.
- */
- rv = bytes = writev(fd->secret->md.osfd, (const struct iovec*)iov, iov_len);
- syserrno = errno;
+ /* Ensured by PR_Writev */
+ PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
/*
- * If we moved some bytes (ie., bytes > 0) how does that implicate
- * the i/o vector list. In other words, exactly where are we within
- * that array? What are the parameters for resumption? Maybe we're
- * done!
+ * We can't pass iov to writev because PRIOVec and struct iovec
+ * may not be binary compatible. Make osiov a copy of iov and
+ * pass osiov to writev. We can modify osiov if we need to
+ * continue the operation.
*/
- if ((bytes > 0) && (!fd->secret->nonblocking))
+ osiov = osiov_local;
+ osiov_len = iov_len;
+ for (iov_index = 0; iov_index < osiov_len; iov_index++)
{
- for (iov_index = 0; iov_index < iov_len; ++iov_index)
- {
- if (bytes < iov[iov_index].iov_len) break; /* continue w/ what's left */
- bytes -= iov[iov_index].iov_len; /* this one's done cooked */
- }
+ osiov[iov_index].iov_base = iov[iov_index].iov_base;
+ osiov[iov_index].iov_len = iov[iov_index].iov_len;
}
- if ((bytes >= 0) && (iov_index < iov_len) && (!fd->secret->nonblocking))
+ rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
+ syserrno = errno;
+
+ if (!fd->secret->nonblocking)
{
- if (PR_INTERVAL_NO_WAIT == timeout)
+ if (bytes >= 0)
{
- rv = -1;
- syserrno = ETIMEDOUT;
+ /*
+ * If we moved some bytes, how does that implicate the
+ * i/o vector list? In other words, exactly where are
+ * we within that array? What are the parameters for
+ * resumption? Maybe we're done!
+ */
+ for ( ;osiov_len > 0; osiov++, osiov_len--)
+ {
+ if (bytes < osiov->iov_len)
+ {
+ /* this one's not done yet */
+ osiov->iov_base = (char*)osiov->iov_base + bytes;
+ osiov->iov_len -= bytes;
+ break; /* go off and do that */
+ }
+ bytes -= osiov->iov_len; /* this one's done cooked */
+ }
+ PR_ASSERT(osiov_len > 0 || bytes == 0);
+ if (osiov_len > 0)
+ {
+ if (PR_INTERVAL_NO_WAIT == timeout)
+ {
+ rv = -1;
+ syserrno = ETIMEDOUT;
+ }
+ else fNeedContinue = PR_TRUE;
+ }
}
- else fNeedContinue = PR_TRUE;
- }
- else if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
- && (!fd->secret->nonblocking))
- {
- if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
- else
+ else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
{
- rv = bytes = 0;
- fNeedContinue = PR_TRUE;
+ if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
+ else
+ {
+ rv = 0;
+ fNeedContinue = PR_TRUE;
+ }
}
}
if (fNeedContinue == PR_TRUE)
{
pt_Continuation op;
- /*
- * Okay. Now we need a modifiable copy of the array.
- * Allocate some storage and copy the (already) modified
- * bits into the new vector. The is copying only the
- * part of the array that's still valid. The array may
- * have a new length and the first element of the array may
- * have different values.
- */
- struct iovec *osiov = NULL, *tiov;
- PRIntn osiov_len = iov_len - iov_index; /* recompute */
- osiov = (struct iovec*)PR_MALLOC(osiov_len * sizeof(struct iovec));
- PR_ASSERT(NULL != osiov);
- for (tiov = osiov; iov_index < iov_len; ++iov_index)
- {
- tiov->iov_base = iov[iov_index].iov_base;
- tiov->iov_len = iov[iov_index].iov_len;
- tiov += 1;
- }
- osiov->iov_len -= bytes; /* that may be partially done */
- /* so advance the description */
- osiov->iov_base = (char*)osiov->iov_base + bytes;
op.fd = fd;
op.arg1.osfd = fd->secret->md.osfd;
@@ -1468,7 +1587,6 @@ static PRInt32 pt_Writev(
op.event = POLLOUT | POLLPRI;
rv = pt_Continue(&op);
syserrno = op.syserrno;
- PR_DELETE(osiov);
}
if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
return rv;
@@ -2037,11 +2155,10 @@ static void pt_aix_sendfile_init_routine(void)
}
/*
- * pt_AIXDispatchTransmitFile
+ * pt_AIXDispatchSendFile
*/
-static PRInt32 pt_AIXDispatchTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
- const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
- PRIntervalTime timeout)
+static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
{
int rv;
@@ -2049,18 +2166,19 @@ static PRInt32 pt_AIXDispatchTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
pt_aix_sendfile_init_routine);
PR_ASSERT(0 == rv);
if (pt_aix_sendfile_fptr) {
- return pt_AIXTransmitFile(sd, fd, headers, hlen, flags, timeout);
+ return pt_AIXSendFile(sd, sfd, flags, timeout);
} else {
- return _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
+ return _PR_UnixSendFile(sd, sfd, flags, timeout);
}
}
#endif /* !HAVE_SEND_FILE */
+
/*
- * pt_AIXTransmitFile
+ * pt_AIXSendFile
*
- * Send file fd across socket sd. If headers is non-NULL, 'hlen'
- * bytes of headers is sent before sending the file.
+ * Send file sfd->fd across socket sd. If specified, header and trailer
+ * buffers are sent before and after the file, respectively.
*
* PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
*
@@ -2070,27 +2188,34 @@ static PRInt32 pt_AIXDispatchTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
* call available in AIX 4.3.2.
*/
-static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
- const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
- PRIntervalTime timeout)
+static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
{
struct sf_parms sf_struct;
uint_t send_flags;
ssize_t rv;
int syserrno;
PRInt32 count;
+ long long saved_file_offset;
+ long long saved_file_bytes;
- sf_struct.header_data = (void *) headers; /* cast away the 'const' */
- sf_struct.header_length = hlen;
- sf_struct.file_descriptor = fd->secret->md.osfd;
+ sf_struct.header_data = (void *) sfd->header; /* cast away the 'const' */
+ sf_struct.header_length = sfd->hlen;
+ sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
sf_struct.file_size = 0;
- sf_struct.file_offset = 0;
- sf_struct.file_bytes = -1;
- sf_struct.trailer_data = NULL;
- sf_struct.trailer_length = 0;
+ sf_struct.file_offset = sfd->file_offset;
+ if (sfd->file_nbytes == 0)
+ sf_struct.file_bytes = -1;
+ else
+ sf_struct.file_bytes = sfd->file_nbytes;
+ sf_struct.trailer_data = (void *) sfd->trailer;
+ sf_struct.trailer_length = sfd->tlen;
sf_struct.bytes_sent = 0;
- send_flags = 0;
+ saved_file_offset = sf_struct.file_offset;
+ saved_file_bytes = sf_struct.file_bytes;
+
+ send_flags = 0; /* flags processed at the end */
do {
rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
@@ -2104,6 +2229,14 @@ static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
}
} else {
count = sf_struct.bytes_sent;
+ /*
+ * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
+ * being updated. So, 'file_bytes' is maintained by NSPR to
+ * avoid conflict when this bug is fixed in AIX, in the future.
+ */
+ if (saved_file_bytes != -1)
+ saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
+ sf_struct.file_bytes = saved_file_bytes;
}
if ((rv == 1) || ((rv == -1) && (count == 0))) {
@@ -2115,7 +2248,7 @@ static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
op.arg4.flags = send_flags;
op.result.code = count;
op.timeout = timeout;
- op.function = pt_aix_transmitfile_cont;
+ op.function = pt_aix_sendfile_cont;
op.event = POLLOUT | POLLPRI;
count = pt_Continue(&op);
syserrno = op.syserrno;
@@ -2128,16 +2261,20 @@ static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
PR_Close(sd);
}
+ PR_ASSERT(count == (sfd->hlen + sfd->tlen +
+ ((sfd->file_nbytes == 0) ?
+ sf_struct.file_size - sfd->file_offset :
+ sfd->file_nbytes)));
return count;
}
#endif /* AIX */
#ifdef HPUX11
/*
- * pt_HPUXTransmitFile
+ * pt_HPUXSendFile
*
- * Send file fd across socket sd. If headers is non-NULL, 'hlen'
- * bytes of headers is sent before sending the file.
+ * Send file sfd->fd across socket sd. If specified, header and trailer
+ * buffers are sent before and after the file, respectively.
*
* PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
*
@@ -2147,28 +2284,30 @@ static PRInt32 pt_AIXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
* call available in HP-UX B.11.00.
*/
-static PRInt32 pt_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
- const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
- PRIntervalTime timeout)
+static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
{
struct stat statbuf;
- size_t nbytes_to_send;
+ size_t nbytes_to_send, file_nbytes_to_send;
struct iovec hdtrl[2]; /* optional header and trailer buffers */
int send_flags;
PRInt32 count;
int syserrno;
/* Get file size */
- if (fstat(fd->secret->md.osfd, &statbuf) == -1) {
+ if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
_PR_MD_MAP_FSTAT_ERROR(errno);
return -1;
}
- nbytes_to_send = hlen + statbuf.st_size;
-
- hdtrl[0].iov_base = (void *) headers; /* cast away the 'const' */
- hdtrl[0].iov_len = hlen;
- hdtrl[1].iov_base = NULL;
- hdtrl[1].iov_base = 0;
+ file_nbytes_to_send = (sfd->file_nbytes == 0) ?
+ statbuf.st_size - sfd->file_offset :
+ sfd->file_nbytes;
+ nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
+
+ hdtrl[0].iov_base = (void *) sfd->header; /* cast away the 'const' */
+ hdtrl[0].iov_len = sfd->hlen;
+ hdtrl[1].iov_base = (void *) sfd->trailer;
+ hdtrl[1].iov_len = sfd->tlen;
/*
* SF_DISCONNECT seems to close the socket even if sendfile()
* only does a partial send on a nonblocking socket. This
@@ -2178,9 +2317,8 @@ static PRInt32 pt_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
send_flags = 0;
do {
- count = sendfile(sd->secret->md.osfd, fd->secret->md.osfd,
- 0, 0, hdtrl, send_flags);
- PR_ASSERT(count <= nbytes_to_send);
+ count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
+ sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
} while (count == -1 && (syserrno = errno) == EINTR);
if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
@@ -2189,25 +2327,50 @@ static PRInt32 pt_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
if (count != -1 && count < nbytes_to_send) {
pt_Continuation op;
- if (count < hlen) {
- hdtrl[0].iov_base = ((char *) headers) + count;
- hdtrl[0].iov_len = hlen - count;
- op.arg3.offset = 0;
- } else {
+ if (count < sfd->hlen) {
+ /* header not sent */
+
+ hdtrl[0].iov_base = ((char *) sfd->header) + count;
+ hdtrl[0].iov_len = sfd->hlen - count;
+ op.arg3.file_spec.offset = sfd->file_offset;
+ op.arg3.file_spec.nbytes = file_nbytes_to_send;
+ } else if (count < (sfd->hlen + file_nbytes_to_send)) {
+ /* header sent, file not sent */
+
hdtrl[0].iov_base = NULL;
hdtrl[0].iov_len = 0;
- op.arg3.offset = count - hlen;
- }
+
+ op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
+ op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
+ } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
+ PRUint32 trailer_nbytes_sent;
+
+ /* header sent, file sent, trailer not sent */
+
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = 0;
+ /*
+ * set file offset and len so that no more file data is
+ * sent
+ */
+ op.arg3.file_spec.offset = statbuf.st_size;
+ op.arg3.file_spec.nbytes = 0;
+
+ trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
+ hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
+ hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
+ }
op.fd = sd;
op.arg1.osfd = sd->secret->md.osfd;
- op.filedesc = fd->secret->md.osfd;
+ op.filedesc = sfd->fd->secret->md.osfd;
op.arg2.buffer = hdtrl;
+ op.arg3.file_spec.st_size = statbuf.st_size;
op.arg4.flags = send_flags;
op.nbytes_to_send = nbytes_to_send - count;
op.result.code = count;
op.timeout = timeout;
- op.function = pt_hpux_transmitfile_cont;
+ op.function = pt_hpux_sendfile_cont;
op.event = POLLOUT | POLLPRI;
count = pt_Continue(&op);
syserrno = op.syserrno;
@@ -2220,33 +2383,27 @@ static PRInt32 pt_HPUXTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
PR_Close(sd);
}
+ PR_ASSERT(count == nbytes_to_send);
return count;
}
+
#endif /* HPUX11 */
static PRInt32 pt_TransmitFile(
PRFileDesc *sd, PRFileDesc *fd, const void *headers,
PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
{
- if (pt_TestAbort()) return -1;
- /* The socket must be in blocking mode. */
- if (sd->secret->nonblocking)
- {
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return -1;
- }
+ PRSendFileData sfd;
-#ifdef HPUX11
- return pt_HPUXTransmitFile(sd, fd, headers, hlen, flags, timeout);
-#elif defined(AIX)
-#ifdef HAVE_SEND_FILE
- return pt_AIXTransmitFile(sd, fd, headers, hlen, flags, timeout);
-#else
- return pt_AIXDispatchTransmitFile(sd, fd, headers, hlen, flags, timeout);
-#endif /* HAVE_SEND_FILE */
-#else
- return _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
-#endif
+ sfd.fd = fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ sfd.header = headers;
+ sfd.hlen = hlen;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+
+ return(PR_SendFile(sd, &sfd, flags, timeout));
} /* pt_TransmitFile */
/*
@@ -2831,7 +2988,15 @@ static PRFileDesc *pt_SetMethods(PRIntn osfd, PRDescType type)
fd->secret->md.osfd = osfd;
fd->secret->state = _PR_FILEDESC_OPEN;
/* By default, a Unix fd is not closed on exec. */
- PR_ASSERT(0 == fcntl(osfd, F_GETFD, 0));
+#ifdef DEBUG
+ /*
+ * Ignore EBADF error on fd's 0, 1, 2 because they are
+ * not open in all processes.
+ */
+ flags = fcntl(osfd, F_GETFD, 0);
+ PR_ASSERT((0 == flags) || (-1 == flags
+ && (0 <= osfd && osfd <= 2) && errno == EBADF));
+#endif
fd->secret->inheritable = PR_TRUE;
switch (type)
{
@@ -3421,55 +3586,34 @@ PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket()
{
- PRFileDesc *fd = NULL;
- PRIntn osfd = -1, syserrno;
PRIntn domain = PF_INET;
- if (!_pr_initialized) _PR_ImplicitInitialization();
-
- if (pt_TestAbort()) return NULL;
-
#if defined(_PR_INET6)
if (_pr_ipv6_enabled)
domain = PF_INET6;
#endif
- osfd = socket(domain, SOCK_DGRAM, 0);
- syserrno = errno;
-
- if (osfd == -1)
- pt_MapError(_PR_MD_MAP_SOCKET_ERROR, syserrno);
- else
- {
- fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP);
- if (fd == NULL) close(osfd);
- }
- return fd;
+ return PR_Socket(domain, SOCK_DGRAM, 0);
} /* PR_NewUDPSocket */
PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket()
{
- PRIntn osfd = -1;
- PRFileDesc *fd = NULL;
PRIntn domain = PF_INET;
- if (!_pr_initialized) _PR_ImplicitInitialization();
-
- if (pt_TestAbort()) return NULL;
-
#if defined(_PR_INET6)
if (_pr_ipv6_enabled)
domain = PF_INET6;
#endif
- osfd = socket(domain, SOCK_STREAM, 0);
+ return PR_Socket(domain, SOCK_STREAM, 0);
+} /* PR_NewTCPSocket */
- if (osfd == -1)
- pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
- else
- {
- fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP);
- if (fd == NULL) close(osfd);
- }
- return fd;
+PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
+{
+ return PR_Socket(af, SOCK_DGRAM, 0);
+} /* PR_NewUDPSocket */
+
+PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
+{
+ return PR_Socket(af, SOCK_STREAM, 0);
} /* PR_NewTCPSocket */
PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
@@ -3970,6 +4114,44 @@ retry:
return rv;
}
+#ifdef AIX
+extern int _pr_aix_send_file_use_disabled;
+#endif
+
+PR_IMPLEMENT(PRInt32) PR_SendFile(
+ PRFileDesc *sd, PRSendFileData *sfd,
+ PRTransmitFileFlags flags, PRIntervalTime timeout)
+{
+ if (pt_TestAbort()) return -1;
+ /* The socket must be in blocking mode. */
+ if (sd->secret->nonblocking)
+ {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return -1;
+ }
+#ifdef HPUX11
+ return(pt_HPUXSendFile(sd, sfd, flags, timeout));
+#elif defined(AIX)
+#ifdef HAVE_SEND_FILE
+ /*
+ * A bug in AIX 4.3.2 results in corruption of data transferred by
+ * send_file(); AIX patch PTF U463956 contains the fix. A user can
+ * disable the use of send_file function in NSPR, when this patch is
+ * not installed on the system, by setting the envionment variable
+ * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
+ */
+ if (_pr_aix_send_file_use_disabled)
+ return(_PR_UnixSendFile(sd, sfd, flags, timeout));
+ else
+ return(pt_AIXSendFile(sd, sfd, flags, timeout));
+#else
+ return(_PR_UnixSendFile(sd, sfd, flags, timeout));
+ /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
+#endif /* HAVE_SEND_FILE */
+#else
+ return(_PR_UnixSendFile(sd, sfd, flags, timeout));
+#endif
+}
#endif /* defined(_PR_PTHREADS) */
/* ptio.c */
diff --git a/pr/src/pthreads/ptmisc.c b/pr/src/pthreads/ptmisc.c
index 1cd4a8f2..ce6d663f 100644
--- a/pr/src/pthreads/ptmisc.c
+++ b/pr/src/pthreads/ptmisc.c
@@ -26,6 +26,9 @@
#include "primpl.h"
#include <stdio.h>
+#ifdef SOLARIS
+#include <thread.h>
+#endif
#define PT_LOG(f)
@@ -33,7 +36,13 @@ void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")}
void _PR_InitStacks(void) {PT_LOG("_PR_InitStacks")}
PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs)
- {PT_LOG("PR_SetConcurrency")}
+{
+#ifdef SOLARIS
+ thr_setconcurrency(numCPUs);
+#else
+ PT_LOG("PR_SetConcurrency");
+#endif
+}
PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 flag)
{PT_LOG("PR_SetThreadRecycleMode")}
diff --git a/pr/src/pthreads/ptsynch.c b/pr/src/pthreads/ptsynch.c
index 2d61ee8c..7beaf450 100644
--- a/pr/src/pthreads/ptsynch.c
+++ b/pr/src/pthreads/ptsynch.c
@@ -649,6 +649,319 @@ PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
return NULL;
}
+#ifdef _PR_HAVE_POSIX_SEMAPHORES
+#include <fcntl.h>
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+ const char *name,
+ PRIntn flags,
+ PRIntn mode,
+ PRUintn value)
+{
+ PRSem *sem;
+ char osname[PR_IPC_NAME_SIZE];
+
+ if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+ == PR_FAILURE)
+ {
+ return NULL;
+ }
+
+ sem = PR_NEW(PRSem);
+ if (NULL == sem)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
+
+ if (flags & PR_SEM_CREATE)
+ {
+ int oflag = O_CREAT;
+
+ if (flags & PR_SEM_EXCL) oflag |= O_EXCL;
+ sem->sem = sem_open(osname, oflag, mode, value);
+ }
+ else
+ {
+ sem->sem = sem_open(osname, 0);
+ }
+ if ((sem_t *) -1 == sem->sem)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ return sem;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+ int rv;
+ rv = sem_wait(sem->sem);
+ if (0 != rv)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+ int rv;
+ rv = sem_post(sem->sem);
+ if (0 != rv)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+ int rv;
+ rv = sem_close(sem->sem);
+ if (0 != rv)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ PR_DELETE(sem);
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+ int rv;
+ char osname[PR_IPC_NAME_SIZE];
+
+ if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+ == PR_FAILURE)
+ {
+ return PR_FAILURE;
+ }
+ rv = sem_unlink(osname);
+ if (0 != rv)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+#endif /* _PR_HAVE_POSIX_SEMAPHORES */
+
+#ifdef _PR_HAVE_SYSV_SEMAPHORES
+
+#include <fcntl.h>
+#include <sys/sem.h>
+
+/*
+ * From the semctl(2) man page in glibc 2.0
+ */
+#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
+/* union semun is defined by including <sys/sem.h> */
+#else
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
+#endif
+
+/*
+ * 'a' (97) is the final closing price of NSCP stock.
+ */
+#define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */
+
+#define NSPR_SEM_MODE 0666
+
+PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
+ const char *name,
+ PRIntn flags,
+ PRIntn mode,
+ PRUintn value)
+{
+ PRSem *sem;
+ key_t key;
+ union semun arg;
+ struct sembuf sop;
+ struct semid_ds seminfo;
+#define MAX_TRIES 60
+ PRIntn i;
+ char osname[PR_IPC_NAME_SIZE];
+
+ if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+ == PR_FAILURE)
+ {
+ return NULL;
+ }
+
+ /* Make sure the file exists before calling ftok. */
+ if (flags & PR_SEM_CREATE)
+ {
+ int osfd = open(osname, O_RDWR|O_CREAT, mode);
+ if (-1 == osfd)
+ {
+ _PR_MD_MAP_OPEN_ERROR(errno);
+ return NULL;
+ }
+ if (close(osfd) == -1)
+ {
+ _PR_MD_MAP_CLOSE_ERROR(errno);
+ return NULL;
+ }
+ }
+ key = ftok(osname, NSPR_IPC_KEY_ID);
+ if ((key_t)-1 == key)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return NULL;
+ }
+
+ sem = PR_NEW(PRSem);
+ if (NULL == sem)
+ {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
+
+ if (flags & PR_SEM_CREATE)
+ {
+ sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL);
+ if (sem->semid >= 0)
+ {
+ /* creator of a semaphore is responsible for initializing it */
+ arg.val = 0;
+ if (semctl(sem->semid, 0, SETVAL, arg) == -1)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ /* call semop to set sem_otime to nonzero */
+ sop.sem_num = 0;
+ sop.sem_op = value;
+ sop.sem_flg = 0;
+ if (semop(sem->semid, &sop, 1) == -1)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ return sem;
+ }
+
+ if (errno != EEXIST || flags & PR_SEM_EXCL)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ }
+
+ sem->semid = semget(key, 1, NSPR_SEM_MODE);
+ if (sem->semid == -1)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ for (i = 0; i < MAX_TRIES; i++)
+ {
+ arg.buf = &seminfo;
+ semctl(sem->semid, 0, IPC_STAT, arg);
+ if (seminfo.sem_otime != 0) break;
+ sleep(1);
+ }
+ if (i == MAX_TRIES)
+ {
+ PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
+ PR_DELETE(sem);
+ return NULL;
+ }
+ return sem;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
+{
+ struct sembuf sop;
+
+ sop.sem_num = 0;
+ sop.sem_op = -1;
+ sop.sem_flg = 0;
+ if (semop(sem->semid, &sop, 1) == -1)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
+{
+ struct sembuf sop;
+
+ sop.sem_num = 0;
+ sop.sem_op = 1;
+ sop.sem_flg = 0;
+ if (semop(sem->semid, &sop, 1) == -1)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
+{
+ PR_DELETE(sem);
+ return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
+{
+ key_t key;
+ int semid;
+ /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
+ union semun unused;
+ char osname[PR_IPC_NAME_SIZE];
+
+ if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
+ == PR_FAILURE)
+ {
+ return PR_FAILURE;
+ }
+ key = ftok(osname, NSPR_IPC_KEY_ID);
+ if ((key_t) -1 == key)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ if (unlink(osname) == -1)
+ {
+ _PR_MD_MAP_UNLINK_ERROR(errno);
+ return PR_FAILURE;
+ }
+ semid = semget(key, 1, NSPR_SEM_MODE);
+ if (-1 == semid)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ unused.val = 0;
+ if (semctl(semid, 0, IPC_RMID, unused) == -1)
+ {
+ _PR_MD_MAP_DEFAULT_ERROR(errno);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+#endif /* _PR_HAVE_SYSV_SEMAPHORES */
+
/**************************************************************/
/**************************************************************/
/******************ROUTINES FOR DCE EMULATION******************/
diff --git a/pr/src/pthreads/ptthread.c b/pr/src/pthreads/ptthread.c
index 943ea926..62e3452d 100644
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -225,6 +225,7 @@ static PRThread* pt_AttachThread(void)
PR_ASSERT(0 == rv);
thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;
+ thred->io_tq_index = -1;
PR_Lock(pt_book.ml);
/* then put it into the list */
@@ -363,6 +364,8 @@ static PRThread* _PR_CreateThread(
thred->stack->stackSize = stackSize;
thred->stack->thr = thred;
+ thred->io_tq_index = -1;
+
#ifdef PT_NO_SIGTIMEDWAIT
pthread_mutex_init(&thred->suspendResumeMutex,NULL);
pthread_cond_init(&thred->suspendResumeCV,NULL);
@@ -839,6 +842,8 @@ void _PR_InitThreads(
thred->stack->thr = thred;
_PR_InitializeStack(thred->stack);
+ thred->io_tq_index = -1;
+
/*
* Create a key for our use to store a backpointer in the pthread
* to our PRThread object. This object gets deleted when the thread
diff --git a/pr/src/threads/combined/prucpu.c b/pr/src/threads/combined/prucpu.c
index d7d9e84d..e4abf5e0 100644
--- a/pr/src/threads/combined/prucpu.c
+++ b/pr/src/threads/combined/prucpu.c
@@ -42,6 +42,7 @@ PRInt32 _pr_cpu_affinity_mask = 0;
static PRUintn _pr_cpuID;
static void PR_CALLBACK _PR_CPU_Idle(void *);
+
static _PRCPU *_PR_CreateCPU(PRThread *thread, PRBool needQueue);
void _PR_InitCPUs()
@@ -57,7 +58,8 @@ void _PR_InitCPUs()
#endif
#ifdef HAVE_CUSTOM_USER_THREADS
- _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
+ if (!_native_threads_only)
+ _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
#endif
/* Now start the first CPU. */
@@ -111,7 +113,6 @@ static _PRCPU *_PR_CreateCPU(PRThread *thread, PRBool needQueue)
*/
cpu = PR_NEWZAP(_PRCPU);
if (cpu) {
-
cpu->last_clock = PR_IntervalNow();
if (needQueue == PR_TRUE)
@@ -131,23 +132,26 @@ static _PRCPU *_PR_CreateCPU(PRThread *thread, PRBool needQueue)
_PR_MD_INIT_RUNNING_CPU(cpu);
thread->cpu = cpu;
- cpu->idle_thread = _PR_CreateThread(PR_SYSTEM_THREAD,
- _PR_CPU_Idle,
- (void *)cpu,
- PR_PRIORITY_NORMAL,
- PR_LOCAL_THREAD,
- PR_UNJOINABLE_THREAD,
- 0,
- _PR_IDLE_THREAD);
-
- if (!cpu->idle_thread) {
- /* didn't clean up CPU queue XXXMB */
- PR_DELETE(cpu);
- return NULL;
- }
- cpu->idle_thread->cpu = cpu;
-
- cpu->idle_thread->no_sched = 0;
+ if (!_native_threads_only) {
+
+ cpu->idle_thread = _PR_CreateThread(PR_SYSTEM_THREAD,
+ _PR_CPU_Idle,
+ (void *)cpu,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ 0,
+ _PR_IDLE_THREAD);
+
+ if (!cpu->idle_thread) {
+ /* didn't clean up CPU queue XXXMB */
+ PR_DELETE(cpu);
+ return NULL;
+ }
+ cpu->idle_thread->cpu = cpu;
+
+ cpu->idle_thread->no_sched = 0;
+ }
cpu->thread = thread;
@@ -178,6 +182,22 @@ static void _PR_RunCPU(void *unused)
PR_ASSERT(NULL != me);
+ /*
+ * _PR_CreateCPU calls _PR_CreateThread to create the
+ * idle thread. Because _PR_CreateThread calls PR_Lock,
+ * the current thread has to remain a global thread
+ * during the _PR_CreateCPU call so that it can wait for
+ * the lock if the lock is held by another thread. If
+ * we clear the _PR_GLOBAL_SCOPE flag in
+ * _PR_MD_CREATE_PRIMORDIAL_THREAD, the current thread
+ * will be treated as a local thread and have trouble
+ * waiting for the lock because the CPU is not fully
+ * constructed yet.
+ *
+ * After the CPU is created, it is safe to mark the
+ * current thread as a local thread.
+ */
+
#ifdef HAVE_CUSTOM_USER_THREADS
_PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
#endif
@@ -185,6 +205,10 @@ static void _PR_RunCPU(void *unused)
me->no_sched = 1;
cpu = _PR_CreateCPU(me, PR_TRUE);
+#ifdef HAVE_CUSTOM_USER_THREADS
+ me->flags &= (~_PR_GLOBAL_SCOPE);
+#endif
+
_PR_MD_SET_CURRENT_CPU(cpu);
_PR_MD_SET_CURRENT_THREAD(cpu->thread);
me->cpu = cpu;
@@ -212,7 +236,6 @@ static void PR_CALLBACK _PR_CPU_Idle(void *_cpu)
while(1) {
PRInt32 is;
PRIntervalTime timeout;
-
if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
_PR_RUNQ_LOCK(cpu);
@@ -243,10 +266,10 @@ static void PR_CALLBACK _PR_CPU_Idle(void *_cpu)
_PR_SLEEPQ_UNLOCK(cpu);
}
-
/* Wait for an IO to complete */
(void)_PR_MD_PAUSE_CPU(timeout);
+
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifdef _PR_HAVE_ATOMIC_OPS
_PR_MD_ATOMIC_DECREMENT(&_pr_md_idle_cpus);
@@ -257,19 +280,18 @@ static void PR_CALLBACK _PR_CPU_Idle(void *_cpu)
#endif /* _PR_HAVE_ATOMIC_OPS */
#endif
- _PR_ClockInterrupt();
+ _PR_ClockInterrupt();
- /* Now schedule any thread that is on the runq
- * INTS must be OFF when calling PR_Schedule()
- */
- me->state = _PR_RUNNABLE;
- _PR_MD_SWITCH_CONTEXT(me);
- if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is);
+ /* Now schedule any thread that is on the runq
+ * INTS must be OFF when calling PR_Schedule()
+ */
+ me->state = _PR_RUNNABLE;
+ _PR_MD_SWITCH_CONTEXT(me);
+ if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is);
}
}
#endif /* _PR_GLOBAL_THREADS_ONLY */
-
PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs)
{
#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_LOCAL_THREADS_ONLY)
@@ -284,7 +306,11 @@ PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs)
PRUintn newCPU;
PRThread *cpu;
+
if (!_pr_initialized) _PR_ImplicitInitialization();
+
+ if (_native_threads_only)
+ return;
_PR_CPU_LIST_LOCK();
if (_pr_numCPU < numCPUs) {
diff --git a/pr/src/threads/combined/prucv.c b/pr/src/threads/combined/prucv.c
index 90e405d1..78c83b59 100644
--- a/pr/src/threads/combined/prucv.c
+++ b/pr/src/threads/combined/prucv.c
@@ -21,6 +21,16 @@
#include "prinrval.h"
#include "prtypes.h"
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif
+
/*
** Notify one thread that it has finished waiting on a condition variable
@@ -332,6 +342,7 @@ void _PR_ClockInterrupt(void)
}
thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
+ PR_ASSERT(thread->cpu == cpu);
if (elapsed < thread->sleep) {
thread->sleep -= elapsed;
@@ -345,6 +356,17 @@ void _PR_ClockInterrupt(void)
_PR_THREAD_LOCK(thread);
+ if (thread->cpu != cpu) {
+ /*
+ ** The thread was switched to another CPU
+ ** between the time we unlocked the sleep
+ ** queue and the time we acquired the thread
+ ** lock, so it is none of our business now.
+ */
+ _PR_THREAD_UNLOCK(thread);
+ continue;
+ }
+
/*
** Consume this sleeper's amount of elapsed time from the elapsed
** time value. The next remaining piece of elapsed time will be
@@ -405,6 +427,13 @@ void _PR_ClockInterrupt(void)
int pri = thread->priority;
thread->io_suspended = PR_TRUE;
+#ifdef WINNT
+ /*
+ * For NT, record the cpu on which I/O was issued
+ * I/O cancellation is done on the same cpu
+ */
+ thread->md.thr_bound_cpu = cpu;
+#endif
PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
PR_ASSERT(thread->cpu == cpu);
diff --git a/pr/src/threads/combined/prulock.c b/pr/src/threads/combined/prulock.c
index aa20cfed..9b4a11ae 100644
--- a/pr/src/threads/combined/prulock.c
+++ b/pr/src/threads/combined/prulock.c
@@ -18,6 +18,16 @@
#include "primpl.h"
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif
+
void _PR_InitLocks(void)
{
@@ -221,6 +231,13 @@ PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
return;
#else /* _PR_GLOBAL_THREADS_ONLY */
+ if (_native_threads_only) {
+ PR_ASSERT(lock->owner != me);
+ _PR_MD_LOCK(&lock->ilock);
+ lock->owner = me;
+ return;
+ }
+
if (!_PR_IS_NATIVE_THREAD(me))
_PR_INTSOFF(is);
@@ -331,6 +348,12 @@ PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
return PR_SUCCESS;
#else /* _PR_GLOBAL_THREADS_ONLY */
+ if (_native_threads_only) {
+ lock->owner = 0;
+ _PR_MD_UNLOCK(&lock->ilock);
+ return PR_SUCCESS;
+ }
+
if (!_PR_IS_NATIVE_THREAD(me))
_PR_INTSOFF(is);
_PR_LOCK_LOCK(lock);
@@ -399,6 +422,17 @@ PR_IMPLEMENT(PRBool) PR_TestAndLock(PRLock *lock)
return PR_FALSE;
#else /* _PR_GLOBAL_THREADS_ONLY */
+#ifndef _PR_LOCAL_THREADS_ONLY
+ if (_native_threads_only) {
+ is = _PR_MD_TEST_AND_LOCK(&lock->ilock);
+ if (is == 0) {
+ lock->owner = me;
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+ }
+#endif
+
if (!_PR_IS_NATIVE_THREAD(me))
_PR_INTSOFF(is);
diff --git a/pr/src/threads/combined/pruthr.c b/pr/src/threads/combined/pruthr.c
index 38d84745..372e0b24 100644
--- a/pr/src/threads/combined/pruthr.c
+++ b/pr/src/threads/combined/pruthr.c
@@ -19,6 +19,15 @@
#include "primpl.h"
#include <signal.h>
#include <string.h>
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif
/* _pr_activeLock protects the following global variables */
PRLock *_pr_activeLock;
@@ -121,6 +130,9 @@ void _PR_InitThreads(PRThreadType type, PRThreadPriority priority,
thread->flags |= _PR_PRIMORDIAL;
#endif
+ if (_native_threads_only)
+ thread->flags |= _PR_GLOBAL_SCOPE;
+
/*
* Needs _PR_PRIMORDIAL flag set before calling
* _PR_MD_INIT_THREAD()
@@ -1095,6 +1107,9 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type,
scope = PR_GLOBAL_THREAD;
#endif
+ if (_native_threads_only)
+ scope = PR_GLOBAL_THREAD;
+
native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD))
&& _PR_IS_NATIVE_THREAD_SUPPORTED());
@@ -1319,7 +1334,7 @@ PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type,
*/
PR_Unlock(_pr_activeLock);
- if ( (thread->flags & _PR_IDLE_THREAD) || _PR_IS_NATIVE_THREAD(me) )
+ if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) )
thread->cpu = _PR_GetPrimordialCPU();
else
thread->cpu = _PR_MD_CURRENT_CPU();
@@ -1805,8 +1820,13 @@ _PR_AddThreadToRunQ(
* "post" the awakened thread to the IO completion port
* for the next idle CPU to execute (this is done in
* _PR_MD_WAKEUP_WAITER).
+ * Threads with a suspended I/O operation remain bound to
+ * the same cpu until I/O is cancelled
*/
- if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {
+ if (!_PR_IS_NATIVE_THREAD(me) && ((cpu == me->cpu) ||
+ (thread->io_suspended))) {
+ PR_ASSERT(!thread->io_suspended ||
+ (thread->md.thr_bound_cpu == cpu));
_PR_RUNQ_LOCK(cpu);
_PR_ADD_RUNQ(thread, cpu, pri);
_PR_RUNQ_UNLOCK(cpu);
diff --git a/pr/src/threads/prcthr.c b/pr/src/threads/prcthr.c
index dae37aa2..9dfb49d1 100644
--- a/pr/src/threads/prcthr.c
+++ b/pr/src/threads/prcthr.c
@@ -18,6 +18,17 @@
#include "primpl.h"
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif
+
+
extern PRLock *_pr_sleeplock; /* allocated and initialized in prinit */
/*
** Routines common to both native and user threads.
@@ -269,17 +280,7 @@ PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env)
PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
{
#ifdef HAVE_THREAD_AFFINITY
-/*
- * Irix ignores the thread argument
- */
-#ifndef IRIX
- if (_PR_IS_NATIVE_THREAD(thread))
- return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
- else
- return 0;
-#else
- return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
-#endif /* !IRIX */
+ return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
#else
#if defined(XP_MAC)
diff --git a/pr/src/threads/prdump.c b/pr/src/threads/prdump.c
index b36899b0..85231130 100644
--- a/pr/src/threads/prdump.c
+++ b/pr/src/threads/prdump.c
@@ -18,6 +18,16 @@
#include "primpl.h"
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif
+
/* XXX use unbuffered nspr stdio */
PRFileDesc *_pr_dumpOut;
diff --git a/pr/src/threads/prtpd.c b/pr/src/threads/prtpd.c
index 5e4b8e31..0fd71e4d 100644
--- a/pr/src/threads/prtpd.c
+++ b/pr/src/threads/prtpd.c
@@ -51,6 +51,16 @@
#include <string.h>
+#if defined(WIN95)
+/*
+** Some local variables report warnings on Win95 because the code paths
+** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
+** The pragma suppresses the warning.
+**
+*/
+#pragma warning(disable : 4101)
+#endif
+
#define _PR_TPD_MODULO 8 /* vectors are extended by this much */
#define _PR_TPD_LIMIT 128 /* arbitary limit on the TPD slots */
static PRInt32 _pr_tpd_length = 0; /* current length of destructor vector */
@@ -158,7 +168,7 @@ PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn his, void *priv)
}
else
{
- if ((NULL == self->privateData) || (self->tpdLength <= index))
+ if ((NULL == self->privateData) || (self->tpdLength <= (PRUint32)index))
{
void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*));
PR_ASSERT(
@@ -212,7 +222,7 @@ PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn his)
{
PRInt32 index = (PRInt32)his;
PRThread *self = PR_GetCurrentThread();
- void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ?
+ void *tpd = ((NULL == self->privateData) || ((PRUint32)index >= self->tpdLength)) ?
NULL : self->privateData[index];
return tpd;
@@ -232,7 +242,7 @@ void _PR_DestroyThreadPrivate(PRThread* self)
PR_ASSERT(0 != self->tpdLength);
do
{
- for (index = 0; index < self->tpdLength; ++index)
+ for (index = 0; (PRUint32)index < self->tpdLength; ++index)
{
void *priv = self->privateData[index]; /* extract */
if (NULL != priv) /* we have data at this index */
diff --git a/pr/tests/Makefile b/pr/tests/Makefile
index 33ae4112..49a5bf61 100644
--- a/pr/tests/Makefile
+++ b/pr/tests/Makefile
@@ -39,7 +39,9 @@ endif
CSRCS = \
accept.c \
acceptread.c \
+ affinity.c \
alarm.c \
+ anonfm.c \
atomic.c \
attach.c \
bigfile.c \
@@ -59,6 +61,7 @@ CSRCS = \
foreign.c \
forktest.c \
fsync.c \
+ gethost.c \
getproto.c \
i2l.c \
initclk.c \
@@ -82,6 +85,7 @@ CSRCS = \
multiacc.c \
multiwait.c \
many_cv.c \
+ nameshm1.c \
nbconn.c \
nblayer.c \
nonblock.c \
@@ -113,6 +117,11 @@ CSRCS = \
selct_to.c \
select2.c \
sem.c \
+ sema.c \
+ semaerr.c \
+ semaerr1.c \
+ semaping.c \
+ semapong.c \
server_test.c \
servr_kk.c \
servr_ku.c \
@@ -148,6 +157,7 @@ CSRCS = \
writev.c \
xnotify.c \
y2k.c \
+ y2ktmo.c \
$(NULL)
ifeq ($(OS_TARGET),OS2)
diff --git a/pr/tests/accept.c b/pr/tests/accept.c
index e77c2cfe..71f00b7f 100644
--- a/pr/tests/accept.c
+++ b/pr/tests/accept.c
@@ -118,6 +118,7 @@ ClientThread(void *_action)
PRInt32 rv;
char buf[CLIENT_DATA];
+ memset(buf, 0xaf, sizeof(buf)); /* initialize with arbitrary data */
sock = PR_NewTCPSocket();
if (!sock) {
if (!debug_mode)
diff --git a/pr/tests/affinity.c b/pr/tests/affinity.c
new file mode 100644
index 00000000..fa0f5acb
--- /dev/null
+++ b/pr/tests/affinity.c
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * Test PR_GetThreadAffinityMask
+ * The function is called by each of local, global and global bound threads
+ * The test should be run on both single and multi-cpu systems
+ */
+static void PR_CALLBACK thread_start(void *arg)
+{
+PRUint32 mask = 0;
+
+ if (PR_GetThreadAffinityMask(PR_GetCurrentThread(), &mask))
+ printf("\tthread_start: PR_GetCurrentThreadAffinityMask failed\n");
+ else
+ printf("\tthread_start: AffinityMask = 0x%x\n",mask);
+
+}
+
+int main(int argc, char **argv)
+{
+ PRThread *t;
+
+ printf("main: creating local thread\n");
+
+ t = PR_CreateThread(PR_USER_THREAD,
+ thread_start, 0,
+ PR_PRIORITY_NORMAL,
+ PR_LOCAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ if (NULL == t) {
+ printf("main: cannot create local thread\n");
+ exit(1);
+ }
+
+ PR_JoinThread(t);
+
+ printf("main: creating global thread\n");
+ t = PR_CreateThread(PR_USER_THREAD,
+ thread_start, 0,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ if (NULL == t) {
+ printf("main: cannot create global thread\n");
+ exit(1);
+ }
+
+ PR_JoinThread(t);
+
+ printf("main: creating global bound thread\n");
+ t = PR_CreateThread(PR_USER_THREAD,
+ thread_start, 0,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_BOUND_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+
+ if (NULL == t) {
+ printf("main: cannot create global bound thread\n");
+ exit(1);
+ }
+
+ PR_JoinThread(t);
+
+ return 0;
+}
diff --git a/pr/tests/anonfm.c b/pr/tests/anonfm.c
new file mode 100644
index 00000000..8ce1b15a
--- /dev/null
+++ b/pr/tests/anonfm.c
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** File: anonfm.c
+** Description: Test anonymous file map
+**
+** Synopsis: anonfm [options] [dirName]
+**
+** Options:
+** -d enable debug mode
+** -h display a help message
+** -s <n> size of the anonymous memory map, in KBytes. default: 100KBytes.
+** -C 1 Operate this process as ClientOne()
+** -C 2 Operate this process as ClientTwo()
+**
+** anonfn.c contains two tests, corresponding to the two protocols for
+** passing an anonymous file map to a child process.
+**
+** ServerOne()/ClientOne() tests the passing of "raw" file map; it uses
+** PR_CreateProcess() [for portability of the test case] to create the
+** child process, but does not use the PRProcessAttr structure for
+** passing the file map data.
+**
+** ServerTwo()/ClientTwo() tests the passing of the file map using the
+** PRProcessAttr structure.
+**
+*/
+#include <plgetopt.h>
+#include <nspr.h>
+#include <private/primpl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+** Test harness infrastructure
+*/
+PRLogModuleInfo *lm;
+PRLogModuleLevel msgLevel = PR_LOG_NONE;
+PRUint32 failed_already = 0;
+
+PRIntn debug = 0;
+PRIntn client = 0; /* invoke client, style */
+char dirName[512] = "."; /* directory name to contain anon mapped file */
+PRSize fmSize = (100 * 1024 );
+PRUint32 fmMode = 0600;
+PRFileMapProtect fmProt = PR_PROT_READWRITE;
+const char *fmEnvName = "nsprFileMapEnvVariable";
+
+/*
+** Emit help text for this test
+*/
+static void Help( void )
+{
+ printf("anonfm [options] [dirName]\n");
+ printf("-d -- enable debug mode\n");
+ printf("dirName is alternate directory name. Default: . (current directory)\n");
+ exit(1);
+} /* end Help() */
+
+
+/*
+** ClientOne() --
+*/
+static void ClientOne( void )
+{
+ PRFileMap *fm;
+ char *fmString;
+ char *addr;
+ PRStatus rc;
+
+ PR_LOG(lm, msgLevel,
+ ("ClientOne() starting"));
+
+ fmString = PR_GetEnv( fmEnvName );
+ if ( NULL == fmString ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_Getenv() failed"));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_Getenv(): found: %s", fmString));
+
+ fm = PR_ImportFileMapFromString( fmString );
+ if ( NULL == fm ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_ImportFileMapFromString() failed"));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_ImportFileMapFromString(): fm: %p", fm ));
+
+ addr = PR_MemMap( fm, 0, fmSize );
+ if ( NULL == addr ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_MemMap() failed, OSError: %d", PR_GetOSError() ));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_MemMap(): addr: %p", addr ));
+
+ /* write to memory map to release server */
+ *addr = 1;
+
+ rc = PR_MemUnmap( addr, fmSize );
+ PR_ASSERT( rc == PR_SUCCESS );
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_MemUnap(): success" ));
+
+ rc = PR_CloseFileMap( fm );
+ if ( PR_FAILURE == rc ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_MemUnap() failed, OSError: %d", PR_GetOSError() ));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ClientOne(): PR_CloseFileMap(): success" ));
+
+ return;
+} /* end ClientOne() */
+
+/*
+** ClientTwo() --
+*/
+static void ClientTwo( void )
+{
+ failed_already = 1;
+} /* end ClientTwo() */
+
+/*
+** ServerOne() --
+*/
+static void ServerOne( void )
+{
+ PRFileMap *fm;
+ PRStatus rc;
+ PRIntn i;
+ char *addr;
+ char fmString[256];
+ char envBuf[256];
+ char *child_argv[8];
+ PRProcess *proc;
+ PRInt32 exit_status;
+
+ PR_LOG(lm, msgLevel,
+ ("ServerOne() starting"));
+
+ fm = PR_OpenAnonFileMap( dirName, fmSize, fmProt );
+ if ( NULL == fm ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("PR_OpenAnonFileMap() failed"));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): FileMap: %p", fm ));
+
+ rc = PR_ExportFileMapAsString( fm, sizeof(fmString), fmString );
+ if ( PR_FAILURE == rc ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("PR_ExportFileMap() failed"));
+ return;
+ }
+
+ /*
+ ** put the string into the environment
+ */
+ PR_snprintf( envBuf, sizeof(envBuf), "%s=%s", fmEnvName, fmString);
+ putenv( envBuf );
+
+ addr = PR_MemMap( fm, 0, fmSize );
+ if ( NULL == addr ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("PR_MemMap() failed"));
+ return;
+ }
+
+ /* set initial value for client */
+ for (i = 0; i < (PRIntn)fmSize ; i++ )
+ *(addr+i) = 0x00;
+
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): PR_MemMap(): addr: %p", addr ));
+
+ /*
+ ** set arguments for child process
+ */
+ child_argv[0] = "anonfm";
+ child_argv[1] = "-C";
+ child_argv[2] = "1";
+ child_argv[3] = NULL;
+
+ proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL);
+ PR_ASSERT( proc );
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): PR_CreateProcess(): proc: %x", proc ));
+
+ /*
+ ** ClientOne() will set the memory to 1
+ */
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): waiting on Client, *addr: %x", *addr ));
+ while( *addr == 0x00 ) {
+ if ( debug )
+ fprintf(stderr, ".");
+ PR_Sleep(PR_MillisecondsToInterval(300));
+ }
+ if ( debug )
+ fprintf(stderr, "\n");
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): Client responded" ));
+
+ rc = PR_WaitProcess( proc, &exit_status );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_MemUnmap( addr, fmSize);
+ if ( PR_FAILURE == rc ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("PR_MemUnmap() failed"));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): PR_MemUnmap(): success" ));
+
+ rc = PR_CloseFileMap(fm);
+ if ( PR_FAILURE == rc ) {
+ failed_already = 1;
+ PR_LOG(lm, msgLevel,
+ ("PR_CloseFileMap() failed"));
+ return;
+ }
+ PR_LOG(lm, msgLevel,
+ ("ServerOne(): PR_CloseFileMap() success" ));
+
+ return;
+} /* end ServerOne() */
+
+/*
+** ServerTwo() --
+*/
+static void ServerTwo( void )
+{
+ PR_LOG(lm, msgLevel,
+ ("ServerTwo(): Not implemented yet" ));
+} /* end ServerTwo() */
+
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+ {
+ /*
+ ** Get command line options
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "hdC:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option)
+ {
+ case 'C': /* Client style */
+ client = atol(opt->value);
+ break;
+ case 's': /* file size */
+ fmSize = atol( opt->value ) * 1024;
+ break;
+ case 'd': /* debug */
+ debug = 1;
+ msgLevel = PR_LOG_DEBUG;
+ break;
+ case 'h': /* help message */
+ Help();
+ break;
+ default:
+ strcpy(dirName, opt->value);
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ lm = PR_NewLogModule("Test"); /* Initialize logging */
+
+ if ( client == 1 ) {
+ ClientOne();
+ } else if ( client == 2 ) {
+ ClientTwo();
+ } else {
+ ServerOne();
+ if ( failed_already ) goto Finished;
+ ServerTwo();
+ }
+
+Finished:
+ if ( debug )
+ printf("%s\n", (failed_already)? "FAIL" : "PASS");
+ return( (failed_already == PR_TRUE )? 1 : 0 );
+} /* main() */
+/* end anonfm.c */
+
diff --git a/pr/tests/concur.c b/pr/tests/concur.c
index eb3583a1..a87c0dcc 100644
--- a/pr/tests/concur.c
+++ b/pr/tests/concur.c
@@ -158,6 +158,7 @@ PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv)
PR_DestroyLock(context.ml);
PR_DestroyCondVar(context.cv);
+ PR_DELETE(threads);
PR_fprintf(PR_STDERR, "PASSED\n");
diff --git a/pr/tests/gethost.c b/pr/tests/gethost.c
new file mode 100644
index 00000000..9b13b9c7
--- /dev/null
+++ b/pr/tests/gethost.c
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * File: gethost.c
+ *
+ * Description: tests various functions in prnetdb.h
+ *
+ * Usage: gethost [-6] [hostname]
+ */
+
+#include "prio.h"
+#include "prnetdb.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define DEFAULT_HOST_NAME "www.netscape.com"
+
+static void Help(void)
+{
+ fprintf(stderr, "Usage: gethost [-6h] [hostname]\n");
+ fprintf(stderr, "\t-6 IPv6 mode (default: FALSE)\n");
+ fprintf(stderr, "\t-h help\n");
+ fprintf(stderr, "\thostname Name of host (default: %s)\n",
+ DEFAULT_HOST_NAME);
+} /* Help */
+
+/*
+ * Prints the contents of a PRHostEnt structure
+ */
+void PrintHostent(const PRHostEnt *he)
+{
+ int i;
+ int j;
+
+ printf("h_name: %s\n", he->h_name);
+ for (i = 0; he->h_aliases[i]; i++) {
+ printf("h_aliases[%d]: %s\n", i, he->h_aliases[i]);
+ }
+ printf("h_addrtype: %d\n", he->h_addrtype);
+ printf("h_length: %d\n", he->h_length);
+ for (i = 0; he->h_addr_list[i]; i++) {
+ printf("h_addr_list[%d]: ", i);
+ for (j = 0; j < he->h_length; j++) {
+ if (j != 0) printf(".");
+ printf("%u", (unsigned char)he->h_addr_list[i][j]);
+ }
+ printf("\n");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ const char *hostName = DEFAULT_HOST_NAME;
+ PRHostEnt he, reversehe;
+ char buf[PR_NETDB_BUF_SIZE];
+ char reversebuf[PR_NETDB_BUF_SIZE];
+ PRIntn idx;
+ PRNetAddr addr;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "6h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case '6': /* Enable IPv6 */
+ if (PR_SetIPv6Enable(PR_TRUE) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetIPv6Enable failed\n");
+ exit(1);
+ }
+ break;
+ case 0: /* naked */
+ hostName = opt->value;
+ break;
+ case 'h': /* Help message */
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (PR_GetHostByName(hostName, buf, sizeof(buf), &he) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetHostByName failed\n");
+ exit(1);
+ }
+ PrintHostent(&he);
+ idx = 0;
+ while (1) {
+ idx = PR_EnumerateHostEnt(idx, &he, 0, &addr);
+ if (idx == -1) {
+ fprintf(stderr, "PR_EnumerateHostEnt failed\n");
+ exit(1);
+ }
+ if (idx == 0) break; /* normal loop termination */
+ printf("reverse lookup\n");
+ if (PR_GetHostByAddr(&addr, reversebuf, sizeof(reversebuf),
+ &reversehe) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetHostByAddr failed\n");
+ exit(1);
+ }
+ PrintHostent(&reversehe);
+ }
+
+ printf("PR_GetIPNodeByName with PR_AF_INET\n");
+ if (PR_GetIPNodeByName(hostName, PR_AF_INET, PR_AI_DEFAULT,
+ buf, sizeof(buf), &he) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetIPNodeByName failed\n");
+ exit(1);
+ }
+ PrintHostent(&he);
+#ifdef _PR_INET6
+ printf("PR_GetIPNodeByName with PR_AF_INET6\n");
+ if (PR_GetIPNodeByName(hostName, PR_AF_INET6, PR_AI_DEFAULT,
+ buf, sizeof(buf), &he) == PR_FAILURE) {
+ fprintf(stderr, "PR_GetIPNodeByName failed\n");
+ exit(1);
+ }
+ PrintHostent(&he);
+#endif
+
+ PR_StringToNetAddr("::1", &addr);
+ PR_StringToNetAddr("127.0.0.1", &addr);
+
+ if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) {
+ fprintf(stderr, "addr should be unspecified address\n");
+ exit(1);
+ }
+ if (PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_InitializeNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+
+ if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) {
+ fprintf(stderr, "addr should be unspecified address\n");
+ exit(1);
+ }
+ if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = 0;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) {
+ fprintf(stderr, "addr should be unspecified address\n");
+ exit(1);
+ }
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = 0;
+ addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+
+#if defined(_PR_INET6)
+ if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) {
+ fprintf(stderr, "addr should be unspecified address\n");
+ exit(1);
+ }
+ if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, 0, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_SetNetAddr failed\n");
+ exit(1);
+ }
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+
+ addr.ipv6.family = PR_AF_INET6;
+ addr.ipv6.port = 0;
+ addr.ipv6.ip = in6addr_any;
+ if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) {
+ fprintf(stderr, "addr should be unspecified address\n");
+ exit(1);
+ }
+ addr.ipv6.family = PR_AF_INET6;
+ addr.ipv6.port = 0;
+ addr.ipv6.ip = in6addr_loopback;
+ if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) {
+ fprintf(stderr, "addr should be loopback address\n");
+ exit(1);
+ }
+#endif /* _PR_INET6 */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/pr/tests/io_timeout.c b/pr/tests/io_timeout.c
index 1dd85727..aeea212d 100644
--- a/pr/tests/io_timeout.c
+++ b/pr/tests/io_timeout.c
@@ -160,6 +160,8 @@ dead:
if (debug_mode)
printf("thread %d is dead\n", info->id);
+
+ PR_Free(info);
}
void
@@ -213,6 +215,9 @@ thread_test(PRThreadScope scope, PRInt32 num_threads)
PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT);
}
PR_Unlock(dead_lock);
+
+ PR_DestroyCondVar(dead_cv);
+ PR_DestroyLock(dead_lock);
}
int main(int argc, char **argv)
diff --git a/pr/tests/ioconthr.c b/pr/tests/ioconthr.c
index 91b90126..7ed03590 100644
--- a/pr/tests/ioconthr.c
+++ b/pr/tests/ioconthr.c
@@ -42,6 +42,11 @@ void ThreadFunc(void *arg)
err, PR_GetOSError());
PR_ProcessExit(1);
}
+ /*
+ * After getting an I/O interrupt, this thread must
+ * close the fd before it exits due to a limitation
+ * of our NT implementation.
+ */
if (PR_Close(fd) == PR_FAILURE) {
fprintf(stderr, "PR_Close failed\n");
PR_ProcessExit(1);
@@ -59,28 +64,20 @@ int main(int argc, char **argv)
PRIntervalTime start, elapsed;
int index;
- fds = (PRFileDesc **) PR_MALLOC(num_threads * sizeof(PRFileDesc *));
+ fds = (PRFileDesc **) PR_MALLOC(2 * num_threads * sizeof(PRFileDesc *));
PR_ASSERT(fds != NULL);
threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *));
PR_ASSERT(threads != NULL);
- for (index = 0; index < (num_threads / 2); index++) {
+ for (index = 0; index < num_threads; index++) {
if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) {
fprintf(stderr, "PR_NewTCPSocket failed\n");
PR_ProcessExit(1);
}
-
- threads[2 * index] = PR_CreateThread(
+ threads[index] = PR_CreateThread(
PR_USER_THREAD, ThreadFunc, fds[2 * index],
PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
- if (NULL == threads[2 * index]) {
- fprintf(stderr, "PR_CreateThread failed\n");
- PR_ProcessExit(1);
- }
- threads[2 * index + 1] = PR_CreateThread(
- PR_USER_THREAD, ThreadFunc, fds[2 * index + 1],
- PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0);
- if (NULL == threads[2 * index + 1]) {
+ if (NULL == threads[index]) {
fprintf(stderr, "PR_CreateThread failed\n");
PR_ProcessExit(1);
}
@@ -115,6 +112,13 @@ int main(int argc, char **argv)
PR_ProcessExit(1);
}
+ for (index = 0; index < num_threads; index++) {
+ /* fds[2 * index] was passed to and closed by threads[index]. */
+ if (PR_Close(fds[2 * index + 1]) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ PR_ProcessExit(1);
+ }
+ }
PR_DELETE(threads);
PR_DELETE(fds);
printf("PASS\n");
diff --git a/pr/tests/many_cv.c b/pr/tests/many_cv.c
index 1ee2ed25..4b3a2583 100644
--- a/pr/tests/many_cv.c
+++ b/pr/tests/many_cv.c
@@ -110,6 +110,8 @@ static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv )
for (index = 0; index < cvs; ++index)
PR_DestroyCondVar(cv[index]);
+ PR_DELETE(cv);
+
PR_DestroyLock(ml);
printf("PASS\n");
diff --git a/pr/tests/nameshm1.c b/pr/tests/nameshm1.c
new file mode 100644
index 00000000..31cbb2aa
--- /dev/null
+++ b/pr/tests/nameshm1.c
@@ -0,0 +1,580 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+** File: nameshm1.c -- Test Named Shared Memory
+**
+** Description:
+** nameshm1 tests Named Shared Memory. nameshm1 performs two tests of
+** named shared memory.
+**
+** The first test is a basic test. The basic test operates as a single
+** process. The process exercises all the API elements of the facility.
+** This test also attempts to write to all locations in the shared
+** memory.
+**
+** The second test is a client-server test. The client-server test
+** creates a new instance of nameshm1, passing the -C argument to the
+** new process; this creates the client-side process. The server-side
+** (the instance of nameshm1 created from the command line) and the
+** client-side interact via inter-process semaphores to verify that the
+** shared memory segment can be read and written by both sides in a
+** synchronized maner.
+**
+** Note: Because this test runs in two processes, the log files created
+** by the test are not in chronological sequence; makes it hard to read.
+** As a temporary circumvention, I changed the definition(s) of the
+** _PUT_LOG() macro in prlog.c to force a flushall(), or equivalent.
+** This causes the log entries to be emitted in true chronological
+** order.
+**
+** Synopsis: nameshm1 [options] [name]
+**
+** Options:
+** -d Enables debug trace via PR_LOG()
+** -v Enables verbose mode debug trace via PR_LOG()
+** -w Causes the basic test to attempt to write to the segment
+** mapped as read-only. When this option is specified, the
+** test should crash with a seg-fault; this is a destructive
+** test and is considered successful when it seg-faults.
+**
+** -C Causes nameshm1 to start as the client-side of a
+** client-server pair of processes. Only the instance
+** of nameshm1 operating as the server-side process should
+** specify the -C option when creating the client-side process;
+** the -C option should not be specified at the command line.
+** The client-side uses the shared memory segment created by
+** the server-side to communicate with the server-side
+** process.
+**
+** -p <n> Specify the number of iterations the client-server tests
+** should perform. Default: 1000.
+**
+** -s <n> Size, in KBytes (1024), of the shared memory segment.
+** Default: (10 * 1024)
+**
+** -i <n> Number of client-side iterations. Default: 3
+**
+** name specifies the name of the shared memory segment to be used.
+** Default: /tmp/xxxNSPRshm
+**
+**
+** See also: prshm.h
+**
+** /lth. Aug-1999.
+*/
+
+#include <plgetopt.h>
+#include <nspr.h>
+#include <stdlib.h>
+#include <string.h>
+#include <private/primpl.h>
+
+#define SEM_NAME1 "/tmp/nameshmSEM1"
+#define SEM_NAME2 "/tmp/nameshmSEM2"
+#define SEM_MODE 0666
+#define SHM_MODE 0666
+
+#define NameSize (1024)
+
+PRIntn debug = 0;
+PRIntn failed_already = 0;
+PRLogModuleLevel msgLevel = PR_LOG_NONE;
+PRLogModuleInfo *lm;
+
+/* command line options */
+PRIntn optDebug = 0;
+PRIntn optVerbose = 0;
+PRUint32 optWriteRO = 0; /* test write to read-only memory. should crash */
+PRUint32 optClient = 0;
+PRUint32 optCreate = 1;
+PRUint32 optAttachRW = 1;
+PRUint32 optAttachRO = 1;
+PRUint32 optClose = 1;
+PRUint32 optDelete = 1;
+PRInt32 optPing = 1000;
+PRUint32 optSize = (10 * 1024 );
+PRInt32 optClientIterations = 3;
+char optName[NameSize] = "/tmp/xxxNSPRshm";
+
+char buf[1024] = "";
+
+
+static void BasicTest( void )
+{
+ PRSharedMemory *shm;
+ char *addr; /* address of shared memory segment */
+ PRUint32 i;
+ PRInt32 rc;
+
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Begin BasicTest" ));
+
+ if ( PR_FAILURE == PR_DeleteSharedMemory( optName )) {
+ PR_LOG( lm, msgLevel,
+ ("nameshm1: Initial PR_DeleteSharedMemory() failed. No problem"));
+ } else
+ PR_LOG( lm, msgLevel,
+ ("nameshm1: Initial PR_DeleteSharedMemory() success"));
+
+
+ shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE );
+ if ( NULL == shm )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Create: success: %p", shm ));
+
+ addr = PR_AttachSharedMemory( shm , 0 );
+ if ( NULL == addr )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Attach: success: %p", addr ));
+
+ /* fill memory with i */
+ for ( i = 0; i < optSize ; i++ )
+ {
+ *(addr + i) = i;
+ }
+
+ rc = PR_DetachSharedMemory( shm, addr );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Detach: success: " ));
+
+ rc = PR_CloseSharedMemory( shm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Close: success: " ));
+
+ rc = PR_DeleteSharedMemory( optName );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Delete: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RW Delete: success: " ));
+
+ PR_LOG( lm, msgLevel,
+ ("nameshm1: BasicTest(): Passed"));
+
+ return;
+} /* end BasicTest() */
+
+static void ReadOnlyTest( void )
+{
+ PRSharedMemory *shm;
+ char *roAddr; /* read-only address of shared memory segment */
+ PRInt32 rc;
+
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Begin ReadOnlyTest" ));
+
+ shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE);
+ if ( NULL == shm )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Create: success: %p", shm ));
+
+
+ roAddr = PR_AttachSharedMemory( shm , PR_SHM_READONLY );
+ if ( NULL == roAddr )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Attach: success: %p", roAddr ));
+
+ if ( optWriteRO )
+ {
+ *roAddr = 0x00; /* write to read-only memory */
+ failed_already = 1;
+ PR_LOG( lm, msgLevel, ("nameshm1: Wrote to read-only memory segment!"));
+ return;
+ }
+
+ rc = PR_DetachSharedMemory( shm, roAddr );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Detach: success: " ));
+
+ rc = PR_CloseSharedMemory( shm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Close: success: " ));
+
+ rc = PR_DeleteSharedMemory( optName );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Destroy: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: RO Destroy: success: " ));
+
+ PR_LOG( lm, msgLevel,
+ ("nameshm1: ReadOnlyTest(): Passed"));
+
+ return;
+} /* end ReadOnlyTest() */
+
+static void DoClient( void )
+{
+ PRStatus rc;
+ PRSem *sem1, *sem2;
+ PRSharedMemory *shm;
+ PRUint32 *addr;
+ PRInt32 i;
+
+ PR_LOG( lm, msgLevel,
+ ("nameshm1: DoClient(): Starting"));
+
+ sem1 = PR_OpenSemaphore( SEM_NAME1, 0, 0, 0 );
+ PR_ASSERT( sem1 );
+
+ sem2 = PR_OpenSemaphore( SEM_NAME2, 0, 0, 0 );
+ PR_ASSERT( sem1 );
+
+ shm = PR_OpenSharedMemory( optName, optSize, 0, SHM_MODE );
+ if ( NULL == shm )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Create: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Create: success: %p", shm ));
+
+ addr = PR_AttachSharedMemory( shm , 0 );
+ if ( NULL == addr )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Attach: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Attach: success: %p", addr ));
+
+ PR_LOG( lm, msgLevel,
+ ( "Client found: %s", addr));
+
+ PR_Sleep(PR_SecondsToInterval(4));
+ for ( i = 0 ; i < optPing ; i++ )
+ {
+ rc = PR_WaitSemaphore( sem2 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ (*addr)++;
+ PR_ASSERT( (*addr % 2) == 0 );
+ if ( optVerbose )
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Client ping: %d, i: %d", *addr, i));
+
+ rc = PR_PostSemaphore( sem1 );
+ PR_ASSERT( PR_FAILURE != rc );
+ }
+
+ rc = PR_CloseSemaphore( sem1 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_CloseSemaphore( sem2 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_DetachSharedMemory( shm, addr );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Detach: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Detach: success: " ));
+
+ rc = PR_CloseSharedMemory( shm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Close: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: DoClient(): Close: success: " ));
+
+ return;
+} /* end DoClient() */
+
+static void ClientServerTest( void )
+{
+ PRStatus rc;
+ PRSem *sem1, *sem2;
+ PRProcess *proc;
+ PRInt32 exit_status;
+ PRSharedMemory *shm;
+ PRUint32 *addr;
+ PRInt32 i;
+ char *child_argv[8];
+ char buf[24];
+
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Begin ClientServerTest" ));
+
+ rc = PR_DeleteSharedMemory( optName );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Destroy: failed. No problem"));
+ } else
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Destroy: success" ));
+
+
+ shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE);
+ if ( NULL == shm )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Create: success: %p", shm ));
+
+ addr = PR_AttachSharedMemory( shm , 0 );
+ if ( NULL == addr )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Attach: success: %p", addr ));
+
+ sem1 = PR_OpenSemaphore( SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0 );
+ PR_ASSERT( sem1 );
+
+ sem2 = PR_OpenSemaphore( SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 1 );
+ PR_ASSERT( sem1 );
+
+ strcpy( (char*)addr, "FooBar" );
+
+ child_argv[0] = "nameshm1";
+ child_argv[1] = "-C";
+ child_argv[2] = "-p";
+ sprintf( buf, "%d", optPing );
+ child_argv[3] = buf;
+ child_argv[4] = optName;
+ child_argv[5] = NULL;
+
+ proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL);
+ PR_ASSERT( proc );
+
+ PR_Sleep( PR_SecondsToInterval(4));
+
+ *addr = 1;
+ for ( i = 0 ; i < optPing ; i++ )
+ {
+ rc = PR_WaitSemaphore( sem1 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ (*addr)++;
+ PR_ASSERT( (*addr % 2) == 1 );
+ if ( optVerbose )
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server pong: %d, i: %d", *addr, i));
+
+
+ rc = PR_PostSemaphore( sem2 );
+ PR_ASSERT( PR_FAILURE != rc );
+ }
+
+ rc = PR_WaitProcess( proc, &exit_status );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_CloseSemaphore( sem1 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_CloseSemaphore( sem2 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_DeleteSemaphore( SEM_NAME1 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_DeleteSemaphore( SEM_NAME2 );
+ PR_ASSERT( PR_FAILURE != rc );
+
+ rc = PR_DetachSharedMemory( shm, addr );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Detach: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Detach: success: " ));
+
+ rc = PR_CloseSharedMemory( shm );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Close: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Close: success: " ));
+
+ rc = PR_DeleteSharedMemory( optName );
+ if ( PR_FAILURE == rc )
+ {
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Destroy: Error: %ld. OSError: %ld",
+ PR_GetError(), PR_GetOSError()));
+ failed_already = 1;
+ return;
+ }
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Server: Destroy: success" ));
+
+ return;
+} /* end ClientServerTest() */
+
+PRIntn main(PRIntn argc, char *argv[])
+{
+ {
+ /*
+ ** Get command line options
+ */
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "Cdvw:s:p:i:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option)
+ {
+ case 'v': /* debug mode */
+ optVerbose = 1;
+ /* no break! fall into debug option */
+ case 'd': /* debug mode */
+ debug = 1;
+ msgLevel = PR_LOG_DEBUG;
+ break;
+ case 'w': /* try writing to memory mapped read-only */
+ optWriteRO = 1;
+ break;
+ case 'C':
+ optClient = 1;
+ break;
+ case 's':
+ optSize = atol(opt->value) * 1024;
+ break;
+ case 'p':
+ optPing = atol(opt->value);
+ break;
+ case 'i':
+ optClientIterations = atol(opt->value);
+ break;
+ default:
+ strcpy( optName, opt->value );
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ }
+
+ lm = PR_NewLogModule("Test"); /* Initialize logging */
+
+ PR_LOG( lm, msgLevel,
+ ( "nameshm1: Starting" ));
+
+ if ( optClient )
+ {
+ DoClient();
+ } else {
+ BasicTest();
+ if ( failed_already != 0 )
+ goto Finished;
+ ReadOnlyTest();
+ if ( failed_already != 0 )
+ goto Finished;
+ ClientServerTest();
+ }
+
+Finished:
+ if ( debug ) printf("%s\n", (failed_already)? "FAIL" : "PASS" );
+ return( (failed_already)? 1 : 0 );
+} /* main() */
+/* end instrumt.c */
diff --git a/pr/tests/parent.c b/pr/tests/parent.c
index 34837e58..e096f9e2 100644
--- a/pr/tests/parent.c
+++ b/pr/tests/parent.c
@@ -96,6 +96,8 @@ PRIntn main (PRIntn argc, char **argv)
child->name, child->argv, NULL, child->attr);
t_elapsed = (PRIntervalTime) (PR_IntervalNow() - t_start);
+ PR_DestroyProcessAttr(child->attr);
+
test_status = (NULL == child->process) ? 1 : 0;
if (NULL != debug)
{
@@ -126,6 +128,7 @@ PRIntn main (PRIntn argc, char **argv)
PR_fprintf(debug, "PR_WaitProcess failed\n");
}
}
+ PR_DELETE(child);
PR_Cleanup();
return test_status;
diff --git a/pr/tests/poll_to.c b/pr/tests/poll_to.c
index 2a4a8979..76942362 100644
--- a/pr/tests/poll_to.c
+++ b/pr/tests/poll_to.c
@@ -59,7 +59,7 @@ PRIntn debug_mode;
int main(int argc, char **argv)
{
- PRFileDesc *listenSock1, *listenSock2;
+ PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL;
PRUint16 listenPort1, listenPort2;
PRNetAddr addr;
char buf[128];
@@ -177,9 +177,17 @@ int main(int argc, char **argv)
}
if (debug_mode) printf("PR_Poll timed out. Test passed.\n\n");
- PR_Cleanup();
- goto exit_now;
exit_now:
+
+ if (listenSock1) {
+ PR_Close(listenSock1);
+ }
+ if (listenSock2) {
+ PR_Close(listenSock2);
+ }
+
+ PR_Cleanup();
+
if(failed_already)
return 1;
else
diff --git a/pr/tests/pollable.c b/pr/tests/pollable.c
index 000794e0..da3dffe9 100644
--- a/pr/tests/pollable.c
+++ b/pr/tests/pollable.c
@@ -267,6 +267,7 @@ int main(int argc, char **argv)
PR_DestroyPollableEvent(data[i].event);
}
PR_DELETE(block);
+ PR_DestroyPollableEvent(selfData.event);
PR_fprintf(PR_STDOUT, "PASSED\n");
return 0;
diff --git a/pr/tests/provider.c b/pr/tests/provider.c
index bf8c485d..9dfd505e 100644
--- a/pr/tests/provider.c
+++ b/pr/tests/provider.c
@@ -1372,6 +1372,7 @@ PRIntn main(PRIntn argc, char** argv)
PT_FPrintStats(debug_out, thread_type);
TimeOfDayMessage("Test exiting at", PR_CurrentThread());
+ PR_Cleanup();
return 0;
} /* main */
diff --git a/pr/tests/runtests.ksh b/pr/tests/runtests.ksh
index 49a0285b..64148079 100755
--- a/pr/tests/runtests.ksh
+++ b/pr/tests/runtests.ksh
@@ -68,7 +68,9 @@ LOGFILE=${NSPR_TEST_LOGFILE:-"/dev/null"}
TESTS="
acceptread
accept
+affinity
alarm
+anonfm
atomic
attach
bigfile
@@ -84,6 +86,7 @@ exit
fileio
foreign
fsync
+gethost
getproto
i2l
initclk
@@ -105,6 +108,7 @@ lockfile
logger
many_cv
multiwait
+nameshm1
nblayer
nonblock
op_2long
@@ -127,6 +131,9 @@ sel_spd
selct_er
selct_nm
selct_to
+sema
+semaerr
+semaping
server_test
servr_kk
servr_uk
@@ -163,11 +170,13 @@ echo "Test\t\t\tResult\n"
for prog in $TESTS
do
echo "$prog\c"
+echo "\nBEGIN TEST: $prog\n" >> ${LOGFILE} 2>&1
./$prog >> ${LOGFILE} 2>&1
if [ 0 = $? ] ; then
echo "\t\t\tPassed";
else
echo "\t\t\tFAILED";
fi;
+echo "\nEND TEST: $prog\n" >> ${LOGFILE} 2>&1
done
echo "END\t\t\t`date`"
diff --git a/pr/tests/runy2ktests.ksh b/pr/tests/runy2ktests.ksh
new file mode 100644
index 00000000..c30322b0
--- /dev/null
+++ b/pr/tests/runy2ktests.ksh
@@ -0,0 +1,241 @@
+#!/bin/ksh
+
+#
+# The contents of this file are subject to the Netscape Public License
+# Version 1.1 (the "NPL"); you may not use this file except in
+# compliance with the NPL. You may obtain a copy of the NPL at
+# http://www.mozilla.org/NPL/
+#
+# Software distributed under the NPL is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+# for the specific language governing rights and limitations under the
+# NPL.
+#
+# The Initial Developer of this code under the NPL is Netscape
+# Communications Corporation. Portions created by Netscape are
+# Copyright (C) 1999 Netscape Communications Corporation. All Rights
+# Reserved.
+#
+
+#
+# runy2ktests.ksh
+# Set system clock to Y2K dates of interest and run the Y2K tests.
+# Needs root/administrator privilege
+#
+# WARNING: Because this script needs to be run with root/administrator
+# privilege, thorough understanding of the script and extreme
+# caution are urged.
+#
+
+#
+# SECTION I
+# Define variables
+#
+
+SYSTEM_INFO=`uname -a`
+OS_ARCH=`uname -s`
+if [ $OS_ARCH = "Windows_NT" ]
+then
+ NULL_DEVICE=nul
+else
+ NULL_DEVICE=/dev/null
+fi
+
+#
+# Test dates for NSPR Y2K tests
+#
+Y2KDATES=" 123123591998.55
+ 090923591999.55
+ 123123591999.55
+ 022823592000.55
+ 022923592000.55
+ 123123592000.55"
+
+Y2KDATES_AIX=" 12312359.5598
+ 09092359.5599
+ 12312359.5599
+ 02282359.5500
+ 02292359.5500
+ 12312359.5500"
+
+Y2KDATES_HPUX=" 123123591998
+ 090923591999
+ 123123591999
+ 022823592000
+ 022923592000
+ 123123592000"
+
+Y2KDATES_MKS=" 1231235998.55
+ 0909235999.55
+ 1231235999.55
+ 0228235900.55
+ 0229235900.55
+ 1231235900.55"
+
+#
+# NSPR Y2K tests
+#
+Y2KTESTS="
+y2k \n
+y2ktmo \n
+y2k \n
+../runtests.ksh"
+
+Y2KTESTS_HPUX="
+y2k \n
+y2ktmo -l 60\n
+y2k \n
+../runtests.ksh"
+
+#
+# SECTION II
+# Define functions
+#
+
+save_date()
+{
+ case $OS_ARCH in
+ AIX)
+ SAVED_DATE=`date "+%m%d%H%M.%S%y"`
+ ;;
+ HP-UX)
+ SAVED_DATE=`date "+%m%d%H%M%Y"`
+ ;;
+ Windows_NT)
+ SAVED_DATE=`date "+%m%d%H%M%y.%S"`
+ ;;
+ *)
+ SAVED_DATE=`date "+%m%d%H%M%Y.%S"`
+ ;;
+ esac
+}
+
+set_date()
+{
+ case $OS_ARCH in
+ Windows_NT)
+#
+# The date command in MKS Toolkit releases 5.1 and 5.2
+# uses the current DST status for the date we want to
+# set the system clock to. However, the DST status for
+# that date may be different from the current DST status.
+# We can work around this problem by invoking the date
+# command with the same date twice.
+#
+ date "$1" > $NULL_DEVICE
+ date "$1" > $NULL_DEVICE
+ ;;
+ *)
+ date "$1" > $NULL_DEVICE
+ ;;
+ esac
+}
+
+restore_date()
+{
+ set_date "$SAVED_DATE"
+}
+
+savedate()
+{
+ case $OS_ARCH in
+ AIX)
+ SAVED_DATE=`date "+%m%d%H%M.%S%y"`
+ ;;
+ HP-UX)
+ SAVED_DATE=`date "+%m%d%H%M%Y"`
+ ;;
+ Windows_NT)
+ SAVED_DATE=`date "+%m%d%H%M%y.%S"`
+ ;;
+ *)
+ SAVED_DATE=`date "+%m%d%H%M%Y.%S"`
+ ;;
+ esac
+}
+
+set_y2k_test_parameters()
+{
+#
+# set dates
+#
+ case $OS_ARCH in
+ AIX)
+ DATES=$Y2KDATES_AIX
+ ;;
+ HP-UX)
+ DATES=$Y2KDATES_HPUX
+ ;;
+ Windows_NT)
+ DATES=$Y2KDATES_MKS
+ ;;
+ *)
+ DATES=$Y2KDATES
+ ;;
+ esac
+
+#
+# set tests
+#
+ case $OS_ARCH in
+ HP-UX)
+ TESTS=$Y2KTESTS_HPUX
+ ;;
+ *)
+ TESTS=$Y2KTESTS
+ ;;
+ esac
+}
+
+#
+# runtests:
+# - runs each test in $TESTS after setting the
+# system clock to each date in $DATES
+#
+
+runtests()
+{
+for newdate in ${DATES}
+do
+ set_date $newdate
+ echo $newdate
+ echo "BEGIN\t\t\t`date`"
+ echo "Date\t\t\t\t\tTest\t\t\tResult"
+ echo $TESTS | while read prog
+ do
+ echo "`date`\t\t\c"
+ echo "$prog\c"
+ ./$prog >> ${LOGFILE} 2>&1
+ if [ 0 = $? ] ; then
+ echo "\t\t\tPassed";
+ else
+ echo "\t\t\tFAILED";
+ fi;
+ done
+ echo "END\t\t\t`date`\n"
+done
+
+}
+
+#
+# SECTION III
+# Run tests
+#
+
+LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE}
+OBJDIR=`basename $PWD`
+echo "\nNSPR Year 2000 Test Results - $OBJDIR\n"
+echo "SYSTEM:\t\t\t${SYSTEM_INFO}"
+echo "NSPR_TEST_LOGFILE:\t${LOGFILE}\n"
+
+
+save_date
+
+#
+# Run NSPR Y2k and standard tests
+#
+
+set_y2k_test_parameters
+runtests
+
+restore_date
diff --git a/pr/tests/sema.c b/pr/tests/sema.c
new file mode 100644
index 00000000..4bcc52bd
--- /dev/null
+++ b/pr/tests/sema.c
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#define SEM_NAME1 "/tmp/foo.sem"
+#define SEM_NAME2 "/tmp/bar.sem"
+#define SEM_MODE 0666
+#define ITERATIONS 1000
+
+static PRBool debug_mode = PR_FALSE;
+static PRIntn iterations = ITERATIONS;
+static PRIntn counter;
+static PRSem *sem1, *sem2;
+
+/*
+ * Thread 2 waits on semaphore 2 and posts to semaphore 1.
+ */
+void ThreadFunc(void *arg)
+{
+ PRIntn i;
+
+ for (i = 0; i < iterations; i++) {
+ if (PR_WaitSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ if (counter == 2*i+1) {
+ if (debug_mode) printf("thread 2: counter = %d\n", counter);
+ } else {
+ fprintf(stderr, "thread 2: counter should be %d but is %d\n",
+ 2*i+1, counter);
+ exit(1);
+ }
+ counter++;
+ if (PR_PostSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ }
+}
+
+static void Help(void)
+{
+ fprintf(stderr, "sema test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-c <count> loop count (%d)\n", ITERATIONS);
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PRThread *thred;
+ PRIntn i;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'c': /* loop count */
+ iterations = atoi(opt->value);
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) {
+ fprintf(stderr, "warning: removed semaphore %s left over "
+ "from previous run\n", SEM_NAME1);
+ }
+ if (PR_DeleteSemaphore(SEM_NAME2) == PR_SUCCESS) {
+ fprintf(stderr, "warning: removed semaphore %s left over "
+ "from previous run\n", SEM_NAME2);
+ }
+
+ sem1 = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 1);
+ if (NULL == sem1) {
+ fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ sem2 = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 0);
+ if (NULL == sem2) {
+ fprintf(stderr, "PR_OpenSemaphore failed\n");
+ exit(1);
+ }
+ thred = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (NULL == thred) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+
+ /*
+ * Thread 1 waits on semaphore 1 and posts to semaphore 2.
+ */
+ for (i = 0; i < iterations; i++) {
+ if (PR_WaitSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ if (counter == 2*i) {
+ if (debug_mode) printf("thread 1: counter = %d\n", counter);
+ } else {
+ fprintf(stderr, "thread 1: counter should be %d but is %d\n",
+ 2*i, counter);
+ exit(1);
+ }
+ counter++;
+ if (PR_PostSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ }
+
+ if (PR_JoinThread(thred) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+
+ if (PR_CloseSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ }
+ if (PR_CloseSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ }
+ if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSemaphore failed\n");
+ }
+ if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSemaphore failed\n");
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/pr/tests/semaerr.c b/pr/tests/semaerr.c
new file mode 100644
index 00000000..82953be0
--- /dev/null
+++ b/pr/tests/semaerr.c
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#define NO_SUCH_SEM_NAME "/tmp/nosuchsem.sem"
+#define SEM_NAME1 "/tmp/foo.sem"
+#define SEM_MODE 0666
+
+static PRBool debug_mode = PR_FALSE;
+
+static void Help(void)
+{
+ fprintf(stderr, "semaerr test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dh");
+ PRSem *sem;
+ char *child_argv[32];
+ char **child_arg;
+ PRProcess *proc;
+ PRInt32 exit_code;
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /*
+ * Open a nonexistent semaphore without the PR_SEM_CREATE
+ * flag should fail with PR_FILE_NOT_FOUND_ERROR.
+ */
+ (void) PR_DeleteSemaphore(NO_SUCH_SEM_NAME);
+ sem = PR_OpenSemaphore(NO_SUCH_SEM_NAME, 0, 0, 0);
+ if (NULL != sem) {
+ fprintf(stderr, "Opening nonexistent semaphore %s "
+ "without the PR_SEM_CREATE flag should fail "
+ "but succeeded\n", NO_SUCH_SEM_NAME);
+ exit(1);
+ }
+ if (PR_GetError() != PR_FILE_NOT_FOUND_ERROR) {
+ fprintf(stderr, "Expected error is %d but got (%d, %d)\n",
+ PR_FILE_NOT_FOUND_ERROR, PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+
+ /*
+ * Create a semaphore and let the another process
+ * try PR_SEM_CREATE and PR_SEM_CREATE|PR_SEM_EXCL.
+ */
+ if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) {
+ fprintf(stderr, "warning: deleted semaphore %s from previous "
+ "run of the test\n", SEM_NAME1);
+ }
+ sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0);
+ if (sem == NULL) {
+ fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ child_arg = child_argv;
+ *child_arg++ = "semaerr1";
+ if (debug_mode) {
+ *child_arg++ = "-d";
+ }
+ *child_arg = NULL;
+ proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL);
+ if (proc == NULL) {
+ fprintf(stderr, "PR_CreateProcess failed\n");
+ exit(1);
+ }
+ if (PR_WaitProcess(proc, &exit_code) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitProcess failed\n");
+ exit(1);
+ }
+ if (exit_code != 0) {
+ fprintf(stderr, "process semaerr1 failed\n");
+ exit(1);
+ }
+ if (PR_CloseSemaphore(sem) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ exit(1);
+ }
+ if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSemaphore failed\n");
+ exit(1);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/pr/tests/semaerr1.c b/pr/tests/semaerr1.c
new file mode 100644
index 00000000..1692cb3b
--- /dev/null
+++ b/pr/tests/semaerr1.c
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#define SEM_NAME1 "/tmp/foo.sem"
+#define SEM_NAME2 "/tmp/bar.sem"
+#define SEM_MODE 0666
+
+static PRBool debug_mode = PR_FALSE;
+
+static void Help(void)
+{
+ fprintf(stderr, "semaerr1 test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dh");
+ PRSem *sem;
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ /*
+ * PR_SEM_CREATE|PR_SEM_EXCL should be able to
+ * create a nonexistent semaphore.
+ */
+ (void) PR_DeleteSemaphore(SEM_NAME2);
+ sem = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0);
+ if (sem == NULL) {
+ fprintf(stderr, "PR_OpenSemaphore failed\n");
+ exit(1);
+ }
+ if (PR_CloseSemaphore(sem) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ exit(1);
+ }
+ if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSemaphore failed\n");
+ exit(1);
+ }
+
+ /*
+ * Opening an existing semaphore with PR_SEM_CREATE|PR_SEM_EXCL.
+ * should fail with PR_FILE_EXISTS_ERROR.
+ */
+ sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0);
+ if (sem != NULL) {
+ fprintf(stderr, "PR_OpenSemaphore should fail but succeeded\n");
+ exit(1);
+ }
+ if (PR_GetError() != PR_FILE_EXISTS_ERROR) {
+ fprintf(stderr, "Expect %d but got %d\n", PR_FILE_EXISTS_ERROR,
+ PR_GetError());
+ exit(1);
+ }
+
+ /*
+ * Try again, with just PR_SEM_CREATE. This should succeed.
+ */
+ sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0);
+ if (sem == NULL) {
+ fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ if (PR_CloseSemaphore(sem) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ exit(1);
+ }
+
+ sem = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0);
+ if (sem == NULL) {
+ fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ if (PR_CloseSemaphore(sem) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ exit(1);
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/pr/tests/semaping.c b/pr/tests/semaping.c
new file mode 100644
index 00000000..c5430aab
--- /dev/null
+++ b/pr/tests/semaping.c
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#define SHM_NAME "/tmp/counter"
+#define SEM_NAME1 "/tmp/foo.sem"
+#define SEM_NAME2 "/tmp/bar.sem"
+#define SEM_MODE 0666
+#define SHM_MODE 0666
+#define ITERATIONS 1000
+
+static PRBool debug_mode = PR_FALSE;
+static PRIntn iterations = ITERATIONS;
+static PRSem *sem1, *sem2;
+
+static void Help(void)
+{
+ fprintf(stderr, "semaping test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-c <count> loop count (%d)\n", ITERATIONS);
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PRProcess *proc;
+ PRIntn i;
+ char *child_argv[32];
+ char **child_arg;
+ char iterations_buf[32];
+ PRSharedMemory *shm;
+ PRIntn *counter_addr;
+ PRInt32 exit_code;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'c': /* loop count */
+ iterations = atoi(opt->value);
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (PR_DeleteSharedMemory(SHM_NAME) == PR_SUCCESS) {
+ fprintf(stderr, "warning: removed shared memory %s left over "
+ "from previous run\n", SHM_NAME);
+ }
+ if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) {
+ fprintf(stderr, "warning: removed semaphore %s left over "
+ "from previous run\n", SEM_NAME1);
+ }
+ if (PR_DeleteSemaphore(SEM_NAME2) == PR_SUCCESS) {
+ fprintf(stderr, "warning: removed semaphore %s left over "
+ "from previous run\n", SEM_NAME2);
+ }
+
+ shm = PR_OpenSharedMemory(SHM_NAME, sizeof(*counter_addr), PR_SHM_CREATE, SHM_MODE);
+ if (NULL == shm) {
+ fprintf(stderr, "PR_OpenSharedMemory failed\n");
+ exit(1);
+ }
+ counter_addr = PR_AttachSharedMemory(shm, 0);
+ if (NULL == counter_addr) {
+ fprintf(stderr, "PR_AttachSharedMemory failed\n");
+ exit(1);
+ }
+ *counter_addr = 0;
+ sem1 = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 1);
+ if (NULL == sem1) {
+ fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ sem2 = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 0);
+ if (NULL == sem2) {
+ fprintf(stderr, "PR_OpenSemaphore failed\n");
+ exit(1);
+ }
+
+ child_arg = &child_argv[0];
+ *child_arg++ = "semapong";
+ if (debug_mode != PR_FALSE) {
+ *child_arg++ = "-d";
+ }
+ if (iterations != ITERATIONS) {
+ *child_arg++ = "-c";
+ PR_snprintf(iterations_buf, sizeof(iterations_buf), "%d", iterations);
+ *child_arg++ = iterations_buf;
+ }
+ *child_arg = NULL;
+ proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL);
+ if (NULL == proc) {
+ fprintf(stderr, "PR_CreateProcess failed\n");
+ exit(1);
+ }
+
+ /*
+ * Process 1 waits on semaphore 1 and posts to semaphore 2.
+ */
+ for (i = 0; i < iterations; i++) {
+ if (PR_WaitSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ if (*counter_addr == 2*i) {
+ if (debug_mode) printf("process 1: counter = %d\n", *counter_addr);
+ } else {
+ fprintf(stderr, "process 1: counter should be %d but is %d\n",
+ 2*i, *counter_addr);
+ exit(1);
+ }
+ (*counter_addr)++;
+ if (PR_PostSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ }
+ if (PR_DetachSharedMemory(shm, counter_addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_DetachSharedMemory failed\n");
+ exit(1);
+ }
+ if (PR_CloseSharedMemory(shm) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSharedMemory failed\n");
+ exit(1);
+ }
+ if (PR_CloseSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ }
+ if (PR_CloseSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ }
+
+ if (PR_WaitProcess(proc, &exit_code) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitProcess failed\n");
+ exit(1);
+ }
+ if (exit_code != 0) {
+ fprintf(stderr, "process 2 failed with exit code %d\n", exit_code);
+ exit(1);
+ }
+
+ if (PR_DeleteSharedMemory(SHM_NAME) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSharedMemory failed\n");
+ }
+ if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSemaphore failed\n");
+ }
+ if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) {
+ fprintf(stderr, "PR_DeleteSemaphore failed\n");
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/pr/tests/semapong.c b/pr/tests/semapong.c
new file mode 100644
index 00000000..932a7985
--- /dev/null
+++ b/pr/tests/semapong.c
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+
+#define SHM_NAME "/tmp/counter"
+#define SEM_NAME1 "/tmp/foo.sem"
+#define SEM_NAME2 "/tmp/bar.sem"
+#define ITERATIONS 1000
+
+static PRBool debug_mode = PR_FALSE;
+static PRIntn iterations = ITERATIONS;
+static PRSem *sem1, *sem2;
+
+static void Help(void)
+{
+ fprintf(stderr, "semapong test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-c <count> loop count (%d)\n", ITERATIONS);
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PRIntn i;
+ PRSharedMemory *shm;
+ PRIntn *counter_addr;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'c': /* loop count */
+ iterations = atoi(opt->value);
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ shm = PR_OpenSharedMemory(SHM_NAME, sizeof(*counter_addr), 0, 0666);
+ if (NULL == shm) {
+ fprintf(stderr, "PR_OpenSharedMemory failed\n");
+ exit(1);
+ }
+ sem1 = PR_OpenSemaphore(SEM_NAME1, 0, 0, 0);
+ if (NULL == sem1) {
+ fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n",
+ PR_GetError(), PR_GetOSError());
+ exit(1);
+ }
+ sem2 = PR_OpenSemaphore(SEM_NAME2, 0, 0, 0);
+ if (NULL == sem2) {
+ fprintf(stderr, "PR_OpenSemaphore failed\n");
+ exit(1);
+ }
+
+ counter_addr = PR_AttachSharedMemory(shm, 0);
+ if (NULL == counter_addr) {
+ fprintf(stderr, "PR_AttachSharedMemory failed\n");
+ exit(1);
+ }
+
+ /*
+ * Process 2 waits on semaphore 2 and posts to semaphore 1.
+ */
+ for (i = 0; i < iterations; i++) {
+ if (PR_WaitSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ if (*counter_addr == 2*i+1) {
+ if (debug_mode) printf("process 2: counter = %d\n", *counter_addr);
+ } else {
+ fprintf(stderr, "process 2: counter should be %d but is %d\n",
+ 2*i+1, *counter_addr);
+ exit(1);
+ }
+ (*counter_addr)++;
+ if (PR_PostSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_WaitSemaphore failed\n");
+ exit(1);
+ }
+ }
+ if (PR_DetachSharedMemory(shm, counter_addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_DetachSharedMemory failed\n");
+ exit(1);
+ }
+ if (PR_CloseSharedMemory(shm) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSharedMemory failed\n");
+ exit(1);
+ }
+ if (PR_CloseSemaphore(sem1) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ }
+ if (PR_CloseSemaphore(sem2) == PR_FAILURE) {
+ fprintf(stderr, "PR_CloseSemaphore failed\n");
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/pr/tests/socket.c b/pr/tests/socket.c
index afac410c..b5accda1 100644
--- a/pr/tests/socket.c
+++ b/pr/tests/socket.c
@@ -38,11 +38,12 @@
#include <pthread.h>
#endif
-#ifdef WINNT
+#ifdef WIN32
#include <process.h>
#endif
static int _debug_on = 0;
+static int test_cancelio = 0;
#ifdef XP_MAC
#include "prlog.h"
@@ -73,9 +74,25 @@ char *TEST_DIR = "/tmp/prsocket_test_dir";
char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file";
char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";
#endif
-#define SMALL_FILE_SIZE (8 * 1024) /* 8 KB */
-#define SMALL_FILE_HEADER_SIZE (64) /* 64 bytes */
-#define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB */
+#define SMALL_FILE_SIZE (3 * 1024) /* 3 KB */
+#define SMALL_FILE_OFFSET_1 (512)
+#define SMALL_FILE_LEN_1 (1 * 1024) /* 1 KB */
+#define SMALL_FILE_OFFSET_2 (75)
+#define SMALL_FILE_LEN_2 (758)
+#define SMALL_FILE_OFFSET_3 (1024)
+#define SMALL_FILE_LEN_3 (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3)
+#define SMALL_FILE_HEADER_SIZE (64) /* 64 bytes */
+#define SMALL_FILE_TRAILER_SIZE (128) /* 128 bytes */
+
+#define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB */
+#define LARGE_FILE_OFFSET_1 (0)
+#define LARGE_FILE_LEN_1 (2 * 1024 * 1024) /* 2 MB */
+#define LARGE_FILE_OFFSET_2 (64)
+#define LARGE_FILE_LEN_2 (1 * 1024 * 1024 + 75)
+#define LARGE_FILE_OFFSET_3 (2 * 1024 * 1024 - 128)
+#define LARGE_FILE_LEN_3 (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3)
+#define LARGE_FILE_HEADER_SIZE (512)
+#define LARGE_FILE_TRAILER_SIZE (64)
#define BUF_DATA_SIZE (2 * 1024)
#define TCP_MESG_SIZE 1024
@@ -84,7 +101,7 @@ char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";
* local host will not be lost
*/
#define UDP_DGRAM_SIZE 128
-#define NUM_TCP_CLIENTS 10
+#define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */
#define NUM_UDP_CLIENTS 10
#ifndef XP_MAC
@@ -150,16 +167,33 @@ readn(PRFileDesc *sockfd, char *buf, int len)
int rem;
int bytes;
int offset = 0;
+ int err, oserr;
+ PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
+
+ if (test_cancelio)
+ timeout = PR_SecondsToInterval(2);
for (rem=len; rem; offset += bytes, rem -= bytes) {
DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
PR_GetCurrentThread(), rem));
+retry:
bytes = PR_Recv(sockfd, buf + offset, rem, 0,
- PR_INTERVAL_NO_TIMEOUT);
+ timeout);
DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
PR_GetCurrentThread(), bytes));
- if (bytes <= 0)
- return -1;
+ if (bytes < 0) {
+#ifdef WINNT
+ printf("PR_Recv: error = %d oserr = %d\n",(err = PR_GetError()),
+ PR_GetOSError());
+ if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) {
+ if (PR_NT_CancelIo(sockfd) != PR_SUCCESS)
+ printf("PR_NT_CancelIO: error = %d\n",PR_GetError());
+ timeout = PR_INTERVAL_NO_TIMEOUT;
+ goto retry;
+ }
+#endif
+ return -1;
+ }
}
return len;
}
@@ -262,7 +296,7 @@ PRThread* create_new_thread(PRThreadType type,
PRInt32 native_thread = 0;
PR_ASSERT(state == PR_UNJOINABLE_THREAD);
-#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WINNT) || defined(WIN95)
+#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32)
switch(index % 4) {
case 0:
scope = (PR_LOCAL_THREAD);
@@ -289,6 +323,7 @@ PRInt32 native_thread = 0;
return (NULL);
#else
HANDLE thandle;
+ unsigned tid;
thandle = (HANDLE) _beginthreadex(
NULL,
@@ -296,7 +331,7 @@ PRInt32 native_thread = 0;
(unsigned (__stdcall *)(void *))start,
arg,
0,
- NULL);
+ &tid);
return((PRThread *) thandle);
#endif
} else {
@@ -474,13 +509,6 @@ UDP_Server(void *arg)
failed_already=1;
return;
}
- if (netaddr.inet.port != PR_htons(UDP_SERVER_PORT)) {
- fprintf(stderr,"prsocket_test: ERROR - tried to bind to UDP "
- "port %hu, but was bound to port %hu\n",
- UDP_SERVER_PORT, PR_ntohs(netaddr.inet.port));
- failed_already=1;
- return;
- }
DPRINTF(("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
netaddr.inet.ip, netaddr.inet.port));
@@ -533,6 +561,7 @@ UDP_Server(void *arg)
}
PR_DELETE(in_buf);
+ PR_Close(sockfd);
/*
* Decrement exit_counter and notify parent thread
@@ -580,14 +609,15 @@ TCP_Client(void *arg)
netaddr.inet.ip = cp->server_addr.inet.ip;
for (i = 0; i < num_tcp_connections_per_client; i++) {
- if ((sockfd = PR_NewTCPSocket()) == NULL) {
- fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
+ if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
failed_already=1;
return;
}
if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){
- fprintf(stderr,"prsocket_test: PR_Connect failed\n");
+ fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
failed_already=1;
return;
}
@@ -599,6 +629,10 @@ TCP_Client(void *arg)
/*
* write to server
*/
+#ifdef WINNT
+ if (test_cancelio && (j == 0))
+ PR_Sleep(PR_SecondsToInterval(12));
+#endif
if (writen(sockfd, out_buf->data, bytes) < bytes) {
fprintf(stderr,"prsocket_test: ERROR - TCP_Client:writen\n");
failed_already=1;
@@ -676,8 +710,8 @@ UDP_Client(void *arg)
failed_already=1;
return;
}
- if ((sockfd = PR_NewUDPSocket()) == NULL) {
- fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n");
+ if ((sockfd = PR_OpenUDPSocket(PR_AF_INET)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_OpenUDPSocket failed\n");
failed_already=1;
return;
}
@@ -1023,6 +1057,7 @@ UDP_Socket_Client_Server_Test(void)
static PRFileDesc *small_file_fd, *large_file_fd;
static void *small_file_addr, *small_file_header, *large_file_addr;
+static void *small_file_trailer, *large_file_header, *large_file_trailer;
/*
* TransmitFile_Client
* Client Thread
@@ -1034,14 +1069,17 @@ TransmitFile_Client(void *arg)
union PRNetAddr netaddr;
char *small_buf, *large_buf;
Client_Param *cp = (Client_Param *) arg;
+ PRInt32 rlen;
- small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE);
+ small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
+ SMALL_FILE_TRAILER_SIZE);
if (small_buf == NULL) {
fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
failed_already=1;
return;
}
- large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE);
+ large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE + LARGE_FILE_HEADER_SIZE +
+ LARGE_FILE_TRAILER_SIZE);
if (large_buf == NULL) {
fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
failed_already=1;
@@ -1103,10 +1141,225 @@ TransmitFile_Client(void *arg)
failed_already=1;
}
#endif
+
+
+ /*
+ * receive data from PR_SendFile
+ */
+ /*
+ * case 1: small file with header and trailer
+ */
+ rlen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
+ SMALL_FILE_TRAILER_SIZE;
+ if (readn(sockfd, small_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
+ fprintf(stderr,
+ "SendFile 1. ERROR - small file header corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
+ SMALL_FILE_SIZE) != 0) {
+ fprintf(stderr,
+ "SendFile 1. ERROR - small file data corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp(small_file_trailer,
+ small_buf + SMALL_FILE_HEADER_SIZE + SMALL_FILE_SIZE,
+ SMALL_FILE_TRAILER_SIZE) != 0) {
+ fprintf(stderr,
+ "SendFile 1. ERROR - small file trailer corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * case 2: partial large file at zero offset, file with header and trailer
+ */
+ rlen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE +
+ LARGE_FILE_TRAILER_SIZE;
+ if (readn(sockfd, large_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
+ fprintf(stderr,
+ "SendFile 2. ERROR - large file header corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp(large_file_addr, large_buf + LARGE_FILE_HEADER_SIZE,
+ LARGE_FILE_LEN_1) != 0) {
+ fprintf(stderr,
+ "SendFile 2. ERROR - large file data corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp(large_file_trailer,
+ large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_1,
+ LARGE_FILE_TRAILER_SIZE) != 0) {
+ fprintf(stderr,
+ "SendFile 2. ERROR - large file trailer corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * case 3: partial small file at non-zero offset, with header
+ */
+ rlen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
+ if (readn(sockfd, small_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
+ fprintf(stderr,
+ "SendFile 3. ERROR - small file header corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_1,
+ small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_1) != 0) {
+ fprintf(stderr,
+ "SendFile 3. ERROR - small file data corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * case 4: partial small file at non-zero offset, with trailer
+ */
+ rlen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
+ if (readn(sockfd, small_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_2, small_buf,
+ SMALL_FILE_LEN_2) != 0) {
+ fprintf(stderr,
+ "SendFile 4. ERROR - small file data corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp(small_file_trailer, small_buf + SMALL_FILE_LEN_2,
+ SMALL_FILE_TRAILER_SIZE) != 0) {
+ fprintf(stderr,
+ "SendFile 4. ERROR - small file trailer corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * case 5: partial large file at non-zero offset, file with header
+ */
+ rlen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
+ if (readn(sockfd, large_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
+ fprintf(stderr,
+ "SendFile 5. ERROR - large file header corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_2,
+ large_buf + LARGE_FILE_HEADER_SIZE,
+ LARGE_FILE_LEN_2) != 0) {
+ fprintf(stderr,
+ "SendFile 5. ERROR - large file data corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * case 6: partial small file at non-zero offset, with header
+ */
+ rlen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
+ if (readn(sockfd, small_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){
+ fprintf(stderr,
+ "SendFile 6. ERROR - small file header corruption\n");
+ return;
+ }
+ if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_3,
+ small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_3) != 0) {
+#if 0
+ char *i, *j;
+ int k;
+
+ i = (char *) small_file_addr + SMALL_FILE_OFFSET_3;
+ j = small_buf + SMALL_FILE_HEADER_SIZE;
+ k = SMALL_FILE_LEN_3;
+ while (k-- > 0) {
+ if (*i++ != *j++)
+ printf("i = %d j = %d\n",
+ (int) (i - ((char *) small_file_addr + SMALL_FILE_OFFSET_3)),
+ (int) (j - (small_buf + SMALL_FILE_HEADER_SIZE)));
+ }
+#endif
+ fprintf(stderr,
+ "SendFile 6. ERROR - small file data corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
+ /*
+ * case 7: partial large file at non-zero offset, with trailer
+ */
+ rlen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
+ if (readn(sockfd, large_buf, rlen) != rlen) {
+ fprintf(stderr,
+ "prsocket_test: SendFile_Client failed to receive file\n");
+ failed_already=1;
+ return;
+ }
+#ifdef XP_UNIX
+ if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){
+ fprintf(stderr,
+ "SendFile 7. ERROR - large file header corruption\n");
+ failed_already=1;
+ return;
+ }
+ if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_3,
+ large_buf + LARGE_FILE_HEADER_SIZE,
+ LARGE_FILE_LEN_3) != 0) {
+ fprintf(stderr,
+ "SendFile 7. ERROR - large file data corruption\n");
+ failed_already=1;
+ return;
+ }
+#endif
PR_DELETE(small_buf);
PR_DELETE(large_buf);
PR_Close(sockfd);
+
/*
* Decrement exit_counter and notify parent thread
*/
@@ -1132,6 +1385,8 @@ Serve_TransmitFile_Client(void *arg)
PRInt32 bytes;
PRFileDesc *local_small_file_fd=NULL;
PRFileDesc *local_large_file_fd=NULL;
+ PRSendFileData sfd;
+ PRInt32 slen;
sockfd = scp->sockfd;
local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY,0);
@@ -1160,13 +1415,175 @@ Serve_TransmitFile_Client(void *arg)
failed_already=1;
}
bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0,
- PR_TRANSMITFILE_CLOSE_SOCKET, PR_INTERVAL_NO_TIMEOUT);
+ PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT);
if (bytes != LARGE_FILE_SIZE) {
fprintf(stderr,
"prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n",
PR_GetError(), PR_GetOSError());
failed_already=1;
}
+
+ /*
+ * PR_SendFile test cases
+ */
+
+ /*
+ * case 1: small file with header and trailer
+ */
+ sfd.fd = local_small_file_fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = 0;
+ sfd.header = small_file_header;
+ sfd.hlen = SMALL_FILE_HEADER_SIZE;
+ sfd.trailer = small_file_trailer;
+ sfd.tlen = SMALL_FILE_TRAILER_SIZE;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE +
+ SMALL_FILE_TRAILER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 1. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+
+ /*
+ * case 2: partial large file at zero offset, file with header and trailer
+ */
+ sfd.fd = local_large_file_fd;
+ sfd.file_offset = 0;
+ sfd.file_nbytes = LARGE_FILE_LEN_1;
+ sfd.header = large_file_header;
+ sfd.hlen = LARGE_FILE_HEADER_SIZE;
+ sfd.trailer = large_file_trailer;
+ sfd.tlen = LARGE_FILE_TRAILER_SIZE;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE +
+ LARGE_FILE_TRAILER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+ /*
+ * case 3: partial small file at non-zero offset, with header
+ */
+ sfd.fd = local_small_file_fd;
+ sfd.file_offset = SMALL_FILE_OFFSET_1;
+ sfd.file_nbytes = SMALL_FILE_LEN_1;
+ sfd.header = small_file_header;
+ sfd.hlen = SMALL_FILE_HEADER_SIZE;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 3. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+ /*
+ * case 4: partial small file at non-zero offset, with trailer
+ */
+ sfd.fd = local_small_file_fd;
+ sfd.file_offset = SMALL_FILE_OFFSET_2;
+ sfd.file_nbytes = SMALL_FILE_LEN_2;
+ sfd.header = NULL;
+ sfd.hlen = 0;
+ sfd.trailer = small_file_trailer;
+ sfd.tlen = SMALL_FILE_TRAILER_SIZE;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 4. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+ /*
+ * case 5: partial large file at non-zero offset, file with header
+ */
+ sfd.fd = local_large_file_fd;
+ sfd.file_offset = LARGE_FILE_OFFSET_2;
+ sfd.file_nbytes = LARGE_FILE_LEN_2;
+ sfd.header = large_file_header;
+ sfd.hlen = LARGE_FILE_HEADER_SIZE;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 5. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+ /*
+ * case 6: partial small file from non-zero offset till end of file, with header
+ */
+ sfd.fd = local_small_file_fd;
+ sfd.file_offset = SMALL_FILE_OFFSET_3;
+ sfd.file_nbytes = 0; /* data from offset to end-of-file */
+ sfd.header = small_file_header;
+ sfd.hlen = SMALL_FILE_HEADER_SIZE;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 6. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
+ /*
+ * case 7: partial large file at non-zero offset till end-of-file, with header
+ */
+ sfd.fd = local_large_file_fd;
+ sfd.file_offset = LARGE_FILE_OFFSET_3;
+ sfd.file_nbytes = 0; /* data until end-of-file */
+ sfd.header = large_file_header;
+ sfd.hlen = LARGE_FILE_HEADER_SIZE;
+ sfd.trailer = NULL;
+ sfd.tlen = 0;
+ bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_CLOSE_SOCKET,
+ PR_INTERVAL_NO_TIMEOUT);
+ slen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
+ if (bytes != slen) {
+ fprintf(stderr,
+ "socket: Error - 7. PR_SendFile send_size = %d, bytes sent = %d\n",
+ slen, bytes);
+ fprintf(stderr,
+ "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
+ PR_GetError(), PR_GetOSError());
+ failed_already=1;
+ }
done:
if (local_small_file_fd != NULL)
PR_Close(local_small_file_fd);
@@ -1199,8 +1616,8 @@ TransmitFile_Server(void *arg)
/*
* Create a tcp socket
*/
- if ((sockfd = PR_NewTCPSocket()) == NULL) {
- fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
+ if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
+ fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
failed_already=1;
goto exit;
}
@@ -1392,7 +1809,7 @@ Socket_Misc_Test(void)
* map the small file; used in checking for data corruption
*/
small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ,
- MAP_PRIVATE, small_file_fd->secret->md.osfd, 0);
+ MAP_SHARED, small_file_fd->secret->md.osfd, 0);
if (small_file_addr == (void *) -1) {
fprintf(stderr,"prsocket_test failed to mmap file %s\n",
SMALL_FILE_NAME);
@@ -1414,6 +1831,18 @@ Socket_Misc_Test(void)
memset(small_file_header, (int) PR_IntervalNow(),
SMALL_FILE_HEADER_SIZE);
/*
+ * trailer for small file
+ */
+ small_file_trailer = PR_MALLOC(SMALL_FILE_TRAILER_SIZE);
+ if (small_file_trailer == NULL) {
+ fprintf(stderr,"prsocket_test failed to malloc header trailer\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ memset(small_file_trailer, (int) PR_IntervalNow(),
+ SMALL_FILE_TRAILER_SIZE);
+ /*
* setup large file
*/
large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
@@ -1452,7 +1881,7 @@ Socket_Misc_Test(void)
* map the large file; used in checking for data corruption
*/
large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ,
- MAP_PRIVATE, large_file_fd->secret->md.osfd, 0);
+ MAP_SHARED, large_file_fd->secret->md.osfd, 0);
if (large_file_addr == (void *) -1) {
fprintf(stderr,"prsocket_test failed to mmap file %s\n",
LARGE_FILE_NAME);
@@ -1461,6 +1890,31 @@ Socket_Misc_Test(void)
goto done;
}
#endif
+ /*
+ * header for large file
+ */
+ large_file_header = PR_MALLOC(LARGE_FILE_HEADER_SIZE);
+ if (large_file_header == NULL) {
+ fprintf(stderr,"prsocket_test failed to malloc header file\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ memset(large_file_header, (int) PR_IntervalNow(),
+ LARGE_FILE_HEADER_SIZE);
+ /*
+ * trailer for large file
+ */
+ large_file_trailer = PR_MALLOC(LARGE_FILE_TRAILER_SIZE);
+ if (large_file_trailer == NULL) {
+ fprintf(stderr,"prsocket_test failed to malloc header trailer\n");
+ failed_already=1;
+ rv = -1;
+ goto done;
+ }
+ memset(large_file_trailer, (int) PR_IntervalNow(),
+ LARGE_FILE_TRAILER_SIZE);
+
datalen = tcp_mesg_size;
thread_count = 0;
/*
@@ -1629,6 +2083,7 @@ main(int argc, char **argv)
goto done;
} else
printf("TCP_Socket_Client_Server_Test Passed\n");
+ test_cancelio = 0;
/*
* run client-server test with UDP
*/
diff --git a/pr/tests/testfile.c b/pr/tests/testfile.c
index ffc9798a..b6b03882 100644
--- a/pr/tests/testfile.c
+++ b/pr/tests/testfile.c
@@ -111,7 +111,7 @@ PRThread* create_new_thread(PRThreadType type,
PRInt32 native_thread = 0;
PR_ASSERT(state == PR_UNJOINABLE_THREAD);
-#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WINNT) || defined(WIN95)
+#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32)
switch(index % 4) {
case 0:
scope = (PR_LOCAL_THREAD);
@@ -138,15 +138,15 @@ PRInt32 native_thread = 0;
return (NULL);
#else
HANDLE thandle;
+ unsigned tid;
- printf("creating Windows thread\n");
thandle = (HANDLE) _beginthreadex(
NULL,
stackSize,
(unsigned (__stdcall *)(void *))start,
arg,
0,
- NULL);
+ &tid);
return((PRThread *) thandle);
#endif
} else {
@@ -950,11 +950,11 @@ int main(int argc, char **argv)
}
#ifdef WIN32
len = GetTempPath(TMPDIR_LEN, testdir);
- if ((len > 0) && (len < (TMPDIR_LEN - 7))) {
+ if ((len > 0) && (len < (TMPDIR_LEN - 6))) {
/*
- * enough space for \prdir
+ * enough space for prdir
*/
- strcpy((testdir + len),"\prdir");
+ strcpy((testdir + len),"prdir");
TEST_DIR = testdir;
printf("TEST_DIR = %s\n",TEST_DIR);
}
diff --git a/pr/tests/tmoacc.c b/pr/tests/tmoacc.c
index aa0fea66..bda47e19 100644
--- a/pr/tests/tmoacc.c
+++ b/pr/tests/tmoacc.c
@@ -174,6 +174,7 @@ static void Accept(void *arg)
PRIntn Tmoacc(PRIntn argc, char **argv)
{
PRStatus rv;
+ PRIntn exitStatus;
PRIntn index;
Shared *shared;
PLOptStatus os;
@@ -190,7 +191,7 @@ PRIntn Tmoacc(PRIntn argc, char **argv)
PR_SetIPv6Enable(PR_TRUE);
#endif
- shared = PR_NEWZAP(Shared); /* this is leaked */
+ shared = PR_NEWZAP(Shared);
shared->debug = NULL;
shared->passed = PR_TRUE;
@@ -232,6 +233,7 @@ PRIntn Tmoacc(PRIntn argc, char **argv)
if (0 == timeout) timeout = DEFAULT_TIMEOUT;
PR_STDIO_INIT();
+ memset(&listenAddr, 0, sizeof(listenAddr));
rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
PR_ASSERT(PR_SUCCESS == rv);
@@ -297,7 +299,9 @@ PRIntn Tmoacc(PRIntn argc, char **argv)
PR_GetSpecialFD(PR_StandardError), "%s\n",
((shared->passed) ? "PASSED" : "FAILED"));
- return (shared->passed) ? 0 : 1;
+ exitStatus = (shared->passed) ? 0 : 1;
+ PR_DELETE(shared);
+ return exitStatus;
}
int main(int argc, char **argv)
diff --git a/pr/tests/tmocon.c b/pr/tests/tmocon.c
index ecf5e52a..d3bb9839 100644
--- a/pr/tests/tmocon.c
+++ b/pr/tests/tmocon.c
@@ -102,11 +102,7 @@ static void CauseTimeout(const Shared *shared)
static PRStatus MakeReceiver(Shared *shared)
{
PRStatus rv = PR_FAILURE;
-#if defined(_PR_INET6)
- if (IN6_IS_ADDR_LOOPBACK(&shared->serverAddress.ipv6.ip))
-#else
- if (PR_htonl(PR_INADDR_LOOPBACK) == shared->serverAddress.inet.ip)
-#endif
+ if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback))
{
char *argv[3];
char path[1024 + sizeof("/tmoacc")];
@@ -183,7 +179,12 @@ static void Connect(void *arg)
*/
PR_Sleep(shared->dally);
- if (shared->debug > 1) PR_fprintf(debug_out, "connecting ... ");
+ if (shared->debug > 1)
+ {
+ char buf[128];
+ PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf));
+ PR_fprintf(debug_out, "connecting to %s ... ", buf);
+ }
rv = PR_Connect(
clientSock, &shared->serverAddress, Timeout(shared));
if (PR_SUCCESS == rv)
@@ -252,55 +253,6 @@ static void Connect(void *arg)
PR_DELETE(buffer);
} /* Connect */
-#ifdef _PR_INET6
-
-/*
- * Below are some of the IPv6 hosts at Netscape and their IPv4
- * addresses. We will use their IPv4-compatible IPv6 addresses
- * for automatic tunneling.
- */
-
-static const char *ipv6_host[] = {
- "dijkstra",
- "wirth",
- "gandalf",
- "raven"
-};
-
-static const unsigned char ipv6_host_ipv4_addr[] = {
- 208, 12, 62, 49,
- 208, 12, 62, 98,
- 208, 12, 62, 55,
- 206, 222, 228, 80
-};
-
-/*
- * Return PR_TRUE if 'host' is an IPv6 host at Netscape in the table
- * above, and fill 'addr->ipv6.ip' with its IPv4-compatible IPv6 address
- * for automatic tunneling.
- */
-
-static PRBool
-IPv6AutoTunnelHost(const char *host, PRNetAddr *addr)
-{
- int nHosts = sizeof(ipv6_host) / sizeof(ipv6_host[0]);
- int i;
-
- for (i = 0; i < nHosts; i++)
- {
- if (strcmp(host, ipv6_host[i]) == 0)
- {
- memset(&addr->ipv6.ip, 0, 12);
- memcpy(((unsigned char *) &addr->ipv6.ip) + 12,
- &ipv6_host_ipv4_addr[4 * i], 4);
- PR_ASSERT(IN6_IS_ADDR_V4COMPAT(&addr->ipv6.ip));
- return PR_TRUE;
- }
- }
- return PR_FALSE;
-}
-#endif /* _PR_INET6 */
-
int Tmocon(int argc, char **argv)
{
/*
@@ -319,6 +271,7 @@ int Tmocon(int argc, char **argv)
*/
PRStatus rv;
+ int exitStatus;
PLOptStatus os;
Shared *shared = NULL;
PRThread **thread = NULL;
@@ -330,7 +283,7 @@ int Tmocon(int argc, char **argv)
#ifdef _PR_INET6
PR_SetIPv6Enable(PR_TRUE);
#endif
- shared = PR_NEWZAP(Shared); /* this is leaked */
+ shared = PR_NEWZAP(Shared);
shared->debug = 0;
shared->failed = PR_FALSE;
@@ -339,6 +292,7 @@ int Tmocon(int argc, char **argv)
shared->message_length = DEFAULT_MESSAGESIZE;
PR_STDIO_INIT();
+ memset(&shared->serverAddress, 0, sizeof(shared->serverAddress));
rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress);
PR_ASSERT(PR_SUCCESS == rv);
@@ -364,21 +318,14 @@ int Tmocon(int argc, char **argv)
break;
case 'h': /* the value for backlock */
{
-#ifdef _PR_INET6
- if (!IPv6AutoTunnelHost(opt->value, &shared->serverAddress))
- {
-#endif
- PRIntn es = 0;
- PRHostEnt host;
- char buffer[1024];
- (void)PR_GetHostByName(
- opt->value, buffer, sizeof(buffer), &host);
- es = PR_EnumerateHostEnt(
- es, &host, BASE_PORT, &shared->serverAddress);
- PR_ASSERT(es > 0);
-#ifdef _PR_INET6
- }
-#endif
+ PRIntn es = 0;
+ PRHostEnt host;
+ char buffer[1024];
+ (void)PR_GetHostByName(
+ opt->value, buffer, sizeof(buffer), &host);
+ es = PR_EnumerateHostEnt(
+ es, &host, BASE_PORT, &shared->serverAddress);
+ PR_ASSERT(es > 0);
}
break;
case 'm': /* number of messages to send */
@@ -425,7 +372,9 @@ int Tmocon(int argc, char **argv)
PR_fprintf(
PR_GetSpecialFD(PR_StandardError), "%s\n",
((shared->failed) ? "FAILED" : "PASSED"));
- return (shared->failed) ? 1 : 0;
+ exitStatus = (shared->failed) ? 1 : 0;
+ PR_DELETE(shared);
+ return exitStatus;
}
int main(int argc, char **argv)
diff --git a/pr/tests/vercheck.c b/pr/tests/vercheck.c
index aef966a1..b616ad2a 100644
--- a/pr/tests/vercheck.c
+++ b/pr/tests/vercheck.c
@@ -33,12 +33,12 @@
#include <stdlib.h>
/*
- * This release (3.1) is backward compatible with all
+ * This release (3.5) is backward compatible with all
* the previous releases. It, of course, is compatible
* with itself.
*/
static char *compatible_version[] = {
- "2.1 19980529", "3.0", "3.0.1", PR_VERSION
+ "2.1 19980529", "3.0", "3.0.1", "3.1", "3.1.1", "3.1.2", PR_VERSION
};
/*
@@ -46,8 +46,7 @@ static char *compatible_version[] = {
* patches.
*/
static char *incompatible_version[] = {
- "3.1.2",
- "3.5", "3.5.1",
+ "3.5.1",
"4.0", "4.0.3",
"10.0", "11.1", "12.14.20"
};
diff --git a/pr/tests/y2k.c b/pr/tests/y2k.c
index c08351f2..7439e780 100644
--- a/pr/tests/y2k.c
+++ b/pr/tests/y2k.c
@@ -19,6 +19,8 @@
/*
* file: y2k.c
* description: Test for y2k compliance for NSPR.
+ *
+ * Sep 1999. lth. Added "Sun" specified dates to the test data.
*/
/***********************************************************************
** Includes
@@ -41,6 +43,8 @@
extern void SetupMacPrintfLog(char *logFile);
#endif
+#define PRINT_DETAILS
+
int failed_already=0;
PRBool debug_mode = PR_FALSE;
@@ -154,7 +158,13 @@ static PRTime prt[] = {
LL_INIT(221612, 2107598848), /* 951818400000000 */
LL_INIT(228975, 663398400), /* 983440800000000 */
LL_INIT(258365, 1974568960), /* 1109671200000000 */
- LL_INIT(218132, 1393788928) /* 936871200000000 */
+ LL_INIT(218132, 1393788928), /* 936871200000000 */
+ /* Sun's dates follow */
+ LL_INIT( 213062, 4077979648 ), /* Dec 31 1998 10:00:00 */
+ LL_INIT( 218152, 1894443008 ), /* Sep 10 1999 10:00:00 */
+ LL_INIT( 221592, 1606944768 ), /* Feb 28 2000 10:00:00 */
+ LL_INIT( 227768, 688924672 ), /* Dec 31 2000 10:00:00 */
+ LL_INIT( 227788, 1189578752 ), /* Jan 1 2001 10:00:00 */
};
static PRExplodedTime gmt[] = {
@@ -163,7 +173,13 @@ static PRExplodedTime gmt[] = {
{ 0, 0, 0, 10, 29, 1, 2000, 2, 59, {0, 0}}, /* 2000/02/29 10:00:00 GMT */
{ 0, 0, 0, 10, 1, 2, 2001, 4, 59, {0, 0}}, /* 2001/3/1 10:00:00 GMT */
{ 0, 0, 0, 10, 1, 2, 2005, 2, 59, {0, 0}}, /* 2005/3/1 10:00:00 GMT */
- { 0, 0, 0, 10, 9, 8, 1999, 4, 251, {0, 0}} /* 1999/9/9 10:00:00 GMT */
+ { 0, 0, 0, 10, 9, 8, 1999, 4, 251, {0, 0}}, /* 1999/9/9 10:00:00 GMT */
+ /* Sun's dates follow */
+ { 0, 0, 0, 10, 31, 11, 1998, 4, 364, {0, 0}}, /* 12/31/1998 10:00:00 GMT */
+ { 0, 0, 0, 10, 10, 8, 1999, 5, 252, {0, 0}}, /* 9/10/1999 10:00:00 GMT */
+ { 0, 0, 0, 10, 28, 1, 2000, 1, 58, {0, 0}}, /* 2/28/2000 10:00:00 GMT */
+ { 0, 0, 0, 10, 31, 11, 2000, 0, 365, {0, 0}}, /* 12/31/2000 10:00:00 GMT */
+ { 0, 0, 0, 10, 1, 0, 2001, 1, 0, {0, 0}} /* 1/1/2001 10:00:00 GMT */
};
static PRExplodedTime uspt[] = {
@@ -172,7 +188,13 @@ static PRExplodedTime uspt[] = {
{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */
{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */
{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */
-{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}} /* 1999/9/9 3:00:00 PDT */
+{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}, /* 1999/9/9 3:00:00 PDT */
+ /* Sun's dates follow */
+ { 0, 0, 0, 2, 31, 11, 1998, 4, 364, {-28800, 0}}, /* 12/31/1998 00:00:00 GMT */
+ { 0, 0, 0, 3, 10, 8, 1999, 5, 252, {-28800, 3600}}, /* 9/10/1999 00:00:00 GMT */
+ { 0, 0, 0, 2, 28, 1, 2000, 1, 58, {-28800, 0}}, /* 2/28/2000 00:00:00 GMT */
+ { 0, 0, 0, 2, 31, 11, 2000, 0, 365, {-28800, 0}}, /* 12/31/2000 00:00:00 GMT */
+ { 0, 0, 0, 2, 1, 0, 2001, 1, 0, {-28800, 0}} /* 1/1/2001 00:00:00 GMT */
};
/*
@@ -188,7 +210,13 @@ static PRExplodedTime localt[] = {
{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */
{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */
{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */
-{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}} /* 1999/9/9 3:00:00 PDT */
+{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}, /* 1999/9/9 3:00:00 PDT */
+ /* Sun's dates follow */
+ { 0, 0, 0, 2, 31, 11, 1998, 4, 364, {-28800, 0}}, /* 12/31/1998 00:00:00 GMT */
+ { 0, 0, 0, 3, 10, 8, 1999, 5, 252, {-28800, 3600}}, /* 9/10/1999 00:00:00 GMT */
+ { 0, 0, 0, 2, 28, 1, 2000, 1, 58, {-28800, 0}}, /* 2/28/2000 00:00:00 GMT */
+ { 0, 0, 0, 2, 31, 11, 2000, 0, 365, {-28800, 0}}, /* 12/31/2000 00:00:00 GMT */
+ { 0, 0, 0, 2, 1, 0, 2001, 1, 0, {-28800, 0}} /* 1/1/2001 00:00:00 GMT */
};
#ifdef US_EASTERN_TIME
@@ -198,7 +226,13 @@ static PRExplodedTime localt[] = {
{ 0, 0, 0, 5, 29, 1, 2000, 2, 59, {-18000, 0}}, /* 2000/02/29 2:00:00 EST */
{ 0, 0, 0, 5, 1, 2, 2001, 4, 59, {-18000, 0}}, /* 2001/3/1 2:00:00 EST */
{ 0, 0, 0, 5, 1, 2, 2005, 2, 59, {-18000, 0}}, /* 2005/3/1 2:00:00 EST */
-{ 0, 0, 0, 6, 9, 8, 1999, 4, 251, {-18000, 3600}} /* 1999/9/9 3:00:00 EDT */
+{ 0, 0, 0, 6, 9, 8, 1999, 4, 251, {-18000, 3600}}, /* 1999/9/9 3:00:00 EDT */
+ /* Sun's dates follow */
+ { 0, 0, 0, 5, 31, 11, 1998, 4, 364, {-18000 0}}, /* 12/31/1998 00:00:00 GMT */
+ { 0, 0, 0, 6, 10, 8, 1999, 5, 252, {-18000 3600}}, /* 9/10/1999 00:00:00 GMT */
+ { 0, 0, 0, 5, 28, 1, 2000, 1, 58, {-18000 0}}, /* 2/28/2000 00:00:00 GMT */
+ { 0, 0, 0, 5, 31, 11, 2000, 0, 365, {-18000 0}}, /* 12/31/2000 00:00:00 GMT */
+ { 0, 0, 0, 5, 1, 0, 2001, 1, 0, {-18000 0}} /* 1/1/2001 00:00:00 GMT */
};
#endif
@@ -217,6 +251,8 @@ static PRStatus TestExplodeImplodeTime(void)
PR_ExplodeTime(prt[idx], PR_GMTParameters, &et_tmp);
if (!ExplodedTimeIsEqual(&et_tmp, &gmt[idx])) {
fprintf(stderr, "GMT not equal\n");
+ PrintExplodedTime(&et_tmp);
+ PrintExplodedTime(&gmt[idx]);
exit(1);
}
prt_tmp = PR_ImplodeTime(&et_tmp);
@@ -233,6 +269,8 @@ static PRStatus TestExplodeImplodeTime(void)
PR_ExplodeTime(prt[idx], PR_USPacificTimeParameters, &et_tmp);
if (!ExplodedTimeIsEqual(&et_tmp, &uspt[idx])) {
fprintf(stderr, "US Pacific Time not equal\n");
+ PrintExplodedTime(&et_tmp);
+ PrintExplodedTime(&uspt[idx]);
exit(1);
}
prt_tmp = PR_ImplodeTime(&et_tmp);
@@ -249,6 +287,8 @@ static PRStatus TestExplodeImplodeTime(void)
PR_ExplodeTime(prt[idx], PR_LocalTimeParameters, &et_tmp);
if (!ExplodedTimeIsEqual(&et_tmp, &localt[idx])) {
fprintf(stderr, "not equal\n");
+ PrintExplodedTime(&et_tmp);
+ PrintExplodedTime(&localt[idx]);
exit(1);
}
prt_tmp = PR_ImplodeTime(&et_tmp);
@@ -512,6 +552,35 @@ static ParseTest parseArray[] =
{ "69-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}},
{ "69/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}},
+ /* "Sun". 31-Dec-1998 (?) */
+ { "Thu 31 Dec 1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+ { "12/31/98 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+ { "12/31/1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+ { "12-31-98 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+ { "12-31-1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+ { "98-12-31 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+ { "98/12/31 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}},
+
+ /* 09-Sep-1999. Interesting because of its use as an eof marker? */
+ { "09 Sep 1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "9/9/99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "9/9/1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "9-9-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "9-9-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "09-09-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "09-09-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+ { "99-09-09 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
+
+ /* "Sun". 10-Sep-1999. Because Sun said so. */
+ { "10 Sep 1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "9/10/99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "9/10/1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "9-10-99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "9-10-1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "09-10-99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "09-10-1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+ { "99-09-10 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}},
+
/* 31-Dec-1999 */
{ "31 Dec 1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}},
{ "12/31/99 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}},
@@ -530,6 +599,15 @@ static ParseTest parseArray[] =
{ "01-01-00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
{ "Saturday 01-01-2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}},
+ /* "Sun". 28-Feb-2000 */
+ { "28 Feb 2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+ { "2/28/00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+ { "2/28/2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+ { "2-28-00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+ { "2-28-2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+ { "02-28-00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+ { "02-28-2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}},
+
/* 29-Feb-2000 */
{ "29 Feb 2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}},
{ "2/29/00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}},
@@ -547,6 +625,24 @@ static ParseTest parseArray[] =
{ "03-01-00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}},
{ "03-01-2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}},
+ /* "Sun". 31-Dec-2000 */
+ { "31 Dec 2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+ { "12/31/00 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+ { "12/31/2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+ { "12-31-00 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+ { "12-31-2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+ { "00-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+ { "00/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}},
+
+ /* "Sun". 01-Jan-2001 */
+ { "01 Jan 2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+ { "1/1/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+ { "1/1/2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+ { "1-1-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+ { "1-1-2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+ { "01-01-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+ { "Saturday 01-01-2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}},
+
/* 01-Mar-2001 */
{ "01 Mar 2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}},
{ "3/1/01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}},
@@ -581,16 +677,6 @@ static ParseTest parseArray[] =
{ "03-01-05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
{ "03-01-2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}},
- /* 09-Sep-1999. Interesting because of its use as an eof marker? */
- { "09 Sep 1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "9/9/99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "9/9/1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "9-9-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "9-9-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "09-09-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "09-09-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
- { "99-09-09 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}},
-
/* last element. string must be null */
{ NULL }
}; /* end array of ParseTest */
diff --git a/pr/tests/y2ktmo.c b/pr/tests/y2ktmo.c
new file mode 100644
index 00000000..0eab0b3d
--- /dev/null
+++ b/pr/tests/y2ktmo.c
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1999 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Test: y2ktmo
+ *
+ * Description:
+ * This test tests the interval time facilities in NSPR for Y2K
+ * compliance. All the functions that take a timeout argument
+ * are tested: PR_Sleep, socket I/O (PR_Accept is taken as a
+ * representative), PR_Poll, PR_WaitCondVar, PR_Wait, and
+ * PR_CWait. A thread of each thread scope (local, global, and
+ * global bound) is created to call each of these functions.
+ * The test should be started at the specified number of seconds
+ * (called the lead time) before a Y2K rollover test date. The
+ * timeout values for these threads will span over the rollover
+ * date by at least the specified number of seconds. For
+ * example, if the lead time is 5 seconds, the test should
+ * be started at time (D - 5), where D is a rollover date, and
+ * the threads will time out at or after time (D + 5). The
+ * timeout values for the threads are spaced one second apart.
+ *
+ * When a thread times out, it calls PR_IntervalNow() to verify
+ * that it did wait for the specified time. In addition, it
+ * calls a platform-native function to verify the actual elapsed
+ * time again, to rule out the possibility that PR_IntervalNow()
+ * is broken. We allow the actual elapsed time to deviate from
+ * the specified timeout by a certain tolerance (in milliseconds).
+ */
+
+#include "nspr.h"
+#include "plgetopt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(XP_UNIX)
+#include <sys/time.h> /* for gettimeofday */
+#endif
+#if defined(WIN32)
+#include <sys/types.h>
+#include <sys/timeb.h> /* for _ftime */
+#endif
+
+#define DEFAULT_LEAD_TIME_SECS 5
+#define DEFAULT_TOLERANCE_MSECS 500
+
+static PRBool debug_mode = PR_FALSE;
+static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS;
+static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS;
+static PRIntervalTime start_time;
+static PRIntervalTime tolerance;
+
+#if defined(XP_UNIX)
+static struct timeval start_time_tv;
+#endif
+#if defined(WIN32)
+static struct _timeb start_time_tb;
+#endif
+
+static void SleepThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32)
+ struct _timeb end_time_tb;
+#endif
+
+ if (PR_Sleep(timeout) == PR_FAILURE) {
+ fprintf(stderr, "PR_Sleep failed\n");
+ exit(1);
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (debug_mode) {
+ fprintf(stderr, "Sleep thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void AcceptThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32)
+ struct _timeb end_time_tb;
+#endif
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ PRFileDesc *accepted;
+
+ sock = PR_NewTCPSocket();
+ if (sock == NULL) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = 0;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ if (PR_Bind(sock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ if (PR_Listen(sock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+ accepted = PR_Accept(sock, NULL, timeout);
+ if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) {
+ fprintf(stderr, "PR_Accept did not time out\n");
+ exit(1);
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ fprintf(stderr, "Accept thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void PollThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32)
+ struct _timeb end_time_tb;
+#endif
+ PRFileDesc *sock;
+ PRNetAddr addr;
+ PRPollDesc pd;
+ PRIntn rv;
+
+ sock = PR_NewTCPSocket();
+ if (sock == NULL) {
+ fprintf(stderr, "PR_NewTCPSocket failed\n");
+ exit(1);
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.inet.family = PR_AF_INET;
+ addr.inet.port = 0;
+ addr.inet.ip = PR_htonl(PR_INADDR_ANY);
+ if (PR_Bind(sock, &addr) == PR_FAILURE) {
+ fprintf(stderr, "PR_Bind failed\n");
+ exit(1);
+ }
+ if (PR_Listen(sock, 5) == PR_FAILURE) {
+ fprintf(stderr, "PR_Listen failed\n");
+ exit(1);
+ }
+ pd.fd = sock;
+ pd.in_flags = PR_POLL_READ;
+ rv = PR_Poll(&pd, 1, timeout);
+ if (rv != 0) {
+ fprintf(stderr, "PR_Poll did not time out\n");
+ exit(1);
+ }
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (PR_Close(sock) == PR_FAILURE) {
+ fprintf(stderr, "PR_Close failed\n");
+ exit(1);
+ }
+ if (debug_mode) {
+ fprintf(stderr, "Poll thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void WaitCondVarThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32)
+ struct _timeb end_time_tb;
+#endif
+ PRLock *ml;
+ PRCondVar *cv;
+
+ ml = PR_NewLock();
+ if (ml == NULL) {
+ fprintf(stderr, "PR_NewLock failed\n");
+ exit(1);
+ }
+ cv = PR_NewCondVar(ml);
+ if (cv == NULL) {
+ fprintf(stderr, "PR_NewCondVar failed\n");
+ exit(1);
+ }
+ PR_Lock(ml);
+ PR_WaitCondVar(cv, timeout);
+ PR_Unlock(ml);
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ PR_DestroyCondVar(cv);
+ PR_DestroyLock(ml);
+ if (debug_mode) {
+ fprintf(stderr, "wait cond var thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void WaitMonitorThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32)
+ struct _timeb end_time_tb;
+#endif
+ PRMonitor *mon;
+
+ mon = PR_NewMonitor();
+ if (mon == NULL) {
+ fprintf(stderr, "PR_NewMonitor failed\n");
+ exit(1);
+ }
+ PR_EnterMonitor(mon);
+ PR_Wait(mon, timeout);
+ PR_ExitMonitor(mon);
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ PR_DestroyMonitor(mon);
+ if (debug_mode) {
+ fprintf(stderr, "wait monitor thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+static void WaitCMonitorThread(void *arg)
+{
+ PRIntervalTime timeout = (PRIntervalTime) arg;
+ PRIntervalTime elapsed;
+#if defined(XP_UNIX) || defined(WIN32)
+ PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout);
+ PRInt32 elapsed_msecs;
+#endif
+#if defined(XP_UNIX)
+ struct timeval end_time_tv;
+#endif
+#if defined(WIN32)
+ struct _timeb end_time_tb;
+#endif
+ int dummy;
+
+ PR_CEnterMonitor(&dummy);
+ PR_CWait(&dummy, timeout);
+ PR_CExitMonitor(&dummy);
+ elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time);
+ if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#if defined(XP_UNIX)
+ gettimeofday(&end_time_tv, NULL);
+ elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec)
+ + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000;
+#endif
+#if defined(WIN32)
+ _ftime(&end_time_tb);
+ elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time)
+ + (end_time_tb.millitm - start_time_tb.millitm);
+#endif
+#if defined(XP_UNIX) || defined(WIN32)
+ if (elapsed_msecs + tolerance_msecs < timeout_msecs
+ || elapsed_msecs > timeout_msecs + tolerance_msecs) {
+ fprintf(stderr, "timeout wrong\n");
+ exit(1);
+ }
+#endif
+ if (debug_mode) {
+ fprintf(stderr, "wait cached monitor thread (scope %d) done\n",
+ PR_GetThreadScope(PR_GetCurrentThread()));
+ }
+}
+
+typedef void (*NSPRThreadFunc)(void*);
+
+static NSPRThreadFunc threadFuncs[] = {
+ SleepThread, AcceptThread, PollThread,
+ WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread};
+
+static PRThreadScope threadScopes[] = {
+ PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD};
+
+static void Help(void)
+{
+ fprintf(stderr, "y2ktmo test program usage:\n");
+ fprintf(stderr, "\t-d debug mode (FALSE)\n");
+ fprintf(stderr, "\t-l <secs> lead time (%d)\n",
+ DEFAULT_LEAD_TIME_SECS);
+ fprintf(stderr, "\t-t <msecs> tolerance (%d)\n",
+ DEFAULT_TOLERANCE_MSECS);
+ fprintf(stderr, "\t-h this message\n");
+} /* Help */
+
+int main(int argc, char **argv)
+{
+ PRThread **threads;
+ int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc);
+ int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope);
+ int i, j;
+ int idx;
+ PRInt32 secs;
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option) {
+ case 'd': /* debug mode */
+ debug_mode = PR_TRUE;
+ break;
+ case 'l': /* lead time */
+ lead_time_secs = atoi(opt->value);
+ break;
+ case 't': /* tolerance */
+ tolerance_msecs = atoi(opt->value);
+ break;
+ case 'h':
+ default:
+ Help();
+ return 2;
+ }
+ }
+ PL_DestroyOptState(opt);
+
+ if (debug_mode) {
+ fprintf(stderr, "lead time: %d secs\n", lead_time_secs);
+ fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs);
+ }
+
+ start_time = PR_IntervalNow();
+#if defined(XP_UNIX)
+ gettimeofday(&start_time_tv, NULL);
+#endif
+#if defined(WIN32)
+ _ftime(&start_time_tb);
+#endif
+ tolerance = PR_MillisecondsToInterval(tolerance_msecs);
+
+ threads = PR_Malloc(
+ num_thread_scopes * num_thread_funcs * sizeof(PRThread*));
+ if (threads == NULL) {
+ fprintf(stderr, "PR_Malloc failed\n");
+ exit(1);
+ }
+
+ /* start to time out 5 seconds after a rollover date */
+ secs = lead_time_secs + 5;
+ idx = 0;
+ for (i = 0; i < num_thread_scopes; i++) {
+ for (j = 0; j < num_thread_funcs; j++) {
+ threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j],
+ (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL,
+ threadScopes[i], PR_JOINABLE_THREAD, 0);
+ if (threads[idx] == NULL) {
+ fprintf(stderr, "PR_CreateThread failed\n");
+ exit(1);
+ }
+ secs++;
+ idx++;
+ }
+ }
+ for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) {
+ if (PR_JoinThread(threads[idx]) == PR_FAILURE) {
+ fprintf(stderr, "PR_JoinThread failed\n");
+ exit(1);
+ }
+ }
+ PR_Free(threads);
+ printf("PASS\n");
+ return 0;
+}